commit
9ea27e9664
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
@ -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)
|
||||||
|
|
||||||
|
@ -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
|
@ -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
|
61
src/main.cpp
61
src/main.cpp
@ -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
|
||||||
}
|
}
|
@ -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
30
src/spi.cpp
Normal 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
9
src/spi.h
Normal 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
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user