commit
c7461e5e7e
@ -351,10 +351,11 @@ Note: all settings are stored in NVRAM and will be reloaded when device starts.
|
|||||||
|
|
||||||
0x09 reset functions (send this command with confirmed ack only to avoid boot loops!)
|
0x09 reset functions (send this command with confirmed ack only to avoid boot loops!)
|
||||||
|
|
||||||
0 = restart device
|
0 = restart device (coldstart)
|
||||||
1 = reset MAC counter to zero
|
1 = reset MAC counter to zero
|
||||||
2 = reset device to factory settings
|
2 = reset device to factory settings
|
||||||
3 = flush send queues
|
3 = flush send queues
|
||||||
|
4 = restart device (warmstart)
|
||||||
9 = reboot device to OTA update via Wifi mode
|
9 = reboot device to OTA update via Wifi mode
|
||||||
|
|
||||||
0x0A set LoRaWAN payload send cycle
|
0x0A set LoRaWAN payload send cycle
|
||||||
|
@ -7,7 +7,8 @@
|
|||||||
extern uint8_t DisplayIsOn;
|
extern uint8_t DisplayIsOn;
|
||||||
|
|
||||||
void refreshTheDisplay(bool nextPage = false);
|
void refreshTheDisplay(bool nextPage = false);
|
||||||
void init_display(uint8_t verbose = 0);
|
void init_display(bool verbose = false);
|
||||||
|
void shutdown_display(void);
|
||||||
void draw_page(time_t t, uint8_t page);
|
void draw_page(time_t t, uint8_t page);
|
||||||
void dp_printf(uint16_t x, uint16_t y, uint8_t font, uint8_t inv,
|
void dp_printf(uint16_t x, uint16_t y, uint8_t font, uint8_t inv,
|
||||||
const char *format, ...);
|
const char *format, ...);
|
||||||
|
@ -52,6 +52,13 @@
|
|||||||
enum sendprio_t { prio_low, prio_normal, prio_high };
|
enum sendprio_t { prio_low, prio_normal, prio_high };
|
||||||
enum timesource_t { _gps, _rtc, _lora, _unsynced };
|
enum timesource_t { _gps, _rtc, _lora, _unsynced };
|
||||||
|
|
||||||
|
enum runmode_t {
|
||||||
|
RUNMODE_POWERCYCLE = 0,
|
||||||
|
RUNMODE_NORMAL,
|
||||||
|
RUNMODE_WAKEUP,
|
||||||
|
RUNMODE_UPDATE
|
||||||
|
};
|
||||||
|
|
||||||
// Struct holding devices's runtime configuration
|
// Struct holding devices's runtime configuration
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t loradr; // 0-15, lora datarate
|
uint8_t loradr; // 0-15, lora datarate
|
||||||
@ -120,6 +127,7 @@ extern TaskHandle_t irqHandlerTask, ClockTask;
|
|||||||
extern TimerHandle_t WifiChanTimer;
|
extern TimerHandle_t WifiChanTimer;
|
||||||
extern Timezone myTZ;
|
extern Timezone myTZ;
|
||||||
extern time_t userUTCTime;
|
extern time_t userUTCTime;
|
||||||
|
extern RTC_DATA_ATTR runmode_t RTC_runmode;
|
||||||
|
|
||||||
// application includes
|
// application includes
|
||||||
#include "led.h"
|
#include "led.h"
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#ifndef _I2CSCAN_H
|
#ifndef _I2C_H
|
||||||
#define _I2CSCAN_H
|
#define _I2C_H
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
||||||
@ -11,6 +11,8 @@
|
|||||||
#define MCP_24AA02E64_PRIMARY_ADDRESS (0x50)
|
#define MCP_24AA02E64_PRIMARY_ADDRESS (0x50)
|
||||||
#define QUECTEL_GPS_PRIMARY_ADDRESS (0x10)
|
#define QUECTEL_GPS_PRIMARY_ADDRESS (0x10)
|
||||||
|
|
||||||
|
void i2c_init(void);
|
||||||
|
void i2c_deinit(void);
|
||||||
int i2c_scan(void);
|
int i2c_scan(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -4,6 +4,7 @@
|
|||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include "rcommand.h"
|
#include "rcommand.h"
|
||||||
#include "timekeeper.h"
|
#include "timekeeper.h"
|
||||||
|
#include <driver/rtc_io.h>
|
||||||
#if (TIME_SYNC_LORASERVER)
|
#if (TIME_SYNC_LORASERVER)
|
||||||
#include "timesync.h"
|
#include "timesync.h"
|
||||||
#endif
|
#endif
|
||||||
@ -21,6 +22,9 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern TaskHandle_t lmicTask, lorasendTask;
|
extern TaskHandle_t lmicTask, lorasendTask;
|
||||||
|
extern RTC_NOINIT_ATTR u4_t RTCnetid, RTCdevaddr;
|
||||||
|
extern RTC_NOINIT_ATTR u1_t RTCnwkKey[16], RTCartKey[16];
|
||||||
|
extern RTC_NOINIT_ATTR int RTCseqnoUp, RTCseqnoDn;
|
||||||
|
|
||||||
// table of LORAWAN MAC commands
|
// table of LORAWAN MAC commands
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -29,7 +33,7 @@ typedef struct {
|
|||||||
const uint8_t params;
|
const uint8_t params;
|
||||||
} mac_t;
|
} mac_t;
|
||||||
|
|
||||||
esp_err_t lora_stack_init();
|
esp_err_t lora_stack_init(bool do_join);
|
||||||
void lora_setupForNetwork(bool preJoin);
|
void lora_setupForNetwork(bool preJoin);
|
||||||
void lmictask(void *pvParameters);
|
void lmictask(void *pvParameters);
|
||||||
void gen_lora_deveui(uint8_t *pdeveui);
|
void gen_lora_deveui(uint8_t *pdeveui);
|
||||||
@ -42,10 +46,10 @@ void showLoraKeys(void);
|
|||||||
void lora_send(void *pvParameters);
|
void lora_send(void *pvParameters);
|
||||||
void lora_enqueuedata(MessageBuffer_t *message);
|
void lora_enqueuedata(MessageBuffer_t *message);
|
||||||
void lora_queuereset(void);
|
void lora_queuereset(void);
|
||||||
void myEventCallback(void *pUserData, ev_t ev);
|
static void IRAM_ATTR myEventCallback(void *pUserData, ev_t ev);
|
||||||
void myRxCallback(void *pUserData, uint8_t port, const uint8_t *pMsg,
|
static void IRAM_ATTR myRxCallback(void *pUserData, uint8_t port,
|
||||||
size_t nMsg);
|
const uint8_t *pMsg, size_t nMsg);
|
||||||
void myTxCallback(void *pUserData, int fSuccess);
|
static void IRAM_ATTR myTxCallback(void *pUserData, int fSuccess);
|
||||||
void mac_decode(const uint8_t cmd[], const uint8_t cmdlen, const mac_t table[],
|
void mac_decode(const uint8_t cmd[], const uint8_t cmdlen, const mac_t table[],
|
||||||
const uint8_t tablesize);
|
const uint8_t tablesize);
|
||||||
uint8_t getBattLevel(void);
|
uint8_t getBattLevel(void);
|
||||||
@ -54,8 +58,8 @@ const char *getBwName(rps_t rps);
|
|||||||
const char *getCrName(rps_t rps);
|
const char *getCrName(rps_t rps);
|
||||||
|
|
||||||
#if (TIME_SYNC_LORAWAN)
|
#if (TIME_SYNC_LORAWAN)
|
||||||
void user_request_network_time_callback(void *pVoidUserUTCTime,
|
static void user_request_network_time_callback(void *pVoidUserUTCTime,
|
||||||
int flagSuccess);
|
int flagSuccess);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -7,8 +7,8 @@
|
|||||||
#include <esp_coexist.h> // needed for showing coex sw version
|
#include <esp_coexist.h> // needed for showing coex sw version
|
||||||
|
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include "power.h"
|
#include "reset.h"
|
||||||
#include "i2cscan.h"
|
#include "i2c.h"
|
||||||
#include "blescan.h"
|
#include "blescan.h"
|
||||||
#include "wifiscan.h"
|
#include "wifiscan.h"
|
||||||
#include "configmanager.h"
|
#include "configmanager.h"
|
||||||
@ -16,8 +16,8 @@
|
|||||||
#include "beacon_array.h"
|
#include "beacon_array.h"
|
||||||
#include "ota.h"
|
#include "ota.h"
|
||||||
#include "irqhandler.h"
|
#include "irqhandler.h"
|
||||||
#include "led.h"
|
|
||||||
#include "spislave.h"
|
#include "spislave.h"
|
||||||
|
|
||||||
#if (HAS_LORA)
|
#if (HAS_LORA)
|
||||||
#include "lorawan.h"
|
#include "lorawan.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -17,7 +17,7 @@ void start_ota_update();
|
|||||||
int version_compare(const String v1, const String v2);
|
int version_compare(const String v1, const String v2);
|
||||||
void ota_display(const uint8_t row, const std::string status,
|
void ota_display(const uint8_t row, const std::string status,
|
||||||
const std::string msg);
|
const std::string msg);
|
||||||
void show_progress(unsigned long current, unsigned long size);
|
static void show_progress(unsigned long current, unsigned long size);
|
||||||
|
|
||||||
#endif // USE_OTA
|
#endif // USE_OTA
|
||||||
|
|
||||||
|
@ -4,7 +4,8 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <driver/adc.h>
|
#include <driver/adc.h>
|
||||||
#include <esp_adc_cal.h>
|
#include <esp_adc_cal.h>
|
||||||
#include "i2cscan.h"
|
#include "i2c.h"
|
||||||
|
#include "reset.h"
|
||||||
|
|
||||||
#define DEFAULT_VREF 1100 // tbd: use adc2_vref_to_gpio() for better estimate
|
#define DEFAULT_VREF 1100 // tbd: use adc2_vref_to_gpio() for better estimate
|
||||||
#define NO_OF_SAMPLES 64 // we do some multisampling to get better values
|
#define NO_OF_SAMPLES 64 // we do some multisampling to get better values
|
||||||
@ -14,13 +15,16 @@ void calibrate_voltage(void);
|
|||||||
bool batt_sufficient(void);
|
bool batt_sufficient(void);
|
||||||
|
|
||||||
#ifdef HAS_PMU
|
#ifdef HAS_PMU
|
||||||
|
|
||||||
#include <axp20x.h>
|
#include <axp20x.h>
|
||||||
void power_event_IRQ(void);
|
enum pmu_power_t { pmu_power_on, pmu_power_off, pmu_power_sleep };
|
||||||
void AXP192_power(bool on);
|
void AXP192_powerevent_IRQ(void);
|
||||||
|
void AXP192_power(pmu_power_t powerlevel);
|
||||||
void AXP192_init(void);
|
void AXP192_init(void);
|
||||||
void AXP192_showstatus(void);
|
void AXP192_showstatus(void);
|
||||||
uint8_t i2c_writeBytes(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t len);
|
uint8_t i2c_writeBytes(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t len);
|
||||||
uint8_t i2c_readBytes(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t len);
|
uint8_t i2c_readBytes(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t len);
|
||||||
|
|
||||||
#endif // HAS_PMU
|
#endif // HAS_PMU
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -24,6 +24,6 @@ typedef struct {
|
|||||||
} cmd_t;
|
} cmd_t;
|
||||||
|
|
||||||
void rcommand(const uint8_t cmd[], const uint8_t cmdlength);
|
void rcommand(const uint8_t cmd[], const uint8_t cmdlength);
|
||||||
void do_reset();
|
void do_reset(bool warmstart);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
12
include/reset.h
Normal file
12
include/reset.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#ifndef _RESET_H
|
||||||
|
#define _RESET_H
|
||||||
|
|
||||||
|
#include <driver/rtc_io.h>
|
||||||
|
#include <rom/rtc.h>
|
||||||
|
#include "i2c.h"
|
||||||
|
|
||||||
|
void do_reset(bool warmstart);
|
||||||
|
void do_after_reset(int reason);
|
||||||
|
void enter_deepsleep(const int wakeup_sec, const gpio_num_t wakeup_gpio);
|
||||||
|
|
||||||
|
#endif // _RESET_H
|
@ -8,7 +8,7 @@
|
|||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
|
|
||||||
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);
|
static void IRAM_ATTR wifi_sniffer_packet_handler(void *buff, wifi_promiscuous_pkt_type_t type);
|
||||||
void switchWifiChannel(TimerHandle_t xTimer);
|
void switchWifiChannel(TimerHandle_t xTimer);
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -43,7 +43,7 @@ description = Paxcounter is a device for metering passenger flows in realtime. I
|
|||||||
|
|
||||||
[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.9.6
|
release_version = 1.9.71
|
||||||
; 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 = 3
|
debug_level = 3
|
||||||
|
@ -33,7 +33,6 @@ void defaultConfig() {
|
|||||||
cfg.vendorfilter = VENDORFILTER; // 0=disabled, 1=enabled
|
cfg.vendorfilter = VENDORFILTER; // 0=disabled, 1=enabled
|
||||||
cfg.rgblum = RGBLUMINOSITY; // RGB Led luminosity (0..100%)
|
cfg.rgblum = RGBLUMINOSITY; // RGB Led luminosity (0..100%)
|
||||||
cfg.monitormode = 0; // 0=disabled, 1=enabled
|
cfg.monitormode = 0; // 0=disabled, 1=enabled
|
||||||
cfg.runmode = 0; // 0=normal, 1=update
|
|
||||||
cfg.payloadmask = PAYLOADMASK; // all payload switched on
|
cfg.payloadmask = PAYLOADMASK; // all payload switched on
|
||||||
cfg.bsecstate[BSEC_MAX_STATE_BLOB_SIZE] = {
|
cfg.bsecstate[BSEC_MAX_STATE_BLOB_SIZE] = {
|
||||||
0}; // init BSEC state for BME680 sensor
|
0}; // init BSEC state for BME680 sensor
|
||||||
@ -157,10 +156,6 @@ void saveConfig() {
|
|||||||
flash8 != cfg.monitormode)
|
flash8 != cfg.monitormode)
|
||||||
nvs_set_i8(my_handle, "monitormode", cfg.monitormode);
|
nvs_set_i8(my_handle, "monitormode", cfg.monitormode);
|
||||||
|
|
||||||
if (nvs_get_i8(my_handle, "runmode", &flash8) != ESP_OK ||
|
|
||||||
flash8 != cfg.runmode)
|
|
||||||
nvs_set_i8(my_handle, "runmode", cfg.runmode);
|
|
||||||
|
|
||||||
if (nvs_get_i16(my_handle, "rssilimit", &flash16) != ESP_OK ||
|
if (nvs_get_i16(my_handle, "rssilimit", &flash16) != ESP_OK ||
|
||||||
flash16 != cfg.rssilimit)
|
flash16 != cfg.rssilimit)
|
||||||
nvs_set_i16(my_handle, "rssilimit", cfg.rssilimit);
|
nvs_set_i16(my_handle, "rssilimit", cfg.rssilimit);
|
||||||
@ -350,14 +345,6 @@ void loadConfig() {
|
|||||||
saveConfig();
|
saveConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nvs_get_i8(my_handle, "runmode", &flash8) == ESP_OK) {
|
|
||||||
cfg.runmode = flash8;
|
|
||||||
ESP_LOGI(TAG, "Run mode = %d", flash8);
|
|
||||||
} else {
|
|
||||||
ESP_LOGI(TAG, "Run mode set to default %d", cfg.runmode);
|
|
||||||
saveConfig();
|
|
||||||
}
|
|
||||||
|
|
||||||
nvs_close(my_handle);
|
nvs_close(my_handle);
|
||||||
ESP_LOGI(TAG, "Done");
|
ESP_LOGI(TAG, "Done");
|
||||||
}
|
}
|
||||||
|
@ -20,8 +20,15 @@ void doHousekeeping() {
|
|||||||
uptime();
|
uptime();
|
||||||
|
|
||||||
// check if update mode trigger switch was set
|
// check if update mode trigger switch was set
|
||||||
if (cfg.runmode == 1)
|
if (RTC_runmode == RUNMODE_UPDATE) {
|
||||||
do_reset();
|
// check battery status if we can before doing ota
|
||||||
|
if (batt_sufficient())
|
||||||
|
do_reset(true); // warmstart to runmode update
|
||||||
|
else {
|
||||||
|
ESP_LOGE(TAG, "Battery voltage %dmV too low for OTA", batt_voltage);
|
||||||
|
RTC_runmode == RUNMODE_NORMAL; // keep running in normal mode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// task storage debugging //
|
// task storage debugging //
|
||||||
ESP_LOGD(TAG, "IRQhandler %d bytes left | Taskstate = %d",
|
ESP_LOGD(TAG, "IRQhandler %d bytes left | Taskstate = %d",
|
||||||
@ -87,7 +94,7 @@ void doHousekeeping() {
|
|||||||
get_salt(); // get new salt for salting hashes
|
get_salt(); // get new salt for salting hashes
|
||||||
|
|
||||||
if (ESP.getMinFreeHeap() <= MEM_LOW) // check again
|
if (ESP.getMinFreeHeap() <= MEM_LOW) // check again
|
||||||
do_reset(); // memory leak, reset device
|
do_reset(true); // memory leak, reset device
|
||||||
}
|
}
|
||||||
|
|
||||||
// check free PSRAM memory
|
// check free PSRAM memory
|
||||||
@ -98,7 +105,7 @@ void doHousekeeping() {
|
|||||||
get_salt(); // get new salt for salting hashes
|
get_salt(); // get new salt for salting hashes
|
||||||
|
|
||||||
if (ESP.getMinFreePsram() <= MEM_LOW) // check again
|
if (ESP.getMinFreePsram() <= MEM_LOW) // check again
|
||||||
do_reset(); // memory leak, reset device
|
do_reset(true); // memory leak, reset device
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ uint8_t displaybuf[DISPLAY_WIDTH * DISPLAY_HEIGHT / 8] = {0};
|
|||||||
|
|
||||||
QRCode qrcode;
|
QRCode qrcode;
|
||||||
|
|
||||||
void init_display(uint8_t verbose) {
|
void init_display(bool verbose) {
|
||||||
|
|
||||||
// block i2c bus access
|
// block i2c bus access
|
||||||
if (!I2C_MUTEX_LOCK())
|
if (!I2C_MUTEX_LOCK())
|
||||||
@ -70,7 +70,7 @@ void init_display(uint8_t verbose) {
|
|||||||
// is we have display RST line we toggle it to re-initialize display
|
// is we have display RST line we toggle it to re-initialize display
|
||||||
#ifdef MY_OLED_RST
|
#ifdef MY_OLED_RST
|
||||||
pinMode(MY_OLED_RST, OUTPUT);
|
pinMode(MY_OLED_RST, OUTPUT);
|
||||||
digitalWrite(MY_OLED_RST, 0); // iniialization of SSD1306 chip is executed
|
digitalWrite(MY_OLED_RST, 0); // initialization of SSD1306 chip is executed
|
||||||
delay(1); // keep RES low for at least 3us according to SSD1306 datasheet
|
delay(1); // keep RES low for at least 3us according to SSD1306 datasheet
|
||||||
digitalWrite(MY_OLED_RST, 1); // normal operation
|
digitalWrite(MY_OLED_RST, 1); // normal operation
|
||||||
#endif
|
#endif
|
||||||
@ -182,6 +182,18 @@ void refreshTheDisplay(bool nextPage) {
|
|||||||
} // mutex
|
} // mutex
|
||||||
} // refreshDisplay()
|
} // refreshDisplay()
|
||||||
|
|
||||||
|
void shutdown_display(void) {
|
||||||
|
// block i2c bus access
|
||||||
|
if (!I2C_MUTEX_LOCK())
|
||||||
|
ESP_LOGV(TAG, "[%0.3f] i2c mutex lock failed", millis() / 1000.0);
|
||||||
|
else {
|
||||||
|
cfg.screenon = 0;
|
||||||
|
oledShutdown();
|
||||||
|
delay(DISPLAYREFRESH_MS / 1000 * 1.1);
|
||||||
|
I2C_MUTEX_UNLOCK(); // release i2c bus access
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void draw_page(time_t t, uint8_t page) {
|
void draw_page(time_t t, uint8_t page) {
|
||||||
|
|
||||||
char timeState;
|
char timeState;
|
||||||
|
@ -1,10 +1,30 @@
|
|||||||
// Basic config
|
// Basic config
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include "i2cscan.h"
|
#include "i2c.h"
|
||||||
|
|
||||||
// Local logging tag
|
// Local logging tag
|
||||||
static const char TAG[] = __FILE__;
|
static const char TAG[] = __FILE__;
|
||||||
|
|
||||||
|
void i2c_init(void) {
|
||||||
|
#ifdef HAS_DISPLAY
|
||||||
|
Wire.begin(MY_OLED_SDA, MY_OLED_SCL, 400000);
|
||||||
|
#else
|
||||||
|
Wire.begin(SDA, SCL, 400000);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void i2c_deinit(void) {
|
||||||
|
Wire.~TwoWire(); // shutdown/power off I2C hardware
|
||||||
|
#ifdef HAS_DISPLAY
|
||||||
|
// to save power, because Wire.end() enables pullups
|
||||||
|
pinMode(MY_OLED_SDA, INPUT);
|
||||||
|
pinMode(MY_OLED_SCL, INPUT);
|
||||||
|
#else
|
||||||
|
pinMode(SDA, INPUT);
|
||||||
|
pinMode(SCL, INPUT);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
int i2c_scan(void) {
|
int i2c_scan(void) {
|
||||||
|
|
||||||
int i2c_ret, addr;
|
int i2c_ret, addr;
|
@ -20,7 +20,15 @@ void irqHandler(void *pvParameters) {
|
|||||||
|
|
||||||
if (InterruptStatus & UNMASK_IRQ) // interrupt handler to be enabled?
|
if (InterruptStatus & UNMASK_IRQ) // interrupt handler to be enabled?
|
||||||
mask_irq = false;
|
mask_irq = false;
|
||||||
else if (mask_irq) // suppress processing if interrupt handler is disabled
|
// else if (mask_irq) // suppress processing if interrupt handler is
|
||||||
|
// disabled
|
||||||
|
#if (HAS_LORA)
|
||||||
|
else if (mask_irq || os_queryTimeCriticalJobs(ms2osticks(100)))
|
||||||
|
#else
|
||||||
|
else if (mask_irq)
|
||||||
|
#endif
|
||||||
|
// suppress processing if interrupt handler is disabled
|
||||||
|
// or time critical lmic jobs are pending in next 100ms
|
||||||
continue;
|
continue;
|
||||||
else if (InterruptStatus & MASK_IRQ) { // interrupt handler to be disabled?
|
else if (InterruptStatus & MASK_IRQ) { // interrupt handler to be disabled?
|
||||||
mask_irq = true;
|
mask_irq = true;
|
||||||
@ -66,7 +74,7 @@ void irqHandler(void *pvParameters) {
|
|||||||
// do we have a power event?
|
// do we have a power event?
|
||||||
#if (HAS_PMU)
|
#if (HAS_PMU)
|
||||||
if (InterruptStatus & PMU_IRQ)
|
if (InterruptStatus & PMU_IRQ)
|
||||||
power_event_IRQ();
|
AXP192_powerevent_IRQ();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// is time to send the payload?
|
// is time to send the payload?
|
||||||
|
@ -28,14 +28,14 @@
|
|||||||
// so consuming more power. You may sharpen (reduce) this value if you are
|
// so consuming more power. You may sharpen (reduce) this value if you are
|
||||||
// limited on battery.
|
// limited on battery.
|
||||||
// ATTN: VALUES > 7 WILL CAUSE RECEPTION AND JOIN PROBLEMS WITH HIGH SF RATES
|
// ATTN: VALUES > 7 WILL CAUSE RECEPTION AND JOIN PROBLEMS WITH HIGH SF RATES
|
||||||
//#define CLOCK_ERROR_PROCENTAGE 5
|
#define CLOCK_ERROR_PROCENTAGE 5
|
||||||
|
|
||||||
// Set this to 1 to enable some basic debug output (using printf) about
|
// Set this to 1 to enable some basic debug output (using printf) about
|
||||||
// RF settings used during transmission and reception. Set to 2 to
|
// RF settings used during transmission and reception. Set to 2 to
|
||||||
// enable more verbose output. Make sure that printf is actually
|
// enable more verbose output. Make sure that printf is actually
|
||||||
// configured (e.g. on AVR it is not by default), otherwise using it can
|
// configured (e.g. on AVR it is not by default), otherwise using it can
|
||||||
// cause crashing.
|
// cause crashing.
|
||||||
//#define LMIC_DEBUG_LEVEL 1
|
//#define LMIC_DEBUG_LEVEL 2
|
||||||
|
|
||||||
// Enable this to allow using printf() to print to the given serial port
|
// Enable this to allow using printf() to print to the given serial port
|
||||||
// (or any other Print object). This can be easy for debugging. The
|
// (or any other Print object). This can be easy for debugging. The
|
||||||
@ -57,8 +57,7 @@
|
|||||||
// Uncomment this to disable all code related to ping
|
// Uncomment this to disable all code related to ping
|
||||||
#define DISABLE_PING
|
#define DISABLE_PING
|
||||||
// Uncomment this to disable all code related to beacon tracking.
|
// Uncomment this to disable all code related to beacon tracking.
|
||||||
// Requires ping to be disabled too
|
// Requires ping to be disabled too#define DISABLE_BEACONS
|
||||||
#define DISABLE_BEACONS
|
|
||||||
|
|
||||||
// Uncomment these to disable the corresponding MAC commands.
|
// Uncomment these to disable the corresponding MAC commands.
|
||||||
// Class A
|
// Class A
|
||||||
|
@ -18,6 +18,11 @@ static const char TAG[] = "lora";
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// variable keep its values after restart or wakeup from sleep
|
||||||
|
RTC_NOINIT_ATTR u4_t RTCnetid, RTCdevaddr;
|
||||||
|
RTC_NOINIT_ATTR u1_t RTCnwkKey[16], RTCartKey[16];
|
||||||
|
RTC_NOINIT_ATTR int RTCseqnoUp, RTCseqnoDn;
|
||||||
|
|
||||||
QueueHandle_t LoraSendQueue;
|
QueueHandle_t LoraSendQueue;
|
||||||
TaskHandle_t lmicTask = NULL, lorasendTask = NULL;
|
TaskHandle_t lmicTask = NULL, lorasendTask = NULL;
|
||||||
|
|
||||||
@ -86,9 +91,9 @@ void lora_setupForNetwork(bool preJoin) {
|
|||||||
#elif CFG_LMIC_EU_like
|
#elif CFG_LMIC_EU_like
|
||||||
// setting for TheThingsNetwork
|
// setting for TheThingsNetwork
|
||||||
// TTN uses SF9, not SF12, for RX2 window
|
// TTN uses SF9, not SF12, for RX2 window
|
||||||
LMIC.dn2Dr = EU868_DR_SF9;
|
// LMIC.dn2Dr = EU868_DR_SF9;
|
||||||
// Disable link check validation
|
// Enable link check validation
|
||||||
LMIC_setLinkCheckMode(0);
|
LMIC_setLinkCheckMode(true);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@ -244,9 +249,9 @@ void lora_send(void *pvParameters) {
|
|||||||
while (1) {
|
while (1) {
|
||||||
|
|
||||||
// postpone until we are joined if we are not
|
// postpone until we are joined if we are not
|
||||||
// while (!LMIC.devaddr) {
|
while (!LMIC.devaddr) {
|
||||||
// vTaskDelay(pdMS_TO_TICKS(500));
|
vTaskDelay(pdMS_TO_TICKS(500));
|
||||||
//}
|
}
|
||||||
|
|
||||||
// fetch next or wait for payload to send from queue
|
// fetch next or wait for payload to send from queue
|
||||||
if (xQueueReceive(LoraSendQueue, &SendBuffer, portMAX_DELAY) != pdTRUE) {
|
if (xQueueReceive(LoraSendQueue, &SendBuffer, portMAX_DELAY) != pdTRUE) {
|
||||||
@ -287,7 +292,7 @@ void lora_send(void *pvParameters) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t lora_stack_init() {
|
esp_err_t lora_stack_init(bool do_join) {
|
||||||
assert(SEND_QUEUE_SIZE);
|
assert(SEND_QUEUE_SIZE);
|
||||||
LoraSendQueue = xQueueCreate(SEND_QUEUE_SIZE, sizeof(MessageBuffer_t));
|
LoraSendQueue = xQueueCreate(SEND_QUEUE_SIZE, sizeof(MessageBuffer_t));
|
||||||
if (LoraSendQueue == 0) {
|
if (LoraSendQueue == 0) {
|
||||||
@ -303,13 +308,22 @@ esp_err_t lora_stack_init() {
|
|||||||
"lmictask", // name of task
|
"lmictask", // name of task
|
||||||
4096, // stack size of task
|
4096, // stack size of task
|
||||||
(void *)1, // parameter of the task
|
(void *)1, // parameter of the task
|
||||||
5, // priority of the task
|
2, // priority of the task
|
||||||
&lmicTask, // task handle
|
&lmicTask, // task handle
|
||||||
1); // CPU core
|
1); // CPU core
|
||||||
|
|
||||||
// start join
|
// Start join procedure if not already joined,
|
||||||
if (!LMIC_startJoining())
|
// lora_setupForNetwork(true) is called by eventhandler when joined
|
||||||
ESP_LOGI(TAG, "Already joined");
|
// else continue current session
|
||||||
|
if (do_join) {
|
||||||
|
if (!LMIC_startJoining())
|
||||||
|
ESP_LOGI(TAG, "Already joined");
|
||||||
|
} else {
|
||||||
|
LMIC_reset();
|
||||||
|
LMIC_setSession(RTCnetid, RTCdevaddr, RTCnwkKey, RTCartKey);
|
||||||
|
LMIC.seqnoUp = RTCseqnoUp;
|
||||||
|
LMIC.seqnoDn = RTCseqnoDn;
|
||||||
|
}
|
||||||
|
|
||||||
// start lmic send task
|
// start lmic send task
|
||||||
xTaskCreatePinnedToCore(lora_send, // task function
|
xTaskCreatePinnedToCore(lora_send, // task function
|
||||||
@ -357,8 +371,8 @@ void lora_enqueuedata(MessageBuffer_t *message) {
|
|||||||
void lora_queuereset(void) { xQueueReset(LoraSendQueue); }
|
void lora_queuereset(void) { xQueueReset(LoraSendQueue); }
|
||||||
|
|
||||||
#if (TIME_SYNC_LORAWAN)
|
#if (TIME_SYNC_LORAWAN)
|
||||||
void IRAM_ATTR user_request_network_time_callback(void *pVoidUserUTCTime,
|
static void IRAM_ATTR user_request_network_time_callback(void *pVoidUserUTCTime,
|
||||||
int flagSuccess) {
|
int flagSuccess) {
|
||||||
// Explicit conversion from void* to uint32_t* to avoid compiler errors
|
// Explicit conversion from void* to uint32_t* to avoid compiler errors
|
||||||
time_t *pUserUTCTime = (time_t *)pVoidUserUTCTime;
|
time_t *pUserUTCTime = (time_t *)pVoidUserUTCTime;
|
||||||
|
|
||||||
@ -428,7 +442,7 @@ void lmictask(void *pvParameters) {
|
|||||||
// so consuming more power. You may sharpen (reduce) CLOCK_ERROR_PERCENTAGE
|
// so consuming more power. You may sharpen (reduce) CLOCK_ERROR_PERCENTAGE
|
||||||
// in src/lmic_config.h if you are limited on battery.
|
// in src/lmic_config.h if you are limited on battery.
|
||||||
#ifdef CLOCK_ERROR_PROCENTAGE
|
#ifdef CLOCK_ERROR_PROCENTAGE
|
||||||
LMIC_setClockError(CLOCK_ERROR_PROCENTAGE * MAX_CLOCK_ERROR / 100);
|
LMIC_setClockError(CLOCK_ERROR_PROCENTAGE * MAX_CLOCK_ERROR / 1000);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
@ -438,7 +452,7 @@ void lmictask(void *pvParameters) {
|
|||||||
} // lmictask
|
} // lmictask
|
||||||
|
|
||||||
// lmic event handler
|
// lmic event handler
|
||||||
void myEventCallback(void *pUserData, ev_t ev) {
|
static void myEventCallback(void *pUserData, ev_t ev) {
|
||||||
|
|
||||||
// using message descriptors from LMIC library
|
// using message descriptors from LMIC library
|
||||||
static const char *const evNames[] = {LMIC_EVENT_NAME_TABLE__INIT};
|
static const char *const evNames[] = {LMIC_EVENT_NAME_TABLE__INIT};
|
||||||
@ -482,8 +496,8 @@ void myEventCallback(void *pUserData, ev_t ev) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// receive message handler
|
// receive message handler
|
||||||
void myRxCallback(void *pUserData, uint8_t port, const uint8_t *pMsg,
|
static void myRxCallback(void *pUserData, uint8_t port, const uint8_t *pMsg,
|
||||||
size_t nMsg) {
|
size_t nMsg) {
|
||||||
|
|
||||||
// display type of received data
|
// display type of received data
|
||||||
if (nMsg)
|
if (nMsg)
|
||||||
@ -537,7 +551,7 @@ void myRxCallback(void *pUserData, uint8_t port, const uint8_t *pMsg,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// transmit complete message handler
|
// transmit complete message handler
|
||||||
void myTxCallback(void *pUserData, int fSuccess) {
|
static void myTxCallback(void *pUserData, int fSuccess) {
|
||||||
|
|
||||||
#if (TIME_SYNC_LORASERVER)
|
#if (TIME_SYNC_LORASERVER)
|
||||||
// if last packet sent was a timesync request, store TX timestamp
|
// if last packet sent was a timesync request, store TX timestamp
|
||||||
|
103
src/main.cpp
103
src/main.cpp
@ -31,7 +31,7 @@ ledloop 0 3 blinks LEDs
|
|||||||
spiloop 0 2 reads/writes data on spi interface
|
spiloop 0 2 reads/writes data on spi interface
|
||||||
IDLE 0 0 ESP32 arduino scheduler -> runs wifi sniffer
|
IDLE 0 0 ESP32 arduino scheduler -> runs wifi sniffer
|
||||||
|
|
||||||
lmictask 1 5 MCCI LMiC LORAWAN stack
|
lmictask 1 2 MCCI LMiC LORAWAN stack
|
||||||
clockloop 1 4 generates realtime telegrams for external clock
|
clockloop 1 4 generates realtime telegrams for external clock
|
||||||
timesync_req 1 3 processes realtime time sync requests
|
timesync_req 1 3 processes realtime time sync requests
|
||||||
irqhandler 1 1 display, timesync, gps, etc. triggered by timers
|
irqhandler 1 1 display, timesync, gps, etc. triggered by timers
|
||||||
@ -129,53 +129,55 @@ void setup() {
|
|||||||
esp_log_level_set("*", ESP_LOG_NONE);
|
esp_log_level_set("*", ESP_LOG_NONE);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Starting Software v%s", PROGVERSION);
|
do_after_reset(rtc_get_reset_reason(0));
|
||||||
|
|
||||||
// print chip information on startup if in verbose mode
|
// print chip information on startup if in verbose mode after coldstart
|
||||||
#if (VERBOSE)
|
#if (VERBOSE)
|
||||||
esp_chip_info_t chip_info;
|
|
||||||
esp_chip_info(&chip_info);
|
if (RTC_runmode == RUNMODE_POWERCYCLE) {
|
||||||
ESP_LOGI(TAG,
|
esp_chip_info_t chip_info;
|
||||||
"This is ESP32 chip with %d CPU cores, WiFi%s%s, silicon revision "
|
esp_chip_info(&chip_info);
|
||||||
"%d, %dMB %s Flash",
|
ESP_LOGI(TAG,
|
||||||
chip_info.cores, (chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "",
|
"This is ESP32 chip with %d CPU cores, WiFi%s%s, silicon revision "
|
||||||
(chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : "",
|
"%d, %dMB %s Flash",
|
||||||
chip_info.revision, spi_flash_get_chip_size() / (1024 * 1024),
|
chip_info.cores,
|
||||||
(chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded"
|
(chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "",
|
||||||
: "external");
|
(chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : "",
|
||||||
ESP_LOGI(TAG, "Internal Total heap %d, internal Free Heap %d",
|
chip_info.revision, spi_flash_get_chip_size() / (1024 * 1024),
|
||||||
ESP.getHeapSize(), ESP.getFreeHeap());
|
(chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded"
|
||||||
|
: "external");
|
||||||
|
ESP_LOGI(TAG, "Internal Total heap %d, internal Free Heap %d",
|
||||||
|
ESP.getHeapSize(), ESP.getFreeHeap());
|
||||||
#ifdef BOARD_HAS_PSRAM
|
#ifdef BOARD_HAS_PSRAM
|
||||||
ESP_LOGI(TAG, "SPIRam Total heap %d, SPIRam Free Heap %d", ESP.getPsramSize(),
|
ESP_LOGI(TAG, "SPIRam Total heap %d, SPIRam Free Heap %d",
|
||||||
ESP.getFreePsram());
|
ESP.getPsramSize(), ESP.getFreePsram());
|
||||||
#endif
|
#endif
|
||||||
ESP_LOGI(TAG, "ChipRevision %d, Cpu Freq %d, SDK Version %s",
|
ESP_LOGI(TAG, "ChipRevision %d, Cpu Freq %d, SDK Version %s",
|
||||||
ESP.getChipRevision(), ESP.getCpuFreqMHz(), ESP.getSdkVersion());
|
ESP.getChipRevision(), ESP.getCpuFreqMHz(), ESP.getSdkVersion());
|
||||||
ESP_LOGI(TAG, "Flash Size %d, Flash Speed %d", ESP.getFlashChipSize(),
|
ESP_LOGI(TAG, "Flash Size %d, Flash Speed %d", ESP.getFlashChipSize(),
|
||||||
ESP.getFlashChipSpeed());
|
ESP.getFlashChipSpeed());
|
||||||
ESP_LOGI(TAG, "Wifi/BT software coexist version %s", esp_coex_version_get());
|
ESP_LOGI(TAG, "Wifi/BT software coexist version %s",
|
||||||
|
esp_coex_version_get());
|
||||||
|
|
||||||
#if (HAS_LORA)
|
#if (HAS_LORA)
|
||||||
ESP_LOGI(TAG, "IBM LMIC version %d.%d.%d", LMIC_VERSION_MAJOR,
|
ESP_LOGI(TAG, "IBM LMIC version %d.%d.%d", LMIC_VERSION_MAJOR,
|
||||||
LMIC_VERSION_MINOR, LMIC_VERSION_BUILD);
|
LMIC_VERSION_MINOR, LMIC_VERSION_BUILD);
|
||||||
ESP_LOGI(TAG, "Arduino LMIC version %d.%d.%d.%d",
|
ESP_LOGI(TAG, "Arduino LMIC version %d.%d.%d.%d",
|
||||||
ARDUINO_LMIC_VERSION_GET_MAJOR(ARDUINO_LMIC_VERSION),
|
ARDUINO_LMIC_VERSION_GET_MAJOR(ARDUINO_LMIC_VERSION),
|
||||||
ARDUINO_LMIC_VERSION_GET_MINOR(ARDUINO_LMIC_VERSION),
|
ARDUINO_LMIC_VERSION_GET_MINOR(ARDUINO_LMIC_VERSION),
|
||||||
ARDUINO_LMIC_VERSION_GET_PATCH(ARDUINO_LMIC_VERSION),
|
ARDUINO_LMIC_VERSION_GET_PATCH(ARDUINO_LMIC_VERSION),
|
||||||
ARDUINO_LMIC_VERSION_GET_LOCAL(ARDUINO_LMIC_VERSION));
|
ARDUINO_LMIC_VERSION_GET_LOCAL(ARDUINO_LMIC_VERSION));
|
||||||
showLoraKeys();
|
showLoraKeys();
|
||||||
#endif // HAS_LORA
|
#endif // HAS_LORA
|
||||||
|
|
||||||
#if (HAS_GPS)
|
#if (HAS_GPS)
|
||||||
ESP_LOGI(TAG, "TinyGPS+ version %s", TinyGPSPlus::libraryVersion());
|
ESP_LOGI(TAG, "TinyGPS+ version %s", TinyGPSPlus::libraryVersion());
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
#endif // VERBOSE
|
||||||
|
|
||||||
// open i2c bus
|
// open i2c bus
|
||||||
#ifdef HAS_DISPLAY
|
i2c_init();
|
||||||
Wire.begin(MY_OLED_SDA, MY_OLED_SCL, 400000);
|
|
||||||
#else
|
|
||||||
Wire.begin(SDA, SCL, 400000);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// setup power on boards with power management logic
|
// setup power on boards with power management logic
|
||||||
#ifdef EXT_POWER_SW
|
#ifdef EXT_POWER_SW
|
||||||
@ -188,8 +190,6 @@ void setup() {
|
|||||||
strcat_P(features, " PMU");
|
strcat_P(features, " PMU");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // verbose
|
|
||||||
|
|
||||||
// read (and initialize on first run) runtime settings from NVRAM
|
// read (and initialize on first run) runtime settings from NVRAM
|
||||||
loadConfig(); // includes initialize if necessary
|
loadConfig(); // includes initialize if necessary
|
||||||
|
|
||||||
@ -197,7 +197,8 @@ void setup() {
|
|||||||
#ifdef HAS_DISPLAY
|
#ifdef HAS_DISPLAY
|
||||||
strcat_P(features, " OLED");
|
strcat_P(features, " OLED");
|
||||||
DisplayIsOn = cfg.screenon;
|
DisplayIsOn = cfg.screenon;
|
||||||
init_display(!cfg.runmode); // note: blocking call
|
// display verbose info only after a coldstart (note: blocking call!)
|
||||||
|
init_display(RTC_runmode == RUNMODE_POWERCYCLE ? true : false);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// scan i2c bus for devices
|
// scan i2c bus for devices
|
||||||
@ -213,7 +214,7 @@ void setup() {
|
|||||||
pinMode(BAT_MEASURE_EN, OUTPUT);
|
pinMode(BAT_MEASURE_EN, OUTPUT);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// initialize leds
|
// initialize leds
|
||||||
#if (HAS_LED != NOT_A_PIN)
|
#if (HAS_LED != NOT_A_PIN)
|
||||||
pinMode(HAS_LED, OUTPUT);
|
pinMode(HAS_LED, OUTPUT);
|
||||||
strcat_P(features, " LED");
|
strcat_P(features, " LED");
|
||||||
@ -266,11 +267,8 @@ void setup() {
|
|||||||
#if (USE_OTA)
|
#if (USE_OTA)
|
||||||
strcat_P(features, " OTA");
|
strcat_P(features, " OTA");
|
||||||
// reboot to firmware update mode if ota trigger switch is set
|
// reboot to firmware update mode if ota trigger switch is set
|
||||||
if (cfg.runmode == 1) {
|
if (RTC_runmode == RUNMODE_UPDATE)
|
||||||
cfg.runmode = 0;
|
|
||||||
saveConfig();
|
|
||||||
start_ota_update();
|
start_ota_update();
|
||||||
}
|
|
||||||
#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
|
||||||
@ -314,7 +312,9 @@ void setup() {
|
|||||||
// initialize LoRa
|
// initialize LoRa
|
||||||
#if (HAS_LORA)
|
#if (HAS_LORA)
|
||||||
strcat_P(features, " LORA");
|
strcat_P(features, " LORA");
|
||||||
assert(lora_stack_init() == ESP_OK);
|
// kick off join, except we come from sleep
|
||||||
|
assert(lora_stack_init(RTC_runmode == RUNMODE_WAKEUP ? false : true) ==
|
||||||
|
ESP_OK);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// initialize SPI
|
// initialize SPI
|
||||||
@ -345,7 +345,7 @@ void setup() {
|
|||||||
strcat_P(features, " LPPPKD");
|
strcat_P(features, " LPPPKD");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// initialize RTC
|
// initialize RTC
|
||||||
#ifdef HAS_RTC
|
#ifdef HAS_RTC
|
||||||
strcat_P(features, " RTC");
|
strcat_P(features, " RTC");
|
||||||
assert(rtc_init());
|
assert(rtc_init());
|
||||||
@ -400,7 +400,7 @@ void setup() {
|
|||||||
assert(irqHandlerTask != NULL); // has interrupt handler task started?
|
assert(irqHandlerTask != NULL); // has interrupt handler task started?
|
||||||
ESP_LOGI(TAG, "Starting Timers...");
|
ESP_LOGI(TAG, "Starting Timers...");
|
||||||
|
|
||||||
// display interrupt
|
// display interrupt
|
||||||
#ifdef HAS_DISPLAY
|
#ifdef HAS_DISPLAY
|
||||||
// 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
|
||||||
@ -410,7 +410,7 @@ void setup() {
|
|||||||
timerAlarmEnable(displayIRQ);
|
timerAlarmEnable(displayIRQ);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// LED Matrix display interrupt
|
// LED Matrix display interrupt
|
||||||
#ifdef HAS_MATRIX_DISPLAY
|
#ifdef HAS_MATRIX_DISPLAY
|
||||||
// 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 3, count up
|
// prescaler 80 -> divides 80 MHz CPU freq to 1 MHz, timer 3, count up
|
||||||
@ -420,7 +420,7 @@ void setup() {
|
|||||||
timerAlarmEnable(matrixDisplayIRQ);
|
timerAlarmEnable(matrixDisplayIRQ);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// initialize button
|
// initialize button
|
||||||
#ifdef HAS_BUTTON
|
#ifdef HAS_BUTTON
|
||||||
strcat_P(features, " BTN_");
|
strcat_P(features, " BTN_");
|
||||||
#ifdef BUTTON_PULLUP
|
#ifdef BUTTON_PULLUP
|
||||||
@ -465,6 +465,9 @@ void setup() {
|
|||||||
// show compiled features
|
// show compiled features
|
||||||
ESP_LOGI(TAG, "Features:%s", features);
|
ESP_LOGI(TAG, "Features:%s", features);
|
||||||
|
|
||||||
|
// set runmode to normal
|
||||||
|
RTC_runmode = RUNMODE_NORMAL;
|
||||||
|
|
||||||
vTaskDelete(NULL);
|
vTaskDelete(NULL);
|
||||||
|
|
||||||
} // setup()
|
} // setup()
|
||||||
|
10
src/ota.cpp
10
src/ota.cpp
@ -40,12 +40,6 @@ inline String getHeaderValue(String header, String headerName) {
|
|||||||
|
|
||||||
void start_ota_update() {
|
void start_ota_update() {
|
||||||
|
|
||||||
// check battery status if we can before doing ota
|
|
||||||
if (!batt_sufficient()) {
|
|
||||||
ESP_LOGE(TAG, "Battery voltage %dmV too low for OTA", batt_voltage);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch_LED(LED_ON);
|
switch_LED(LED_ON);
|
||||||
|
|
||||||
// init display
|
// init display
|
||||||
@ -105,7 +99,7 @@ end:
|
|||||||
ESP_LOGI(TAG, "Rebooting to %s firmware", (ret == 0) ? "new" : "current");
|
ESP_LOGI(TAG, "Rebooting to %s firmware", (ret == 0) ? "new" : "current");
|
||||||
ota_display(5, "**", ""); // mark line rebooting
|
ota_display(5, "**", ""); // mark line rebooting
|
||||||
delay(5000);
|
delay(5000);
|
||||||
ESP.restart();
|
do_reset(false);
|
||||||
|
|
||||||
} // start_ota_update
|
} // start_ota_update
|
||||||
|
|
||||||
@ -320,7 +314,7 @@ void ota_display(const uint8_t row, const std::string status,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// callback function to show download progress while streaming data
|
// callback function to show download progress while streaming data
|
||||||
void show_progress(unsigned long current, unsigned long size) {
|
static void show_progress(unsigned long current, unsigned long size) {
|
||||||
#ifdef HAS_DISPLAY
|
#ifdef HAS_DISPLAY
|
||||||
char buf[17];
|
char buf[17];
|
||||||
snprintf(buf, 17, "%-9lu (%3lu%%)", current, current * 100 / size);
|
snprintf(buf, 17, "%-9lu (%3lu%%)", current, current * 100 / size);
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
// Note: After editing, before "build", use "clean" button in PlatformIO!
|
// Note: After editing, before "build", use "clean" button in PlatformIO!
|
||||||
|
|
||||||
// Verbose enables serial output
|
// Verbose enables serial output
|
||||||
#define VERBOSE 1 // set to 0 to silence the device, for mute use build option
|
#define VERBOSE 0 // set to 0 to silence the device, for mute use build option
|
||||||
|
|
||||||
// Payload send cycle and encoding
|
// Payload send cycle and encoding
|
||||||
#define SENDCYCLE 30 // payload send cycle [seconds/2], 0 .. 255
|
#define SENDCYCLE 30 // payload send cycle [seconds/2], 0 .. 255
|
||||||
|
@ -5,11 +5,24 @@
|
|||||||
// Local logging tag
|
// Local logging tag
|
||||||
static const char TAG[] = __FILE__;
|
static const char TAG[] = __FILE__;
|
||||||
|
|
||||||
#ifdef HAS_PMU
|
#ifdef BAT_MEASURE_ADC
|
||||||
|
esp_adc_cal_characteristics_t *adc_characs =
|
||||||
|
(esp_adc_cal_characteristics_t *)calloc(
|
||||||
|
1, sizeof(esp_adc_cal_characteristics_t));
|
||||||
|
|
||||||
|
#ifndef BAT_MEASURE_ADC_UNIT // ADC1
|
||||||
|
static const adc1_channel_t adc_channel = BAT_MEASURE_ADC;
|
||||||
|
#else // ADC2
|
||||||
|
static const adc2_channel_t adc_channel = BAT_MEASURE_ADC;
|
||||||
|
#endif
|
||||||
|
static const adc_atten_t atten = ADC_ATTEN_DB_11;
|
||||||
|
static const adc_unit_t unit = ADC_UNIT_1;
|
||||||
|
#endif // BAT_MEASURE_ADC
|
||||||
|
|
||||||
|
#ifdef HAS_PMU
|
||||||
AXP20X_Class pmu;
|
AXP20X_Class pmu;
|
||||||
|
|
||||||
void power_event_IRQ(void) {
|
void AXP192_powerevent_IRQ(void) {
|
||||||
|
|
||||||
pmu.readIRQ();
|
pmu.readIRQ();
|
||||||
|
|
||||||
@ -34,15 +47,17 @@ void power_event_IRQ(void) {
|
|||||||
if (pmu.isBattTempHighIRQ())
|
if (pmu.isBattTempHighIRQ())
|
||||||
ESP_LOGI(TAG, "Battery low temperature.");
|
ESP_LOGI(TAG, "Battery low temperature.");
|
||||||
|
|
||||||
// display on/off
|
// short press -> esp32 deep sleep mode, can be exited by pressing user button
|
||||||
// if (pmu.isPEKShortPressIRQ()) {
|
#ifdef HAS_BUTTON
|
||||||
// cfg.screenon = !cfg.screenon;
|
if (pmu.isPEKShortPressIRQ() && (RTC_runmode == RUNMODE_NORMAL)) {
|
||||||
//}
|
enter_deepsleep(0, HAS_BUTTON);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// shutdown power
|
// long press -> shutdown power, can be exited by another longpress
|
||||||
if (pmu.isPEKLongtPressIRQ()) {
|
if (pmu.isPEKLongtPressIRQ()) {
|
||||||
AXP192_power(false); // switch off Lora, GPS, display
|
AXP192_power(pmu_power_off); // switch off Lora, GPS, display
|
||||||
pmu.shutdown(); // switch off device
|
pmu.shutdown(); // switch off device
|
||||||
}
|
}
|
||||||
|
|
||||||
pmu.clearIRQ();
|
pmu.clearIRQ();
|
||||||
@ -51,18 +66,31 @@ void power_event_IRQ(void) {
|
|||||||
read_voltage();
|
read_voltage();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AXP192_power(bool on) {
|
void AXP192_power(pmu_power_t powerlevel) {
|
||||||
if (on) {
|
|
||||||
pmu.setPowerOutPut(AXP192_LDO2, AXP202_ON); // Lora on T-Beam V1.0
|
switch (powerlevel) {
|
||||||
pmu.setPowerOutPut(AXP192_LDO3, AXP202_ON); // Gps on T-Beam V1.0
|
|
||||||
pmu.setPowerOutPut(AXP192_DCDC1, AXP202_ON); // OLED on T-Beam v1.0
|
case pmu_power_off:
|
||||||
// pmu.setChgLEDMode(AXP20X_LED_LOW_LEVEL);
|
|
||||||
pmu.setChgLEDMode(AXP20X_LED_BLINK_1HZ);
|
|
||||||
} else {
|
|
||||||
pmu.setChgLEDMode(AXP20X_LED_OFF);
|
pmu.setChgLEDMode(AXP20X_LED_OFF);
|
||||||
pmu.setPowerOutPut(AXP192_DCDC1, AXP202_OFF);
|
pmu.setPowerOutPut(AXP192_DCDC1, AXP202_OFF);
|
||||||
pmu.setPowerOutPut(AXP192_LDO3, AXP202_OFF);
|
pmu.setPowerOutPut(AXP192_LDO3, AXP202_OFF);
|
||||||
pmu.setPowerOutPut(AXP192_LDO2, AXP202_OFF);
|
pmu.setPowerOutPut(AXP192_LDO2, AXP202_OFF);
|
||||||
|
// pmu.setPowerOutPut(AXP192_DCDC3, AXP202_OFF);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case pmu_power_sleep:
|
||||||
|
pmu.setChgLEDMode(AXP20X_LED_BLINK_1HZ);
|
||||||
|
// we don't cut off DCDC1, because then display blocks i2c bus
|
||||||
|
pmu.setPowerOutPut(AXP192_LDO3, AXP202_OFF); // gps off
|
||||||
|
pmu.setPowerOutPut(AXP192_LDO2, AXP202_OFF); // lora off
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: // all rails power on
|
||||||
|
pmu.setPowerOutPut(AXP192_LDO2, AXP202_ON); // Lora on T-Beam V1.0
|
||||||
|
pmu.setPowerOutPut(AXP192_LDO3, AXP202_ON); // Gps on T-Beam V1.0
|
||||||
|
pmu.setPowerOutPut(AXP192_DCDC1, AXP202_ON); // OLED on T-Beam v1.0
|
||||||
|
pmu.setChgLEDMode(AXP20X_LED_LOW_LEVEL);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,7 +131,7 @@ void AXP192_init(void) {
|
|||||||
pmu.adc1Enable(AXP202_VBUS_CUR_ADC1, true);
|
pmu.adc1Enable(AXP202_VBUS_CUR_ADC1, true);
|
||||||
|
|
||||||
// switch power rails on
|
// switch power rails on
|
||||||
AXP192_power(true);
|
AXP192_power(pmu_power_on);
|
||||||
|
|
||||||
#ifdef PMU_INT
|
#ifdef PMU_INT
|
||||||
pinMode(PMU_INT, INPUT_PULLUP);
|
pinMode(PMU_INT, INPUT_PULLUP);
|
||||||
@ -119,7 +147,7 @@ void AXP192_init(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// helper functions for mutexing i2c access
|
// helper functions for mutexing pmu i2c access
|
||||||
uint8_t i2c_readBytes(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t len) {
|
uint8_t i2c_readBytes(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t len) {
|
||||||
if (I2C_MUTEX_LOCK()) {
|
if (I2C_MUTEX_LOCK()) {
|
||||||
|
|
||||||
@ -170,21 +198,6 @@ uint8_t i2c_writeBytes(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t len) {
|
|||||||
|
|
||||||
#endif // HAS_PMU
|
#endif // HAS_PMU
|
||||||
|
|
||||||
#ifdef BAT_MEASURE_ADC
|
|
||||||
esp_adc_cal_characteristics_t *adc_characs =
|
|
||||||
(esp_adc_cal_characteristics_t *)calloc(
|
|
||||||
1, sizeof(esp_adc_cal_characteristics_t));
|
|
||||||
|
|
||||||
#ifndef BAT_MEASURE_ADC_UNIT // ADC1
|
|
||||||
static const adc1_channel_t adc_channel = BAT_MEASURE_ADC;
|
|
||||||
#else // ADC2
|
|
||||||
static const adc2_channel_t adc_channel = BAT_MEASURE_ADC;
|
|
||||||
#endif
|
|
||||||
static const adc_atten_t atten = ADC_ATTEN_DB_11;
|
|
||||||
static const adc_unit_t unit = ADC_UNIT_1;
|
|
||||||
|
|
||||||
#endif // BAT_MEASURE_ADC
|
|
||||||
|
|
||||||
void calibrate_voltage(void) {
|
void calibrate_voltage(void) {
|
||||||
#ifdef BAT_MEASURE_ADC
|
#ifdef BAT_MEASURE_ADC
|
||||||
// configure ADC
|
// configure ADC
|
||||||
|
@ -5,21 +5,12 @@
|
|||||||
// Local logging tag
|
// Local logging tag
|
||||||
static const char TAG[] = __FILE__;
|
static const char TAG[] = __FILE__;
|
||||||
|
|
||||||
// helper function
|
|
||||||
void do_reset() {
|
|
||||||
ESP_LOGI(TAG, "Remote command: restart device");
|
|
||||||
#if (HAS_LORA)
|
|
||||||
LMIC_shutdown();
|
|
||||||
#endif
|
|
||||||
delay(3000);
|
|
||||||
esp_restart();
|
|
||||||
}
|
|
||||||
|
|
||||||
// set of functions that can be triggered by remote commands
|
// set of functions that can be triggered by remote commands
|
||||||
void set_reset(uint8_t val[]) {
|
void set_reset(uint8_t val[]) {
|
||||||
switch (val[0]) {
|
switch (val[0]) {
|
||||||
case 0: // restart device
|
case 0: // restart device with cold start (clear RTC saved variables)
|
||||||
do_reset();
|
ESP_LOGI(TAG, "Remote command: restart device cold");
|
||||||
|
do_reset(false);
|
||||||
break;
|
break;
|
||||||
case 1: // reset MAC counter
|
case 1: // reset MAC counter
|
||||||
ESP_LOGI(TAG, "Remote command: reset MAC counter");
|
ESP_LOGI(TAG, "Remote command: reset MAC counter");
|
||||||
@ -34,10 +25,14 @@ void set_reset(uint8_t val[]) {
|
|||||||
ESP_LOGI(TAG, "Remote command: flush send queue");
|
ESP_LOGI(TAG, "Remote command: flush send queue");
|
||||||
flushQueues();
|
flushQueues();
|
||||||
break;
|
break;
|
||||||
|
case 4: // restart device with warm start (keep RTC saved variables)
|
||||||
|
ESP_LOGI(TAG, "Remote command: restart device warm");
|
||||||
|
do_reset(true);
|
||||||
|
break;
|
||||||
case 9: // reset and ask for software update via Wifi OTA
|
case 9: // reset and ask for software update via Wifi OTA
|
||||||
ESP_LOGI(TAG, "Remote command: software update via Wifi");
|
ESP_LOGI(TAG, "Remote command: software update via Wifi");
|
||||||
#if (USE_OTA)
|
#if (USE_OTA)
|
||||||
cfg.runmode = 1;
|
RTC_runmode = RUNMODE_UPDATE;
|
||||||
#endif // USE_OTA
|
#endif // USE_OTA
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -346,7 +341,7 @@ static cmd_t table[] = {
|
|||||||
{0x03, set_gps, 1, true}, {0x04, set_display, 1, true},
|
{0x03, set_gps, 1, true}, {0x04, set_display, 1, true},
|
||||||
{0x05, set_loradr, 1, true}, {0x06, set_lorapower, 1, true},
|
{0x05, set_loradr, 1, true}, {0x06, set_lorapower, 1, true},
|
||||||
{0x07, set_loraadr, 1, true}, {0x08, set_screensaver, 1, true},
|
{0x07, set_loraadr, 1, true}, {0x08, set_screensaver, 1, true},
|
||||||
{0x09, set_reset, 1, true}, {0x0a, set_sendcycle, 1, true},
|
{0x09, set_reset, 1, false}, {0x0a, set_sendcycle, 1, true},
|
||||||
{0x0b, set_wifichancycle, 1, true}, {0x0c, set_blescantime, 1, true},
|
{0x0b, set_wifichancycle, 1, true}, {0x0c, set_blescantime, 1, true},
|
||||||
{0x0d, set_vendorfilter, 1, false}, {0x0e, set_blescan, 1, true},
|
{0x0d, set_vendorfilter, 1, false}, {0x0e, set_blescan, 1, true},
|
||||||
{0x0f, set_wifiant, 1, true}, {0x10, set_rgblum, 1, true},
|
{0x0f, set_wifiant, 1, true}, {0x10, set_rgblum, 1, true},
|
||||||
|
114
src/reset.cpp
Normal file
114
src/reset.cpp
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
// Basic Config
|
||||||
|
#include "globals.h"
|
||||||
|
#include "reset.h"
|
||||||
|
|
||||||
|
// Local logging tag
|
||||||
|
static const char TAG[] = __FILE__;
|
||||||
|
|
||||||
|
// variable keep its values after restart or wakeup from sleep
|
||||||
|
RTC_NOINIT_ATTR runmode_t RTC_runmode;
|
||||||
|
|
||||||
|
void do_reset(bool warmstart) {
|
||||||
|
if (warmstart) {
|
||||||
|
// store LMIC keys and counters in RTC memory
|
||||||
|
#if (HAS_LORA)
|
||||||
|
LMIC_getSessionKeys(&RTCnetid, &RTCdevaddr, RTCnwkKey, RTCartKey);
|
||||||
|
RTCseqnoUp = LMIC.seqnoUp;
|
||||||
|
RTCseqnoDn = LMIC.seqnoDn;
|
||||||
|
#endif
|
||||||
|
ESP_LOGI(TAG, "restarting device (warmstart), keeping runmode %d",
|
||||||
|
RTC_runmode);
|
||||||
|
} else {
|
||||||
|
#if (HAS_LORA)
|
||||||
|
if (RTC_runmode == RUNMODE_NORMAL)
|
||||||
|
LMIC_shutdown();
|
||||||
|
#endif
|
||||||
|
RTC_runmode = RUNMODE_POWERCYCLE;
|
||||||
|
ESP_LOGI(TAG, "restarting device (coldstart), set runmode %d", RTC_runmode);
|
||||||
|
}
|
||||||
|
esp_restart();
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_after_reset(int reason) {
|
||||||
|
|
||||||
|
switch (reason) {
|
||||||
|
|
||||||
|
case POWERON_RESET: // 0x01 Vbat power on reset
|
||||||
|
case RTCWDT_BROWN_OUT_RESET: // 0x0f Reset when the vdd voltage is not
|
||||||
|
// stable
|
||||||
|
RTC_runmode = RUNMODE_POWERCYCLE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DEEPSLEEP_RESET: // 0x05 Deep Sleep reset digital core
|
||||||
|
RTC_runmode = RUNMODE_WAKEUP;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SW_RESET: // 0x03 Software reset digital core
|
||||||
|
case OWDT_RESET: // 0x04 Legacy watch dog reset digital core
|
||||||
|
case SDIO_RESET: // 0x06 Reset by SLC module, reset digital core
|
||||||
|
case TG0WDT_SYS_RESET: // 0x07 Timer Group0 Watch dog reset digital core
|
||||||
|
case TG1WDT_SYS_RESET: // 0x08 Timer Group1 Watch dog reset digital core
|
||||||
|
case RTCWDT_SYS_RESET: // 0x09 RTC Watch dog Reset digital core
|
||||||
|
case INTRUSION_RESET: // 0x0a Instrusion tested to reset CPU
|
||||||
|
case TGWDT_CPU_RESET: // 0x0b Time Group reset CPU
|
||||||
|
case SW_CPU_RESET: // 0x0c Software reset CPU
|
||||||
|
case RTCWDT_CPU_RESET: // 0x0d RTC Watch dog Reset CPU
|
||||||
|
case EXT_CPU_RESET: // 0x0e for APP CPU, reseted by PRO CPU
|
||||||
|
case RTCWDT_RTC_RESET: // 0x10 RTC Watch dog reset digital core and rtc mode
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "Starting Software v%s, runmode %d", PROGVERSION, RTC_runmode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void enter_deepsleep(const int wakeup_sec, const gpio_num_t wakeup_gpio) {
|
||||||
|
|
||||||
|
if ((!wakeup_sec) && (!wakeup_gpio) && (RTC_runmode == RUNMODE_NORMAL))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// set up power domains
|
||||||
|
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_SLOW_MEM, ESP_PD_OPTION_ON);
|
||||||
|
|
||||||
|
// set wakeup timer
|
||||||
|
if (wakeup_sec)
|
||||||
|
esp_sleep_enable_timer_wakeup(wakeup_sec * 1000000);
|
||||||
|
|
||||||
|
// set wakeup gpio
|
||||||
|
if (wakeup_gpio != NOT_A_PIN) {
|
||||||
|
rtc_gpio_isolate(wakeup_gpio);
|
||||||
|
esp_sleep_enable_ext1_wakeup(1ULL << wakeup_gpio, ESP_EXT1_WAKEUP_ALL_LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
// store LMIC keys and counters in RTC memory
|
||||||
|
#if (HAS_LORA)
|
||||||
|
LMIC_getSessionKeys(&RTCnetid, &RTCdevaddr, RTCnwkKey, RTCartKey);
|
||||||
|
RTCseqnoUp = LMIC.seqnoUp;
|
||||||
|
RTCseqnoDn = LMIC.seqnoDn;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// halt interrupts accessing i2c bus
|
||||||
|
mask_user_IRQ();
|
||||||
|
|
||||||
|
// switch off display
|
||||||
|
#ifdef HAS_DISPLAY
|
||||||
|
shutdown_display();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// switch off wifi & ble
|
||||||
|
#if (BLECOUNTER)
|
||||||
|
stop_BLEscan();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// reduce power if has PMU
|
||||||
|
#ifdef HAS_PMU
|
||||||
|
AXP192_power(pmu_power_sleep);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// shutdown i2c bus
|
||||||
|
i2c_deinit();
|
||||||
|
|
||||||
|
// enter sleep mode
|
||||||
|
ESP_LOGI(TAG, "Going to sleep...");
|
||||||
|
esp_deep_sleep_start();
|
||||||
|
}
|
@ -29,7 +29,7 @@ typedef struct {
|
|||||||
} wifi_ieee80211_packet_t;
|
} wifi_ieee80211_packet_t;
|
||||||
|
|
||||||
// using IRAM_:ATTR here to speed up callback function
|
// using IRAM_:ATTR here to speed up callback function
|
||||||
IRAM_ATTR void wifi_sniffer_packet_handler(void *buff,
|
static IRAM_ATTR void wifi_sniffer_packet_handler(void *buff,
|
||||||
wifi_promiscuous_pkt_type_t type) {
|
wifi_promiscuous_pkt_type_t type) {
|
||||||
|
|
||||||
const wifi_promiscuous_pkt_t *ppkt = (wifi_promiscuous_pkt_t *)buff;
|
const wifi_promiscuous_pkt_t *ppkt = (wifi_promiscuous_pkt_t *)buff;
|
||||||
|
Loading…
Reference in New Issue
Block a user