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.
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.