RTOS Tasks and Timers Reference¶
RFID Tasks¶
pollNewTask (void *params)
pollNewTask()
is the entry point for the RFID control loop. Once it detects a new card it suspends itself. It is very important it is resumed at the appropriate places for the control loop to keep
functioning (ie. once we have entered timeoutTask
). However, this also means that we can disable this task as a means of suspending the RFID functionality, see the EstopFire and
EstopClear tasks for more details.
This task also receives a task notification. This notification is made from onMqttMessage()
when a card is denied by the server. The LEDParam structs are out of scope of the MQTT callback functions
of the AsynMQTTClient library and I could not figure out a way of passing them the value. Instead pollNewTask()
, which is also resumed when a card is denied, is notified so that it may change the LEDParams
to blinking red.
When WiFi/MQTT is connected only CARD_BIT_0 is set in pollNewTask()
and AUTH_BIT_1 is set elsewhere in onMqttMessgae()
based the MQTT payload of tool/auth/rsp
.
When a WiFi or MQTT disconnection event occurs WIFIOUT_BIT_7 is set. This is detected by bitmasking xEventGroupGetBits(rfidStatesGroup)
to check the 7th bit (WIFIOUT_BIT_7)
to see if it has been set. If the WIFIOUT_BIT_7 has been set both CARD_BIT_0 and AUTH_BIT_1 are set within pollNewTask()
without server authorization.
This is where future implementation for flash memory logging should be placed.
RTOS API calls summary
WaitBits() |
SetBits() |
GetBits () |
vTaskDelay() |
TaskNotifyTake() |
vTaskSuspend |
---|---|---|---|---|---|
N/A |
If WIFIOUT_BIT_7 not set CARD_BIT_0 |
Used to check WIFIOUT_BIT_7 |
MS_POLL_TIMER |
notificationValue == 1 toggle LEDparams n Red blinkTemp |
NULL |
N/A |
If WIFIOUT_BIT_7 is set else CARD_BIT_0 | AUTH_BIT_1 |
pollPresTask(void *params)
Unblocks when CARD_BIT_0 and AUTH_BIT_1 are set. Because both pollPresTask
and collPollTask
occur in the same state and both utilize the SPI bus a Mutex is given/taken by the two Tasks.
If pollPres()
detects that a card has left the RF field the CARD_BIT_0 and AUTH_BIT_1 is cleared then the TIMEOUT_BIT_3 is set. This unblocks the timeoutTask()
while placing both
pollPresTask()
and collPollTask()
back in the blocked state.
LEDs are set to blink blue when a card removal is detected.
WaitBits() |
SetBits() |
ClearBits () |
vTaskDelay() |
SemaphoreGive/Take () |
vTaskResume () |
---|---|---|---|---|---|
CARD_BIT_0 | AUTH_BIT_1 |
TIMEOUT_BIT_3 |
CARD_BIT_0 | AUTH_BIT_1 |
MS_POLL_TIMER_PERIOD |
SPIMutexHandle |
blinkLEDHand0/1 |
collPollTask(void *8*params)
Unblocks when CARD_BIT_0 and AUTH_BIT_1 are set. It gives/takes a mutes with pollPresTask()
to avoid conflicting access of the SPI bus. If a collision is detected by collPolling()
CARD_BIT_0 | AUTH_BIT_1 are cleared and the TIMEOUT_BIT_3 | COLL_BIT_4 are set in order to execute a transition to the timeout state.
LEDs are set to blink purple to indicate a collision has been detected.
WaitBits() |
SetBits() |
ClearBits () |
vTaskDelay() |
SemaphoreGive/Take () |
vTaskResume () |
---|---|---|---|---|---|
CARD_BIT_0 | AUTH_BIT_1 |
TIMEOUT_BIT_3 | COLL_BIT_4 |
CARD_BIT_0 | AUTH_BIT_1 |
? |
SPIMutexHandle |
blinkLEDHand0/1 |
timeoutTask (void *params)
Unblocks on the TIMEOUT_BIT_3. The first thing that is done is publishing to the MQTT rfid/auth/eou
(end of use) topic. This is done before
pollNewTask()
is resumed so that it cannot be interrupted by introduction of a new card. Next closeRelayTask
is resumed so that if a new card is introduced
the relay can be closed. A bitmask operation is carried out against xEventGroupGetBits
to determine if both TIMEOUT_BIT_3 and COLL_BIT_4 are set.
If just TIMEOUT_BIT_3 is set pollNewTask()
is resumed so that a new card can be introduced and authorized without the relay being opened.
If TIMEOUT_BIT_3 and COLL_BIT_4 is set the full timeout is enforced and the relay is re-opened before pollNewTask()
is resumed.
When the full timeout occurs RELAY_BIT_2, TIMEOUT_BIT_3, and COLL_BIT_4 are all cleared.
WaitBits() |
ClearBits() |
GetBits () |
vTaskDelay() |
vTaskResume () |
---|---|---|---|---|
TIMEOUT_BIT_3 |
RELAY_BIT_2 | TIMEOUT_BIT_3 |
Used to check if TIMEOUT_BIT_3 and/or COLL_BIT_4 is set |
MS_TIMEOUT_PERIOD |
blinkLEDHand0/1 pollNewHandle |
EStop Tasks¶
eStopFireTask (void *params)
Unblocks on ESTOPFIRE_BIT_5 which is set in onMqttMessage()
on receipt of rfid/estop/fire
. A xEventGroupGetBits()
is used to check the state of the hardware. If
no bits are set pollNewTask()
is suspended cutting off the access point to the RFID functionality. If any of the EventBits are set all the bits are cleared, the relay is
opened and then pollNewTask()
is suspended. The LEDs are then set to flash yellow.
The ESTOPSET_BIT_6 auto clears on the the successful xEventGroupWaitBits()
.
WaitBits() |
GetBits () |
ClearBits() |
vTaskResume () |
---|---|---|---|
ESTOPFIRE_BIT_5 |
If no bits set |
N/A |
blinkLEDHand0/1 pollNewHandle |
If bit other than ESTOPbits set |
CARD_BIT_0 | AUTH_BIT_1 | RELAY_BIT_2 | TIMEOUT_BIT_3 | COLL_BIT_4 |
eStopClearTask (void *params)
Unblocks on ESTOPCLEAR_BIT_6 which is set in onMqttMessage()
on receipt of rfid/estop/fire
. This task simply turns off the LEDs and resumes pollNewTask()
.
The ESTOPCLEAR_BIT_6 auto clears on the the successful xEventGroupWaitBits()
.
WaitBits() |
vTaskResume () |
---|---|
ESTOPCLEAR_BIT_5 |
blinkLEDHand0/1 pollNewHandle |
Relay Task¶
closeRelayTask(void *params)
Unblocks once CARD_BIT_0 and AUTH_BIT_1 are set. It closes the relay, sets the RELAY_BIT_2 (not currently used for anything), changes the LEDs to a solid green to
indicate this to the user. The task then suspends itself once all of this has been achieved. This task is resumed in timeoutTask()
.
WaitBits() |
SetBits() |
vTaskSuspend () |
vTaskResume () |
---|---|---|---|
CARD_BIT_0|AUTH_BIT_1 |
RELAY_BIT_2 |
NULL |
blinkLEDHand0/1 |
Addressable LED Tasks¶
Library : FastLED
Control of the COM12999 addressable LEDs is done via the FastLED library, a single RTOS task definition blinkyLEDTask
and a single software timer LEDblinkTimer
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | void blinkyLED (void *params){
LEDParams *l = (LEDParams*)params; // Dumping our struct parameters into task instance of LEDParams via casting of void *params to LEDParams
for (;;){ // Infinite loop required for RTOS tasks b/c if allowed to return they would delete
// Branch based on blink status
if(l->blink){ // if blink flag has been set
if (l->blinkTemp){ // If the blinkTemp flag is set we start the LEDblinkTimer
l->blinkTemp=0; // Only want the timer started once
xTimerStart(LEDblinkTimer, 0); // Start the timer
}
leds[l->led] = CRGB::Black; // Set LED specified in passed params to OFF state
FastLED.show(); // Toggle the LED state to new
vTaskDelay(pdMS_TO_TICKS(l->time)); // RTOS delay blocks task not processor
leds[l->led] = l->myColour; // Set LED specified in passed params to the colour specified in same passed params
FastLED.show();
vTaskDelay(pdMS_TO_TICKS(l->time)); // Set delay time according to passed param AND div by port TICK period ms
}
else{
leds[l->led] = l->myColour; // Set LED specified in passed params to the colour specified in same passed params
FastLED.show(); // Show it
vTaskSuspend ( NULL ); // Suspend ourselves since blink = false therefore the task need not keep running
}
}
}
void LEDTimerCallback (TimerHandle_t LEDblinkTimer){
metaStruct *progParams = (metaStruct*) pvTimerGetTimerID (LEDblinkTimer);
progParams->LEDParams0.myColour = CRGB::Black; // Once our timer expires our callback function simply resets out LEDs to off
progParams->LEDParams1.myColour = CRGB::Black;
progParams->LEDParams0.blink = 0;
progParams->LEDParams1.blink = 0;
}
|
Where the LED control tasks differ slightly from the other RTOS tasks is at creation they are passed the address of their parameter struct rather than the address of the metaStruct. The LED tasks need only access to the LED parameters while other tasks needs access to their own parameters and the LED parameters.
//Task creation
xTaskCreatePinnedToCore(blinkyLED, "blinkLED", 1024, &progParams.LEDParams0, 1, &blinkLEDHandle0, 1);
xTaskCreatePinnedToCore(blinkyLED, "blinkLED1", 1024, &progParams.LEDParams1, 1, &blinkLEDHandle1, 1);
// Software timer creation
LEDblinkTimer = xTimerCreate("LEDblinkTimer", LEDBLINK_PERIOD, pdFALSE, (void*)&progParams, reinterpret_cast<TimerCallbackFunction_t>(LEDTimerCallback));
Manipulation of the LEDs can then be achieve simply by changing the values held in LEDParams0
and LEDParams1
via the void pointer.
Note
If the previous state of an LED was blink == 0
then its respective LEDTask will have to be resumed.
void exampleTask (void *params){
metaStruct *progParams = (metaStruct*) params;
for(;;){
progParams->LEDParams0.myColour = CRGB::Red; // Set LED0 to Red
progParams->LEDParams1.myColour = CRGB::Purple; // Set LED1 to Purple
progParams->LEDParams0.blink = 0; // Set LED0 to continuous one
progParams->LEDParams1.blink = 1; // Set LED1 to blink
// Without changing progParams->LEDParams1.time LED1 will blink at whatever period was last defined there
vTaskResume(blinkLEDHandle0); // Resume the LED task
vTaskResume(blinkLEDHandle1); // Resume the LED task
}
}
MQTT software timers and callback functions¶
The MQTT funcitonality utilizes software timers to handle disconnection/reconnection events from WiFi and the MQTT server. These are found in void setup()
of
toolAccessRTOS.ino
.
mqttReconnectTimer = xTimerCreate("mqttTimer", MS_MQTT_RECONNECT_PERIOD, pdFALSE, (void*)0, reinterpret_cast<TimerCallbackFunction_t>(connectToMqtt));
wifiReconnectTimer = xTimerCreate("wifiTimer", MS_WIFI_RECONNECT_PERIOD, pdFALSE, (void*)0, reinterpret_cast<TimerCallbackFunction_t>(connectToWifi));
As mentioned above, the MQTT functions are those included in the FullyFeatured-ESP32.ino
example included with the library. Most of them remain unmodified, the exceptions to this are
connectToWifi()
, WiFiEvent()
, onMqttConnect()
, and onMqttMessage()
. As such I will only discuss these functions here.
connectToWifi()
WiFi credentials are accessed here. Create your own credentials.h
with #define SSID, PASS
.
WiFiEvent()
WIFIOUT_BIT_7 is set here when disconnection occurs to change behaviour of pollNewTask()
onMqttConnect()
Hardcoded subscriptions can be placed here. Ideally in the future have the subscriptions read out of a modifyable variable/struct/JSON doc would allow for modification of those subscriptions. See Whomami implementation in Roadmap to Further Development section.
onMqttMessage()
MQTT payloads from subscriptions enter here. Payloads are read and operated on resulting in the possible setting or clearing of various EventBits:
Task notification: 0’th bit of pollNewHandle
is set to notify the pollNewTask()
that a card has been denied and to blink red LEDs at the user.
Topic |
Payload |
SetBits() |
ClearBits() |
xTaskNotify() |
vTaskResume () |
---|---|---|---|---|---|
rfid/auth/rsp |
auth |
AUTH_BIT_1 |
N/A |
N/A |
N/A |
denied |
N/A |
CARD_BIT_0 | AUTH_BIT_1 |
pollNewHandle, (1<<0), eSetBits |
pollNewHandle |
|
seekiosk |
N/A |
N/A |
N/A |
N/A |
|
rfid/estop |
fire |
ESTOPFIRE_BIT_5 |
N/A |
N/A |
N/A |
clear |
ESTOPCLEAR_BIT_5 |
N/A |
N/A |
N/A |
Warning
Care should be taken using strncmp()
to evaluate topics and payloads. Specifically, the size_t num
parameter should be utilized where possible as payloads may
be coming from non-null terminating languages such as Java-script.