Serial queue with RS-232 connection

Hi all,

I’m starting out writing my first PAC Control strategy and had a question about how best to handle communicating with multiple serial devices on the same comm handle.

For reference, I’m talking to a bunch of Alicat devices through one of their BB-9 boards, which essentially combines separate devices onto a single RS-232 connection, each device being addressable by a unit ID (“A”, “B”, etc).

All I really want to do is be able to poll the device status and occasionally send a command or two. I know how to do this using a single chart for a single device, but with multiple devices operating on a single comm handle, it becomes a bit more complicated.

My initial thought was to have separate charts for each device and use a flag lock to ensure they don’t overwrite/overread each other on the comm handle, with a delay at the end of each. That does seem to work, but it also seems like the charts aren’t necessarily executed in order – sometimes my B device will get data for a while (10-20s) before A or C get anything.

I was wondering if there is a better way of doing this (besides building my own round-robin queue) to ensure each chart gets run in order, or if there is a different way of doing it altogether.

Thanks!
Patrick

It is difficult to manage a singled comm handle in multiple charts, as a rule you should avoid that, though as you found it can be done with appropriate locking.

I would recommend a single chart in a loop where you iterate through the Unit Ids. You can also implement a timer/timer table for polling each device. That is useful for when you may have devices that are offline where you can increase the polling time for those to keep the rest of the devices responsive.

Here is a short example of a polling timer table:

if(utPollingUpTimer == 0.0) then
  StartTimer(utPollingUpTimer);
endif

if(utPollingUpTimer > 0.5) then
  //increment timer table
  fPollingTimerValue = GetRestartTimer(utPollingUpTimer);
  for nLoopVar = 0 to 10 step 1
    ftTimerTable[nLoopVar] = ftTimerTable[nLoopVar] + fPollingTimerValue;
  next
endif

Here is a structure on how to handle polling the devices in a loop with handling a timeout and increasing the poll time in that case. DoCommWork could be a subroutine you create or you can put the logic directly in the loop.

for nLoopVar = 0 to 10 step 1
  if(ftTimerTable[nLoopVar] > ftPollTime[nLoopVar]) then //time to get data
    ftTimerTable[nLoopVar] = 0.0;
    sUnitId = stUnitId[nLoopVar];
    //Do comm work here for sUnitId
    //DoCommWork(sUnitId, sResults, nTimeoutError);

    if(nTimeoutError) then
      ftPollTime[nLoopVar] = 60.0; //Retry in 60 seconds
    else
      ftPollTime[nLoopVar] = fDefaultPollTime;
    endif
  endif
next

For sending commands (based on some other trigger), I would create a queue to put the commands in and check the queue as part of the loop. The command queue could be outside of the polling timer condition so they are sent immediately.

2 Likes

This is extremely useful advice, thanks so much! I’ll try this approach.

1 Like