Command GetNumCharsWaiting() in Subroutine

I have a subroutine that opens a TCP pipe to an Ethernet device. The process for the subroutine is:

  1. Open a TCP pipe to the ethernet device
  2. Send a command string to the device.
  3. Check for a waiting return value using GetNumCharsWaiting()
  4. Get the string using the ReceiveNChars() command. Using the number of characters returned above as an argument to the ReceiveNChars() command.

When I step into the subroutine in debug mode it returns the correct number of characters. When I step over the subroutine it returns a 0 as the number of characters waiting.

What is going on? Have I found a bug?

Is the subroutine parameter holding the number of characters a literal or a variable? If you want to see the value from the subroutine it needs to be setup as a variable.

The number of characters is a variable within the subroutine; it is not passed out of the subroutine. The subroutine uses this value to receive a string with ReceiveNChars() that is passed out of the subroutine; the parameter passed out of the subroutine is a variable string.

So I assume you are calling GetNumCharsWaiting in the subroutine? In debug, once you step out of the subroutine, you can no longer see any of the variables inside it.

No, that’s not what I’m seeing. When I step into the subroutine GetNumCharsWaiting returns a proper value. When I step over the subroutine GetNumCharsWaiting will return a 0 value, an incorrect value, for the number of characters waiting. In both cases, GetNumCharsWaiting is called from inside the subroutine.

How are you viewing the value returned by GetNumCharsWaiting?

I added a temporary return value to the subroutine.

Is this temporary value parameter setup as an integer variable?

The temporary value was set up as an integer variable.

Does your subroutine loop back if there are no characters waiting and wait for them to arrive?

I suspect when stepping over, there are no characters waiting because they haven’t arrived yet on the network.

My subroutine does not loop back. Can you give me an example?

image

This flow will wait for some characters to show up or timeout.

2 Likes

This thread is a really solid one that has helped a lot of people get up and running.
Review both the thread posts and Mary’s link.

Here’s what I’ve come up with, see below. This appears to work. Would you need a similar delay and retry anywhere there was a poll/response between the external and Opto22 controller? For example, in the bolded lines of the code listed below.

Why wouldn’t handshaking be part of the OptoScript commands?

Dale

/////////////////////////////////////////////////////// Code Starts Here ////////////////////////////////////////////////////////
// Initialize variables
sReturnString = “SubUndef”;
nReturnStatus = -99;
nSubCharCount = 0;
nRecBuffFlag = 1;
sResponse = “SubUndef”;

//Open a communcation handle
sComString = “tcp:” + slIPAddress + “:50001”; //Construct the connection string
SetCommunicationHandleValue(sComString, chSpellmaneSL); //Comm handle for Spellman eSL power supply
nStatus = OpenOutgoingCommunication(chSpellmaneSL); //Open an outing communcation channel

//Build string and send it
sSendString = chr(2) + slCode + “,” + chr(3); // Build a string to transmit
nStatus = TransmitString(sSendString, chSpellmaneSL); //transmit the Spellman command string

//Setup a timer
SetDownTimerPreset(1.0,SpellmanTimeout); //Set the spellman time
StartTimer(SpellmanTimeout); //Start the timeout timer

//Wait for characters in the buffer or timeout
while (nRecBuffFlag == 1)
nSubCharCount = GetNumCharsWaiting(chSpellmaneSL); //Get number of characters in buffer
if (nSubCharCount == 0) then
if (HasTimerExpired(SpellmanTimeout)) then
nRecBuffFlag = 0; //Set flag to stop trying to receive buffer
nStringReturnStatus = -1; //set subroutine as a failed return status
else
DelayMsec(10); //Wait for 2 spellman scan cycles
nRecBuffFlag = 1; //Set flag to continue to receive the buffer
endif
else
nRecBuffFlag = 0; //Set flag to stop trying to receive buffer
nStringReturnStatus = 0; //set subroutine as sucess return status
endif
wend

//Get the characters waiting and close socket
nStringReturnStatus = ReceiveNChars(sReturnString, nSubCharCount, chSpellmaneSL);
nStatus = CloseCommunication(chSpellmaneSL); //Close the spellman network socket

//Clip first and last character of return string
nEndPos = nSubCharCount - 2; //Find last character in string
GetSubstring(sReturnString, 1, nEndPos, sResponse);

// Return the Spellman return string
sSpellReturnString = sResponse;
nReturnStatus = nStringReturnStatus;

/////////////////////////////////////////////////////// Code Ends Here ////////////////////////////////////////////////////////

No, OpenOutgoingCommunication will not return until there is a connection or a timeout.

I’m not sure what you mean.

Note that you should only open the comm handle one time and leave it open if you are going to continue to communicate to the device. If you run your current code in a loop you will exhaust the networking resources on the controller.

Will the TransmitString() command not return until there is a timeout? This is what I mean by “handshaking.”

Thanks for the tip on not closing the comm handle on every transaction.

No, TransmitString returns right away, and that is a good thing for being able to handle communications asynchronously.

There is a Transmit Receive String command that will wait until the data is received or timeout, but you need to have payload with a termination character (which you may have).

How do I know what commands do not wait for data to be received or a timeout and those that do?

Dale

For the most part, if it has the word receive in the name it will wait until it receives something or times out.