I’m writing a linux-based app using posix timers (not FreeRTOS) but I believe the approach to this problem should be similar to how it’d have been done in FreeRTOS. Feel free to delete this question if it violates any rules. Apologies in advance but any help is greatly appreciated.
The idea is there’s an app that needs to send certain commands over UART every specific intervals. For instance, <CMD-A> needs to be sent every X seconds whereas <CMD-B> every Y seconds.
My initial thought was having a timer for each command (via timer_create()) and setting the expiry/reload time accordingly. So if I have 5 different commands, I’d have 5 different timers that would invoke a callback within a new thread every expiry time, and the callback sends the passed-in command over to serial port.
I have a couple questions:
Would it sound feasible to have timers instantiated for each command? Say, TimerA sends <CMD_A> every X seconds whereas TimerB sends <CMD_B> every Y seconds. This way these two timers are independently invoking a callback that sends a corresponding command over to serial port. Are there better ways around it? Could I really make it work with a single timer? I have been able to run it fine on my end but i’m uncertain of consequences as I scale up the app.
Given I could have timer for each function, in what scenario would it make sense to have timers defined inside respective threads?
This architecture looks extremly error prone and unfitting for the problem at hand. A UART by definition must be addressed in a strictly serialized fashion. Trying to drive data out of the same UART from several logical strands of execution may yield all kinds of concurrency problems.
Of course, if you use OS timers, you “coincidentally” end up driving the UART from the same task (the timer task), but the control flow still obfuscates the necessity for a strictly serialized driver. The other issue, of course, is that depending on your protocol, you may also need to read and evaluate the responses “in line” which means potentially starving out the other timers serviced.
Typically, a protocol driver works the other way around. There is a dedicated task for output that may be message box driven and emits the approriate commands when a message is received. You really want your UART driven by a single thread of execution.
Trying to drive data out of the same UART from several logical strands of execution may yield all kinds of concurrency problems.
Makes sense. But posix timer fires the callback at a specific time and if both timers have the same expiry, one would fire before another does, no?
you may also need to read and evaluate the responses “in line” which means potentially starving out the other timers serviced
are you implying the case where the main thread needs to send stuff over UART and what if that happens during the expiry time of any of the timers?
Basically I’m thinking of having one MAIN layer that talks directly to the UART driver and the timer APIs reside under that MAIN layer. MAIN layer would have two threads: one would be blocked on reading UART data over serial port while another that takes inputs from local tasks (including timer) and sends it over to serial port.
So the MAIN thread shall have one message queue that the timers would write to when they need to send over serial port
I don’t know about POSIX timers and their contexts, so I will not be able to answer that question. But in any case you will need to address the question what happens at time stamp 10 if you have one periodic timer firing at 2 and another one at 5. Is is feasible protocol wise if in one scenario your 2 timer fires first and in another scenario timer 5? I believe that you are much better off trying to be deterministic which is easier if you serve the entire protocol sequence in a single task.
No, I was just thinking through your proposed architecture. In your original post you implied that any timer expiration function would need to write data out the serial port. In synchronous protocols (see below) that means you must wait for a response. In order to prevent other timer callbacks to write stuff out before the answer is processed, you will need to synchronize that with your timer callback, but that may well mean you delay your callback such that other timers get starved out.
This architecture will only work on full duplex asynchronous protocols which are extremly rare. Most protocols are synchronous, which makes separate read and write tasks on the same physical port useless because you will need to synchronize the reads and writes anyways so a single task would be the better solution in all respects.
Is is feasible protocol wise if in one scenario your 2 timer fires first and in another scenario timer 5?
Perhaps there could be a priority set for commands that need to be sent out around the time. So if timer 2 has a higher priority than timer 5, and they both expire around the same time, timer 2 would go first. Perhaps? How could you make it more deterministic?
In synchronous protocols (see below) that means you must wait for a response. In order to prevent other timer callbacks to write stuff out before the answer is processed, you will need to synchronize that with your timer callback, but that may well mean you delay your callback such that other timers get starved out
That’s a good point. Yes I must wait for a response/ACK after sending the command through timer over serial port and it could starve other timers that were supposed to fire around the same time. Are you suggesting to get around it by using a single task? Like one task that has all the timers instantiated inside it?
I already outlined that here. That’s a fairly typical control flow. In this case, you may have typed mailbox commands such as “send timer 2 command”, “send timer 5 command” (which are put into the mailbox by expired timers or any other mechanisms), “send DS packet xyz” or something. In first approximation, that works well enough, but soon you’ll discover that periodic commands are best processed inline (otherwise you run into issues like overflowing mail boxes when the peer is offline). Something like this:
forever do
{
read from mailbox with timeout();
if success emit packet from mailbox queue, read response and process
else
if timer2 expired* emit timer2 command, read response and process
else
if timer5 expired* emit timer5 command, read response and process
else
delay task to allow other tasks the CPU
}
In this case, the best strategy to implement the timers is simply to record the last invocations of the respective timer commands, for example as timer tick stamps and compute the delta between the current timer tick and the last recording. No need whatsoever for asynchronous timers, they just give you headaches.
This encapsulates all accesses to the serial port in one task and makes the control flow much more obvious, linear and robust.
In this case, you may have typed mailbox commands such as “send timer 2 command”, “send timer 5 command” (which are put into the mailbox by expired timers or any other mechanisms)
So we are still defining a timer for each command to be sent out? It’s just each timer writes the respective command to the mailbox/message queue of the main task which you send it over serial port.
Following is my understanding:
/* timers.c */
timer_t timer2, timer5, timer10;
// each timer is instantiated via `timer_create()` and `timer_settime()`.
/* main.c */
mqd_t mainMsgQueue;
void callbackThread(union sigval sigev_value) // invoked every expiry time for each timer
{
// parse the data and write to mainMsgQueue
}
void mainThread(void *args)
{
while(1)
{
// block on mainMsgQueue
// stuff the data from mainMsgQueue into a packet
// send it over serial port
// wait for an ACK/response
}
}
int main(void)
{
// create mainThread via pthread_create
}
how are you dealing with timer starvation in case both commands expire at the same time given there’s a wait time for an ACK/response for each command sent?