From 1eceea2686980004411ca3baae109465a2cbc654 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Wed, 3 Oct 2018 16:24:45 +0200 Subject: [PATCH] new lmic tasking --- platformio.ini | 6 ++--- src/cyclic.cpp | 5 +++- src/globals.h | 2 +- src/gps.cpp | 3 +++ src/led.cpp | 2 ++ src/lorawan.cpp | 39 +++++++++++++++++++--------- src/lorawan.h | 2 +- src/main.cpp | 61 +++++++++++++++++++++++--------------------- src/senddata.cpp | 27 -------------------- src/spi.cpp | 30 ++++++++++++++++++++++ src/spi.h | 9 +++++++ src/statemachine.cpp | 7 +++-- 12 files changed, 115 insertions(+), 78 deletions(-) create mode 100644 src/spi.cpp create mode 100644 src/spi.h diff --git a/platformio.ini b/platformio.ini index 9683cda7..fe7ad5a5 100644 --- a/platformio.ini +++ b/platformio.ini @@ -26,13 +26,13 @@ description = Paxcounter is a proof-of-concept ESP32 device for metering passeng [common] ; for release_version use max. 10 chars total, use any decimal format like "a.b.c" -release_version = 1.5.18 +release_version = 1.6.0 ; DEBUG LEVEL: For production run set to 0, otherwise device will leak RAM while running! ; 0=None, 1=Error, 2=Warn, 3=Info, 4=Debug, 5=Verbose debug_level = 0 ; UPLOAD MODE: select esptool to flash via USB/UART, select custom to upload to cloud for OTA -;upload_protocol = esptool -upload_protocol = custom +upload_protocol = esptool +;upload_protocol = custom extra_scripts = pre:build.py keyfile = ota.conf platform_espressif32 = espressif32@1.4.0 diff --git a/src/cyclic.cpp b/src/cyclic.cpp index 4dbff221..39ace8e5 100644 --- a/src/cyclic.cpp +++ b/src/cyclic.cpp @@ -26,11 +26,14 @@ void doHousekeeping() { // task storage debugging // ESP_LOGD(TAG, "Wifiloop %d bytes left", uxTaskGetStackHighWaterMark(wifiSwitchTask)); - ESP_LOGD(TAG, "Statemachine %d bytes left", + ESP_LOGD(TAG, "Stateloop %d bytes left", uxTaskGetStackHighWaterMark(stateMachineTask)); #ifdef HAS_GPS ESP_LOGD(TAG, "Gpsloop %d bytes left", uxTaskGetStackHighWaterMark(GpsTask)); #endif +#ifdef HAS_SPI + ESP_LOGD(TAG, "Spiloop %d bytes left", uxTaskGetStackHighWaterMark(SpiTask)); +#endif #if (HAS_LED != NOT_A_PIN) || defined(HAS_RGB_LED) ESP_LOGD(TAG, "LEDloop %d bytes left", uxTaskGetStackHighWaterMark(ledLoopTask)); #endif diff --git a/src/globals.h b/src/globals.h index eb0adc11..1f863dfe 100644 --- a/src/globals.h +++ b/src/globals.h @@ -71,7 +71,7 @@ extern TaskHandle_t ledLoopTask; #endif #ifdef HAS_SPI -extern QueueHandle_t SPISendQueue; +#include "spi.h" #endif #ifdef HAS_DISPLAY diff --git a/src/gps.cpp b/src/gps.cpp index 849ca30e..d2958a8b 100644 --- a/src/gps.cpp +++ b/src/gps.cpp @@ -7,6 +7,7 @@ static const char TAG[] = "main"; TinyGPSPlus gps; gpsStatus_t gps_status; +TaskHandle_t GpsTask; // read GPS data and cast to global struct void gps_read() { @@ -67,6 +68,8 @@ void gps_loop(void *pvParameters) { } // end of infinite loop + vTaskDelete(NULL); // shoud never be reached + } // gps_loop() #endif // HAS_GPS \ No newline at end of file diff --git a/src/led.cpp b/src/led.cpp index 9379d9e4..59965dce 100644 --- a/src/led.cpp +++ b/src/led.cpp @@ -6,6 +6,8 @@ led_states LEDState = LED_OFF; // LED state global for state machine led_states previousLEDState = LED_ON; // This will force LED to be off at boot since State is OFF +TaskHandle_t ledLoopTask; + uint16_t LEDColor = COLOR_NONE, LEDBlinkDuration = 0; // state machine variables unsigned long LEDBlinkStarted = 0; // When (in millis() led blink started) diff --git a/src/lorawan.cpp b/src/lorawan.cpp index 49a6b861..d7e85d36 100644 --- a/src/lorawan.cpp +++ b/src/lorawan.cpp @@ -6,6 +6,9 @@ // Local logging Tag static const char TAG[] = "lora"; +osjob_t sendjob; +QueueHandle_t LoraSendQueue; + // LMIC enhanced Pin mapping const lmic_pinmap lmic_pins = {.mosi = PIN_SPI_MOSI, .miso = PIN_SPI_MISO, @@ -63,18 +66,6 @@ void RevBytes(unsigned char *b, size_t c) { } } -// initial lmic job -void initlmic(osjob_t *j) { - // reset MAC state - LMIC_reset(); - // This tells LMIC to make the receive windows bigger, in case your clock is - // 1% faster or slower. - LMIC_setClockError(MAX_CLOCK_ERROR * 1 / 100); - // start joining - LMIC_startJoining(); - // init done - onEvent() callback will be invoked... -} - // LMIC callback functions void os_getDevKey(u1_t *buf) { memcpy(buf, APPKEY, 16); } @@ -216,6 +207,9 @@ void onEvent(ev_t ev) { // the library) switch_lora(cfg.lorasf, cfg.txpower); + // kickoff first send job + os_setCallback(&sendjob, lora_send); + // show effective LoRa parameters after join ESP_LOGI(TAG, "ADR=%d, SF=%d, TXPOWER=%d", cfg.adrmode, cfg.lorasf, cfg.txpower); @@ -300,4 +294,25 @@ void switch_lora(uint8_t sf, uint8_t tx) { } } +void lora_send(osjob_t *job) { + MessageBuffer_t SendBuffer; + // Check if there is a pending TX/RX job running, if yes don't eat data + // since it cannot be sent right now + if ((LMIC.opmode & (OP_JOINING | OP_REJOIN | OP_TXDATA | OP_POLL)) != 0) { + // waiting for LoRa getting ready + } else { + if (xQueueReceive(LoraSendQueue, &SendBuffer, (TickType_t)0) == pdTRUE) { + // SendBuffer gets struct MessageBuffer with next payload from queue + LMIC_setTxData2(SendBuffer.MessagePort, SendBuffer.Message, + SendBuffer.MessageSize, (cfg.countermode & 0x02)); + ESP_LOGI(TAG, "%d bytes sent to LoRa", SendBuffer.MessageSize); + sprintf(display_line7, "PACKET QUEUED"); + } + } + // reschedule job every 0,5 - 1 sec. including a bit of random to prevent + // systematic collisions + os_setTimedCallback(job, os_getTime() + 500 + ms2osticks(random(500)), + lora_send); +} + #endif // HAS_LORA \ No newline at end of file diff --git a/src/lorawan.h b/src/lorawan.h index 162caa25..66d77f5b 100644 --- a/src/lorawan.h +++ b/src/lorawan.h @@ -25,6 +25,6 @@ void os_getArtEui(u1_t *buf); void os_getDevEui(u1_t *buf); void showLoraKeys(void); void switch_lora(uint8_t sf, uint8_t tx); -void initlmic(osjob_t *j); +void lora_send(osjob_t *job); #endif \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 0961af1a..4b61abdf 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -29,11 +29,12 @@ Task Core Prio Purpose ==================================================================================== wifiloop 0 4 rotates wifi channels ledloop 0 3 blinks LEDs -gpsloop 0 2 read data from GPS over serial or i2c +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 task +IDLE 0 0 ESP32 arduino scheduler -> runs wifi sniffer -looptask 1 1 arduino loop() -> runs the LMIC stack +looptask 1 1 arduino core -> runs the LMIC LoRa stack IDLE 1 0 ESP32 arduino scheduler ESP32 hardware timers @@ -65,23 +66,6 @@ TaskHandle_t stateMachineTask, wifiSwitchTask; SemaphoreHandle_t xWifiChannelSwitchSemaphore; -// RTos send queues for payload transmit -#ifdef HAS_LORA -QueueHandle_t LoraSendQueue; -#endif - -#ifdef HAS_SPI -QueueHandle_t SPISendQueue; -#endif - -#ifdef HAS_GPS -TaskHandle_t GpsTask; -#endif - -#if (HAS_LED != NOT_A_PIN) || defined(HAS_RGB_LED) -TaskHandle_t ledLoopTask; -#endif - std::set macs; // container holding unique MAC adress hashes // initialize payload encoder @@ -138,7 +122,6 @@ void setup() { strcat_P(features, " BLE"); #else bool btstop = btStop(); - //esp_bt_controller_mem_release(ESP_BT_MODE_BTDM); #endif // initialize battery status @@ -189,6 +172,16 @@ void setup() { } else ESP_LOGI(TAG, "LORA send queue created, size %d Bytes", SEND_QUEUE_SIZE * PAYLOAD_BUFFER_SIZE); + + ESP_LOGI(TAG, "Starting LMIC..."); + os_init(); // initialize lmic run-time environment on core 1 + LMIC_reset(); // initialize lmic MAC + LMIC_setClockError(MAX_CLOCK_ERROR * 1 / + 100); // This tells LMIC to make the receive windows + // bigger, in case your clock is 1% faster or slower. + + LMIC_startJoining(); // start joining + #endif // initialize SPI @@ -293,7 +286,7 @@ void setup() { get_salt(); // get new 16bit for salting hashes #ifdef HAS_GPS - ESP_LOGI(TAG, "Starting GPS..."); + ESP_LOGI(TAG, "Starting GPSloop..."); xTaskCreatePinnedToCore(gps_loop, /* task function */ "gpsloop", /* name of task */ 1024, /* stack size of task */ @@ -303,6 +296,17 @@ void setup() { 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 */ +#endif + // start state machine ESP_LOGI(TAG, "Starting Statemachine..."); xTaskCreatePinnedToCore(stateMachine, /* task function */ @@ -338,14 +342,13 @@ void setup() { } // setup() void loop() { - osjob_t initjob; - // initialize run-time env - os_init(); - // setup initial job - os_setCallback(&initjob, initlmic); - // execute scheduled jobs and events + while (1) { - os_runloop_once(); // execute LMIC jobs +#ifdef HAS_LORA + os_runloop_once(); // execute lmic scheduled jobs and events +#endif vTaskDelay(2 / portTICK_PERIOD_MS); // yield to CPU } + + vTaskDelete(NULL); // shoud never be reached } \ No newline at end of file diff --git a/src/senddata.cpp b/src/senddata.cpp index d4f89d62..fa4eb946 100644 --- a/src/senddata.cpp +++ b/src/senddata.cpp @@ -75,33 +75,6 @@ void IRAM_ATTR SendCycleIRQ() { portEXIT_CRITICAL(&mutexSendCycle); } -// interrupt triggered function to eat data from send queues and transmit it -void checkSendQueues() { - MessageBuffer_t SendBuffer; - -#ifdef HAS_LORA - // Check if there is a pending TX/RX job running - if ((LMIC.opmode & (OP_JOINING | OP_REJOIN | OP_TXDATA | OP_POLL)) != 0) { - // LoRa Busy -> don't eat data from queue, since it cannot be sent - } else { - if (xQueueReceive(LoraSendQueue, &SendBuffer, (TickType_t)0) == pdTRUE) { - // SendBuffer gets struct MessageBuffer with next payload from queue - LMIC_setTxData2(SendBuffer.MessagePort, SendBuffer.Message, - SendBuffer.MessageSize, (cfg.countermode & 0x02)); - ESP_LOGI(TAG, "%d bytes sent to LoRa", SendBuffer.MessageSize); - sprintf(display_line7, "PACKET QUEUED"); - } - } -#endif - -#ifdef HAS_SPI - if (xQueueReceive(SPISendQueue, &SendBuffer, (TickType_t)0) == pdTRUE) { - ESP_LOGI(TAG, "%d bytes sent to SPI", SendBuffer.MessageSize); - } -#endif - -} // checkSendQueues - void flushQueues() { #ifdef HAS_LORA xQueueReset(LoraSendQueue); diff --git a/src/spi.cpp b/src/spi.cpp new file mode 100644 index 00000000..57da9287 --- /dev/null +++ b/src/spi.cpp @@ -0,0 +1,30 @@ +#ifdef HAS_SPI + +#include "globals.h" + +// Local logging tag +static const char TAG[] = "main"; + +MessageBuffer_t SendBuffer; + +QueueHandle_t SPISendQueue; +TaskHandle_t SpiTask; + +// SPI feed Task +void spi_loop(void *pvParameters) { + + configASSERT(((uint32_t)pvParameters) == 1); // FreeRTOS check + + while (1) { + if (xQueueReceive(SPISendQueue, &SendBuffer, (TickType_t)0) == pdTRUE) { + ESP_LOGI(TAG, "%d bytes sent to SPI", SendBuffer.MessageSize); + } + vTaskDelay(2 / portTICK_PERIOD_MS); // yield to CPU + + } // end of infinite loop + + vTaskDelete(NULL); // shoud never be reached + +} // spi_loop() + +#endif // HAS_SPI \ No newline at end of file diff --git a/src/spi.h b/src/spi.h new file mode 100644 index 00000000..b258a2ce --- /dev/null +++ b/src/spi.h @@ -0,0 +1,9 @@ +#ifndef _SPI_H +#define _SPI_H + +extern TaskHandle_t SpiTask; +extern QueueHandle_t SPISendQueue; + +void spi_loop(void *pvParameters); + +#endif \ No newline at end of file diff --git a/src/statemachine.cpp b/src/statemachine.cpp index b0476ccb..2592aa07 100644 --- a/src/statemachine.cpp +++ b/src/statemachine.cpp @@ -27,12 +27,11 @@ void stateMachine(void *pvParameters) { // check housekeeping cycle and if due do the work if (HomeCycleIRQ) doHousekeeping(); - // check send cycle and if due enqueue payload to send + + // check send cycle and if due enqueue payload to send if (SendCycleTimerIRQ) sendPayload(); - // check send queues and process due payload to send - checkSendQueues(); - + // give yield to CPU vTaskDelay(2 / portTICK_PERIOD_MS); }