commit
9ea27e9664
@ -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
|
||||
|
@ -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
|
||||
|
@ -71,7 +71,7 @@ extern TaskHandle_t ledLoopTask;
|
||||
#endif
|
||||
|
||||
#ifdef HAS_SPI
|
||||
extern QueueHandle_t SPISendQueue;
|
||||
#include "spi.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAS_DISPLAY
|
||||
|
@ -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
|
@ -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)
|
||||
|
||||
|
@ -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
|
@ -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
|
61
src/main.cpp
61
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<uint16_t> 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
|
||||
}
|
@ -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);
|
||||
|
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
|
||||
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);
|
||||
|
Loading…
Reference in New Issue
Block a user