RTOS Mail

A fejezet tartalma:

Az mbed-RTOS Mail (levélküldés) szolgáltatása az üzenetsor (Queue) és a vele társított memóriakészlet (MemoryPool) tulajdonságait egyesíti egyetlen objektumosztályban. Ennek annyi előnye van csupán, hogy nem kell külön-külön példányosítanunk az üzenetsort és a memóriakészletet, s így nem kell külön névvel bajlódnunk és véletlenül sem fordulhat elő, hogy azokat különböző típusúnak vagy méretűnek definiáljuk. Az előzőekhez hasonlóan az mbed-RTOS Mail is templát osztály, azaz nekünk meg megadnunk, hogy milyen adatstruktúrákat tároljon, és azokból legfeljebb hány darabot.


1. ábra: Az mbed-RTOS levélküldő szolgáltatása

Levelesláda létrehozása

Meg kell adnunk az elküldeni kívánt üzenetek (levelek) struktúra típusát, és az egyidejűleg tárolni kívánt üzenetek maximális darabszámát (a levelesláda méretét). Például:

typedef struct {
float voltage; // ADC feszültségmérés eredménye
float current; // ADC árammérés eredménye
uint32_t counter; // Egy kiolvasott számláló értéke
} message_t;

Mail mailbox; // 16 elemű levelesláda létrehozása

Levelesláda kezelése

Üzenetküldés szempontjából az mbed-RTOS Mail is templát osztály ugyanúgy használható, mint a Queue üzenetsor, memóriakezelés (lefoglalás, eltárolás, felszabadítás) szempontjából pedig ugyanolyan, mint a MemoryPool (memória készlet). Ezek alapján nem meglepő, hogy a Mail osztály tagfüggvényei a Queue és a MemoryPool tagfüggvényeinek egyesített halmazát imitálják. Van azonban néhány apró különbség a paraméterezésben.

A memória blokkok lefoglalása a Mail objektumpéldányok alloc() metódusával végezhető:

T*  alloc ( uint32_t timeout = 0 )       
Paraméterek:

timeout - a maximális várakozási idő, ezredmásodpercekben megadva. Az alapértelmezett 0 érték azt jelenti, hogy nincs várakozás.

Visszatérési érték:

A függvény visszatérési értéke a szabad memória blokkra mutató pointer, vagy NULL, hiba esetén. A kapott pointer típusa (amit itt a T* jelöl) olyan adatstruktúrára mutató lesz, amilyen struktúra típust a Mail példányosításakor megadtunk.

Megjegyzés: Ez a függvény megszakításból is hívható, de csak 0 paraméterrel!

A felhasznált memória blokk felszabadítása a Mail objektumpéldányok free() metódusával végezhető:
osStatus free ( T *  mptr )        
Paraméterek:

mptr - az absztrakt T típusú üzenetre mutató pointer, amelyet a Mail::get() hívásakor kaptunk. A T* olyan adatstruktúrára mutató típust jelent, amilyen struktúra típust a Mail példányosításakor megadtunk.


Visszatérési érték:

A függvény visszatérési értéke az alábbi státusz, vagy hibakódok valamelyike lehet:
  • osOK: a memória blokk felszabadult
  • osErrorValue: a blokk nem tartozik a levelesláda által lefoglalt memória területhez
  • osErrorParameter: érvénytelen paraméter
Megjegyzés: Ez a függvény megszakításból is hívható.

Az üzenetek küldése a Mail objektumpéldányok put() metódusával végezhető:
osStatus put ( T *  mptr )        
Paraméterek:

mptr - az absztrakt T típusú üzenetre mutató pointer

Visszatérési érték:

A függvény visszatérési értéke az alábbi státusz, vagy hibakódok valamelyike lehet:
  • osOK: az üzenet bekerült az üzenetsorba
  • osErrorValue: az üzenet tárhelye előzőleg nem lett lefoglalva
  • osErrorParameter: érvénytelen paraméter
Megjegyzés: Ez a függvény megszakításból is hívható.

Az üzenetek fogadása a Mail objektumpéldányok get() metódusával végezhető:
osEvent get ( uint32_t  timeout = osWaitForever )        
Paraméterek:

timeout - a maximális várakozási idő, ezredmásodpercekben megadva. A várakozás alapértelmezetten korlátlan ideig tarthat.

