new feature deep sleep (wokring alpha)
This commit is contained in:
parent
016d69b5bb
commit
36afe66df9
@ -20,9 +20,10 @@
|
||||
|
||||
extern TaskHandle_t lmicTask, lorasendTask;
|
||||
|
||||
void lora_stack_reset();
|
||||
esp_err_t lora_stack_init(bool do_join);
|
||||
esp_err_t lmic_init(void);
|
||||
void lora_setupForNetwork(bool preJoin);
|
||||
void SaveLMICToRTC(int deepsleep_sec);
|
||||
void LoadLMICFromRTC();
|
||||
void lmictask(void *pvParameters);
|
||||
void gen_lora_deveui(uint8_t *pdeveui);
|
||||
void RevBytes(unsigned char *b, size_t c);
|
||||
@ -33,6 +34,7 @@ void os_getDevEui(u1_t *buf);
|
||||
void lora_send(void *pvParameters);
|
||||
void lora_enqueuedata(MessageBuffer_t *message);
|
||||
void lora_queuereset(void);
|
||||
uint32_t lora_queuewaiting(void);
|
||||
uint8_t myBattLevelCb(void *pUserData);
|
||||
void IRAM_ATTR myEventCallback(void *pUserData, ev_t ev);
|
||||
void IRAM_ATTR myRxCallback(void *pUserData, uint8_t port, const uint8_t *pMsg,
|
||||
|
@ -18,7 +18,8 @@ extern Ticker sendTimer;
|
||||
void SendPayload(uint8_t port, sendprio_t prio);
|
||||
void sendData(void);
|
||||
void checkSendQueues(void);
|
||||
void flushQueues();
|
||||
void flushQueues(void);
|
||||
bool allQueuesEmtpy(void);
|
||||
void setSendIRQ(void);
|
||||
|
||||
#endif // _SENDDATA_H_
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
; ---> SELECT THE TARGET PLATFORM HERE! <---
|
||||
[board]
|
||||
halfile = generic.h
|
||||
;halfile = generic.h
|
||||
;halfile = ebox.h
|
||||
;halfile = eboxtube.h
|
||||
;halfile = ecopower.h
|
||||
@ -19,7 +19,7 @@ halfile = generic.h
|
||||
;halfile = ttgov21new.h
|
||||
;halfile = ttgofox.h
|
||||
;halfile = ttgobeam.h
|
||||
;halfile = ttgobeam10.h
|
||||
halfile = ttgobeam10.h
|
||||
;halfile = ttgotdisplay.h
|
||||
;halfile = fipy.h
|
||||
;halfile = lopy.h
|
||||
@ -47,7 +47,7 @@ description = Paxcounter is a device for metering passenger flows in realtime. I
|
||||
|
||||
[common]
|
||||
; for release_version use max. 10 chars total, use any decimal format like "a.b.c"
|
||||
release_version = 2.0.4
|
||||
release_version = 2.0.51
|
||||
; DEBUG LEVEL: For production run set to 0, otherwise device will leak RAM while running!
|
||||
; 0=None, 1=Error, 2=Warn, 3=Info, 4=Debug, 5=Verbose
|
||||
debug_level = 3
|
||||
@ -55,7 +55,7 @@ extra_scripts = pre:build.py
|
||||
otakeyfile = ota.conf
|
||||
lorakeyfile = loraconf.h
|
||||
lmicconfigfile = lmic_config.h
|
||||
platform_espressif32 = espressif32@2.0.0
|
||||
platform_espressif32 = espressif32@2.1.0
|
||||
monitor_speed = 115200
|
||||
upload_speed = 115200 ; set by build.py and taken from hal file
|
||||
display_library = ; set by build.py and taken from hal file
|
||||
@ -65,7 +65,7 @@ lib_deps_display =
|
||||
bitbank2/OneBitDisplay @ 1.9.0
|
||||
bitbank2/BitBang_I2C @ ^2.1.3
|
||||
ricmoo/QRCode @ ^0.0.1
|
||||
bodmer/TFT_eSPI @ ^2.2.20
|
||||
bodmer/TFT_eSPI @ ^2.3.51
|
||||
lib_deps_ledmatrix =
|
||||
seeed-studio/Ultrathin_LED_Matrix @ ^1.0.0
|
||||
lib_deps_rgbled =
|
||||
@ -76,8 +76,7 @@ lib_deps_sensors =
|
||||
adafruit/Adafruit Unified Sensor @ ^1.1.4
|
||||
adafruit/Adafruit BME280 Library @ ^2.1.1
|
||||
adafruit/Adafruit BMP085 Library @ ^1.1.0
|
||||
;boschsensortec/BSEC Software Library @ 1.6.1480
|
||||
https://github.com/BoschSensortec/BSEC-Arduino-library.git
|
||||
boschsensortec/BSEC Software Library @ 1.6.1480
|
||||
https://github.com/ricki-z/SDS011.git
|
||||
lib_deps_basic =
|
||||
bblanchon/ArduinoJson @ <6
|
||||
@ -117,7 +116,7 @@ framework = arduino
|
||||
board = esp32dev
|
||||
board_build.partitions = min_spiffs.csv
|
||||
upload_speed = ${common.upload_speed}
|
||||
;upload_port = COM8
|
||||
;upload_port = COM3
|
||||
platform = ${common.platform_espressif32}
|
||||
lib_deps = ${common.lib_deps_all}
|
||||
build_flags = ${common.build_flags_all}
|
||||
|
@ -95,6 +95,13 @@ void irqHandler(void *pvParameters) {
|
||||
if (InterruptStatus & SENDCYCLE_IRQ) {
|
||||
sendData();
|
||||
InterruptStatus &= ~SENDCYCLE_IRQ;
|
||||
// goto sleep if we have a sleep cycle
|
||||
if (cfg.sleepcycle)
|
||||
#ifdef HAS_BUTTON
|
||||
enter_deepsleep(cfg.sleepcycle * 2, HAS_BUTTON);
|
||||
#else
|
||||
enter_deepsleep(cfg.sleepcycle * 2);
|
||||
#endif
|
||||
}
|
||||
} // for
|
||||
} // irqHandler()
|
||||
|
237
src/lorawan.cpp
237
src/lorawan.cpp
@ -6,6 +6,9 @@
|
||||
// Local logging Tag
|
||||
static const char TAG[] = "lora";
|
||||
|
||||
// Saves the LMIC structure during deep sleep
|
||||
RTC_DATA_ATTR lmic_t RTC_LMIC;
|
||||
|
||||
#if CLOCK_ERROR_PROCENTAGE > 7
|
||||
#warning CLOCK_ERROR_PROCENTAGE value in lmic_config.h is too high; values > 7 will cause side effects
|
||||
#endif
|
||||
@ -16,11 +19,6 @@ static const char TAG[] = "lora";
|
||||
#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;
|
||||
TaskHandle_t lmicTask = NULL, lorasendTask = NULL;
|
||||
|
||||
@ -83,8 +81,6 @@ void lora_setupForNetwork(bool preJoin) {
|
||||
getSfName(updr2rps(LMIC.datarate)),
|
||||
getBwName(updr2rps(LMIC.datarate)),
|
||||
getCrName(updr2rps(LMIC.datarate)));
|
||||
// store LMIC keys and counters in RTC memory
|
||||
LMIC_getSessionKeys(&RTCnetid, &RTCdevaddr, RTCnwkKey, RTCartKey);
|
||||
}
|
||||
}
|
||||
|
||||
@ -197,59 +193,47 @@ void lora_send(void *pvParameters) {
|
||||
}
|
||||
|
||||
// fetch next or wait for payload to send from queue
|
||||
if (xQueueReceive(LoraSendQueue, &SendBuffer, portMAX_DELAY) != pdTRUE) {
|
||||
// do not delete item from queue until it is transmitted
|
||||
if (xQueuePeek(LoraSendQueue, &SendBuffer, portMAX_DELAY) != pdTRUE) {
|
||||
ESP_LOGE(TAG, "Premature return from xQueueReceive() with no data!");
|
||||
continue;
|
||||
}
|
||||
|
||||
// attempt to transmit payload
|
||||
else {
|
||||
|
||||
switch (LMIC_setTxData2_strict(SendBuffer.MessagePort, SendBuffer.Message,
|
||||
SendBuffer.MessageSize,
|
||||
(cfg.countermode & 0x02))) {
|
||||
|
||||
case LMIC_ERROR_SUCCESS:
|
||||
// save current Fcnt to RTC RAM
|
||||
RTCseqnoUp = LMIC.seqnoUp;
|
||||
RTCseqnoDn = LMIC.seqnoDn;
|
||||
switch (LMIC_setTxData2_strict(SendBuffer.MessagePort, SendBuffer.Message,
|
||||
SendBuffer.MessageSize,
|
||||
(cfg.countermode & 0x02))) {
|
||||
|
||||
case LMIC_ERROR_SUCCESS:
|
||||
#if (TIME_SYNC_LORASERVER)
|
||||
// if last packet sent was a timesync request, store TX timestamp
|
||||
if (SendBuffer.MessagePort == TIMEPORT)
|
||||
// store LMIC time when we started transmit of timesync request
|
||||
timesync_store(osticks2ms(os_getTime()), timesync_tx);
|
||||
// if last packet sent was a timesync request, store TX timestamp
|
||||
if (SendBuffer.MessagePort == TIMEPORT)
|
||||
// store LMIC time when we started transmit of timesync request
|
||||
timesync_store(osticks2ms(os_getTime()), timesync_tx);
|
||||
#endif
|
||||
ESP_LOGI(TAG, "%d byte(s) sent to LORA", SendBuffer.MessageSize);
|
||||
// delete sent item from queue
|
||||
xQueueReceive(LoraSendQueue, &SendBuffer, (TickType_t)0);
|
||||
break;
|
||||
case LMIC_ERROR_TX_BUSY: // LMIC already has a tx message pending
|
||||
case LMIC_ERROR_TX_FAILED: // message was not sent
|
||||
vTaskDelay(pdMS_TO_TICKS(500 + random(400))); // wait a while
|
||||
break;
|
||||
case LMIC_ERROR_TX_TOO_LARGE: // message size exceeds LMIC buffer size
|
||||
case LMIC_ERROR_TX_NOT_FEASIBLE: // message too large for current
|
||||
// datarate
|
||||
ESP_LOGI(TAG, "Message too large to send, message not sent and deleted");
|
||||
// we need some kind of error handling here -> to be done
|
||||
break;
|
||||
default: // other LMIC return code
|
||||
ESP_LOGE(TAG, "LMIC error, message not sent and deleted");
|
||||
|
||||
ESP_LOGI(TAG, "%d byte(s) sent to LORA", SendBuffer.MessageSize);
|
||||
break;
|
||||
case LMIC_ERROR_TX_BUSY: // LMIC already has a tx message pending
|
||||
case LMIC_ERROR_TX_FAILED: // message was not sent
|
||||
// ESP_LOGD(TAG, "LMIC busy, message re-enqueued"); // very noisy
|
||||
vTaskDelay(pdMS_TO_TICKS(1000 + random(500))); // wait a while
|
||||
lora_enqueuedata(&SendBuffer); // re-enqueue the undelivered message
|
||||
break;
|
||||
case LMIC_ERROR_TX_TOO_LARGE: // message size exceeds LMIC buffer size
|
||||
case LMIC_ERROR_TX_NOT_FEASIBLE: // message too large for current
|
||||
// datarate
|
||||
ESP_LOGI(TAG,
|
||||
"Message too large to send, message not sent and deleted");
|
||||
// we need some kind of error handling here -> to be done
|
||||
break;
|
||||
default: // other LMIC return code
|
||||
ESP_LOGE(TAG, "LMIC error, message not sent and deleted");
|
||||
|
||||
} // switch
|
||||
}
|
||||
} // switch
|
||||
delay(2); // yield to CPU
|
||||
}
|
||||
} // while(1)
|
||||
}
|
||||
|
||||
void lora_stack_reset() {
|
||||
LMIC_reset(); // reset LMIC MAC
|
||||
}
|
||||
|
||||
esp_err_t lora_stack_init(bool do_join) {
|
||||
esp_err_t lmic_init(void) {
|
||||
_ASSERT(SEND_QUEUE_SIZE > 0);
|
||||
LoraSendQueue = xQueueCreate(SEND_QUEUE_SIZE, sizeof(MessageBuffer_t));
|
||||
if (LoraSendQueue == 0) {
|
||||
@ -259,7 +243,58 @@ esp_err_t lora_stack_init(bool do_join) {
|
||||
ESP_LOGI(TAG, "LORA send queue created, size %d Bytes",
|
||||
SEND_QUEUE_SIZE * sizeof(MessageBuffer_t));
|
||||
|
||||
// start lorawan stack
|
||||
// setup LMIC stack
|
||||
os_init_ex(&myPinmap); // initialize lmic run-time environment
|
||||
|
||||
// register a callback for downlink messages and lmic events.
|
||||
// We aren't trying to write reentrant code, so pUserData is NULL.
|
||||
// LMIC_reset() doesn't affect callbacks, so we can do this first.
|
||||
LMIC_registerRxMessageCb(myRxCallback, NULL);
|
||||
LMIC_registerEventCb(myEventCallback, NULL);
|
||||
// to come with future LMIC version
|
||||
// LMIC_registerBattLevelCb(myBattLevelCb, NULL);
|
||||
|
||||
// Reset the MAC state. Session and pending data transfers will be
|
||||
// discarded.
|
||||
LMIC_reset();
|
||||
|
||||
// This tells LMIC to make the receive windows bigger, in case your clock is
|
||||
// faster or slower. This causes the transceiver to be earlier switched on,
|
||||
// so consuming more power. You may sharpen (reduce) CLOCK_ERROR_PERCENTAGE
|
||||
// in src/lmic_config.h if you are limited on battery.
|
||||
#ifdef CLOCK_ERROR_PROCENTAGE
|
||||
LMIC_setClockError(CLOCK_ERROR_PROCENTAGE * MAX_CLOCK_ERROR / 1000);
|
||||
#endif
|
||||
|
||||
// Pass ABP parameters to LMIC_setSession
|
||||
#ifdef LORA_ABP
|
||||
setABPParameters(); // These parameters are defined as macro in loraconf.h
|
||||
|
||||
// load saved session from RTC, if we have one
|
||||
if (RTC_runmode == RUNMODE_WAKEUP) {
|
||||
LoadLMICFromRTC();
|
||||
} else {
|
||||
uint8_t appskey[sizeof(APPSKEY)];
|
||||
uint8_t nwkskey[sizeof(NWKSKEY)];
|
||||
memcpy_P(appskey, APPSKEY, sizeof(APPSKEY));
|
||||
memcpy_P(nwkskey, NWKSKEY, sizeof(NWKSKEY));
|
||||
LMIC_setSession(NETID, DEVADDR, nwkskey, appskey);
|
||||
}
|
||||
|
||||
// Pass OTA parameters to LMIC_setSession
|
||||
#else
|
||||
// load saved session from RTC, if we have one
|
||||
if (RTC_runmode == RUNMODE_WAKEUP) {
|
||||
LoadLMICFromRTC();
|
||||
}
|
||||
// otherwise start join procedure if not already joined
|
||||
else {
|
||||
if (!LMIC_startJoining())
|
||||
ESP_LOGI(TAG, "Already joined");
|
||||
}
|
||||
#endif
|
||||
|
||||
// start lmic loop task
|
||||
ESP_LOGI(TAG, "Starting LMIC...");
|
||||
xTaskCreatePinnedToCore(lmictask, // task function
|
||||
"lmictask", // name of task
|
||||
@ -269,31 +304,7 @@ esp_err_t lora_stack_init(bool do_join) {
|
||||
&lmicTask, // task handle
|
||||
1); // CPU core
|
||||
|
||||
#ifdef LORA_ABP
|
||||
// Pass ABP parameters to LMIC_setSession
|
||||
lora_stack_reset();
|
||||
uint8_t appskey[sizeof(APPSKEY)];
|
||||
uint8_t nwkskey[sizeof(NWKSKEY)];
|
||||
memcpy_P(appskey, APPSKEY, sizeof(APPSKEY));
|
||||
memcpy_P(nwkskey, NWKSKEY, sizeof(NWKSKEY));
|
||||
LMIC_setSession(NETID, DEVADDR, nwkskey, appskey);
|
||||
// These parameters are defined as macro in loraconf.h
|
||||
setABPParameters();
|
||||
#else
|
||||
// Start join procedure if not already joined,
|
||||
// lora_setupForNetwork(true) is called by eventhandler when joined
|
||||
// else continue current session
|
||||
if (do_join) {
|
||||
if (!LMIC_startJoining())
|
||||
ESP_LOGI(TAG, "Already joined");
|
||||
} else {
|
||||
lora_stack_reset();
|
||||
LMIC_setSession(RTCnetid, RTCdevaddr, RTCnwkKey, RTCartKey);
|
||||
LMIC.seqnoUp = RTCseqnoUp;
|
||||
LMIC.seqnoDn = RTCseqnoDn;
|
||||
}
|
||||
#endif
|
||||
// start lmic send task
|
||||
// start lora send task
|
||||
xTaskCreatePinnedToCore(lora_send, // task function
|
||||
"lorasendtask", // name of task
|
||||
3072, // stack size of task
|
||||
@ -319,11 +330,11 @@ void lora_enqueuedata(MessageBuffer_t *message) {
|
||||
ESP_LOGW(TAG, "LORA sendqueue purged, data is lost");
|
||||
}
|
||||
case prio_normal:
|
||||
ret = xQueueSendToFront(LoraSendQueue, (void *)message, (TickType_t)0);
|
||||
ret = xQueueSendToBack(LoraSendQueue, (void *)message, (TickType_t)0);
|
||||
break;
|
||||
case prio_low:
|
||||
default:
|
||||
ret = xQueueSendToBack(LoraSendQueue, (void *)message, (TickType_t)0);
|
||||
ret = xQueueSendToFront(LoraSendQueue, (void *)message, (TickType_t)0);
|
||||
break;
|
||||
}
|
||||
if (ret != pdTRUE) {
|
||||
@ -338,38 +349,18 @@ void lora_enqueuedata(MessageBuffer_t *message) {
|
||||
|
||||
void lora_queuereset(void) { xQueueReset(LoraSendQueue); }
|
||||
|
||||
// LMIC lorawan stack task
|
||||
uint32_t lora_queuewaiting(void) {
|
||||
return uxQueueMessagesWaiting(LoraSendQueue);
|
||||
}
|
||||
|
||||
// LMIC loop task
|
||||
void lmictask(void *pvParameters) {
|
||||
_ASSERT((uint32_t)pvParameters == 1);
|
||||
|
||||
// setup LMIC stack
|
||||
os_init_ex(&myPinmap); // initialize lmic run-time environment
|
||||
|
||||
// register a callback for downlink messages and lmic events.
|
||||
// We aren't trying to write reentrant code, so pUserData is NULL.
|
||||
// LMIC_reset() doesn't affect callbacks, so we can do this first.
|
||||
LMIC_registerRxMessageCb(myRxCallback, NULL);
|
||||
LMIC_registerEventCb(myEventCallback, NULL);
|
||||
// to come with future LMIC version
|
||||
// LMIC_registerBattLevelCb(myBattLevelCb, NULL);
|
||||
|
||||
// Reset the MAC state. Session and pending data transfers will be
|
||||
// discarded.
|
||||
lora_stack_reset();
|
||||
|
||||
// This tells LMIC to make the receive windows bigger, in case your clock is
|
||||
// faster or slower. This causes the transceiver to be earlier switched on,
|
||||
// so consuming more power. You may sharpen (reduce) CLOCK_ERROR_PERCENTAGE
|
||||
// in src/lmic_config.h if you are limited on battery.
|
||||
#ifdef CLOCK_ERROR_PROCENTAGE
|
||||
LMIC_setClockError(CLOCK_ERROR_PROCENTAGE * MAX_CLOCK_ERROR / 1000);
|
||||
#endif
|
||||
|
||||
while (1) {
|
||||
os_runloop_once(); // execute lmic scheduled jobs and events
|
||||
delay(2); // yield to CPU
|
||||
}
|
||||
} // lmictask
|
||||
}
|
||||
|
||||
// lmic event handler
|
||||
void myEventCallback(void *pUserData, ev_t ev) {
|
||||
@ -410,7 +401,7 @@ void myEventCallback(void *pUserData, ev_t ev) {
|
||||
case EV_JOIN_FAILED:
|
||||
// must call LMIC_reset() to stop joining
|
||||
// otherwise join procedure continues.
|
||||
lora_stack_reset();
|
||||
LMIC_reset();
|
||||
break;
|
||||
|
||||
case EV_JOIN_TXCOMPLETE:
|
||||
@ -560,4 +551,44 @@ void mac_decode(const uint8_t cmd[], const uint8_t cmdlen, bool is_down) {
|
||||
} // mac_decode()
|
||||
#endif // VERBOSE
|
||||
|
||||
// following code snippet was taken from
|
||||
// https://github.com/JackGruber/ESP32-LMIC-DeepSleep-example/blob/master/src/main.cpp
|
||||
|
||||
void SaveLMICToRTC(int deepsleep_sec) {
|
||||
RTC_LMIC = LMIC;
|
||||
|
||||
// ESP32 can't track millis during DeepSleep and no option to advance
|
||||
// millis after DeepSleep. Therefore reset DutyCyles
|
||||
|
||||
unsigned long now = millis();
|
||||
|
||||
// EU Like Bands
|
||||
#if defined(CFG_LMIC_EU_like)
|
||||
for (int i = 0; i < MAX_BANDS; i++) {
|
||||
ostime_t correctedAvail =
|
||||
RTC_LMIC.bands[i].avail -
|
||||
((now / 1000.0 + deepsleep_sec) * OSTICKS_PER_SEC);
|
||||
if (correctedAvail < 0) {
|
||||
correctedAvail = 0;
|
||||
}
|
||||
RTC_LMIC.bands[i].avail = correctedAvail;
|
||||
}
|
||||
|
||||
RTC_LMIC.globalDutyAvail = RTC_LMIC.globalDutyAvail -
|
||||
((now / 1000.0 + deepsleep_sec) * OSTICKS_PER_SEC);
|
||||
if (RTC_LMIC.globalDutyAvail < 0) {
|
||||
RTC_LMIC.globalDutyAvail = 0;
|
||||
}
|
||||
#else
|
||||
ESP_LOGW(TAG, "No DutyCycle recalculation function!");
|
||||
#endif
|
||||
|
||||
ESP_LOGI(TAG, "LMIC state saved");
|
||||
}
|
||||
|
||||
void LoadLMICFromRTC() {
|
||||
LMIC = RTC_LMIC;
|
||||
ESP_LOGI(TAG, "LMIC state loaded");
|
||||
}
|
||||
|
||||
#endif // HAS_LORA
|
@ -348,9 +348,7 @@ void setup() {
|
||||
// initialize LoRa
|
||||
#if (HAS_LORA)
|
||||
strcat_P(features, " LORA");
|
||||
// kick off join, except we come from sleep
|
||||
_ASSERT(lora_stack_init(RTC_runmode == RUNMODE_WAKEUP ? false : true) ==
|
||||
ESP_OK);
|
||||
_ASSERT(lmic_init() == ESP_OK);
|
||||
#endif
|
||||
|
||||
// initialize SPI
|
||||
|
@ -115,7 +115,8 @@ void mqtt_client_task(void *param) {
|
||||
while (1) {
|
||||
|
||||
// fetch next or wait for payload to send from queue
|
||||
if (xQueueReceive(MQTTSendQueue, &msg, portMAX_DELAY) != pdTRUE) {
|
||||
// do not delete item from queue until it is transmitted
|
||||
if (xQueuePeek(MQTTSendQueue, &msg, portMAX_DELAY) != pdTRUE) {
|
||||
ESP_LOGE(TAG, "Premature return from xQueueReceive() with no data!");
|
||||
continue;
|
||||
}
|
||||
@ -129,19 +130,17 @@ void mqtt_client_task(void *param) {
|
||||
|
||||
if (mqttClient.publish(MQTT_OUTTOPIC, buffer)) {
|
||||
ESP_LOGI(TAG, "%d byte(s) sent to MQTT server", msg.MessageSize + 2);
|
||||
// delete sent item from queue
|
||||
xQueueReceive(MQTTSendQueue, &msg, (TickType_t)0);
|
||||
continue;
|
||||
} else {
|
||||
mqtt_enqueuedata(&msg); // postpone the undelivered message
|
||||
ESP_LOGD(TAG,
|
||||
"Couldn't sent message to MQTT server, message postponed");
|
||||
}
|
||||
} else
|
||||
ESP_LOGD(TAG, "Couldn't sent message to MQTT server");
|
||||
|
||||
} else {
|
||||
// attempt to reconnect to MQTT server
|
||||
ESP_LOGD(TAG, "MQTT client reconnecting...");
|
||||
ESP_LOGD(TAG, "MQTT last_error = %d / rc = %d", mqttClient.lastError(),
|
||||
mqttClient.returnCode());
|
||||
mqtt_enqueuedata(&msg); // postpone the undelivered message
|
||||
delay(MQTT_RETRYSEC * 1000);
|
||||
mqtt_connect(MQTT_SERVER, MQTT_PORT);
|
||||
}
|
||||
@ -161,11 +160,11 @@ void mqtt_enqueuedata(MessageBuffer_t *message) {
|
||||
if (!uxQueueSpacesAvailable(MQTTSendQueue))
|
||||
xQueueReceive(MQTTSendQueue, &DummyBuffer, (TickType_t)0);
|
||||
case prio_normal:
|
||||
ret = xQueueSendToFront(MQTTSendQueue, (void *)message, (TickType_t)0);
|
||||
ret = xQueueSendToBack(MQTTSendQueue, (void *)message, (TickType_t)0);
|
||||
break;
|
||||
case prio_low:
|
||||
default:
|
||||
ret = xQueueSendToBack(MQTTSendQueue, (void *)message, (TickType_t)0);
|
||||
ret = xQueueSendToFront(MQTTSendQueue, (void *)message, (TickType_t)0);
|
||||
break;
|
||||
}
|
||||
if (ret != pdTRUE)
|
||||
@ -185,6 +184,11 @@ void mqtt_loop(void) {
|
||||
}
|
||||
|
||||
void mqtt_queuereset(void) { xQueueReset(MQTTSendQueue); }
|
||||
|
||||
uint32_t mqtt_queuewaiting(void) {
|
||||
return uxQueueMessagesWaitingMQTTSendQueue);
|
||||
}
|
||||
|
||||
void setMqttIRQ(void) { xTaskNotify(irqHandlerTask, MQTT_IRQ, eSetBits); }
|
||||
|
||||
#endif // HAS_MQTT
|
@ -11,12 +11,13 @@
|
||||
|
||||
// Payload send cycle and encoding
|
||||
#define SENDCYCLE 30 // payload send cycle [seconds/2], 0 .. 255
|
||||
#define SLEEPCYCLE 0 // sleep time after a send cycle [seconds/2], 0 .. 255; 0 means no sleep [default = 0]
|
||||
#define PAYLOAD_ENCODER 2 // payload encoder: 1=Plain, 2=Packed, 3=Cayenne LPP dynamic, 4=Cayenne LPP packed
|
||||
#define COUNTERMODE 0 // 0=cyclic, 1=cumulative, 2=cyclic confirmed
|
||||
|
||||
// MAC sniffing parameters
|
||||
#define VENDORFILTER 0 // set to 0 if you want to scan all devices, not filtering smartphone OUIs
|
||||
#define BLECOUNTER 0 // set to 0 if you do not want to install the BLE sniffer
|
||||
#define BLECOUNTER 1 // set to 0 if you do not want to install the BLE sniffer
|
||||
#define WIFICOUNTER 1 // set to 0 if you do not want to install the WIFI sniffer
|
||||
#define MAC_QUEUE_SIZE 50 // size of MAC processing buffer (number of MACs) [default = 50]
|
||||
|
||||
@ -26,11 +27,11 @@
|
||||
#define BLESCANINTERVAL 80 // [illiseconds] scan interval, see below, 3 .. 10240, default 80ms = 100% duty cycle
|
||||
|
||||
// Corona Exposure Notification Service(ENS) counter
|
||||
#define COUNT_ENS 0 // count found number of devices which advertise Exposure Notification Service
|
||||
// set to 0 if you do not want to enable this function
|
||||
#define COUNT_ENS 1 // count found number of devices which advertise Exposure Notification Service
|
||||
// set to 1 if you want to enable this function [default=0]
|
||||
|
||||
// for additional sensors (added by some user)
|
||||
#define HAS_SENSOR_1 0 // set to 1 to enable data transfer of user sensor #1 (also used as ENS counter) [default=0]
|
||||
#define HAS_SENSOR_1 1 // set to 1 to enable data transfer of user sensor #1 (also used as ENS counter) [default=0]
|
||||
#define HAS_SENSOR_2 0 // set to 1 to enable data transfer of user sensor #2 [default=0]
|
||||
#define HAS_SENSOR_3 0 // set to 1 to enable data transfer of user sensor #3 [default=0]
|
||||
|
||||
@ -83,10 +84,10 @@
|
||||
#define RESPONSE_TIMEOUT_MS 60000 // firmware binary server connection timeout [milliseconds]
|
||||
|
||||
// settings for syncing time of node with a time source (network / gps / rtc / timeserver)
|
||||
#define TIME_SYNC_LORAWAN 1 // set to 1 to use LORA network as time source, 0 means off [default = 1]
|
||||
#define TIME_SYNC_LORAWAN 0 // set to 1 to use LORA network as time source, 0 means off [default = 1]
|
||||
#define TIME_SYNC_LORASERVER 0 // set to 1 to use LORA timeserver as time source, 0 means off [default = 0]
|
||||
#define TIME_SYNC_INTERVAL 60 // sync time attempt each .. minutes from time source [default = 60], 0 means off
|
||||
#define TIME_SYNC_INTERVAL_RETRY 10 // retry time sync after lost sync each .. minutes [default = 10], 0 means off
|
||||
#define TIME_SYNC_INTERVAL_RETRY 10 // retry time sync after lost sync each .. minutes [default = 10], 0 means off
|
||||
#define TIME_SYNC_SAMPLES 1 // number of time requests for averaging, max. 255
|
||||
#define TIME_SYNC_CYCLE 60 // delay between two time samples [seconds]
|
||||
#define TIME_SYNC_TIMEOUT 400 // timeout waiting for timeserver answer [seconds]
|
||||
|
@ -48,7 +48,7 @@ void AXP192_powerevent_IRQ(void) {
|
||||
ESP_LOGI(TAG, "Battery low temperature.");
|
||||
|
||||
// short press -> esp32 deep sleep mode, can be exited by pressing user button
|
||||
if (pmu.isPEKShortPressIRQ() && (RTC_runmode == RUNMODE_NORMAL)) {
|
||||
if (pmu.isPEKShortPressIRQ()) {
|
||||
enter_deepsleep(0, HAS_BUTTON);
|
||||
}
|
||||
|
||||
|
@ -5,21 +5,27 @@
|
||||
// Local logging tag
|
||||
static const char TAG[] = __FILE__;
|
||||
|
||||
// Conversion factor for micro seconds to seconds
|
||||
#define uS_TO_S_FACTOR 1000000ULL
|
||||
|
||||
// variable keep its values after restart or wakeup from sleep
|
||||
RTC_NOINIT_ATTR runmode_t RTC_runmode;
|
||||
|
||||
const char *runmode[4] = {"powercycle", "normal", "wakeup", "update"};
|
||||
|
||||
void do_reset(bool warmstart) {
|
||||
if (warmstart) {
|
||||
// store LMIC keys and counters in RTC memory
|
||||
ESP_LOGI(TAG, "restarting device (warmstart), keeping runmode %d",
|
||||
RTC_runmode);
|
||||
ESP_LOGI(TAG, "restarting device (warmstart), keeping runmode %s",
|
||||
runmode[RTC_runmode]);
|
||||
} else {
|
||||
#if (HAS_LORA)
|
||||
if (RTC_runmode == RUNMODE_NORMAL)
|
||||
if (RTC_runmode == RUNMODE_NORMAL) {
|
||||
LMIC_shutdown();
|
||||
}
|
||||
#endif
|
||||
RTC_runmode = RUNMODE_POWERCYCLE;
|
||||
ESP_LOGI(TAG, "restarting device (coldstart), set runmode %d", RTC_runmode);
|
||||
ESP_LOGI(TAG, "restarting device (coldstart), setting runmode %s",
|
||||
runmode[RTC_runmode]);
|
||||
}
|
||||
esp_restart();
|
||||
}
|
||||
@ -40,9 +46,6 @@ void do_after_reset(int reason) {
|
||||
|
||||
case DEEPSLEEP_RESET: // 0x05 Deep Sleep reset digital core
|
||||
RTC_runmode = RUNMODE_WAKEUP;
|
||||
#if (HAS_LORA)
|
||||
// to be done: restore LoRaWAN channel configuration and datarate here
|
||||
#endif
|
||||
break;
|
||||
|
||||
case SW_RESET: // 0x03 Software reset digital core
|
||||
@ -61,32 +64,61 @@ void do_after_reset(int reason) {
|
||||
break;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Starting Software v%s, runmode %d", PROGVERSION, RTC_runmode);
|
||||
ESP_LOGI(TAG, "Starting Software v%s, runmode %s", PROGVERSION,
|
||||
runmode[RTC_runmode]);
|
||||
}
|
||||
|
||||
void enter_deepsleep(const int wakeup_sec, const gpio_num_t wakeup_gpio) {
|
||||
void enter_deepsleep(const int wakeup_sec = 60,
|
||||
const gpio_num_t wakeup_gpio = GPIO_NUM_MAX) {
|
||||
|
||||
if ((!wakeup_sec) && (!wakeup_gpio) && (RTC_runmode == RUNMODE_NORMAL))
|
||||
return;
|
||||
|
||||
// wait until LMIC is in safe state before going to sleep
|
||||
// ensure we are in normal runmode, not udpate or wakeup
|
||||
if ((RTC_runmode != RUNMODE_NORMAL)
|
||||
#if (HAS_LORA)
|
||||
while (os_queryTimeCriticalJobs(ms2osticks(wakeup_sec * 1000)))
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
|
||||
// to be done: save current LoRaWAN configuration here
|
||||
|| (LMIC.opmode & (OP_JOINING | OP_REJOIN))
|
||||
#endif
|
||||
) {
|
||||
ESP_LOGE(TAG, "Can't go to sleep now");
|
||||
return;
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Attempting to sleep...");
|
||||
}
|
||||
|
||||
// switch off radio
|
||||
#if (BLECOUNTER)
|
||||
stop_BLEscan();
|
||||
btStop();
|
||||
#endif
|
||||
#if (WIFICOUNTER)
|
||||
switch_wifi_sniffer(0);
|
||||
#endif
|
||||
|
||||
// set up power domains
|
||||
//esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_SLOW_MEM, ESP_PD_OPTION_ON);
|
||||
// wait until all send queues are empty
|
||||
ESP_LOGI(TAG, "Waiting until send queues are empty...");
|
||||
while (!allQueuesEmtpy())
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
|
||||
// set wakeup timer
|
||||
if (wakeup_sec)
|
||||
esp_sleep_enable_timer_wakeup(wakeup_sec * 1000000);
|
||||
#if (HAS_LORA)
|
||||
// shutdown LMIC safely
|
||||
ESP_LOGI(TAG, "Waiting until LMIC is idle...");
|
||||
while ((LMIC.opmode & OP_TXRXPEND) ||
|
||||
os_queryTimeCriticalJobs(sec2osticks(wakeup_sec)))
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
|
||||
// set wakeup gpio
|
||||
if (wakeup_gpio != NOT_A_PIN) {
|
||||
SaveLMICToRTC(wakeup_sec);
|
||||
// vTaskDelete(lmicTask);
|
||||
// LMIC_shutdown();
|
||||
#endif // (HAS_LORA)
|
||||
|
||||
// set up RTC power domains
|
||||
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_SLOW_MEM, ESP_PD_OPTION_ON);
|
||||
|
||||
// set up RTC wakeup timer, if we have
|
||||
if (wakeup_sec > 0) {
|
||||
esp_sleep_enable_timer_wakeup(wakeup_sec * uS_TO_S_FACTOR);
|
||||
}
|
||||
|
||||
// set wakeup gpio, if we have
|
||||
if (wakeup_gpio != GPIO_NUM_MAX) {
|
||||
rtc_gpio_isolate(wakeup_gpio);
|
||||
esp_sleep_enable_ext1_wakeup(1ULL << wakeup_gpio, ESP_EXT1_WAKEUP_ALL_LOW);
|
||||
}
|
||||
@ -99,15 +131,6 @@ void enter_deepsleep(const int wakeup_sec, const gpio_num_t wakeup_gpio) {
|
||||
dp_shutdown();
|
||||
#endif
|
||||
|
||||
// switch off radio
|
||||
#if (BLECOUNTER)
|
||||
stop_BLEscan();
|
||||
btStop();
|
||||
#endif
|
||||
#if (WIFICOUNTER)
|
||||
switch_wifi_sniffer(0);
|
||||
#endif
|
||||
|
||||
// reduce power if has PMU
|
||||
#ifdef HAS_PMU
|
||||
AXP192_power(pmu_power_sleep);
|
||||
@ -117,6 +140,6 @@ void enter_deepsleep(const int wakeup_sec, const gpio_num_t wakeup_gpio) {
|
||||
i2c_deinit();
|
||||
|
||||
// enter sleep mode
|
||||
ESP_LOGI(TAG, "Going to sleep...");
|
||||
ESP_LOGI(TAG, "Going to sleep, good bye.");
|
||||
esp_deep_sleep_start();
|
||||
}
|
@ -10,6 +10,8 @@ void setSendIRQ() {
|
||||
// put data to send in RTos Queues used for transmit over channels Lora and SPI
|
||||
void SendPayload(uint8_t port, sendprio_t prio) {
|
||||
|
||||
ESP_LOGD(TAG, "sending Payload for Port %d (prio %d)", port, prio);
|
||||
|
||||
MessageBuffer_t
|
||||
SendBuffer; // contains MessageSize, MessagePort, MessagePrio, Message[]
|
||||
|
||||
@ -187,14 +189,9 @@ void sendData() {
|
||||
bitmask &= ~mask;
|
||||
mask <<= 1;
|
||||
} // while (bitmask)
|
||||
|
||||
// goto sleep if we have a sleep cycle
|
||||
if ((cfg.sleepcycle) && (RTC_runmode == RUNMODE_NORMAL))
|
||||
enter_deepsleep(cfg.sleepcycle * 2, HAS_BUTTON);
|
||||
|
||||
} // sendData()
|
||||
|
||||
void flushQueues() {
|
||||
void flushQueues(void) {
|
||||
#if (HAS_LORA)
|
||||
lora_queuereset();
|
||||
#endif
|
||||
@ -205,3 +202,17 @@ void flushQueues() {
|
||||
mqtt_queuereset();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool allQueuesEmtpy(void) {
|
||||
uint32_t rc = 0;
|
||||
#if (HAS_LORA)
|
||||
rc += lora_queuewaiting();
|
||||
#endif
|
||||
#ifdef HAS_SPI
|
||||
rc += spi_queuewaiting();
|
||||
#endif
|
||||
#ifdef HAS_MQTT
|
||||
rc += mqtt_queuewaiting();
|
||||
#endif
|
||||
return (rc == 0) ? true : false;
|
||||
}
|
||||
|
@ -57,7 +57,8 @@ void spi_slave_task(void *param) {
|
||||
memset(rxbuf, 0, sizeof(rxbuf));
|
||||
|
||||
// fetch next or wait for payload to send from queue
|
||||
if (xQueueReceive(SPISendQueue, &msg, portMAX_DELAY) != pdTRUE) {
|
||||
// do not delete item from queue until it is transmitted
|
||||
if (xQueuePeek(SPISendQueue, &msg, portMAX_DELAY) != pdTRUE) {
|
||||
ESP_LOGE(TAG, "Premature return from xQueueReceive() with no data!");
|
||||
continue;
|
||||
}
|
||||
@ -96,6 +97,9 @@ void spi_slave_task(void *param) {
|
||||
ESP_LOGI(TAG, "Transaction finished with size %zu bits",
|
||||
spi_transaction.trans_len);
|
||||
|
||||
// delete sent item from queue
|
||||
xQueueReceive(SPISendQueue, &msg, (TickType_t)0);
|
||||
|
||||
// check if command was received, then call interpreter with command payload
|
||||
if ((spi_transaction.trans_len) && ((rxbuf[2]) == RCMDPORT)) {
|
||||
rcommand(rxbuf + HEADER_SIZE, spi_transaction.trans_len - HEADER_SIZE);
|
||||
@ -159,11 +163,11 @@ void spi_enqueuedata(MessageBuffer_t *message) {
|
||||
if (!uxQueueSpacesAvailable(SPISendQueue))
|
||||
xQueueReceive(SPISendQueue, &DummyBuffer, (TickType_t)0);
|
||||
case prio_normal:
|
||||
ret = xQueueSendToFront(SPISendQueue, (void *)message, (TickType_t)0);
|
||||
ret = xQueueSendToBack(SPISendQueue, (void *)message, (TickType_t)0);
|
||||
break;
|
||||
case prio_low:
|
||||
default:
|
||||
ret = xQueueSendToBack(SPISendQueue, (void *)message, (TickType_t)0);
|
||||
ret = xQueueSendToFront(SPISendQueue, (void *)message, (TickType_t)0);
|
||||
break;
|
||||
}
|
||||
if (ret != pdTRUE)
|
||||
@ -172,4 +176,6 @@ void spi_enqueuedata(MessageBuffer_t *message) {
|
||||
|
||||
void spi_queuereset(void) { xQueueReset(SPISendQueue); }
|
||||
|
||||
uint32_t spi_queuewaiting(void) { return uxQueueMessagesWaiting(SPISendQueue); }
|
||||
|
||||
#endif // HAS_SPI
|
Loading…
Reference in New Issue
Block a user