The Arduino-compatible IDE or integrated development environment for the LaunchPads is called Energia. Energia also includes Energia MT for selected boards, including the MSP432 LaunchPad, the CC3200 LaunchPad and the CC2650 SensorTag..
Energia MT stands for Energia Multi-Tasking and is based on Texas Instruments RTOS, aka. Real Time Operating System. Real-time means each task is completed within a determined period of time, and RTOS is an operating system built on it.
I've developed libraries which encapsulate the RTOS elements into classes with a consistent and minimal set of functions. The goal is to provide libraries with the same ease of use as the standard classes (e.g. SPI, I²C, Serial) provided by the Wiring / Arduino framework. All the libraries are bundled in one single package called Galaxia, and are included in the Energia distribution.
Problem: How to Send and Manage Data Across Tasks?Let's consider three tasks:
- Two tasks and senders and send messages.
- The third task is the client, receives and prints the messages.
We want the message to include a timestamp and a text. Here is the corresponding structure.
// myMessage type for mailbox
typedef struct myMessage_t
{
uint32_t chrono;
char buffer[10];
};
Mailbox with Two Senders and One ReceiverThe mailbox is defined by two parameters:
- the kind of data, here the structure myMessage_t
- the number of slots, here 4 set during initialisation with begin().
Contrary to the Queue element that stores pointers, the Mailbox element copies and stores the messages inside. This provides a safe and clean way for sending data from one task to another.
// myMessage type for mailbox
typedef struct myMessage_t
{
uint32_t chrono;
char buffer[10];
};
// Number of messages on the mailbox
#define NUMBER 4
// Mailbox post modality: either BIOS_WAIT_FOREVER or BIOS_NO_WAIT.
#define MODALITY BIOS_WAIT_FOREVER
// myMailbox
Mailbox<myMessage_t> myMailbox;
The Mailbox element shares the same logic and same limitation with the Event element. The Mailbox element can have multiple senders but only one receiver.
The Two Senders
The first sender includes a setup() function to initialise the Serial port and the mailbox myMailBox. Here, the mailbox is set with NUMBER = 4 slots.
void MailboxSender1_setup()
{
Serial.begin(115200);
myMailbox.begin(NUMBER); // default = 16
}
The two senders share the same code for the loop() function.
void MailboxSender1_loop()
{
messageS.chrono = millis();
strcpy(messageS.buffer, "from 1");
// Mailbox post modality: either BIOS_WAIT_FOREVER or BIOS_NO_WAIT.
bool result = myMailbox.post(messageS, MODALITY);
delay(300);
}
The Client
The client loop() waits for a message to be available, and prints it to the Serial port.
void MailboxClient_loop()
{
myMailbox.waitFor(messageR);
mySemaphore.waitFor();
Serial.print("*<\t");
Serial.print(millis(), DEC);
Serial.print("\tRX\t");
Serial.print(messageB.chrono, DEC);
Serial.print("\t");
Serial.print(messageB.buffer);
Serial.print("\t");
Serial.print(myMailbox.available());
Serial.println("\t:\t");
mySemaphore.post();
delay(300);
}
The available() function returns the number of messages on the mailbox to be read. 0 means the mailbox is empty.
The MODALITY ParameterIf there's no slot available and one client wants to send a message, what happens? How to manage it?
The solution is the important parameter MODALITY. There are two values: BIOS_WAIT_FOREVER and BIOS_NO_WAIT.
Depending on the MODALITY value,
- If MODALITY is set to BIOS_WAIT_FOREVER, the post() function waits until a slot is available, and then posts the message and returns TRUE.
? Chrono Action Message Available Result
? .chrono .buffer
1> 6 TX 6 from 1 1 1
*< 100 RX 6 from 1 1
2> 102 TX 100 from 2 1 1
2> 304 TX 304 from 2 2 1
*< 402 RX 100 from 2 1
2> 506 TX 506 from 2 2 1
1> 508 TX 508 from 1 3 1
*< 704 RX 304 from 2 2
2> 708 TX 708 from 2 3 1
2> 910 TX 910 from 2 4 1
*< 1006 RX 506 from 2 3
1> 1010 TX 1010 from 1 4 1
*< 1308 RX 508 from 1 4
2> 1310 TX 1112 from 2 4 1
*< 1610 RX 708 from 2 4
1> 1612 TX 1512 from 1 4 1
*< 1912 RX 910 from 2 4
2> 1914 TX 1513 from 2 4 1
*< 2214 RX 1010 from 1 4
1> 2216 TX 2115 from 1 4 1
*< 2516 RX 1112 from 2 4
2> 2518 TX 211 from 2 4 1
- If MODALITY is set to BIOS_NO_WAIT, the post() function posts the message if a slot is available and return TRUE, otherwise return FALSE as the message hasn't been posted.
? Chrono Action Message Available Result
? .chrono .buffer
1> 6 TX 6 from 1 1 1
*< 100 RX 6 from 1 1 1
2> 102 TX 100 from 2 1 1
2> 304 TX 304 from 2 2 1
*< 402 RX 100 from 2 1 1
2> 506 TX 506 from 2 2 1
1> 508 TX 508 from 1 3 1
*< 704 RX 304 from 2 2 1
2> 708 TX 708 from 2 3 1
2> 910 TX 910 from 2 4 1
*< 1006 RX 506 from 2 3 0 <= not posted
1> 1010 TX 1010 from 1 4 1
2> 1112 TX 1112 from 2 4 0 <= not posted
*< 1308 RX 508 from 1 3 0 <= not posted
2> 1314 TX 1314 from 2 4 1
1> 1512 TX 1512 from 1 4 0 <= not posted
2> 1516 TX 1516 from 2 4 0 <= not posted
*< 1610 RX 708 from 2 3
2> 1718 TX 1718 from 2 4 1
Compare the messages marked as <= not posted and the timestamps between the two logs.
ConclusionThe option BIOS_NO_WAIT allows the post() process to be non-blocking, at the expense of loosing messages. So the returned value should be tested.
Comments