Ha 0 értéket adunk meg, az azt jelenti, hogy nincs várakozás, tehát ha van a tárban üzenet, akkor kivesszük, egyébként pedig hibakóddal tér vissza a függvény.

Visszatérési érték:

A függvény visszatérési értéke egy osEvent típusú struktúra, melynek status nevű eleme az alábbi státusz, vagy hibakódok valamelyike lehet:
  • osOK: nincs beérkezett üzenet (ha timeout 0-nak volt megadva)
  • osEventTimeout: a megadott várakozási idő alatt nem érkezett üzenet
  • osEventMail: üzenet érkezett, melynek mutatóját az osEvent típusú struktúra value.p elemére történő hivatkozással vehetünk elő.
  • osErrorParameter: érvénytelen paraméter, vagy a paraméter értéke kívül esik a megengedett tartományon.

Megjegyzés: Ez a függvény megszakításból is hívható, de csak 0 várakozási értékkel.

Mintapélda: Üzenetküldés a Mail objektumosztály használatával

Az alábbi program csupán az előző fejezetben mutatott mintapélda átirata. A programban most is három lebegőpontos (float) típusú adatot tartalmazó adatstruktúrákat küldözgetünk üzenet gyanánt, melyeknek itt egy Mail típusú levelesláda biztosít tárterületet.

Az első programszál véletlen színek közötti átmenetekhez generál RGB színkódokat interpolációval (a színkomponensek 0 - 1.0 közötti lebegőpontos számok), s ezeket a színkódokat küldjük el üzenetként, s minden üzenet után 0.1 másodpercet várunk.

A második programszál fogadja az üzeneteket, az RGB LED-en megjeleníti a kapott színkombinációt, majd felszabadítja a kapott üzenethez tartozó memória blokkot.

  Hardver követelmények:
1. lista: A 11_rtos_mailbox/main.cpp program listája
#include "mbed.h"
#include "rtos.h"
PwmOut rled(LED_RED);
PwmOut gled(LED_GREEN);
PwmOut bled(LED_BLUE);

typedef struct {
float red;
float green;
float blue;
} message_t;

Mail <memory_t,4> mbox; //Mailbox for 4 messages

void led_thread(void const *argument) {
rled.period_ms(20); //Set period to 20 ms
rled.write(1.0f); //Initialize to 0% duty cycle
gled.period_ms(20); //Set period to 20 ms
gled.write(1.0f); //Initialize to 0% duty cycle
bled.period_ms(20); //Set period to 20 ms
bled.write(1.0f); //Initialize to 0% duty cycle
while (true) {
osEvent evt = mbox.get(); //Wait for a message
if(evt.status == osEventMail) {
message_t *mymessage = (message_t*)evt.value.p;
rled = 1.0f - mymessage->red;
gled = 1.0f - mymessage->green;
bled = 1.0f - mymessage->blue;
mbox.free(mymessage); //Free up memory
}
}
}

float frand(void) {
int32_t rv = 0x8000 -(rand()&0xFFFF);
return (rv*rv/1073741824.0f);
}

int main (void) {
float RGB1[3];
float RGB2[3];
float INC[3];
Thread thread2(led_thread);
//--- Create a random color ---------------------
for (int x=0; x<3; x++) {
RGB1[x] = frand();
}

while (true) {
//--- Create a new random color -----------------
for (int x=0; x<3; x++) {
RGB2[x] = frand();
}
//--- Determine increments to go from color 1 to color 2 in 25 steps
for (int x=0; x<3; x++) {
INC[x] = (RGB1[x] - RGB2[x]) / 25;
}
//--- Send color codes to thread2 ---------------
for (int s=0; s<25; s++) {
message_t *message = mbox.alloc(); //Allocate memory
message->red = RGB1[0];
message->green = RGB1[1];
message->blue = RGB1[2];
mbox.put(message); //Send data as message
Thread::wait(100);
for (int x=0; x<3; x++) {
RGB1[x] -= INC[x]; //Approach to second colour
}
}
}
}
Megjegyzés: A véletlenszám generátor itt egy újabbra cseréltük, az előző fejezethez képest, abban a reményben, hogy ez talán előnyben részesíti a "tisztább" színeket, a kevert átlag helyett.