A real world migration from TI-RTOS to the POSIX API of TI SimpleLink. Texas Instruments migrated from the proprietary TI-RTOS to the open POSIX API. I'm migrating a project that extensively used the TI paradigms to that POSIX API. You're my witness.
|
Hardcore POSIX again. Moving from TI-RTOS MailBox API to POSIX message queues. Again, not too complex. The changes to the code are small.
As always, the ideas are not my own. This time I used a Stack Overflow question as guideline: https://stackoverflow.com/questions/3056307/how-do-i-use-mqueue-in-a-c-program-on-a-linux-based-system.
Message Queue
The use of a POSIX message queue is virtually identical to a TI-RTOS MailBox.
You have a task that puts info on the message queue. In our case, that is a SCPI command that tells our Programmable Electronic Load to enable or disable its input.
There's also a task that listens to the message queue and is woken up by the RTOS when a message is available on the mailbox. In our case the task that guards the Input Enable functionality.
If nothing is posted on that queue, the message is inactive and takes very little resources. Only when the SCPI command puts a message on the queue, the task gets processor time to consume the message and go back to sleep.
In the spirit of this blog series, I don't show the original TI-RTOS code. You can find it back by surfing to github:
Let's first look at the consumer side - the task that sleeps unless there's a message arriving. The first part of that task initialises the queue in read mode. The while() loop sleeps and reacts on messages.
#include <mqueue.h>
#include mqd_t mq; struct mq_attr attr; attr.mq_flags = 0; attr.mq_maxmsg = 1; attr.mq_msgsize = MSGINPUTENABLE_SIZE; attr.mq_curmsgs = 0; mq = mq_open(QUEUE_NAME_INPUTENABLE, O_CREAT | O_RDONLY, 0644, &attr); while (1) { ssize_t bytes_read; bytes_read = mq_receive(mq, (char *)&d_msg, MSGINPUTENABLE_SIZE, NULL); /* wait for mailbox to be posted by writer() */ if (bytes_read) { d_iotxBuffer[1] = d_msg.value ? 0x3F : 0xFF; // bit 7 low is output enable. if (! I2C_transfer(i2c_implGetHandle(), &d_ioi2cTransaction)) { } else { bInputEnable_State = d_msg.value; } } } }
The sender side is also straightforward. We post a message when we want to enable or disable our instrument's input.
#include void eloadInputEnable(bool bEnable) { MsgInputEnable pMsg; // value has to be validated before it arrives here. We assume it's valid pMsg.value = bEnable; /* enqueue message */ mqd_t mq; mq = mq_open(QUEUE_NAME_INPUTENABLE, O_WRONLY); mq_send(mq, (char *)&pMsg, MSGINPUTENABLE_SIZE, 0); }
In this case, we open the queue for writing. I don't close the queue - not sure if that's correct or if I'm leaking resources. Shout out in the comments if this is wrong.
To understand the code a little better, here's the declaration of the message structure:
#define QUEUE_NAME_INPUTENABLE "/inputenable_queue" typedef struct MsgInputEnable { bool value; } MsgInputEnable; // for TI-RTOS message size, use the structure size: #define MSGINPUTENABLE_SIZE (sizeof(MsgInputEnable))
The whole setup isn't very different from what's happening in TI-RTOS. And the functionality is identical.
Very little resources are necessary to support the mechanism. No loops are polling for input. The microcontroller time is either spent on another task or the processor goes into a well deserved sleep.
Top Comments