As you know I am working on an Industrial Control System — ICS/DCS to be more specific — and this system requires a task schedule to activate some pumps with a very strict calendar, monitoring the amount of liquid that has been passed through the valve, and it should allow manual operations, interrupting the automatic operation of that node on the plant. This seems to be difficult to implement, as I wrote in past posts, we are using a priority queue that contains task requests, where every priority is entirely dynamic, and dependent on the state of the current state machine that is being executed according to the operation request.
During the state machine execution, each state transition has a guard ensuring that the step that will take place on the transition is guaranteed to be executed depending on the environment, if not the step is reserved to the next PLC scan cycle — do you remember that ProView operates C and C++ applications like PLC programs?. The same guard ensure that the operation on the pump will take the required minutes to deactivate the pump, meeting the task calendar. Once the pump is active, its task priority — which is hold on the request data structure — changes its priority, and using the top() and pop() methods of the STL std::priority_queue, is extracted from the queue, the priority is changed, and it is pushed again on the queue using the push() method.
All requests that are using the communication channel have the higher priority, because we have only one communication channel, so we must ensure some concurrency on the channel usage, and we call the io_read() and io_write() ProView functions only once it is required, ensuring that the communication channel is used by one device at time. I think that this is the biggest problem of the system, because the communication channel is very small, and shared between several devices, and it must be used concurrently. But locks are not an option. If the channel blocks due to its usage, the system should continue its work and must keep its system review — reviewing channel status and signal status, and reviewing the error status for several devices.
Since several requests are not using the communication channel, the queue never gets saturated, and every transition is executed. It only blocks on communication channel usage, but it calls the io_read() and io_write() ProView functions rather than using some kind of lock, like semaphore or similar one. Also, errors are not allowed, the code should not have any programming error, and it is being traced by strace(1) and valgrind(1). Also, we are thinking to check the model using spin(1), I have started some Promela code related to the processing model, at least it looks well for now. It will probably get more complexity on the future, but the model looks well, and the code seems to be really good.