tasking + statemachine restructured

This commit is contained in:
Klaus K Wilting 2018-09-21 18:23:34 +02:00
parent 67832da09d
commit 5b9327512b
6 changed files with 93 additions and 75 deletions

View File

@ -10,7 +10,11 @@
static const char TAG[] = "main"; static const char TAG[] = "main";
// do all housekeeping // do all housekeeping
void doHomework() { void doHousekeeping() {
portENTER_CRITICAL(&timerMux);
HomeCycleIRQ = 0;
portEXIT_CRITICAL(&timerMux);
// update uptime counter // update uptime counter
uptime(); uptime();
@ -49,16 +53,7 @@ void doHomework() {
if (esp_get_minimum_free_heap_size() <= MEM_LOW) // check again if (esp_get_minimum_free_heap_size() <= MEM_LOW) // check again
esp_restart(); // memory leak, reset device esp_restart(); // memory leak, reset device
} }
} // doHomework() } // doHousekeeping()
void checkHousekeeping() {
if (HomeCycleIRQ) {
portENTER_CRITICAL(&timerMux);
HomeCycleIRQ = 0;
portEXIT_CRITICAL(&timerMux);
doHomework();
}
}
void IRAM_ATTR homeCycleIRQ() { void IRAM_ATTR homeCycleIRQ() {
portENTER_CRITICAL(&timerMux); portENTER_CRITICAL(&timerMux);

View File

@ -1,8 +1,7 @@
#ifndef _CYCLIC_H #ifndef _CYCLIC_H
#define _CYCLIC_H #define _CYCLIC_H
void doHomework(void); void doHousekeeping(void);
void checkHousekeeping(void);
void homeCycleIRQ(void); void homeCycleIRQ(void);
uint64_t uptime(void); uint64_t uptime(void);
void reset_counters(void); void reset_counters(void);

View File

@ -33,14 +33,14 @@ uint16_t macs_total = 0, macs_wifi = 0, macs_ble = 0,
batt_voltage = 0; // globals for display batt_voltage = 0; // globals for display
// hardware timer for cyclic tasks // hardware timer for cyclic tasks
hw_timer_t *channelSwitch = NULL, *displaytimer = NULL, *sendCycle = NULL, hw_timer_t *channelSwitch, *displaytimer, *sendCycle, *homeCycle;
*homeCycle = NULL;
// this variables will be changed in the ISR, and read in main loop // this variables will be changed in the ISR, and read in main loop
volatile int ButtonPressedIRQ = 0, ChannelTimerIRQ = 0, SendCycleTimerIRQ = 0, volatile int ButtonPressedIRQ = 0, ChannelTimerIRQ = 0, SendCycleTimerIRQ = 0,
DisplayTimerIRQ = 0, HomeCycleIRQ = 0; DisplayTimerIRQ = 0, HomeCycleIRQ = 0;
TaskHandle_t WifiLoopTask = NULL; TaskHandle_t WifiLoopTask = NULL;
TaskHandle_t StateTask = NULL;
// RTos send queues for payload transmit // RTos send queues for payload transmit
#ifdef HAS_LORA #ifdef HAS_LORA
@ -68,9 +68,6 @@ PayloadConvert payload(PAYLOAD_BUFFER_SIZE);
// local Tag for logging // local Tag for logging
static const char TAG[] = "main"; static const char TAG[] = "main";
/* begin Aruino SETUP
* ------------------------------------------------------------ */
void setup() { void setup() {
// disable the default wifi logging // disable the default wifi logging
@ -229,6 +226,7 @@ void setup() {
// reload interrupt after each trigger of display refresh cycle // reload interrupt after each trigger of display refresh cycle
timerAlarmWrite(displaytimer, DISPLAYREFRESH_MS * 1000, true); timerAlarmWrite(displaytimer, DISPLAYREFRESH_MS * 1000, true);
// enable display interrupt // enable display interrupt
yield();
timerAlarmEnable(displaytimer); timerAlarmEnable(displaytimer);
#endif #endif
@ -236,7 +234,6 @@ void setup() {
channelSwitch = timerBegin(1, 800, true); channelSwitch = timerBegin(1, 800, true);
timerAttachInterrupt(channelSwitch, &ChannelSwitchIRQ, true); timerAttachInterrupt(channelSwitch, &ChannelSwitchIRQ, true);
timerAlarmWrite(channelSwitch, cfg.wifichancycle * 1000, true); timerAlarmWrite(channelSwitch, cfg.wifichancycle * 1000, true);
//ESP_LOGI(TAG, "chanelswitch alarm threshold %d", cfg.wifichancycle * 1000);
// setup send cycle trigger IRQ using esp32 hardware timer 2 // setup send cycle trigger IRQ using esp32 hardware timer 2
sendCycle = timerBegin(2, 8000, true); sendCycle = timerBegin(2, 8000, true);
@ -248,9 +245,13 @@ void setup() {
timerAttachInterrupt(homeCycle, &homeCycleIRQ, true); timerAttachInterrupt(homeCycle, &homeCycleIRQ, true);
timerAlarmWrite(homeCycle, HOMECYCLE * 10000, true); timerAlarmWrite(homeCycle, HOMECYCLE * 10000, true);
//enable timers, caution: order is critical here // enable timers
// caution, see: https://github.com/espressif/arduino-esp32/issues/1313
yield();
timerAlarmEnable(homeCycle); timerAlarmEnable(homeCycle);
yield();
timerAlarmEnable(sendCycle); timerAlarmEnable(sendCycle);
yield();
timerAlarmEnable(channelSwitch); timerAlarmEnable(channelSwitch);
// show payload encoder // show payload encoder
@ -283,13 +284,35 @@ void setup() {
// join network // join network
LMIC_startJoining(); LMIC_startJoining();
/*
Overview Tasks & Timer
Task Core Prio Purpose
====================================================================
IDLE 0 0 ESP32 arduino scheduler
wifiloop 0 1 switches Wifi channels
gpsloop 0 2 reasd data from GPS over serial or i2c
IDLE 1 0 Arduino loop() -> unused
loraloop 1 1 runs the LMIC stack
statemachine 1 3 switches process logic
Timers
======
0 Display-Refresh
1 Wifi Channel Switch
2 Send Cycle
3 Housekeeping
*/
// start lmic runloop in rtos task on core 1 // start lmic runloop in rtos task on core 1
// (note: arduino main loop runs on core 1, too) // (note: arduino main loop runs on core 1, too)
// https://techtutorialsx.com/2017/05/09/esp32-get-task-execution-core/ // https://techtutorialsx.com/2017/05/09/esp32-get-task-execution-core/
ESP_LOGI(TAG, "Starting Lora..."); ESP_LOGI(TAG, "Starting Lora...");
xTaskCreatePinnedToCore(lorawan_loop, "loraloop", 2048, (void *)1, xTaskCreatePinnedToCore(lorawan_loop, "loraloop", 2048, (void *)1, 1,
(5 | portPRIVILEGE_BIT), &LoraTask, 1); &LoraTask, 1);
#endif #endif
// if device has GPS and it is enabled, start GPS reader task on core 0 with // if device has GPS and it is enabled, start GPS reader task on core 0 with
@ -317,18 +340,19 @@ void setup() {
reset_salt(); // get new 16bit for salting hashes reset_salt(); // get new 16bit for salting hashes
xTaskCreatePinnedToCore(wifi_channel_loop, "wifiloop", 2048, (void *)1, 1, xTaskCreatePinnedToCore(wifi_channel_loop, "wifiloop", 2048, (void *)1, 1,
&WifiLoopTask, 0); &WifiLoopTask, 0);
// start state machine
ESP_LOGI(TAG, "Starting Statemachine...");
xTaskCreatePinnedToCore(stateMachine, "stateloop", 2048, (void *)1, 3,
&StateTask, 1);
} // setup() } // setup()
/* end Arduino SETUP void stateMachine(void *pvParameters) {
* ------------------------------------------------------------ */
/* begin Arduino main loop configASSERT(((uint32_t)pvParameters) == 1); // FreeRTOS check
* ------------------------------------------------------ */
void loop() { while (1) {
// state machine for switching display, LED, button, housekeeping,
// senddata
#if (HAS_LED != NOT_A_PIN) || defined(HAS_RGB_LED) #if (HAS_LED != NOT_A_PIN) || defined(HAS_RGB_LED)
led_loop(); led_loop();
@ -342,16 +366,17 @@ void loop() {
updateDisplay(); updateDisplay();
#endif #endif
// check housekeeping cycle and if expired do homework // check housekeeping cycle and if expired do the work
checkHousekeeping(); if (HomeCycleIRQ)
doHousekeeping();
// check send queue and process it // check send queue and process it
processSendBuffer(); processSendBuffer();
// check send cycle and enqueue payload if cycle is expired // check send cycle and enqueue payload if cycle is expired
if (SendCycleTimerIRQ)
sendPayload(); sendPayload();
// yield to CPU // yield to CPU
vTaskDelay(2 / portTICK_PERIOD_MS); vTaskDelay(2 / portTICK_PERIOD_MS);
}
}
} // loop() void loop() { vTaskDelay(2 / portTICK_PERIOD_MS); }
/* end Arduino main loop
* ------------------------------------------------------------ */

View File

@ -13,5 +13,8 @@
#include <esp_spi_flash.h> // needed for reading ESP32 chip attributes #include <esp_spi_flash.h> // needed for reading ESP32 chip attributes
#include <esp_event_loop.h> // needed for Wifi event handler #include <esp_event_loop.h> // needed for Wifi event handler
#include <esp32-hal-timer.h> // needed for timers
void stateMachine(void *pvParameters);
#endif #endif

View File

@ -246,7 +246,7 @@ int version_compare(const String v1, const String v2) {
// vnum stores each numeric part of version // vnum stores each numeric part of version
int vnum1 = 0, vnum2 = 0; int vnum1 = 0, vnum2 = 0;
// loop untill both string are processed // loop until both string are processed
for (int i = 0, j = 0; (i < v1.length() || j < v2.length());) { for (int i = 0, j = 0; (i < v1.length() || j < v2.length());) {
// storing numeric part of version 1 in vnum1 // storing numeric part of version 1 in vnum1
while (i < v1.length() && v1[i] != '.') { while (i < v1.length() && v1[i] != '.') {

View File

@ -34,10 +34,9 @@ void SendData(uint8_t port) {
} }
} // SendData } // SendData
// cyclic called function to prepare payload to send // interrupt triggered function to prepare payload to send
void sendPayload() { void sendPayload() {
if (SendCycleTimerIRQ) {
portENTER_CRITICAL(&timerMux); portENTER_CRITICAL(&timerMux);
SendCycleTimerIRQ = 0; SendCycleTimerIRQ = 0;
portEXIT_CRITICAL(&timerMux); portEXIT_CRITICAL(&timerMux);
@ -51,8 +50,7 @@ void sendPayload() {
// show NMEA data in debug mode, useful for debugging GPS on board // show NMEA data in debug mode, useful for debugging GPS on board
// connection // connection
ESP_LOGD(TAG, "GPS NMEA data: passed %d / failed: %d / with fix: %d", ESP_LOGD(TAG, "GPS NMEA data: passed %d / failed: %d / with fix: %d",
gps.passedChecksum(), gps.failedChecksum(), gps.passedChecksum(), gps.failedChecksum(), gps.sentencesWithFix());
gps.sentencesWithFix());
// log GPS position if we have a fix and gps data mode is enabled // log GPS position if we have a fix and gps data mode is enabled
if ((cfg.gpsmode) && (gps.location.isValid())) { if ((cfg.gpsmode) && (gps.location.isValid())) {
gps_read(); gps_read();
@ -66,7 +64,6 @@ void sendPayload() {
} }
#endif #endif
SendData(COUNTERPORT); SendData(COUNTERPORT);
}
} // sendpayload() } // sendpayload()
// interrupt handler used for payload send cycle timer // interrupt handler used for payload send cycle timer
@ -76,9 +73,8 @@ void IRAM_ATTR SendCycleIRQ() {
portEXIT_CRITICAL(&timerMux); portEXIT_CRITICAL(&timerMux);
} }
// cyclic called function to eat data from RTos send queues and transmit it // interrupt triggered function to eat data from RTos send queues and transmit it
void processSendBuffer() { void processSendBuffer() {
MessageBuffer_t SendBuffer; MessageBuffer_t SendBuffer;
#ifdef HAS_LORA #ifdef HAS_LORA