diff --git a/src/button.cpp b/src/button.cpp index 086c3231..fd96545c 100644 --- a/src/button.cpp +++ b/src/button.cpp @@ -1,22 +1,12 @@ #ifdef HAS_BUTTON #include "globals.h" +#include "button.h" // Local logging tag static const char TAG[] = "main"; -portMUX_TYPE mutexButton = portMUX_INITIALIZER_UNLOCKED; - -void IRAM_ATTR ButtonIRQ() { - portENTER_CRITICAL(&mutexButton); - ButtonPressedIRQ++; - portEXIT_CRITICAL(&mutexButton); -} - void readButton() { - portENTER_CRITICAL(&mutexButton); - ButtonPressedIRQ = 0; - portEXIT_CRITICAL(&mutexButton); ESP_LOGI(TAG, "Button pressed"); payload.reset(); payload.addButton(0x01); diff --git a/src/button.h b/src/button.h index 9cb6e7b4..bae8e6b5 100644 --- a/src/button.h +++ b/src/button.h @@ -3,7 +3,7 @@ #include "senddata.h" -void IRAM_ATTR ButtonIRQ(void); -void readButton(void); +void IRAM_ATTR ButtonIRQ(); +void readButton(); #endif \ No newline at end of file diff --git a/src/cyclic.cpp b/src/cyclic.cpp index 5f7ca3dc..06d45b62 100644 --- a/src/cyclic.cpp +++ b/src/cyclic.cpp @@ -7,15 +7,9 @@ // Local logging tag static const char TAG[] = "main"; -portMUX_TYPE mutexHomeCycle = portMUX_INITIALIZER_UNLOCKED; - // do all housekeeping void doHousekeeping() { - portENTER_CRITICAL(&mutexHomeCycle); - HomeCycleIRQ = 0; - portEXIT_CRITICAL(&mutexHomeCycle); - // update uptime counter uptime(); @@ -26,8 +20,8 @@ void doHousekeeping() { // task storage debugging // ESP_LOGD(TAG, "Wifiloop %d bytes left", uxTaskGetStackHighWaterMark(wifiSwitchTask)); - ESP_LOGD(TAG, "Stateloop %d bytes left", - uxTaskGetStackHighWaterMark(stateMachineTask)); + ESP_LOGD(TAG, "IRQhandler %d bytes left", + uxTaskGetStackHighWaterMark(irqHandlerTask)); #ifdef HAS_GPS ESP_LOGD(TAG, "Gpsloop %d bytes left", uxTaskGetStackHighWaterMark(GpsTask)); #endif @@ -70,12 +64,6 @@ void doHousekeeping() { } } // doHousekeeping() -void IRAM_ATTR homeCycleIRQ() { - portENTER_CRITICAL(&mutexHomeCycle); - HomeCycleIRQ++; - portEXIT_CRITICAL(&mutexHomeCycle); -} - // uptime counter 64bit to prevent millis() rollover after 49 days uint64_t uptime() { static uint32_t low32, high32; diff --git a/src/display.cpp b/src/display.cpp index 1eaef6c5..edcf8cdd 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -15,10 +15,6 @@ const char lora_datarate[] = {"100908078CNA121110090807"}; uint8_t volatile DisplayState = 0; -hw_timer_t *displaytimer; - -portMUX_TYPE mutexDisplay = portMUX_INITIALIZER_UNLOCKED; - // helper function, prints a hex key on display void DisplayKey(const uint8_t *key, uint8_t len, bool lsb) { const uint8_t *p; @@ -31,17 +27,6 @@ void DisplayKey(const uint8_t *key, uint8_t len, bool lsb) { void init_display(const char *Productname, const char *Version) { - // setup display refresh trigger IRQ using esp32 hardware timer - // https://techtutorialsx.com/2017/10/07/esp32-arduino-timer-interrupts/ - // prescaler 80 -> divides 80 MHz CPU freq to 1 MHz, timer 0, count up - displaytimer = timerBegin(0, 80, true); - // interrupt handler DisplayIRQ, triggered by edge - timerAttachInterrupt(displaytimer, &DisplayIRQ, true); - // reload interrupt after each trigger of display refresh cycle - timerAlarmWrite(displaytimer, DISPLAYREFRESH_MS * 1000, true); - // enable display interrupt - timerAlarmEnable(displaytimer); - // show startup screen uint8_t buf[32]; u8x8.begin(); @@ -107,10 +92,6 @@ void init_display(const char *Productname, const char *Version) { void refreshtheDisplay() { - portENTER_CRITICAL(&mutexDisplay); - DisplayTimerIRQ = 0; - portEXIT_CRITICAL(&mutexDisplay); - // set display on/off according to current device configuration if (DisplayState != cfg.screenon) { DisplayState = cfg.screenon; @@ -206,10 +187,4 @@ void refreshtheDisplay() { } // refreshDisplay() -void IRAM_ATTR DisplayIRQ() { - portENTER_CRITICAL_ISR(&mutexDisplay); - DisplayTimerIRQ++; - portEXIT_CRITICAL_ISR(&mutexDisplay); -} - #endif // HAS_DISPLAY \ No newline at end of file diff --git a/src/globals.h b/src/globals.h index 38d9e4ee..703b46d0 100644 --- a/src/globals.h +++ b/src/globals.h @@ -46,14 +46,11 @@ extern uint16_t volatile macs_total, macs_wifi, macs_ble, batt_voltage; // display values extern std::set macs; // temp storage for MACs extern hw_timer_t *channelSwitch, *sendCycle; -extern volatile uint8_t SendCycleTimerIRQ, HomeCycleIRQ, DisplayTimerIRQ, - ChannelTimerIRQ, ButtonPressedIRQ; extern std::array::iterator it; extern std::array beacons; -extern SemaphoreHandle_t xWifiChannelSwitchSemaphore; -extern TaskHandle_t stateMachineTask, wifiSwitchTask; +extern TaskHandle_t irqHandlerTask, wifiSwitchTask; #ifdef HAS_GPS #include "gps.h" diff --git a/src/irqhandler.cpp b/src/irqhandler.cpp new file mode 100644 index 00000000..61aa6d2e --- /dev/null +++ b/src/irqhandler.cpp @@ -0,0 +1,74 @@ +#include "irqhandler.h" + +// Local logging tag +static const char TAG[] = "main"; + +// irq handler task, handles all our application level interrupts +void irqHandler(void *pvParameters) { + + configASSERT(((uint32_t)pvParameters) == 1); // FreeRTOS check + + uint32_t InterruptStatus; + + // task remains in blocked state until it is notified by an irq + for (;;) { + xTaskNotifyWait( + 0x00, // Don't clear any bits on entry + ULONG_MAX, // Clear all bits on exit + &InterruptStatus, // Receives the notification value + portMAX_DELAY); // wait forever (missing error handling here...) + +// button pressed? +#ifdef HAS_BUTTON + if (InterruptStatus & BUTTON_IRQ) + readButton(); +#endif + +// display needs refresh? +#ifdef HAS_DISPLAY + if (InterruptStatus & DISPLAY_IRQ) + refreshtheDisplay(); +#endif + + // are cyclic tasks due? + if (InterruptStatus & CYCLIC_IRQ) + doHousekeeping(); + + // is time to send the payload? + if (InterruptStatus & SENDPAYLOAD_IRQ) + sendPayload(); + } + vTaskDelete(NULL); // shoud never be reached +} + +// esp32 hardware timer triggered interrupt service routines +// they notify the irq handler task + +void IRAM_ATTR ChannelSwitchIRQ() { + xTaskNotifyGive(wifiSwitchTask); + portYIELD_FROM_ISR(); +} + +void IRAM_ATTR homeCycleIRQ() { + xTaskNotifyFromISR(irqHandlerTask, CYCLIC_IRQ, eSetBits, NULL); + portYIELD_FROM_ISR(); +} + +void IRAM_ATTR SendCycleIRQ() { + xTaskNotifyFromISR(irqHandlerTask, SENDPAYLOAD_IRQ, eSetBits, NULL); + portYIELD_FROM_ISR(); +} + +#ifdef HAS_DISPLAY +void IRAM_ATTR DisplayIRQ() { + xTaskNotifyFromISR(irqHandlerTask, DISPLAY_IRQ, eSetBits, NULL); + portYIELD_FROM_ISR(); +} +#endif + +#ifdef HAS_BUTTON +void IRAM_ATTR ButtonIRQ() { + xTaskNotifyFromISR(irqHandlerTask, BUTTON_IRQ, eSetBits, NULL); + portYIELD_FROM_ISR(); +} +#endif diff --git a/src/irqhandler.h b/src/irqhandler.h new file mode 100644 index 00000000..fab9bee1 --- /dev/null +++ b/src/irqhandler.h @@ -0,0 +1,18 @@ +#ifndef _IRQHANDLER_H +#define _IRQHANDLER_H + +#define DISPLAY_IRQ 0x01 +#define BUTTON_IRQ 0x02 +#define SENDPAYLOAD_IRQ 0x04 +#define CYCLIC_IRQ 0x08 + +#include "globals.h" +#include "cyclic.h" +#include "button.h" +#include "display.h" +#include "cyclic.h" +#include "senddata.h" + +void irqHandler(void *pvParameters); + +#endif diff --git a/src/main.cpp b/src/main.cpp index 29d1b433..abc94c9e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -31,10 +31,10 @@ wifiloop 0 4 rotates wifi channels ledloop 0 3 blinks LEDs gpsloop 0 2 reads data from GPS over serial or i2c spiloop 0 2 reads/writes data on spi interface -statemachine 0 1 switches application process logic IDLE 0 0 ESP32 arduino scheduler -> runs wifi sniffer looptask 1 1 arduino core -> runs the LMIC LoRa stack +irqhandler 1 1 executes tasks triggered by irq IDLE 1 0 ESP32 arduino scheduler ESP32 hardware timers @@ -55,16 +55,8 @@ uint8_t volatile channel = 0; // channel rotation counter uint16_t volatile macs_total = 0, macs_wifi = 0, macs_ble = 0, batt_voltage = 0; // globals for display -// hardware timer for cyclic tasks -hw_timer_t *channelSwitch, *sendCycle, *homeCycle; - -// this variables will be changed in the ISR, and read in main loop -uint8_t volatile ButtonPressedIRQ = 0, ChannelTimerIRQ = 0, - SendCycleTimerIRQ = 0, DisplayTimerIRQ = 0, HomeCycleIRQ = 0; - -TaskHandle_t stateMachineTask, wifiSwitchTask; - -SemaphoreHandle_t xWifiChannelSwitchSemaphore; +hw_timer_t *channelSwitch, *sendCycle, *homeCycle, *displaytimer; // irq tasks +TaskHandle_t irqHandlerTask, wifiSwitchTask; std::set macs; // container holding unique MAC adress hashes @@ -227,26 +219,32 @@ void setup() { #ifdef HAS_DISPLAY strcat_P(features, " OLED"); DisplayState = cfg.screenon; + init_display(PRODUCTNAME, PROGVERSION); + + // setup display refresh trigger IRQ using esp32 hardware timer + // https://techtutorialsx.com/2017/10/07/esp32-arduino-timer-interrupts/ + // prescaler 80 -> divides 80 MHz CPU freq to 1 MHz, timer 0, count up + displaytimer = timerBegin(0, 80, true); + // interrupt handler DisplayIRQ, triggered by edge + timerAttachInterrupt(displaytimer, &DisplayIRQ, true); + // reload interrupt after each trigger of display refresh cycle + timerAlarmWrite(displaytimer, DISPLAYREFRESH_MS * 1000, true); #endif // setup send cycle trigger IRQ using esp32 hardware timer 2 sendCycle = timerBegin(2, 8000, true); timerAttachInterrupt(sendCycle, &SendCycleIRQ, true); timerAlarmWrite(sendCycle, cfg.sendcycle * 2 * 10000, true); - timerAlarmEnable(sendCycle); // setup house keeping cycle trigger IRQ using esp32 hardware timer 3 homeCycle = timerBegin(3, 8000, true); timerAttachInterrupt(homeCycle, &homeCycleIRQ, true); timerAlarmWrite(homeCycle, HOMECYCLE * 10000, true); - timerAlarmEnable(homeCycle); // setup channel rotation trigger IRQ using esp32 hardware timer 1 - xWifiChannelSwitchSemaphore = xSemaphoreCreateBinary(); channelSwitch = timerBegin(1, 800, true); timerAttachInterrupt(channelSwitch, &ChannelSwitchIRQ, true); timerAlarmWrite(channelSwitch, cfg.wifichancycle * 1000, true); - timerAlarmEnable(channelSwitch); // show payload encoder #if PAYLOAD_ENCODER == 1 @@ -287,35 +285,35 @@ void setup() { #ifdef HAS_GPS ESP_LOGI(TAG, "Starting GPSloop..."); - xTaskCreatePinnedToCore(gps_loop, /* task function */ - "gpsloop", /* name of task */ - 1024, /* stack size of task */ - (void *)1, /* parameter of the task */ - 2, /* priority of the task */ - &GpsTask, /* task handle*/ - 0); /* CPU core */ + xTaskCreatePinnedToCore(gps_loop, // task function + "gpsloop", // name of task + 1024, // stack size of task + (void *)1, // parameter of the task + 2, // priority of the task + &GpsTask, // task handle + 0); // CPU core #endif #ifdef HAS_SPI ESP_LOGI(TAG, "Starting SPIloop..."); - xTaskCreatePinnedToCore(spi_loop, /* task function */ - "spiloop", /* name of task */ - 2048, /* stack size of task */ - (void *)1, /* parameter of the task */ - 2, /* priority of the task */ - &SpiTask, /* task handle*/ - 0); /* CPU core */ + xTaskCreatePinnedToCore(spi_loop, // task function + "spiloop", // name of task + 2048, // stack size of task + (void *)1, // parameter of the task + 2, // priority of the task + &SpiTask, // task handle + 0); // CPU core #endif // start state machine - ESP_LOGI(TAG, "Starting Statemachine..."); - xTaskCreatePinnedToCore(stateMachine, /* task function */ - "stateloop", /* name of task */ - 2048, /* stack size of task */ - (void *)1, /* parameter of the task */ - 1, /* priority of the task */ - &stateMachineTask, /* task handle */ - 0); /* CPU core */ + ESP_LOGI(TAG, "Starting IRQ Handler..."); + xTaskCreatePinnedToCore(irqHandler, // task function + "irqhandler", // name of task + 2048, // stack size of task + (void *)1, // parameter of the task + 1, // priority of the task + &irqHandlerTask, // task handle + 1); // CPU core #if (HAS_LED != NOT_A_PIN) || defined(HAS_RGB_LED) // start led loop @@ -339,6 +337,15 @@ void setup() { &wifiSwitchTask, // task handle 0); // CPU core + // start timer triggered interrupts + ESP_LOGI(TAG, "Starting Interrupts..."); +#ifdef HAS_DISPLAY + timerAlarmEnable(displaytimer); +#endif + timerAlarmEnable(sendCycle); + timerAlarmEnable(homeCycle); + timerAlarmEnable(channelSwitch); + } // setup() void loop() { diff --git a/src/main.h b/src/main.h index ff4ae180..9c74aef5 100644 --- a/src/main.h +++ b/src/main.h @@ -11,6 +11,6 @@ #include "cyclic.h" #include "beacon_array.h" #include "ota.h" -#include "statemachine.h" +#include "irqhandler.h" #endif \ No newline at end of file diff --git a/src/senddata.cpp b/src/senddata.cpp index fa4eb946..ee293485 100644 --- a/src/senddata.cpp +++ b/src/senddata.cpp @@ -1,8 +1,6 @@ // Basic Config #include "globals.h" -portMUX_TYPE mutexSendCycle = portMUX_INITIALIZER_UNLOCKED; - // put data to send in RTos Queues used for transmit over channels Lora and SPI void SendData(uint8_t port) { @@ -39,10 +37,6 @@ void SendData(uint8_t port) { // interrupt triggered function to prepare payload to send void sendPayload() { - portENTER_CRITICAL(&mutexSendCycle); - SendCycleTimerIRQ = 0; - portEXIT_CRITICAL(&mutexSendCycle); - // append counter data to payload payload.reset(); payload.addCount(macs_wifi, cfg.blescan ? macs_ble : 0); @@ -68,13 +62,6 @@ void sendPayload() { SendData(COUNTERPORT); } // sendpayload() -// interrupt handler used for payload send cycle timer -void IRAM_ATTR SendCycleIRQ() { - portENTER_CRITICAL(&mutexSendCycle); - SendCycleTimerIRQ++; - portEXIT_CRITICAL(&mutexSendCycle); -} - void flushQueues() { #ifdef HAS_LORA xQueueReset(LoraSendQueue); diff --git a/src/statemachine.cpp b/src/statemachine.cpp deleted file mode 100644 index c1607fb6..00000000 --- a/src/statemachine.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include "statemachine.h" - -// Local logging tag -static const char TAG[] = "main"; - -void stateMachine(void *pvParameters) { - - configASSERT(((uint32_t)pvParameters) == 1); // FreeRTOS check - - // initialize display - caution: must be done on core 1 in arduino loop! -#ifdef HAS_DISPLAY - init_display(PRODUCTNAME, PROGVERSION); -#endif - - while (1) { - -#ifdef HAS_BUTTON - if (ButtonPressedIRQ) - readButton(); -#endif - -#ifdef HAS_DISPLAY - if (DisplayTimerIRQ) - refreshtheDisplay(); -#endif - - // check housekeeping cycle and if due do the work - if (HomeCycleIRQ) - doHousekeeping(); - - // check send cycle and if due enqueue payload to send - if (SendCycleTimerIRQ) - sendPayload(); - - // give yield to CPU - vTaskDelay(2 / portTICK_PERIOD_MS); - } - vTaskDelete(NULL); // shoud never be reached -} \ No newline at end of file diff --git a/src/statemachine.h b/src/statemachine.h deleted file mode 100644 index a2a87097..00000000 --- a/src/statemachine.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef _STATEMACHINE_H -#define _STATEMACHINE_H - -#include "globals.h" -#include "cyclic.h" - -void stateMachine(void *pvParameters); -void stateMachineInit(); - -#endif diff --git a/src/wifiscan.cpp b/src/wifiscan.cpp index 4e2500b6..5613a5ec 100644 --- a/src/wifiscan.cpp +++ b/src/wifiscan.cpp @@ -46,21 +46,12 @@ void wifi_sniffer_init(void) { ESP_ERROR_CHECK(esp_wifi_set_promiscuous(true)); // now switch on monitor mode } -// IRQ Handler -void IRAM_ATTR ChannelSwitchIRQ() { - BaseType_t xHigherPriorityTaskWoken = pdFALSE; - // unblock wifi channel rotation task - xSemaphoreGiveFromISR(xWifiChannelSwitchSemaphore, &xHigherPriorityTaskWoken); -} - // Wifi channel rotation task void switchWifiChannel(void *parameter) { while (1) { - // task is remaining in block state waiting for channel switch timer - // interrupt event - xSemaphoreTake(xWifiChannelSwitchSemaphore, portMAX_DELAY); - // rotates variable channel 1..WIFI_CHANNEL_MAX - channel = (channel % WIFI_CHANNEL_MAX) + 1; + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); // waiting for channel switch timer + channel = + (channel % WIFI_CHANNEL_MAX) + 1; // rotate channel 1..WIFI_CHANNEL_MAX esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE); ESP_LOGD(TAG, "Wifi set channel %d", channel); }