commit
aa00cb896e
@ -26,7 +26,7 @@ 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.16
|
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
|
||||||
|
@ -1,23 +1,12 @@
|
|||||||
#ifdef HAS_BUTTON
|
#ifdef HAS_BUTTON
|
||||||
|
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include "senddata.h"
|
#include "button.h"
|
||||||
|
|
||||||
// Local logging tag
|
// Local logging tag
|
||||||
static const char TAG[] = "main";
|
static const char TAG[] = "main";
|
||||||
|
|
||||||
portMUX_TYPE mutexButton = portMUX_INITIALIZER_UNLOCKED;
|
|
||||||
|
|
||||||
void IRAM_ATTR ButtonIRQ() {
|
|
||||||
portENTER_CRITICAL(&mutexButton);
|
|
||||||
ButtonPressedIRQ++;
|
|
||||||
portEXIT_CRITICAL(&mutexButton);
|
|
||||||
}
|
|
||||||
|
|
||||||
void readButton() {
|
void readButton() {
|
||||||
portENTER_CRITICAL(&mutexButton);
|
|
||||||
ButtonPressedIRQ = 0;
|
|
||||||
portEXIT_CRITICAL(&mutexButton);
|
|
||||||
ESP_LOGI(TAG, "Button pressed");
|
ESP_LOGI(TAG, "Button pressed");
|
||||||
payload.reset();
|
payload.reset();
|
||||||
payload.addButton(0x01);
|
payload.addButton(0x01);
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
#ifndef _BUTTON_H
|
#ifndef _BUTTON_H
|
||||||
#define _BUTTON_H
|
#define _BUTTON_H
|
||||||
|
|
||||||
void IRAM_ATTR ButtonIRQ(void);
|
#include "senddata.h"
|
||||||
void readButton(void);
|
|
||||||
|
void readButton();
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -2,22 +2,14 @@
|
|||||||
/* Interval can be set in paxcounter.conf (HOMECYCLE) */
|
/* Interval can be set in paxcounter.conf (HOMECYCLE) */
|
||||||
|
|
||||||
// Basic config
|
// Basic config
|
||||||
#include "globals.h"
|
#include "cyclic.h"
|
||||||
#include "senddata.h"
|
|
||||||
#include "ota.h"
|
|
||||||
|
|
||||||
// Local logging tag
|
// Local logging tag
|
||||||
static const char TAG[] = "main";
|
static const char TAG[] = "main";
|
||||||
|
|
||||||
portMUX_TYPE mutexHomeCycle = portMUX_INITIALIZER_UNLOCKED;
|
|
||||||
|
|
||||||
// do all housekeeping
|
// do all housekeeping
|
||||||
void doHousekeeping() {
|
void doHousekeeping() {
|
||||||
|
|
||||||
portENTER_CRITICAL(&mutexHomeCycle);
|
|
||||||
HomeCycleIRQ = 0;
|
|
||||||
portEXIT_CRITICAL(&mutexHomeCycle);
|
|
||||||
|
|
||||||
// update uptime counter
|
// update uptime counter
|
||||||
uptime();
|
uptime();
|
||||||
|
|
||||||
@ -26,17 +18,19 @@ void doHousekeeping() {
|
|||||||
ESP.restart();
|
ESP.restart();
|
||||||
|
|
||||||
// task storage debugging //
|
// task storage debugging //
|
||||||
#ifdef HAS_LORA
|
|
||||||
ESP_LOGD(TAG, "Loraloop %d bytes left",
|
|
||||||
uxTaskGetStackHighWaterMark(LoraTask));
|
|
||||||
#endif
|
|
||||||
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, "IRQhandler %d bytes left",
|
||||||
uxTaskGetStackHighWaterMark(stateMachineTask));
|
uxTaskGetStackHighWaterMark(irqHandlerTask));
|
||||||
#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)
|
||||||
|
ESP_LOGD(TAG, "LEDloop %d bytes left", uxTaskGetStackHighWaterMark(ledLoopTask));
|
||||||
|
#endif
|
||||||
|
|
||||||
// read battery voltage into global variable
|
// read battery voltage into global variable
|
||||||
#ifdef HAS_BATTERY_PROBE
|
#ifdef HAS_BATTERY_PROBE
|
||||||
@ -70,12 +64,6 @@ void doHousekeeping() {
|
|||||||
}
|
}
|
||||||
} // doHousekeeping()
|
} // doHousekeeping()
|
||||||
|
|
||||||
void IRAM_ATTR homeCycleIRQ() {
|
|
||||||
portENTER_CRITICAL(&mutexHomeCycle);
|
|
||||||
HomeCycleIRQ++;
|
|
||||||
portEXIT_CRITICAL(&mutexHomeCycle);
|
|
||||||
}
|
|
||||||
|
|
||||||
// uptime counter 64bit to prevent millis() rollover after 49 days
|
// uptime counter 64bit to prevent millis() rollover after 49 days
|
||||||
uint64_t uptime() {
|
uint64_t uptime() {
|
||||||
static uint32_t low32, high32;
|
static uint32_t low32, high32;
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
#ifndef _CYCLIC_H
|
#ifndef _CYCLIC_H
|
||||||
#define _CYCLIC_H
|
#define _CYCLIC_H
|
||||||
|
|
||||||
|
#include "globals.h"
|
||||||
|
#include "senddata.h"
|
||||||
|
|
||||||
void doHousekeeping(void);
|
void doHousekeeping(void);
|
||||||
void IRAM_ATTR homeCycleIRQ(void);
|
|
||||||
uint64_t uptime(void);
|
uint64_t uptime(void);
|
||||||
void reset_counters(void);
|
void reset_counters(void);
|
||||||
int redirect_log(const char *fmt, va_list args);
|
int redirect_log(const char *fmt, va_list args);
|
||||||
|
@ -15,8 +15,6 @@ const char lora_datarate[] = {"100908078CNA121110090807"};
|
|||||||
|
|
||||||
uint8_t volatile DisplayState = 0;
|
uint8_t volatile DisplayState = 0;
|
||||||
|
|
||||||
portMUX_TYPE mutexDisplay = portMUX_INITIALIZER_UNLOCKED;
|
|
||||||
|
|
||||||
// helper function, prints a hex key on display
|
// helper function, prints a hex key on display
|
||||||
void DisplayKey(const uint8_t *key, uint8_t len, bool lsb) {
|
void DisplayKey(const uint8_t *key, uint8_t len, bool lsb) {
|
||||||
const uint8_t *p;
|
const uint8_t *p;
|
||||||
@ -27,8 +25,9 @@ void DisplayKey(const uint8_t *key, uint8_t len, bool lsb) {
|
|||||||
u8x8.printf("\n");
|
u8x8.printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// show startup screen
|
|
||||||
void init_display(const char *Productname, const char *Version) {
|
void init_display(const char *Productname, const char *Version) {
|
||||||
|
|
||||||
|
// show startup screen
|
||||||
uint8_t buf[32];
|
uint8_t buf[32];
|
||||||
u8x8.begin();
|
u8x8.begin();
|
||||||
u8x8.setFont(u8x8_font_chroma48medium8_r);
|
u8x8.setFont(u8x8_font_chroma48medium8_r);
|
||||||
@ -93,10 +92,6 @@ void init_display(const char *Productname, const char *Version) {
|
|||||||
|
|
||||||
void refreshtheDisplay() {
|
void refreshtheDisplay() {
|
||||||
|
|
||||||
portENTER_CRITICAL(&mutexDisplay);
|
|
||||||
DisplayTimerIRQ = 0;
|
|
||||||
portEXIT_CRITICAL(&mutexDisplay);
|
|
||||||
|
|
||||||
// set display on/off according to current device configuration
|
// set display on/off according to current device configuration
|
||||||
if (DisplayState != cfg.screenon) {
|
if (DisplayState != cfg.screenon) {
|
||||||
DisplayState = cfg.screenon;
|
DisplayState = cfg.screenon;
|
||||||
@ -107,7 +102,7 @@ void refreshtheDisplay() {
|
|||||||
if (!DisplayState)
|
if (!DisplayState)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
uint8_t msgWaiting = 0;
|
uint8_t msgWaiting;
|
||||||
char buff[16]; // 16 chars line buffer
|
char buff[16]; // 16 chars line buffer
|
||||||
|
|
||||||
// update counter (lines 0-1)
|
// update counter (lines 0-1)
|
||||||
@ -192,10 +187,4 @@ void refreshtheDisplay() {
|
|||||||
|
|
||||||
} // refreshDisplay()
|
} // refreshDisplay()
|
||||||
|
|
||||||
void IRAM_ATTR DisplayIRQ() {
|
|
||||||
portENTER_CRITICAL_ISR(&mutexDisplay);
|
|
||||||
DisplayTimerIRQ++;
|
|
||||||
portEXIT_CRITICAL_ISR(&mutexDisplay);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // HAS_DISPLAY
|
#endif // HAS_DISPLAY
|
@ -9,6 +9,5 @@ extern HAS_DISPLAY u8x8;
|
|||||||
void init_display(const char *Productname, const char *Version);
|
void init_display(const char *Productname, const char *Version);
|
||||||
void refreshtheDisplay(void);
|
void refreshtheDisplay(void);
|
||||||
void DisplayKey(const uint8_t *key, uint8_t len, bool lsb);
|
void DisplayKey(const uint8_t *key, uint8_t len, bool lsb);
|
||||||
void IRAM_ATTR DisplayIRQ(void);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -46,34 +46,28 @@ extern uint16_t volatile macs_total, macs_wifi, macs_ble,
|
|||||||
batt_voltage; // display values
|
batt_voltage; // display values
|
||||||
extern std::set<uint16_t> macs; // temp storage for MACs
|
extern std::set<uint16_t> macs; // temp storage for MACs
|
||||||
extern hw_timer_t *channelSwitch, *sendCycle;
|
extern hw_timer_t *channelSwitch, *sendCycle;
|
||||||
extern volatile uint8_t SendCycleTimerIRQ, HomeCycleIRQ, DisplayTimerIRQ,
|
|
||||||
ChannelTimerIRQ, ButtonPressedIRQ;
|
|
||||||
|
|
||||||
extern std::array<uint64_t, 0xff>::iterator it;
|
extern std::array<uint64_t, 0xff>::iterator it;
|
||||||
extern std::array<uint64_t, 0xff> beacons;
|
extern std::array<uint64_t, 0xff> beacons;
|
||||||
|
|
||||||
extern SemaphoreHandle_t xWifiChannelSwitchSemaphore;
|
extern TaskHandle_t irqHandlerTask, wifiSwitchTask;
|
||||||
extern TaskHandle_t stateMachineTask, wifiSwitchTask;
|
|
||||||
|
|
||||||
#ifdef HAS_GPS
|
#ifdef HAS_GPS
|
||||||
extern TaskHandle_t GpsTask;
|
|
||||||
#include "gps.h"
|
#include "gps.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAS_LED
|
#if (HAS_LED != NOT_A_PIN) || defined(HAS_RGB_LED)
|
||||||
#include "led.h"
|
#include "led.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "payload.h"
|
#include "payload.h"
|
||||||
|
|
||||||
#ifdef HAS_LORA
|
#ifdef HAS_LORA
|
||||||
extern QueueHandle_t LoraSendQueue;
|
|
||||||
extern TaskHandle_t LoraTask;
|
|
||||||
#include "lorawan.h"
|
#include "lorawan.h"
|
||||||
#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
|
@ -19,6 +19,7 @@ typedef struct {
|
|||||||
extern TinyGPSPlus gps; // Make TinyGPS++ instance globally availabe
|
extern TinyGPSPlus gps; // Make TinyGPS++ instance globally availabe
|
||||||
extern gpsStatus_t
|
extern gpsStatus_t
|
||||||
gps_status; // Make struct for storing gps data globally available
|
gps_status; // Make struct for storing gps data globally available
|
||||||
|
extern TaskHandle_t GpsTask;
|
||||||
|
|
||||||
void gps_read(void);
|
void gps_read(void);
|
||||||
void gps_loop(void *pvParameters);
|
void gps_loop(void *pvParameters);
|
||||||
|
74
src/irqhandler.cpp
Normal file
74
src/irqhandler.cpp
Normal file
@ -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
|
28
src/irqhandler.h
Normal file
28
src/irqhandler.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#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 "senddata.h"
|
||||||
|
|
||||||
|
void irqHandler(void *pvParameters);
|
||||||
|
void IRAM_ATTR ChannelSwitchIRQ();
|
||||||
|
void IRAM_ATTR homeCycleIRQ();
|
||||||
|
void IRAM_ATTR SendCycleIRQ();
|
||||||
|
|
||||||
|
#ifdef HAS_DISPLAY
|
||||||
|
#include "display.h"
|
||||||
|
void IRAM_ATTR DisplayIRQ();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAS_BUTTON
|
||||||
|
#include "button.h"
|
||||||
|
void IRAM_ATTR ButtonIRQ();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
14
src/led.cpp
14
src/led.cpp
@ -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)
|
||||||
|
|
||||||
@ -94,7 +96,8 @@ void blink_LED(uint16_t set_color, uint16_t set_blinkduration) {
|
|||||||
LEDState = LED_ON; // Let main set LED on
|
LEDState = LED_ON; // Let main set LED on
|
||||||
}
|
}
|
||||||
|
|
||||||
void led_loop() {
|
void ledLoop(void *parameter) {
|
||||||
|
while (1) {
|
||||||
// Custom blink running always have priority other LoRaWAN led management
|
// Custom blink running always have priority other LoRaWAN led management
|
||||||
if (LEDBlinkStarted && LEDBlinkDuration) {
|
if (LEDBlinkStarted && LEDBlinkDuration) {
|
||||||
// Custom blink is finished, let this order, avoid millis() overflow
|
// Custom blink is finished, let this order, avoid millis() overflow
|
||||||
@ -116,7 +119,8 @@ void led_loop() {
|
|||||||
if (LMIC.opmode & (OP_JOINING | OP_REJOIN)) {
|
if (LMIC.opmode & (OP_JOINING | OP_REJOIN)) {
|
||||||
LEDColor = COLOR_YELLOW;
|
LEDColor = COLOR_YELLOW;
|
||||||
// quick blink 20ms on each 1/5 second
|
// quick blink 20ms on each 1/5 second
|
||||||
LEDState = ((millis() % 200) < 20) ? LED_ON : LED_OFF; // TX data pending
|
LEDState =
|
||||||
|
((millis() % 200) < 20) ? LED_ON : LED_OFF; // TX data pending
|
||||||
} else if (LMIC.opmode & (OP_TXDATA | OP_TXRXPEND)) {
|
} else if (LMIC.opmode & (OP_TXDATA | OP_TXRXPEND)) {
|
||||||
LEDColor = COLOR_BLUE;
|
LEDColor = COLOR_BLUE;
|
||||||
// small blink 10ms on each 1/2sec (not when joining)
|
// small blink 10ms on each 1/2sec (not when joining)
|
||||||
@ -157,6 +161,10 @@ void led_loop() {
|
|||||||
}
|
}
|
||||||
previousLEDState = LEDState;
|
previousLEDState = LEDState;
|
||||||
}
|
}
|
||||||
}; // led_loop()
|
// give yield to CPU
|
||||||
|
vTaskDelay(2 / portTICK_PERIOD_MS);
|
||||||
|
} // while(1)
|
||||||
|
vTaskDelete(NULL); // shoud never be reached
|
||||||
|
}; // ledloop()
|
||||||
|
|
||||||
#endif // #if (HAS_LED != NOT_A_PIN) || defined(HAS_RGB_LED)
|
#endif // #if (HAS_LED != NOT_A_PIN) || defined(HAS_RGB_LED)
|
||||||
|
@ -31,9 +31,11 @@ struct RGBColor {
|
|||||||
|
|
||||||
enum led_states { LED_OFF, LED_ON };
|
enum led_states { LED_OFF, LED_ON };
|
||||||
|
|
||||||
|
extern TaskHandle_t ledLoopTask;
|
||||||
|
|
||||||
// Exported Functions
|
// Exported Functions
|
||||||
void rgb_set_color(uint16_t hue);
|
void rgb_set_color(uint16_t hue);
|
||||||
void blink_LED(uint16_t set_color, uint16_t set_blinkduration);
|
void blink_LED(uint16_t set_color, uint16_t set_blinkduration);
|
||||||
void led_loop();
|
void ledLoop(void *parameter);
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -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,
|
||||||
@ -204,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);
|
||||||
@ -241,17 +247,6 @@ void onEvent(ev_t ev) {
|
|||||||
|
|
||||||
} // onEvent()
|
} // onEvent()
|
||||||
|
|
||||||
// LMIC FreeRTos Task
|
|
||||||
void lorawan_loop(void *pvParameters) {
|
|
||||||
|
|
||||||
configASSERT(((uint32_t)pvParameters) == 1); // FreeRTOS check
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
os_runloop_once(); // execute LMIC jobs
|
|
||||||
vTaskDelay(2 / portTICK_PERIOD_MS); // yield to CPU
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// helper function to assign LoRa datarates to numeric spreadfactor values
|
// helper function to assign LoRa datarates to numeric spreadfactor values
|
||||||
void switch_lora(uint8_t sf, uint8_t tx) {
|
void switch_lora(uint8_t sf, uint8_t tx) {
|
||||||
if (tx > 20)
|
if (tx > 20)
|
||||||
@ -299,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
|
@ -14,6 +14,8 @@
|
|||||||
#include <Wire.h>
|
#include <Wire.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
extern QueueHandle_t LoraSendQueue;
|
||||||
|
|
||||||
void onEvent(ev_t ev);
|
void onEvent(ev_t ev);
|
||||||
void gen_lora_deveui(uint8_t *pdeveui);
|
void gen_lora_deveui(uint8_t *pdeveui);
|
||||||
void RevBytes(unsigned char *b, size_t c);
|
void RevBytes(unsigned char *b, size_t c);
|
||||||
@ -22,7 +24,7 @@ void os_getDevKey(u1_t *buf);
|
|||||||
void os_getArtEui(u1_t *buf);
|
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 lorawan_loop(void *pvParameters);
|
|
||||||
void switch_lora(uint8_t sf, uint8_t tx);
|
void switch_lora(uint8_t sf, uint8_t tx);
|
||||||
|
void lora_send(osjob_t *job);
|
||||||
|
|
||||||
#endif
|
#endif
|
206
src/main.cpp
206
src/main.cpp
@ -27,19 +27,22 @@ Uused tasks and timers:
|
|||||||
|
|
||||||
Task Core Prio Purpose
|
Task Core Prio Purpose
|
||||||
====================================================================================
|
====================================================================================
|
||||||
IDLE 0 0 ESP32 arduino scheduler -> runs wifi sniffer task
|
|
||||||
gpsloop 0 2 read data from GPS over serial or i2c
|
|
||||||
IDLE 1 0 Arduino loop() -> used for LED switching
|
|
||||||
loraloop 1 2 runs the LMIC stack
|
|
||||||
statemachine 1 1 switches application process logic
|
|
||||||
wifiloop 0 4 rotates wifi channels
|
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
|
||||||
|
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
|
ESP32 hardware timers
|
||||||
==========================
|
==========================
|
||||||
0 Display-Refresh
|
0 Trigger display refresh
|
||||||
1 Wifi Channel Switch
|
1 Trigger Wifi channel switch
|
||||||
2 Send Cycle
|
2 Trigger send payload cycle
|
||||||
3 Housekeeping
|
3 Trigger housekeeping cycle
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -52,30 +55,8 @@ uint8_t volatile channel = 0; // channel rotation counter
|
|||||||
uint16_t volatile macs_total = 0, macs_wifi = 0, macs_ble = 0,
|
uint16_t volatile macs_total = 0, macs_wifi = 0, macs_ble = 0,
|
||||||
batt_voltage = 0; // globals for display
|
batt_voltage = 0; // globals for display
|
||||||
|
|
||||||
// hardware timer for cyclic tasks
|
hw_timer_t *channelSwitch, *sendCycle, *homeCycle, *displaytimer; // irq tasks
|
||||||
hw_timer_t *channelSwitch, *displaytimer, *sendCycle, *homeCycle;
|
TaskHandle_t irqHandlerTask, wifiSwitchTask;
|
||||||
|
|
||||||
// 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;
|
|
||||||
|
|
||||||
// RTos send queues for payload transmit
|
|
||||||
#ifdef HAS_LORA
|
|
||||||
QueueHandle_t LoraSendQueue;
|
|
||||||
TaskHandle_t LoraTask = NULL;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAS_SPI
|
|
||||||
QueueHandle_t SPISendQueue;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAS_GPS
|
|
||||||
TaskHandle_t GpsTask = NULL;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
std::set<uint16_t> macs; // container holding unique MAC adress hashes
|
std::set<uint16_t> macs; // container holding unique MAC adress hashes
|
||||||
|
|
||||||
@ -159,12 +140,10 @@ void setup() {
|
|||||||
strcat_P(features, "PU");
|
strcat_P(features, "PU");
|
||||||
// install button interrupt (pullup mode)
|
// install button interrupt (pullup mode)
|
||||||
pinMode(HAS_BUTTON, INPUT_PULLUP);
|
pinMode(HAS_BUTTON, INPUT_PULLUP);
|
||||||
attachInterrupt(digitalPinToInterrupt(HAS_BUTTON), ButtonIRQ, RISING);
|
|
||||||
#else
|
#else
|
||||||
strcat_P(features, "PD");
|
strcat_P(features, "PD");
|
||||||
// install button interrupt (pulldown mode)
|
// install button interrupt (pulldown mode)
|
||||||
pinMode(HAS_BUTTON, INPUT_PULLDOWN);
|
pinMode(HAS_BUTTON, INPUT_PULLDOWN);
|
||||||
attachInterrupt(digitalPinToInterrupt(HAS_BUTTON), ButtonIRQ, FALLING);
|
|
||||||
#endif // BUTTON_PULLUP
|
#endif // BUTTON_PULLUP
|
||||||
#endif // HAS_BUTTON
|
#endif // HAS_BUTTON
|
||||||
|
|
||||||
@ -183,6 +162,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
|
||||||
@ -232,16 +221,12 @@ void setup() {
|
|||||||
|
|
||||||
// setup display refresh trigger IRQ using esp32 hardware timer
|
// setup display refresh trigger IRQ using esp32 hardware timer
|
||||||
// https://techtutorialsx.com/2017/10/07/esp32-arduino-timer-interrupts/
|
// https://techtutorialsx.com/2017/10/07/esp32-arduino-timer-interrupts/
|
||||||
|
|
||||||
// prescaler 80 -> divides 80 MHz CPU freq to 1 MHz, timer 0, count up
|
// prescaler 80 -> divides 80 MHz CPU freq to 1 MHz, timer 0, count up
|
||||||
displaytimer = timerBegin(0, 80, true);
|
displaytimer = timerBegin(0, 80, true);
|
||||||
// interrupt handler DisplayIRQ, triggered by edge
|
// interrupt handler DisplayIRQ, triggered by edge
|
||||||
timerAttachInterrupt(displaytimer, &DisplayIRQ, true);
|
timerAttachInterrupt(displaytimer, &DisplayIRQ, true);
|
||||||
// reload interrupt after each trigger of display refresh cycle
|
// reload interrupt after each trigger of display refresh cycle
|
||||||
timerAlarmWrite(displaytimer, DISPLAYREFRESH_MS * 1000, true);
|
timerAlarmWrite(displaytimer, DISPLAYREFRESH_MS * 1000, true);
|
||||||
// enable display interrupt
|
|
||||||
yield();
|
|
||||||
timerAlarmEnable(displaytimer);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// setup send cycle trigger IRQ using esp32 hardware timer 2
|
// setup send cycle trigger IRQ using esp32 hardware timer 2
|
||||||
@ -255,20 +240,10 @@ void setup() {
|
|||||||
timerAlarmWrite(homeCycle, HOMECYCLE * 10000, true);
|
timerAlarmWrite(homeCycle, HOMECYCLE * 10000, true);
|
||||||
|
|
||||||
// setup channel rotation trigger IRQ using esp32 hardware timer 1
|
// setup channel rotation trigger IRQ using esp32 hardware timer 1
|
||||||
xWifiChannelSwitchSemaphore = xSemaphoreCreateBinary();
|
|
||||||
channelSwitch = timerBegin(1, 800, true);
|
channelSwitch = timerBegin(1, 800, true);
|
||||||
timerAttachInterrupt(channelSwitch, &ChannelSwitchIRQ, true);
|
timerAttachInterrupt(channelSwitch, &ChannelSwitchIRQ, true);
|
||||||
timerAlarmWrite(channelSwitch, cfg.wifichancycle * 1000, true);
|
timerAlarmWrite(channelSwitch, cfg.wifichancycle * 1000, true);
|
||||||
|
|
||||||
// enable timers
|
|
||||||
// caution, see: https://github.com/espressif/arduino-esp32/issues/1313
|
|
||||||
yield();
|
|
||||||
timerAlarmEnable(homeCycle);
|
|
||||||
yield();
|
|
||||||
timerAlarmEnable(sendCycle);
|
|
||||||
yield();
|
|
||||||
timerAlarmEnable(channelSwitch);
|
|
||||||
|
|
||||||
// show payload encoder
|
// show payload encoder
|
||||||
#if PAYLOAD_ENCODER == 1
|
#if PAYLOAD_ENCODER == 1
|
||||||
strcat_P(features, " PLAIN");
|
strcat_P(features, " PLAIN");
|
||||||
@ -288,43 +263,6 @@ void setup() {
|
|||||||
#ifdef VERBOSE
|
#ifdef VERBOSE
|
||||||
showLoraKeys();
|
showLoraKeys();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// initialize LoRaWAN LMIC run-time environment
|
|
||||||
os_init();
|
|
||||||
// reset LMIC 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);
|
|
||||||
// join network
|
|
||||||
LMIC_startJoining();
|
|
||||||
|
|
||||||
// start lmic runloop in rtos task on core 1
|
|
||||||
// (note: arduino main loop runs on core 1, too)
|
|
||||||
// https://techtutorialsx.com/2017/05/09/esp32-get-task-execution-core/
|
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Starting Lora...");
|
|
||||||
xTaskCreatePinnedToCore(lorawan_loop, /* task function */
|
|
||||||
"loraloop", /* name of task */
|
|
||||||
3048, /* stack size of task */
|
|
||||||
(void *)1, /* parameter of the task */
|
|
||||||
2, /* priority of the task */
|
|
||||||
&LoraTask, /* task handle*/
|
|
||||||
1); /* CPU core */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// if device has GPS and it is enabled, start GPS reader task on core 0 with
|
|
||||||
// higher priority than wifi channel rotation task since we process serial
|
|
||||||
// streaming NMEA data
|
|
||||||
#ifdef HAS_GPS
|
|
||||||
ESP_LOGI(TAG, "Starting GPS...");
|
|
||||||
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
|
#endif
|
||||||
|
|
||||||
// start BLE scan callback if BLE function is enabled in NVRAM configuration
|
// start BLE scan callback if BLE function is enabled in NVRAM configuration
|
||||||
@ -343,34 +281,88 @@ void setup() {
|
|||||||
// function gets it's seed from RF noise
|
// function gets it's seed from RF noise
|
||||||
get_salt(); // get new 16bit for salting hashes
|
get_salt(); // get new 16bit for salting hashes
|
||||||
|
|
||||||
// start wifi channel rotation task
|
#ifdef HAS_GPS
|
||||||
xTaskCreatePinnedToCore(switchWifiChannel, /* task function */
|
ESP_LOGI(TAG, "Starting GPSloop...");
|
||||||
"wifiloop", /* name of task */
|
xTaskCreatePinnedToCore(gps_loop, // task function
|
||||||
2048, /* stack size of task */
|
"gpsloop", // name of task
|
||||||
NULL, /* parameter of the task */
|
1024, // stack size of task
|
||||||
4, /* priority of the task */
|
(void *)1, // parameter of the task
|
||||||
&wifiSwitchTask, /* task handle*/
|
2, // priority of the task
|
||||||
0); /* CPU core */
|
&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
|
||||||
|
#endif
|
||||||
|
|
||||||
// start state machine
|
// start state machine
|
||||||
ESP_LOGI(TAG, "Starting Statemachine...");
|
ESP_LOGI(TAG, "Starting IRQ Handler...");
|
||||||
xTaskCreatePinnedToCore(stateMachine, /* task function */
|
xTaskCreatePinnedToCore(irqHandler, // task function
|
||||||
"stateloop", /* name of task */
|
"irqhandler", // name of task
|
||||||
2048, /* stack size of task */
|
2048, // stack size of task
|
||||||
(void *)1, /* parameter of the task */
|
(void *)1, // parameter of the task
|
||||||
1, /* priority of the task */
|
1, // priority of the task
|
||||||
&stateMachineTask, /* task handle */
|
&irqHandlerTask, // task handle
|
||||||
1); /* CPU core */
|
1); // CPU core
|
||||||
|
|
||||||
|
#if (HAS_LED != NOT_A_PIN) || defined(HAS_RGB_LED)
|
||||||
|
// start led loop
|
||||||
|
ESP_LOGI(TAG, "Starting LEDloop...");
|
||||||
|
xTaskCreatePinnedToCore(ledLoop, // task function
|
||||||
|
"ledloop", // name of task
|
||||||
|
1024, // stack size of task
|
||||||
|
(void *)1, // parameter of the task
|
||||||
|
3, // priority of the task
|
||||||
|
&ledLoopTask, // task handle
|
||||||
|
0); // CPU core
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// start wifi channel rotation task
|
||||||
|
ESP_LOGI(TAG, "Starting Wifi Channel rotation...");
|
||||||
|
xTaskCreatePinnedToCore(switchWifiChannel, // task function
|
||||||
|
"wifiloop", // name of task
|
||||||
|
2048, // stack size of task
|
||||||
|
NULL, // parameter of the task
|
||||||
|
4, // priority of the task
|
||||||
|
&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);
|
||||||
|
|
||||||
|
// start button interrupt
|
||||||
|
#ifdef HAS_BUTTON
|
||||||
|
#ifdef BUTTON_PULLUP
|
||||||
|
attachInterrupt(digitalPinToInterrupt(HAS_BUTTON), ButtonIRQ, RISING);
|
||||||
|
#else
|
||||||
|
attachInterrupt(digitalPinToInterrupt(HAS_BUTTON), ButtonIRQ, FALLING);
|
||||||
|
#endif
|
||||||
|
#endif // HAS_BUTTON
|
||||||
|
|
||||||
} // setup()
|
} // setup()
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
|
|
||||||
// switch LED state if device has LED(s)
|
while (1) {
|
||||||
#if (HAS_LED != NOT_A_PIN) || defined(HAS_RGB_LED)
|
#ifdef HAS_LORA
|
||||||
led_loop();
|
os_runloop_once(); // execute lmic scheduled jobs and events
|
||||||
#endif
|
#endif
|
||||||
|
vTaskDelay(2 / portTICK_PERIOD_MS); // yield to CPU
|
||||||
|
}
|
||||||
|
|
||||||
// give yield to CPU
|
vTaskDelete(NULL); // shoud never be reached
|
||||||
vTaskDelay(2 / portTICK_PERIOD_MS);
|
|
||||||
}
|
}
|
@ -6,12 +6,11 @@
|
|||||||
#include <esp32-hal-timer.h> // needed for timers
|
#include <esp32-hal-timer.h> // needed for timers
|
||||||
|
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include "led.h"
|
|
||||||
#include "wifiscan.h"
|
#include "wifiscan.h"
|
||||||
#include "configmanager.h"
|
#include "configmanager.h"
|
||||||
#include "cyclic.h"
|
#include "cyclic.h"
|
||||||
#include "beacon_array.h"
|
#include "beacon_array.h"
|
||||||
#include "ota.h"
|
#include "ota.h"
|
||||||
#include "statemachine.h"
|
#include "irqhandler.h"
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -1,8 +1,6 @@
|
|||||||
// Basic Config
|
// Basic Config
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
|
|
||||||
portMUX_TYPE mutexSendCycle = portMUX_INITIALIZER_UNLOCKED;
|
|
||||||
|
|
||||||
// put data to send in RTos Queues used for transmit over channels Lora and SPI
|
// put data to send in RTos Queues used for transmit over channels Lora and SPI
|
||||||
void SendData(uint8_t port) {
|
void SendData(uint8_t port) {
|
||||||
|
|
||||||
@ -39,10 +37,6 @@ void SendData(uint8_t port) {
|
|||||||
// interrupt triggered function to prepare payload to send
|
// interrupt triggered function to prepare payload to send
|
||||||
void sendPayload() {
|
void sendPayload() {
|
||||||
|
|
||||||
portENTER_CRITICAL(&mutexSendCycle);
|
|
||||||
SendCycleTimerIRQ = 0;
|
|
||||||
portEXIT_CRITICAL(&mutexSendCycle);
|
|
||||||
|
|
||||||
// append counter data to payload
|
// append counter data to payload
|
||||||
payload.reset();
|
payload.reset();
|
||||||
payload.addCount(macs_wifi, cfg.blescan ? macs_ble : 0);
|
payload.addCount(macs_wifi, cfg.blescan ? macs_ble : 0);
|
||||||
@ -68,40 +62,6 @@ void sendPayload() {
|
|||||||
SendData(COUNTERPORT);
|
SendData(COUNTERPORT);
|
||||||
} // sendpayload()
|
} // sendpayload()
|
||||||
|
|
||||||
// interrupt handler used for payload send cycle timer
|
|
||||||
void IRAM_ATTR SendCycleIRQ() {
|
|
||||||
portENTER_CRITICAL(&mutexSendCycle);
|
|
||||||
SendCycleTimerIRQ++;
|
|
||||||
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);
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
void SendData(uint8_t port);
|
void SendData(uint8_t port);
|
||||||
void sendPayload(void);
|
void sendPayload(void);
|
||||||
void IRAM_ATTR SendCycleIRQ(void);
|
|
||||||
void checkSendQueues(void);
|
void checkSendQueues(void);
|
||||||
void flushQueues();
|
void flushQueues();
|
||||||
|
|
||||||
|
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
|
@ -1,35 +0,0 @@
|
|||||||
#include "statemachine.h"
|
|
||||||
|
|
||||||
// Local logging tag
|
|
||||||
static const char TAG[] = "main";
|
|
||||||
|
|
||||||
void stateMachine(void *pvParameters) {
|
|
||||||
|
|
||||||
configASSERT(((uint32_t)pvParameters) == 1); // FreeRTOS check
|
|
||||||
|
|
||||||
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();
|
|
||||||
// check send queues and process due payload to send
|
|
||||||
checkSendQueues();
|
|
||||||
|
|
||||||
// give yield to CPU
|
|
||||||
vTaskDelay(2 / portTICK_PERIOD_MS);
|
|
||||||
}
|
|
||||||
vTaskDelete(NULL); // shoud never be reached
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
#ifndef _STATEMACHINE_H
|
|
||||||
#define _STATEMACHINE_H
|
|
||||||
|
|
||||||
#include "globals.h"
|
|
||||||
#include "led.h"
|
|
||||||
#include "wifiscan.h"
|
|
||||||
#include "senddata.h"
|
|
||||||
#include "cyclic.h"
|
|
||||||
|
|
||||||
void stateMachine(void *pvParameters);
|
|
||||||
void stateMachineInit();
|
|
||||||
|
|
||||||
#endif
|
|
@ -46,21 +46,12 @@ void wifi_sniffer_init(void) {
|
|||||||
ESP_ERROR_CHECK(esp_wifi_set_promiscuous(true)); // now switch on monitor mode
|
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
|
// Wifi channel rotation task
|
||||||
void switchWifiChannel(void *parameter) {
|
void switchWifiChannel(void *parameter) {
|
||||||
while (1) {
|
while (1) {
|
||||||
// task is remaining in block state waiting for channel switch timer
|
ulTaskNotifyTake(pdTRUE, portMAX_DELAY); // waiting for channel switch timer
|
||||||
// interrupt event
|
channel =
|
||||||
xSemaphoreTake(xWifiChannelSwitchSemaphore, portMAX_DELAY);
|
(channel % WIFI_CHANNEL_MAX) + 1; // rotate channel 1..WIFI_CHANNEL_MAX
|
||||||
// rotates variable channel 1..WIFI_CHANNEL_MAX
|
|
||||||
channel = (channel % WIFI_CHANNEL_MAX) + 1;
|
|
||||||
esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE);
|
esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE);
|
||||||
ESP_LOGD(TAG, "Wifi set channel %d", channel);
|
ESP_LOGD(TAG, "Wifi set channel %d", channel);
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,6 @@ typedef struct {
|
|||||||
|
|
||||||
void wifi_sniffer_init(void);
|
void wifi_sniffer_init(void);
|
||||||
void IRAM_ATTR wifi_sniffer_packet_handler(void *buff, wifi_promiscuous_pkt_type_t type);
|
void IRAM_ATTR wifi_sniffer_packet_handler(void *buff, wifi_promiscuous_pkt_type_t type);
|
||||||
void IRAM_ATTR ChannelSwitchIRQ(void);
|
|
||||||
void switchWifiChannel(void * parameter);
|
void switchWifiChannel(void * parameter);
|
||||||
|
|
||||||
#endif
|
#endif
|
Loading…
Reference in New Issue
Block a user