new feature deep sleep (wokring alpha)
This commit is contained in:
parent
016d69b5bb
commit
36afe66df9
@ -20,9 +20,10 @@
|
|||||||
|
|
||||||
extern TaskHandle_t lmicTask, lorasendTask;
|
extern TaskHandle_t lmicTask, lorasendTask;
|
||||||
|
|
||||||
void lora_stack_reset();
|
esp_err_t lmic_init(void);
|
||||||
esp_err_t lora_stack_init(bool do_join);
|
|
||||||
void lora_setupForNetwork(bool preJoin);
|
void lora_setupForNetwork(bool preJoin);
|
||||||
|
void SaveLMICToRTC(int deepsleep_sec);
|
||||||
|
void LoadLMICFromRTC();
|
||||||
void lmictask(void *pvParameters);
|
void lmictask(void *pvParameters);
|
||||||
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);
|
||||||
@ -33,6 +34,7 @@ void os_getDevEui(u1_t *buf);
|
|||||||
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);
|
||||||
|
uint32_t lora_queuewaiting(void);
|
||||||
uint8_t myBattLevelCb(void *pUserData);
|
uint8_t myBattLevelCb(void *pUserData);
|
||||||
void IRAM_ATTR myEventCallback(void *pUserData, ev_t ev);
|
void IRAM_ATTR myEventCallback(void *pUserData, ev_t ev);
|
||||||
void IRAM_ATTR myRxCallback(void *pUserData, uint8_t port, const uint8_t *pMsg,
|
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 SendPayload(uint8_t port, sendprio_t prio);
|
||||||
void sendData(void);
|
void sendData(void);
|
||||||
void checkSendQueues(void);
|
void checkSendQueues(void);
|
||||||
void flushQueues();
|
void flushQueues(void);
|
||||||
|
bool allQueuesEmtpy(void);
|
||||||
void setSendIRQ(void);
|
void setSendIRQ(void);
|
||||||
|
|
||||||
#endif // _SENDDATA_H_
|
#endif // _SENDDATA_H_
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
; ---> SELECT THE TARGET PLATFORM HERE! <---
|
; ---> SELECT THE TARGET PLATFORM HERE! <---
|
||||||
[board]
|
[board]
|
||||||
halfile = generic.h
|
;halfile = generic.h
|
||||||
;halfile = ebox.h
|
;halfile = ebox.h
|
||||||
;halfile = eboxtube.h
|
;halfile = eboxtube.h
|
||||||
;halfile = ecopower.h
|
;halfile = ecopower.h
|
||||||
@ -19,7 +19,7 @@ halfile = generic.h
|
|||||||
;halfile = ttgov21new.h
|
;halfile = ttgov21new.h
|
||||||
;halfile = ttgofox.h
|
;halfile = ttgofox.h
|
||||||
;halfile = ttgobeam.h
|
;halfile = ttgobeam.h
|
||||||
;halfile = ttgobeam10.h
|
halfile = ttgobeam10.h
|
||||||
;halfile = ttgotdisplay.h
|
;halfile = ttgotdisplay.h
|
||||||
;halfile = fipy.h
|
;halfile = fipy.h
|
||||||
;halfile = lopy.h
|
;halfile = lopy.h
|
||||||
@ -47,7 +47,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 = 2.0.4
|
release_version = 2.0.51
|
||||||
; 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
|
||||||
@ -55,7 +55,7 @@ extra_scripts = pre:build.py
|
|||||||
otakeyfile = ota.conf
|
otakeyfile = ota.conf
|
||||||
lorakeyfile = loraconf.h
|
lorakeyfile = loraconf.h
|
||||||
lmicconfigfile = lmic_config.h
|
lmicconfigfile = lmic_config.h
|
||||||
platform_espressif32 = espressif32@2.0.0
|
platform_espressif32 = espressif32@2.1.0
|
||||||
monitor_speed = 115200
|
monitor_speed = 115200
|
||||||
upload_speed = 115200 ; set by build.py and taken from hal file
|
upload_speed = 115200 ; set by build.py and taken from hal file
|
||||||
display_library = ; 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/OneBitDisplay @ 1.9.0
|
||||||
bitbank2/BitBang_I2C @ ^2.1.3
|
bitbank2/BitBang_I2C @ ^2.1.3
|
||||||
ricmoo/QRCode @ ^0.0.1
|
ricmoo/QRCode @ ^0.0.1
|
||||||
bodmer/TFT_eSPI @ ^2.2.20
|
bodmer/TFT_eSPI @ ^2.3.51
|
||||||
lib_deps_ledmatrix =
|
lib_deps_ledmatrix =
|
||||||
seeed-studio/Ultrathin_LED_Matrix @ ^1.0.0
|
seeed-studio/Ultrathin_LED_Matrix @ ^1.0.0
|
||||||
lib_deps_rgbled =
|
lib_deps_rgbled =
|
||||||
@ -76,8 +76,7 @@ lib_deps_sensors =
|
|||||||
adafruit/Adafruit Unified Sensor @ ^1.1.4
|
adafruit/Adafruit Unified Sensor @ ^1.1.4
|
||||||
adafruit/Adafruit BME280 Library @ ^2.1.1
|
adafruit/Adafruit BME280 Library @ ^2.1.1
|
||||||
adafruit/Adafruit BMP085 Library @ ^1.1.0
|
adafruit/Adafruit BMP085 Library @ ^1.1.0
|
||||||
;boschsensortec/BSEC Software Library @ 1.6.1480
|
boschsensortec/BSEC Software Library @ 1.6.1480
|
||||||
https://github.com/BoschSensortec/BSEC-Arduino-library.git
|
|
||||||
https://github.com/ricki-z/SDS011.git
|
https://github.com/ricki-z/SDS011.git
|
||||||
lib_deps_basic =
|
lib_deps_basic =
|
||||||
bblanchon/ArduinoJson @ <6
|
bblanchon/ArduinoJson @ <6
|
||||||
@ -117,7 +116,7 @@ framework = arduino
|
|||||||
board = esp32dev
|
board = esp32dev
|
||||||
board_build.partitions = min_spiffs.csv
|
board_build.partitions = min_spiffs.csv
|
||||||
upload_speed = ${common.upload_speed}
|
upload_speed = ${common.upload_speed}
|
||||||
;upload_port = COM8
|
;upload_port = COM3
|
||||||
platform = ${common.platform_espressif32}
|
platform = ${common.platform_espressif32}
|
||||||
lib_deps = ${common.lib_deps_all}
|
lib_deps = ${common.lib_deps_all}
|
||||||
build_flags = ${common.build_flags_all}
|
build_flags = ${common.build_flags_all}
|
||||||
|
@ -95,6 +95,13 @@ void irqHandler(void *pvParameters) {
|
|||||||
if (InterruptStatus & SENDCYCLE_IRQ) {
|
if (InterruptStatus & SENDCYCLE_IRQ) {
|
||||||
sendData();
|
sendData();
|
||||||
InterruptStatus &= ~SENDCYCLE_IRQ;
|
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
|
} // for
|
||||||
} // irqHandler()
|
} // irqHandler()
|
||||||
|
237
src/lorawan.cpp
237
src/lorawan.cpp
@ -6,6 +6,9 @@
|
|||||||
// Local logging Tag
|
// Local logging Tag
|
||||||
static const char TAG[] = "lora";
|
static const char TAG[] = "lora";
|
||||||
|
|
||||||
|
// Saves the LMIC structure during deep sleep
|
||||||
|
RTC_DATA_ATTR lmic_t RTC_LMIC;
|
||||||
|
|
||||||
#if CLOCK_ERROR_PROCENTAGE > 7
|
#if CLOCK_ERROR_PROCENTAGE > 7
|
||||||
#warning CLOCK_ERROR_PROCENTAGE value in lmic_config.h is too high; values > 7 will cause side effects
|
#warning CLOCK_ERROR_PROCENTAGE value in lmic_config.h is too high; values > 7 will cause side effects
|
||||||
#endif
|
#endif
|
||||||
@ -16,11 +19,6 @@ 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;
|
||||||
|
|
||||||
@ -83,8 +81,6 @@ void lora_setupForNetwork(bool preJoin) {
|
|||||||
getSfName(updr2rps(LMIC.datarate)),
|
getSfName(updr2rps(LMIC.datarate)),
|
||||||
getBwName(updr2rps(LMIC.datarate)),
|
getBwName(updr2rps(LMIC.datarate)),
|
||||||
getCrName(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
|
// 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!");
|
ESP_LOGE(TAG, "Premature return from xQueueReceive() with no data!");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// attempt to transmit payload
|
// attempt to transmit payload
|
||||||
else {
|
switch (LMIC_setTxData2_strict(SendBuffer.MessagePort, SendBuffer.Message,
|
||||||
|
SendBuffer.MessageSize,
|
||||||
switch (LMIC_setTxData2_strict(SendBuffer.MessagePort, SendBuffer.Message,
|
(cfg.countermode & 0x02))) {
|
||||||
SendBuffer.MessageSize,
|
|
||||||
(cfg.countermode & 0x02))) {
|
|
||||||
|
|
||||||
case LMIC_ERROR_SUCCESS:
|
|
||||||
// save current Fcnt to RTC RAM
|
|
||||||
RTCseqnoUp = LMIC.seqnoUp;
|
|
||||||
RTCseqnoDn = LMIC.seqnoDn;
|
|
||||||
|
|
||||||
|
case LMIC_ERROR_SUCCESS:
|
||||||
#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
|
||||||
if (SendBuffer.MessagePort == TIMEPORT)
|
if (SendBuffer.MessagePort == TIMEPORT)
|
||||||
// store LMIC time when we started transmit of timesync request
|
// store LMIC time when we started transmit of timesync request
|
||||||
timesync_store(osticks2ms(os_getTime()), timesync_tx);
|
timesync_store(osticks2ms(os_getTime()), timesync_tx);
|
||||||
#endif
|
#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);
|
} // switch
|
||||||
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
|
|
||||||
}
|
|
||||||
delay(2); // yield to CPU
|
delay(2); // yield to CPU
|
||||||
}
|
} // while(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
void lora_stack_reset() {
|
esp_err_t lmic_init(void) {
|
||||||
LMIC_reset(); // reset LMIC MAC
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t lora_stack_init(bool do_join) {
|
|
||||||
_ASSERT(SEND_QUEUE_SIZE > 0);
|
_ASSERT(SEND_QUEUE_SIZE > 0);
|
||||||
LoraSendQueue = xQueueCreate(SEND_QUEUE_SIZE, sizeof(MessageBuffer_t));
|
LoraSendQueue = xQueueCreate(SEND_QUEUE_SIZE, sizeof(MessageBuffer_t));
|
||||||
if (LoraSendQueue == 0) {
|
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",
|
ESP_LOGI(TAG, "LORA send queue created, size %d Bytes",
|
||||||
SEND_QUEUE_SIZE * sizeof(MessageBuffer_t));
|
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...");
|
ESP_LOGI(TAG, "Starting LMIC...");
|
||||||
xTaskCreatePinnedToCore(lmictask, // task function
|
xTaskCreatePinnedToCore(lmictask, // task function
|
||||||
"lmictask", // name of task
|
"lmictask", // name of task
|
||||||
@ -269,31 +304,7 @@ esp_err_t lora_stack_init(bool do_join) {
|
|||||||
&lmicTask, // task handle
|
&lmicTask, // task handle
|
||||||
1); // CPU core
|
1); // CPU core
|
||||||
|
|
||||||
#ifdef LORA_ABP
|
// start lora send task
|
||||||
// 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
|
|
||||||
xTaskCreatePinnedToCore(lora_send, // task function
|
xTaskCreatePinnedToCore(lora_send, // task function
|
||||||
"lorasendtask", // name of task
|
"lorasendtask", // name of task
|
||||||
3072, // stack size 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");
|
ESP_LOGW(TAG, "LORA sendqueue purged, data is lost");
|
||||||
}
|
}
|
||||||
case prio_normal:
|
case prio_normal:
|
||||||
ret = xQueueSendToFront(LoraSendQueue, (void *)message, (TickType_t)0);
|
ret = xQueueSendToBack(LoraSendQueue, (void *)message, (TickType_t)0);
|
||||||
break;
|
break;
|
||||||
case prio_low:
|
case prio_low:
|
||||||
default:
|
default:
|
||||||
ret = xQueueSendToBack(LoraSendQueue, (void *)message, (TickType_t)0);
|
ret = xQueueSendToFront(LoraSendQueue, (void *)message, (TickType_t)0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (ret != pdTRUE) {
|
if (ret != pdTRUE) {
|
||||||
@ -338,38 +349,18 @@ void lora_enqueuedata(MessageBuffer_t *message) {
|
|||||||
|
|
||||||
void lora_queuereset(void) { xQueueReset(LoraSendQueue); }
|
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) {
|
void lmictask(void *pvParameters) {
|
||||||
_ASSERT((uint32_t)pvParameters == 1);
|
_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) {
|
while (1) {
|
||||||
os_runloop_once(); // execute lmic scheduled jobs and events
|
os_runloop_once(); // execute lmic scheduled jobs and events
|
||||||
delay(2); // yield to CPU
|
delay(2); // yield to CPU
|
||||||
}
|
}
|
||||||
} // lmictask
|
}
|
||||||
|
|
||||||
// lmic event handler
|
// lmic event handler
|
||||||
void myEventCallback(void *pUserData, ev_t ev) {
|
void myEventCallback(void *pUserData, ev_t ev) {
|
||||||
@ -410,7 +401,7 @@ void myEventCallback(void *pUserData, ev_t ev) {
|
|||||||
case EV_JOIN_FAILED:
|
case EV_JOIN_FAILED:
|
||||||
// must call LMIC_reset() to stop joining
|
// must call LMIC_reset() to stop joining
|
||||||
// otherwise join procedure continues.
|
// otherwise join procedure continues.
|
||||||
lora_stack_reset();
|
LMIC_reset();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EV_JOIN_TXCOMPLETE:
|
case EV_JOIN_TXCOMPLETE:
|
||||||
@ -560,4 +551,44 @@ void mac_decode(const uint8_t cmd[], const uint8_t cmdlen, bool is_down) {
|
|||||||
} // mac_decode()
|
} // mac_decode()
|
||||||
#endif // VERBOSE
|
#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
|
#endif // HAS_LORA
|
@ -348,9 +348,7 @@ void setup() {
|
|||||||
// initialize LoRa
|
// initialize LoRa
|
||||||
#if (HAS_LORA)
|
#if (HAS_LORA)
|
||||||
strcat_P(features, " LORA");
|
strcat_P(features, " LORA");
|
||||||
// kick off join, except we come from sleep
|
_ASSERT(lmic_init() == ESP_OK);
|
||||||
_ASSERT(lora_stack_init(RTC_runmode == RUNMODE_WAKEUP ? false : true) ==
|
|
||||||
ESP_OK);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// initialize SPI
|
// initialize SPI
|
||||||
|
@ -115,7 +115,8 @@ void mqtt_client_task(void *param) {
|
|||||||
while (1) {
|
while (1) {
|
||||||
|
|
||||||
// fetch next or wait for payload to send from queue
|
// 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!");
|
ESP_LOGE(TAG, "Premature return from xQueueReceive() with no data!");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -129,19 +130,17 @@ void mqtt_client_task(void *param) {
|
|||||||
|
|
||||||
if (mqttClient.publish(MQTT_OUTTOPIC, buffer)) {
|
if (mqttClient.publish(MQTT_OUTTOPIC, buffer)) {
|
||||||
ESP_LOGI(TAG, "%d byte(s) sent to MQTT server", msg.MessageSize + 2);
|
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;
|
continue;
|
||||||
} else {
|
} else
|
||||||
mqtt_enqueuedata(&msg); // postpone the undelivered message
|
ESP_LOGD(TAG, "Couldn't sent message to MQTT server");
|
||||||
ESP_LOGD(TAG,
|
|
||||||
"Couldn't sent message to MQTT server, message postponed");
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// attempt to reconnect to MQTT server
|
// attempt to reconnect to MQTT server
|
||||||
ESP_LOGD(TAG, "MQTT client reconnecting...");
|
ESP_LOGD(TAG, "MQTT client reconnecting...");
|
||||||
ESP_LOGD(TAG, "MQTT last_error = %d / rc = %d", mqttClient.lastError(),
|
ESP_LOGD(TAG, "MQTT last_error = %d / rc = %d", mqttClient.lastError(),
|
||||||
mqttClient.returnCode());
|
mqttClient.returnCode());
|
||||||
mqtt_enqueuedata(&msg); // postpone the undelivered message
|
|
||||||
delay(MQTT_RETRYSEC * 1000);
|
delay(MQTT_RETRYSEC * 1000);
|
||||||
mqtt_connect(MQTT_SERVER, MQTT_PORT);
|
mqtt_connect(MQTT_SERVER, MQTT_PORT);
|
||||||
}
|
}
|
||||||
@ -161,11 +160,11 @@ void mqtt_enqueuedata(MessageBuffer_t *message) {
|
|||||||
if (!uxQueueSpacesAvailable(MQTTSendQueue))
|
if (!uxQueueSpacesAvailable(MQTTSendQueue))
|
||||||
xQueueReceive(MQTTSendQueue, &DummyBuffer, (TickType_t)0);
|
xQueueReceive(MQTTSendQueue, &DummyBuffer, (TickType_t)0);
|
||||||
case prio_normal:
|
case prio_normal:
|
||||||
ret = xQueueSendToFront(MQTTSendQueue, (void *)message, (TickType_t)0);
|
ret = xQueueSendToBack(MQTTSendQueue, (void *)message, (TickType_t)0);
|
||||||
break;
|
break;
|
||||||
case prio_low:
|
case prio_low:
|
||||||
default:
|
default:
|
||||||
ret = xQueueSendToBack(MQTTSendQueue, (void *)message, (TickType_t)0);
|
ret = xQueueSendToFront(MQTTSendQueue, (void *)message, (TickType_t)0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (ret != pdTRUE)
|
if (ret != pdTRUE)
|
||||||
@ -185,6 +184,11 @@ void mqtt_loop(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void mqtt_queuereset(void) { xQueueReset(MQTTSendQueue); }
|
void mqtt_queuereset(void) { xQueueReset(MQTTSendQueue); }
|
||||||
|
|
||||||
|
uint32_t mqtt_queuewaiting(void) {
|
||||||
|
return uxQueueMessagesWaitingMQTTSendQueue);
|
||||||
|
}
|
||||||
|
|
||||||
void setMqttIRQ(void) { xTaskNotify(irqHandlerTask, MQTT_IRQ, eSetBits); }
|
void setMqttIRQ(void) { xTaskNotify(irqHandlerTask, MQTT_IRQ, eSetBits); }
|
||||||
|
|
||||||
#endif // HAS_MQTT
|
#endif // HAS_MQTT
|
@ -11,12 +11,13 @@
|
|||||||
|
|
||||||
// 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
|
||||||
|
#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 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
|
#define COUNTERMODE 0 // 0=cyclic, 1=cumulative, 2=cyclic confirmed
|
||||||
|
|
||||||
// MAC sniffing parameters
|
// MAC sniffing parameters
|
||||||
#define VENDORFILTER 0 // set to 0 if you want to scan all devices, not filtering smartphone OUIs
|
#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 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]
|
#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
|
#define BLESCANINTERVAL 80 // [illiseconds] scan interval, see below, 3 .. 10240, default 80ms = 100% duty cycle
|
||||||
|
|
||||||
// Corona Exposure Notification Service(ENS) counter
|
// Corona Exposure Notification Service(ENS) counter
|
||||||
#define COUNT_ENS 0 // count found number of devices which advertise Exposure Notification Service
|
#define COUNT_ENS 1 // count found number of devices which advertise Exposure Notification Service
|
||||||
// set to 0 if you do not want to enable this function
|
// set to 1 if you want to enable this function [default=0]
|
||||||
|
|
||||||
// for additional sensors (added by some user)
|
// 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_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]
|
#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]
|
#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)
|
// 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_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 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_SAMPLES 1 // number of time requests for averaging, max. 255
|
||||||
#define TIME_SYNC_CYCLE 60 // delay between two time samples [seconds]
|
#define TIME_SYNC_CYCLE 60 // delay between two time samples [seconds]
|
||||||
#define TIME_SYNC_TIMEOUT 400 // timeout waiting for timeserver answer [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.");
|
ESP_LOGI(TAG, "Battery low temperature.");
|
||||||
|
|
||||||
// short press -> esp32 deep sleep mode, can be exited by pressing user button
|
// 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);
|
enter_deepsleep(0, HAS_BUTTON);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,21 +5,27 @@
|
|||||||
// Local logging tag
|
// Local logging tag
|
||||||
static const char TAG[] = __FILE__;
|
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
|
// variable keep its values after restart or wakeup from sleep
|
||||||
RTC_NOINIT_ATTR runmode_t RTC_runmode;
|
RTC_NOINIT_ATTR runmode_t RTC_runmode;
|
||||||
|
|
||||||
|
const char *runmode[4] = {"powercycle", "normal", "wakeup", "update"};
|
||||||
|
|
||||||
void do_reset(bool warmstart) {
|
void do_reset(bool warmstart) {
|
||||||
if (warmstart) {
|
if (warmstart) {
|
||||||
// store LMIC keys and counters in RTC memory
|
ESP_LOGI(TAG, "restarting device (warmstart), keeping runmode %s",
|
||||||
ESP_LOGI(TAG, "restarting device (warmstart), keeping runmode %d",
|
runmode[RTC_runmode]);
|
||||||
RTC_runmode);
|
|
||||||
} else {
|
} else {
|
||||||
#if (HAS_LORA)
|
#if (HAS_LORA)
|
||||||
if (RTC_runmode == RUNMODE_NORMAL)
|
if (RTC_runmode == RUNMODE_NORMAL) {
|
||||||
LMIC_shutdown();
|
LMIC_shutdown();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
RTC_runmode = RUNMODE_POWERCYCLE;
|
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();
|
esp_restart();
|
||||||
}
|
}
|
||||||
@ -40,9 +46,6 @@ void do_after_reset(int reason) {
|
|||||||
|
|
||||||
case DEEPSLEEP_RESET: // 0x05 Deep Sleep reset digital core
|
case DEEPSLEEP_RESET: // 0x05 Deep Sleep reset digital core
|
||||||
RTC_runmode = RUNMODE_WAKEUP;
|
RTC_runmode = RUNMODE_WAKEUP;
|
||||||
#if (HAS_LORA)
|
|
||||||
// to be done: restore LoRaWAN channel configuration and datarate here
|
|
||||||
#endif
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SW_RESET: // 0x03 Software reset digital core
|
case SW_RESET: // 0x03 Software reset digital core
|
||||||
@ -61,32 +64,61 @@ void do_after_reset(int reason) {
|
|||||||
break;
|
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))
|
// ensure we are in normal runmode, not udpate or wakeup
|
||||||
return;
|
if ((RTC_runmode != RUNMODE_NORMAL)
|
||||||
|
|
||||||
// wait until LMIC is in safe state before going to sleep
|
|
||||||
#if (HAS_LORA)
|
#if (HAS_LORA)
|
||||||
while (os_queryTimeCriticalJobs(ms2osticks(wakeup_sec * 1000)))
|
|| (LMIC.opmode & (OP_JOINING | OP_REJOIN))
|
||||||
vTaskDelay(pdMS_TO_TICKS(100));
|
#endif
|
||||||
|
) {
|
||||||
// to be done: save current LoRaWAN configuration here
|
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
|
#endif
|
||||||
|
|
||||||
// set up power domains
|
// wait until all send queues are empty
|
||||||
//esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_SLOW_MEM, ESP_PD_OPTION_ON);
|
ESP_LOGI(TAG, "Waiting until send queues are empty...");
|
||||||
|
while (!allQueuesEmtpy())
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(100));
|
||||||
|
|
||||||
// set wakeup timer
|
#if (HAS_LORA)
|
||||||
if (wakeup_sec)
|
// shutdown LMIC safely
|
||||||
esp_sleep_enable_timer_wakeup(wakeup_sec * 1000000);
|
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
|
SaveLMICToRTC(wakeup_sec);
|
||||||
if (wakeup_gpio != NOT_A_PIN) {
|
// 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);
|
rtc_gpio_isolate(wakeup_gpio);
|
||||||
esp_sleep_enable_ext1_wakeup(1ULL << wakeup_gpio, ESP_EXT1_WAKEUP_ALL_LOW);
|
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();
|
dp_shutdown();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// switch off radio
|
|
||||||
#if (BLECOUNTER)
|
|
||||||
stop_BLEscan();
|
|
||||||
btStop();
|
|
||||||
#endif
|
|
||||||
#if (WIFICOUNTER)
|
|
||||||
switch_wifi_sniffer(0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// reduce power if has PMU
|
// reduce power if has PMU
|
||||||
#ifdef HAS_PMU
|
#ifdef HAS_PMU
|
||||||
AXP192_power(pmu_power_sleep);
|
AXP192_power(pmu_power_sleep);
|
||||||
@ -117,6 +140,6 @@ void enter_deepsleep(const int wakeup_sec, const gpio_num_t wakeup_gpio) {
|
|||||||
i2c_deinit();
|
i2c_deinit();
|
||||||
|
|
||||||
// enter sleep mode
|
// enter sleep mode
|
||||||
ESP_LOGI(TAG, "Going to sleep...");
|
ESP_LOGI(TAG, "Going to sleep, good bye.");
|
||||||
esp_deep_sleep_start();
|
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
|
// put data to send in RTos Queues used for transmit over channels Lora and SPI
|
||||||
void SendPayload(uint8_t port, sendprio_t prio) {
|
void SendPayload(uint8_t port, sendprio_t prio) {
|
||||||
|
|
||||||
|
ESP_LOGD(TAG, "sending Payload for Port %d (prio %d)", port, prio);
|
||||||
|
|
||||||
MessageBuffer_t
|
MessageBuffer_t
|
||||||
SendBuffer; // contains MessageSize, MessagePort, MessagePrio, Message[]
|
SendBuffer; // contains MessageSize, MessagePort, MessagePrio, Message[]
|
||||||
|
|
||||||
@ -187,14 +189,9 @@ void sendData() {
|
|||||||
bitmask &= ~mask;
|
bitmask &= ~mask;
|
||||||
mask <<= 1;
|
mask <<= 1;
|
||||||
} // while (bitmask)
|
} // 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()
|
} // sendData()
|
||||||
|
|
||||||
void flushQueues() {
|
void flushQueues(void) {
|
||||||
#if (HAS_LORA)
|
#if (HAS_LORA)
|
||||||
lora_queuereset();
|
lora_queuereset();
|
||||||
#endif
|
#endif
|
||||||
@ -205,3 +202,17 @@ void flushQueues() {
|
|||||||
mqtt_queuereset();
|
mqtt_queuereset();
|
||||||
#endif
|
#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));
|
memset(rxbuf, 0, sizeof(rxbuf));
|
||||||
|
|
||||||
// fetch next or wait for payload to send from queue
|
// 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!");
|
ESP_LOGE(TAG, "Premature return from xQueueReceive() with no data!");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -96,6 +97,9 @@ void spi_slave_task(void *param) {
|
|||||||
ESP_LOGI(TAG, "Transaction finished with size %zu bits",
|
ESP_LOGI(TAG, "Transaction finished with size %zu bits",
|
||||||
spi_transaction.trans_len);
|
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
|
// check if command was received, then call interpreter with command payload
|
||||||
if ((spi_transaction.trans_len) && ((rxbuf[2]) == RCMDPORT)) {
|
if ((spi_transaction.trans_len) && ((rxbuf[2]) == RCMDPORT)) {
|
||||||
rcommand(rxbuf + HEADER_SIZE, spi_transaction.trans_len - HEADER_SIZE);
|
rcommand(rxbuf + HEADER_SIZE, spi_transaction.trans_len - HEADER_SIZE);
|
||||||
@ -159,11 +163,11 @@ void spi_enqueuedata(MessageBuffer_t *message) {
|
|||||||
if (!uxQueueSpacesAvailable(SPISendQueue))
|
if (!uxQueueSpacesAvailable(SPISendQueue))
|
||||||
xQueueReceive(SPISendQueue, &DummyBuffer, (TickType_t)0);
|
xQueueReceive(SPISendQueue, &DummyBuffer, (TickType_t)0);
|
||||||
case prio_normal:
|
case prio_normal:
|
||||||
ret = xQueueSendToFront(SPISendQueue, (void *)message, (TickType_t)0);
|
ret = xQueueSendToBack(SPISendQueue, (void *)message, (TickType_t)0);
|
||||||
break;
|
break;
|
||||||
case prio_low:
|
case prio_low:
|
||||||
default:
|
default:
|
||||||
ret = xQueueSendToBack(SPISendQueue, (void *)message, (TickType_t)0);
|
ret = xQueueSendToFront(SPISendQueue, (void *)message, (TickType_t)0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (ret != pdTRUE)
|
if (ret != pdTRUE)
|
||||||
@ -172,4 +176,6 @@ void spi_enqueuedata(MessageBuffer_t *message) {
|
|||||||
|
|
||||||
void spi_queuereset(void) { xQueueReset(SPISendQueue); }
|
void spi_queuereset(void) { xQueueReset(SPISendQueue); }
|
||||||
|
|
||||||
|
uint32_t spi_queuewaiting(void) { return uxQueueMessagesWaiting(SPISendQueue); }
|
||||||
|
|
||||||
#endif // HAS_SPI
|
#endif // HAS_SPI
|
Loading…
Reference in New Issue
Block a user