new lmic tasking

This commit is contained in:
Klaus K Wilting 2018-10-03 16:24:45 +02:00
parent e5df1013b3
commit 1eceea2686
12 changed files with 115 additions and 78 deletions

View File

@ -26,13 +26,13 @@ description = Paxcounter is a proof-of-concept ESP32 device for metering passeng
[common] [common]
; for release_version use max. 10 chars total, use any decimal format like "a.b.c" ; 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! ; 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 ; 0=None, 1=Error, 2=Warn, 3=Info, 4=Debug, 5=Verbose
debug_level = 0 debug_level = 0
; UPLOAD MODE: select esptool to flash via USB/UART, select custom to upload to cloud for OTA ; UPLOAD MODE: select esptool to flash via USB/UART, select custom to upload to cloud for OTA
;upload_protocol = esptool upload_protocol = esptool
upload_protocol = custom ;upload_protocol = custom
extra_scripts = pre:build.py extra_scripts = pre:build.py
keyfile = ota.conf keyfile = ota.conf
platform_espressif32 = espressif32@1.4.0 platform_espressif32 = espressif32@1.4.0

View File

@ -26,11 +26,14 @@ void doHousekeeping() {
// task storage debugging // // task storage debugging //
ESP_LOGD(TAG, "Wifiloop %d bytes left", ESP_LOGD(TAG, "Wifiloop %d bytes left",
uxTaskGetStackHighWaterMark(wifiSwitchTask)); uxTaskGetStackHighWaterMark(wifiSwitchTask));
ESP_LOGD(TAG, "Statemachine %d bytes left", ESP_LOGD(TAG, "Stateloop %d bytes left",
uxTaskGetStackHighWaterMark(stateMachineTask)); uxTaskGetStackHighWaterMark(stateMachineTask));
#ifdef HAS_GPS #ifdef HAS_GPS
ESP_LOGD(TAG, "Gpsloop %d bytes left", uxTaskGetStackHighWaterMark(GpsTask)); ESP_LOGD(TAG, "Gpsloop %d bytes left", uxTaskGetStackHighWaterMark(GpsTask));
#endif #endif
#ifdef HAS_SPI
ESP_LOGD(TAG, "Spiloop %d bytes left", uxTaskGetStackHighWaterMark(SpiTask));
#endif
#if (HAS_LED != NOT_A_PIN) || defined(HAS_RGB_LED) #if (HAS_LED != NOT_A_PIN) || defined(HAS_RGB_LED)
ESP_LOGD(TAG, "LEDloop %d bytes left", uxTaskGetStackHighWaterMark(ledLoopTask)); ESP_LOGD(TAG, "LEDloop %d bytes left", uxTaskGetStackHighWaterMark(ledLoopTask));
#endif #endif

View File

@ -71,7 +71,7 @@ extern TaskHandle_t ledLoopTask;
#endif #endif
#ifdef HAS_SPI #ifdef HAS_SPI
extern QueueHandle_t SPISendQueue; #include "spi.h"
#endif #endif
#ifdef HAS_DISPLAY #ifdef HAS_DISPLAY

View File

@ -7,6 +7,7 @@ static const char TAG[] = "main";
TinyGPSPlus gps; TinyGPSPlus gps;
gpsStatus_t gps_status; gpsStatus_t gps_status;
TaskHandle_t GpsTask;
// read GPS data and cast to global struct // read GPS data and cast to global struct
void gps_read() { void gps_read() {
@ -67,6 +68,8 @@ void gps_loop(void *pvParameters) {
} // end of infinite loop } // end of infinite loop
vTaskDelete(NULL); // shoud never be reached
} // gps_loop() } // gps_loop()
#endif // HAS_GPS #endif // HAS_GPS

View File

@ -6,6 +6,8 @@ led_states LEDState = LED_OFF; // LED state global for state machine
led_states previousLEDState = led_states previousLEDState =
LED_ON; // This will force LED to be off at boot since State is OFF 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 uint16_t LEDColor = COLOR_NONE, LEDBlinkDuration = 0; // state machine variables
unsigned long LEDBlinkStarted = 0; // When (in millis() led blink started) unsigned long LEDBlinkStarted = 0; // When (in millis() led blink started)

View File

@ -6,6 +6,9 @@
// Local logging Tag // Local logging Tag
static const char TAG[] = "lora"; static const char TAG[] = "lora";
osjob_t sendjob;
QueueHandle_t LoraSendQueue;
// LMIC enhanced Pin mapping // LMIC enhanced Pin mapping
const lmic_pinmap lmic_pins = {.mosi = PIN_SPI_MOSI, const lmic_pinmap lmic_pins = {.mosi = PIN_SPI_MOSI,
.miso = PIN_SPI_MISO, .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 // LMIC callback functions
void os_getDevKey(u1_t *buf) { memcpy(buf, APPKEY, 16); } void os_getDevKey(u1_t *buf) { memcpy(buf, APPKEY, 16); }
@ -216,6 +207,9 @@ void onEvent(ev_t ev) {
// the library) // the library)
switch_lora(cfg.lorasf, cfg.txpower); switch_lora(cfg.lorasf, cfg.txpower);
// kickoff first send job
os_setCallback(&sendjob, lora_send);
// show effective LoRa parameters after join // show effective LoRa parameters after join
ESP_LOGI(TAG, "ADR=%d, SF=%d, TXPOWER=%d", cfg.adrmode, cfg.lorasf, ESP_LOGI(TAG, "ADR=%d, SF=%d, TXPOWER=%d", cfg.adrmode, cfg.lorasf,
cfg.txpower); 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 #endif // HAS_LORA

View File

@ -25,6 +25,6 @@ void os_getArtEui(u1_t *buf);
void os_getDevEui(u1_t *buf); void os_getDevEui(u1_t *buf);
void showLoraKeys(void); void showLoraKeys(void);
void switch_lora(uint8_t sf, uint8_t tx); void switch_lora(uint8_t sf, uint8_t tx);
void initlmic(osjob_t *j); void lora_send(osjob_t *job);
#endif #endif

View File

@ -29,11 +29,12 @@ Task Core Prio Purpose
==================================================================================== ====================================================================================
wifiloop 0 4 rotates wifi channels wifiloop 0 4 rotates wifi channels
ledloop 0 3 blinks LEDs 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 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 IDLE 1 0 ESP32 arduino scheduler
ESP32 hardware timers ESP32 hardware timers
@ -65,23 +66,6 @@ TaskHandle_t stateMachineTask, wifiSwitchTask;
SemaphoreHandle_t xWifiChannelSwitchSemaphore; 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<uint16_t> macs; // container holding unique MAC adress hashes std::set<uint16_t> macs; // container holding unique MAC adress hashes
// initialize payload encoder // initialize payload encoder
@ -138,7 +122,6 @@ void setup() {
strcat_P(features, " BLE"); strcat_P(features, " BLE");
#else #else
bool btstop = btStop(); bool btstop = btStop();
//esp_bt_controller_mem_release(ESP_BT_MODE_BTDM);
#endif #endif
// initialize battery status // initialize battery status
@ -189,6 +172,16 @@ void setup() {
} else } else
ESP_LOGI(TAG, "LORA send queue created, size %d Bytes", ESP_LOGI(TAG, "LORA send queue created, size %d Bytes",
SEND_QUEUE_SIZE * PAYLOAD_BUFFER_SIZE); 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 #endif
// initialize SPI // initialize SPI
@ -293,7 +286,7 @@ void setup() {
get_salt(); // get new 16bit for salting hashes get_salt(); // get new 16bit for salting hashes
#ifdef HAS_GPS #ifdef HAS_GPS
ESP_LOGI(TAG, "Starting GPS..."); ESP_LOGI(TAG, "Starting GPSloop...");
xTaskCreatePinnedToCore(gps_loop, /* task function */ xTaskCreatePinnedToCore(gps_loop, /* task function */
"gpsloop", /* name of task */ "gpsloop", /* name of task */
1024, /* stack size of task */ 1024, /* stack size of task */
@ -303,6 +296,17 @@ void setup() {
0); /* CPU core */ 0); /* CPU core */
#endif #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 // start state machine
ESP_LOGI(TAG, "Starting Statemachine..."); ESP_LOGI(TAG, "Starting Statemachine...");
xTaskCreatePinnedToCore(stateMachine, /* task function */ xTaskCreatePinnedToCore(stateMachine, /* task function */
@ -338,14 +342,13 @@ void setup() {
} // setup() } // setup()
void loop() { 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) { 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 vTaskDelay(2 / portTICK_PERIOD_MS); // yield to CPU
} }
vTaskDelete(NULL); // shoud never be reached
} }

View File

@ -75,33 +75,6 @@ void IRAM_ATTR SendCycleIRQ() {
portEXIT_CRITICAL(&mutexSendCycle); 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() { void flushQueues() {
#ifdef HAS_LORA #ifdef HAS_LORA
xQueueReset(LoraSendQueue); xQueueReset(LoraSendQueue);

30
src/spi.cpp Normal file
View File

@ -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

9
src/spi.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef _SPI_H
#define _SPI_H
extern TaskHandle_t SpiTask;
extern QueueHandle_t SPISendQueue;
void spi_loop(void *pvParameters);
#endif

View File

@ -27,11 +27,10 @@ void stateMachine(void *pvParameters) {
// check housekeeping cycle and if due do the work // check housekeeping cycle and if due do the work
if (HomeCycleIRQ) if (HomeCycleIRQ)
doHousekeeping(); doHousekeeping();
// check send cycle and if due enqueue payload to send
// check send cycle and if due enqueue payload to send
if (SendCycleTimerIRQ) if (SendCycleTimerIRQ)
sendPayload(); sendPayload();
// check send queues and process due payload to send
checkSendQueues();
// give yield to CPU // give yield to CPU
vTaskDelay(2 / portTICK_PERIOD_MS); vTaskDelay(2 / portTICK_PERIOD_MS);