From 3af348fb65a26299963cdf1ea846c13b37e4f728 Mon Sep 17 00:00:00 2001 From: Christian Ambach Date: Wed, 31 Oct 2018 09:44:06 +0100 Subject: [PATCH 01/36] Revert "SPI wire interface (experimental)" This reverts commit 00b1faab8358d1575e4567d462a5329201023bc2. --- src/spisend.cpp | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/spisend.cpp b/src/spisend.cpp index 6d28f5a87..c778a8879 100644 --- a/src/spisend.cpp +++ b/src/spisend.cpp @@ -41,32 +41,34 @@ void spi_loop(void *pvParameters) { void hal_spi_init() { SPI.begin(SCK, MISO, MOSI, SS); } -void hal_spi_trx(uint8_t port, uint8_t *buf, int len, uint8_t is_read) { +void hal_spi_trx(u1_t cmd, u1_t *buf, int len, u1_t is_read) { + u1_t nss = SS; SPISettings settings(1E6, MSBFIRST, SPI_MODE0); SPI.beginTransaction(settings); - digitalWrite(SS, 0); - SPI.transfer(port); + digitalWrite(nss, 0); - for (uint8_t i = 0; i < len; i++) { - uint8_t *p = buf + i; - uint8_t data = is_read ? 0x00 : *p; + SPI.transfer(cmd); + + for (u1_t i = 0; i < len; i++) { + u1_t *p = buf + i; + u1_t data = is_read ? 0x00 : *p; data = SPI.transfer(data); if (is_read) *p = data; } - digitalWrite(SS, 1); + digitalWrite(nss, 1); SPI.endTransaction(); } -void hal_spi_write(uint8_t port, const uint8_t *buf, int len) { - hal_spi_trx(port, (uint8_t *)buf, len, 0); +void hal_spi_write(u1_t cmd, const u1_t *buf, int len) { + hal_spi_trx(cmd, (u1_t *)buf, len, 0); } -void hal_spi_read(uint8_t port, uint8_t *buf, int len) { - hal_spi_trx(port, buf, len, 1); +void hal_spi_read(u1_t cmd, u1_t *buf, int len) { + hal_spi_trx(cmd, buf, len, 1); } #endif // HAS_SPI \ No newline at end of file From 4cab5113cac68429871197685abea30e8b0609cd Mon Sep 17 00:00:00 2001 From: Christian Ambach Date: Wed, 31 Oct 2018 09:44:16 +0100 Subject: [PATCH 02/36] Revert "SPI code added (experimental)" This reverts commit 16759c4dd55abecc6f51539ba00dffcffc1e29d0. --- include/spisend.h | 25 ------------------------ src/spisend.cpp | 50 +++-------------------------------------------- 2 files changed, 3 insertions(+), 72 deletions(-) diff --git a/include/spisend.h b/include/spisend.h index 70cc44370..750a3c20f 100644 --- a/include/spisend.h +++ b/include/spisend.h @@ -1,34 +1,9 @@ #ifndef _SPISEND_H #define _SPISEND_H -#include "globals.h" -#include "spi.h" - extern TaskHandle_t SpiTask; extern QueueHandle_t SPISendQueue; -/* - * Process data in SPI send queue - */ void spi_loop(void *pvParameters); -/* -* initialize local SPI wire interface -*/ -void hal_spi_init(); - -/* - * Perform SPI write transaction on local SPI wire interface - * - write the command byte 'cmd' - * - write 'len' bytes out of 'buf' - */ -void hal_spi_write(uint8_t cmd, const uint8_t* buf, int len); - -/* - * Perform SPI read transaction on local SPI wire interface - * - read the command byte 'cmd' - * - read 'len' bytes into 'buf' - */ -void hal_spi_read(uint8_t cmd, uint8_t* buf, int len); - #endif \ No newline at end of file diff --git a/src/spisend.cpp b/src/spisend.cpp index c778a8879..57da92879 100644 --- a/src/spisend.cpp +++ b/src/spisend.cpp @@ -1,6 +1,6 @@ #ifdef HAS_SPI -#include "spisend.h" +#include "globals.h" // Local logging tag static const char TAG[] = "main"; @@ -13,62 +13,18 @@ TaskHandle_t SpiTask; // SPI feed Task void spi_loop(void *pvParameters) { - uint8_t buf[32]; - configASSERT(((uint32_t)pvParameters) == 1); // FreeRTOS check while (1) { - // check if data to send on SPI interface if (xQueueReceive(SPISendQueue, &SendBuffer, (TickType_t)0) == pdTRUE) { - hal_spi_write(SendBuffer.MessagePort, SendBuffer.Message, - SendBuffer.MessageSize); ESP_LOGI(TAG, "%d bytes sent to SPI", SendBuffer.MessageSize); } - - // check if command is received on SPI command port, then call interpreter - hal_spi_read(RCMDPORT, buf, 32); - if (buf[0]) - rcommand(buf, sizeof(buf)); - vTaskDelay(2 / portTICK_PERIOD_MS); // yield to CPU - } // end of infinite loop + + } // end of infinite loop vTaskDelete(NULL); // shoud never be reached } // spi_loop() -// SPI hardware abstraction layer - -void hal_spi_init() { SPI.begin(SCK, MISO, MOSI, SS); } - -void hal_spi_trx(u1_t cmd, u1_t *buf, int len, u1_t is_read) { - - u1_t nss = SS; - SPISettings settings(1E6, MSBFIRST, SPI_MODE0); - SPI.beginTransaction(settings); - - digitalWrite(nss, 0); - - SPI.transfer(cmd); - - for (u1_t i = 0; i < len; i++) { - u1_t *p = buf + i; - u1_t data = is_read ? 0x00 : *p; - data = SPI.transfer(data); - if (is_read) - *p = data; - } - - digitalWrite(nss, 1); - SPI.endTransaction(); -} - -void hal_spi_write(u1_t cmd, const u1_t *buf, int len) { - hal_spi_trx(cmd, (u1_t *)buf, len, 0); -} - -void hal_spi_read(u1_t cmd, u1_t *buf, int len) { - hal_spi_trx(cmd, buf, len, 1); -} - #endif // HAS_SPI \ No newline at end of file From a8043b8d654e5b07a27327332c383c0aa4a87189 Mon Sep 17 00:00:00 2001 From: Christian Ambach Date: Wed, 31 Oct 2018 16:54:45 +0100 Subject: [PATCH 03/36] set log level for LOG_LOCAL_LEVEL otherwise log functions like ESP_LOG_BUFFER_HEXDUMP will not use the defined log level Signed-off-by: Christian Ambach --- platformio.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/platformio.ini b/platformio.ini index a21e5d4ab..8d08dbb2c 100644 --- a/platformio.ini +++ b/platformio.ini @@ -58,6 +58,7 @@ build_flags = -w '-DARDUINO_LMIC_PROJECT_CONFIG_H=../../../src/lmic_config.h' '-DCORE_DEBUG_LEVEL=${common.debug_level}' + '-DLOG_LOCAL_LEVEL=${common.debug_level}' '-DBINTRAY_PACKAGE="${PIOENV}"' '-DPROGVERSION="${common.release_version}"' From bf3516bf45fe4d57845f2ea2a5818a404d915189 Mon Sep 17 00:00:00 2001 From: Christian Ambach Date: Fri, 2 Nov 2018 09:00:48 +0100 Subject: [PATCH 04/36] fix the build for devices without LoRa Signed-off-by: Christian Ambach --- src/cyclic.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cyclic.cpp b/src/cyclic.cpp index f75daacf0..081bb5564 100644 --- a/src/cyclic.cpp +++ b/src/cyclic.cpp @@ -3,6 +3,7 @@ // Basic config #include "cyclic.h" +#include "rcommand.h" // Local logging tag static const char TAG[] = "main"; From a3750ef01ba6c633df8400e2ee21dfbc9a30b05c Mon Sep 17 00:00:00 2001 From: Christian Ambach Date: Tue, 11 Sep 2018 16:15:39 +0200 Subject: [PATCH 05/36] add SPI slave support Set up SPI slave transactions for entries in the SPI send queue. Add a header to each SPI datagram that includes a CRC16, the type and the size of the message that follows. Does not act on received bytes (yet). Signed-off-by: Christian Ambach --- include/globals.h | 4 -- include/spisend.h | 9 --- include/spislave.h | 36 +++++++++++ src/cyclic.cpp | 7 ++- src/hal/generic.h | 5 ++ src/hal/lopy4.h | 6 ++ src/main.cpp | 20 +----- src/senddata.cpp | 13 ++-- src/spisend.cpp | 30 --------- src/spislave.cpp | 152 +++++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 209 insertions(+), 73 deletions(-) delete mode 100644 include/spisend.h create mode 100644 include/spislave.h delete mode 100644 src/spisend.cpp create mode 100644 src/spislave.cpp diff --git a/include/globals.h b/include/globals.h index 78df4a959..d946b2df9 100644 --- a/include/globals.h +++ b/include/globals.h @@ -66,10 +66,6 @@ extern TaskHandle_t irqHandlerTask, wifiSwitchTask; #include "lorawan.h" #endif -#ifdef HAS_SPI -#include "spisend.h" -#endif - #ifdef HAS_DISPLAY #include "display.h" #endif diff --git a/include/spisend.h b/include/spisend.h deleted file mode 100644 index 750a3c20f..000000000 --- a/include/spisend.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef _SPISEND_H -#define _SPISEND_H - -extern TaskHandle_t SpiTask; -extern QueueHandle_t SPISendQueue; - -void spi_loop(void *pvParameters); - -#endif \ No newline at end of file diff --git a/include/spislave.h b/include/spislave.h new file mode 100644 index 000000000..526203b95 --- /dev/null +++ b/include/spislave.h @@ -0,0 +1,36 @@ +/* + +//////////////////////// ESP32-Paxcounter \\\\\\\\\\\\\\\\\\\\\\\\\\ + +Copyright 2018 Christian Ambach + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +NOTICE: +Parts of the source files in this repository are made available under different +licenses. Refer to LICENSE.txt file in repository for more details. + +*/ +#ifndef _SPISLAVE_H +#define _SPISLAVE_H + +#include "globals.h" + +esp_err_t spi_init(); + +void spi_enqueuedata(uint8_t messageType, MessageBuffer_t *message); +void spi_queuereset(); + +void spi_housekeeping(); + +#endif // _SPISLAVE_H diff --git a/src/cyclic.cpp b/src/cyclic.cpp index 081bb5564..d8a0490f1 100644 --- a/src/cyclic.cpp +++ b/src/cyclic.cpp @@ -4,6 +4,7 @@ // Basic config #include "cyclic.h" #include "rcommand.h" +#include "spislave.h" // Local logging tag static const char TAG[] = "main"; @@ -26,9 +27,9 @@ void doHousekeeping() { #ifdef HAS_GPS ESP_LOGD(TAG, "Gpsloop %d bytes left", uxTaskGetStackHighWaterMark(GpsTask)); #endif -#ifdef HAS_SPI - ESP_LOGD(TAG, "Spiloop %d bytes left", uxTaskGetStackHighWaterMark(SpiTask)); -#endif + + spi_housekeeping(); + #if (HAS_LED != NOT_A_PIN) || defined(HAS_RGB_LED) ESP_LOGD(TAG, "LEDloop %d bytes left", uxTaskGetStackHighWaterMark(ledLoopTask)); #endif diff --git a/src/hal/generic.h b/src/hal/generic.h index 7e2256dff..a8a5555d0 100644 --- a/src/hal/generic.h +++ b/src/hal/generic.h @@ -7,6 +7,11 @@ #define HAS_LORA 1 // comment out if device shall not send data via LoRa or has no LoRa #define HAS_SPI 1 // comment out if device shall not send data via SPI +// pin definitions for SPI slave interface +#define SPI_MOSI GPIO_NUM_23 +#define SPI_MISO GPIO_NUM_19 +#define SPI_SCLK GPIO_NUM_18 +#define SPI_CS GPIO_NUM_5 #define CFG_sx1276_radio 1 // select LoRa chip //#define CFG_sx1272_radio 1 // select LoRa chip diff --git a/src/hal/lopy4.h b/src/hal/lopy4.h index 79e80a363..6b93baad6 100644 --- a/src/hal/lopy4.h +++ b/src/hal/lopy4.h @@ -7,6 +7,12 @@ #define HAS_LORA 1 // comment out if device shall not send data via LoRa #define HAS_SPI 1 // comment out if device shall not send data via SPI +// pin definitions for SPI slave interface +#define SPI_MOSI GPIO_NUM_22 +#define SPI_MISO GPIO_NUM_33 +#define SPI_SCLK GPIO_NUM_26 +#define SPI_CS GPIO_NUM_36 + #define CFG_sx1276_radio 1 //#define HAS_LED NOT_A_PIN // LoPy4 has no on board mono LED, we use on board RGB LED #define HAS_RGB_LED (0) // WS2812B RGB LED on GPIO0 (P2) diff --git a/src/main.cpp b/src/main.cpp index af5fdd4c1..de80e7186 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -48,6 +48,7 @@ ESP32 hardware timers // Basic Config #include "main.h" +#include "spislave.h" configData_t cfg; // struct holds current device configuration char display_line6[16], display_line7[16]; // display buffers @@ -197,14 +198,8 @@ void setup() { // initialize SPI #ifdef HAS_SPI strcat_P(features, " SPI"); - SPISendQueue = xQueueCreate(SEND_QUEUE_SIZE, sizeof(MessageBuffer_t)); - if (SPISendQueue == 0) { - ESP_LOGE(TAG, "Could not create SPI send queue. Aborting."); - exit(0); - } else - ESP_LOGI(TAG, "SPI send queue created, size %d Bytes", - SEND_QUEUE_SIZE * PAYLOAD_BUFFER_SIZE); #endif + assert(spi_init() == ESP_OK); #ifdef VENDORFILTER strcat_P(features, " OUIFLT"); @@ -312,17 +307,6 @@ void setup() { 1); // CPU core #endif -#ifdef HAS_SPI - ESP_LOGI(TAG, "Starting SPIloop..."); - xTaskCreatePinnedToCore(spi_loop, // task function - "spiloop", // name of task - 2048, // stack size of task - (void *)1, // parameter of the task - 2, // priority of the task - &SpiTask, // task handle - 0); // CPU core -#endif - // start state machine ESP_LOGI(TAG, "Starting IRQ Handler..."); xTaskCreatePinnedToCore(irqHandler, // task function diff --git a/src/senddata.cpp b/src/senddata.cpp index ee2934851..896571142 100644 --- a/src/senddata.cpp +++ b/src/senddata.cpp @@ -1,5 +1,6 @@ // Basic Config #include "globals.h" +#include "spislave.h" // put data to send in RTos Queues used for transmit over channels Lora and SPI void SendData(uint8_t port) { @@ -19,12 +20,7 @@ void SendData(uint8_t port) { ESP_LOGI(TAG, "%d bytes enqueued to send on LoRa", payload.getSize()); #endif -// enqueue message in SPI send queue -#ifdef HAS_SPI - if (xQueueSendToBack(SPISendQueue, (void *)&SendBuffer, (TickType_t)0) == - pdTRUE) - ESP_LOGI(TAG, "%d bytes enqueued to send on SPI", payload.getSize()); -#endif + spi_enqueuedata(port, &SendBuffer); // clear counter if not in cumulative counter mode if ((port == COUNTERPORT) && (cfg.countermode != 1)) { @@ -66,7 +62,6 @@ void flushQueues() { #ifdef HAS_LORA xQueueReset(LoraSendQueue); #endif -#ifdef HAS_SPI - xQueueReset(SPISendQueue); -#endif + + spi_queuereset(); } \ No newline at end of file diff --git a/src/spisend.cpp b/src/spisend.cpp deleted file mode 100644 index 57da92879..000000000 --- a/src/spisend.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#ifdef HAS_SPI - -#include "globals.h" - -// Local logging tag -static const char TAG[] = "main"; - -MessageBuffer_t SendBuffer; - -QueueHandle_t SPISendQueue; -TaskHandle_t SpiTask; - -// SPI feed Task -void spi_loop(void *pvParameters) { - - configASSERT(((uint32_t)pvParameters) == 1); // FreeRTOS check - - while (1) { - if (xQueueReceive(SPISendQueue, &SendBuffer, (TickType_t)0) == pdTRUE) { - ESP_LOGI(TAG, "%d bytes sent to SPI", SendBuffer.MessageSize); - } - vTaskDelay(2 / portTICK_PERIOD_MS); // yield to CPU - - } // end of infinite loop - - vTaskDelete(NULL); // shoud never be reached - -} // spi_loop() - -#endif // HAS_SPI \ No newline at end of file diff --git a/src/spislave.cpp b/src/spislave.cpp new file mode 100644 index 000000000..7cd8d7292 --- /dev/null +++ b/src/spislave.cpp @@ -0,0 +1,152 @@ +/* + +//////////////////////// ESP32-Paxcounter \\\\\\\\\\\\\\\\\\\\\\\\\\ + +Copyright 2018 Christian Ambach + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +NOTICE: +Parts of the source files in this repository are made available under different +licenses. Refer to LICENSE.txt file in repository for more details. + +*/ + +#include "spislave.h" + +#include +#include +#include + +static const char TAG[] = __FILE__; + +#define HEADER_SIZE 4 +// SPI transaction size needs to be at least 8 bytes and dividable by 4, see +// https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/spi_slave.html +#define BUFFER_SIZE \ + (MAX(8, HEADER_SIZE + PAYLOAD_BUFFER_SIZE) + \ + (4 - MAX(8, HEADER_SIZE + PAYLOAD_BUFFER_SIZE) % 4)) +DMA_ATTR uint8_t txbuf[BUFFER_SIZE]; +DMA_ATTR uint8_t rxbuf[BUFFER_SIZE]; + +QueueHandle_t SPISendQueue; + +TaskHandle_t spiTask; + +void spi_slave_task(void *param) { + while (1) { + MessageBuffer_t msg; + size_t transaction_size; + + memset(txbuf, 0, sizeof(txbuf)); + memset(rxbuf, 0, sizeof(rxbuf)); + + if (xQueueReceive(SPISendQueue, &msg, portMAX_DELAY) != pdTRUE) { + ESP_LOGE(TAG, "Premature return from xQueueReceive() with no data!"); + continue; + } + + uint8_t *messageType = txbuf + 2; + *messageType = msg.MessagePort; + uint8_t *messageSize = txbuf + 3; + *messageSize = msg.MessageSize; + memcpy(txbuf + HEADER_SIZE, &msg.Message, msg.MessageSize); + + transaction_size = HEADER_SIZE + msg.MessageSize; + transaction_size += (4 - transaction_size % 4); + + uint16_t *crc = (uint16_t *)txbuf; + *crc = crc16_be(0, messageType, msg.MessageSize + HEADER_SIZE - 2); + + spi_slave_transaction_t spi_transaction = {0}; + spi_transaction.length = transaction_size * 8; + spi_transaction.tx_buffer = txbuf; + spi_transaction.rx_buffer = rxbuf; + + ESP_LOGI(TAG, "Prepared SPI transaction for %zu bytes", transaction_size); + ESP_LOG_BUFFER_HEXDUMP(TAG, txbuf, transaction_size, ESP_LOG_DEBUG); + esp_err_t ret = + spi_slave_transmit(HSPI_HOST, &spi_transaction, portMAX_DELAY); + ESP_LOG_BUFFER_HEXDUMP(TAG, rxbuf, transaction_size, ESP_LOG_DEBUG); + ESP_LOGI(TAG, "Transaction finished with size %zu bits", + spi_transaction.trans_len); + } +} + +esp_err_t spi_init() { +#ifndef HAS_SPI + return ESP_OK; +#else + + SPISendQueue = xQueueCreate(SEND_QUEUE_SIZE, sizeof(MessageBuffer_t)); + if (SPISendQueue == 0) { + ESP_LOGE(TAG, "Could not create SPI send queue. Aborting."); + return ESP_FAIL; + } + ESP_LOGI(TAG, "SPI send queue created, size %d Bytes", + SEND_QUEUE_SIZE * PAYLOAD_BUFFER_SIZE); + + spi_bus_config_t spi_bus_cfg = {.mosi_io_num = SPI_MOSI, + .miso_io_num = SPI_MISO, + .sclk_io_num = SPI_SCLK, + .quadwp_io_num = -1, + .quadhd_io_num = -1, + .max_transfer_sz = 0, + .flags = 0}; + + spi_slave_interface_config_t spi_slv_cfg = {.spics_io_num = SPI_CS, + .flags = 0, + .queue_size = 1, + .mode = 0, + .post_setup_cb = NULL, + .post_trans_cb = NULL}; + + gpio_set_pull_mode(SPI_MOSI, GPIO_PULLUP_ONLY); + gpio_set_pull_mode(SPI_SCLK, GPIO_PULLUP_ONLY); + gpio_set_pull_mode(SPI_CS, GPIO_PULLUP_ONLY); + + ESP_LOGI(TAG, "Starting SPIloop..."); + xTaskCreate(spi_slave_task, "spiloop", 4096, (void *)NULL, 2, &spiTask); + + esp_err_t ret = + spi_slave_initialize(HSPI_HOST, &spi_bus_cfg, &spi_slv_cfg, 1); + return ret; + +#endif +} + +void spi_enqueuedata(uint8_t messageType, MessageBuffer_t *message) { + // enqueue message in SPI send queue +#ifdef HAS_SPI + BaseType_t ret = + xQueueSendToBack(SPISendQueue, (void *)message, (TickType_t)0); + if (ret == pdTRUE) { + ESP_LOGI(TAG, "%d bytes enqueued for SPI consumption", + message->MessageSize); + } else { + ESP_LOGW(TAG, "SPI sendqueue is full"); + } +#endif +} + +void spi_queuereset(void) { +#ifdef HAS_SPI + xQueueReset(SPISendQueue); +#endif +} + +void spi_housekeeping(void) { +#ifdef HAS_SPI + ESP_LOGD(TAG, "spiloop %d bytes left", uxTaskGetStackHighWaterMark(spiTask)); +#endif +} \ No newline at end of file From a30f0bcf863f3df939b292222c87fca102c558ed Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sat, 3 Nov 2018 20:08:48 +0100 Subject: [PATCH 06/36] main.cpp: pointer initialization --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index af5fdd4c1..27b2f7daa 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -55,7 +55,7 @@ uint8_t volatile channel = 0; // channel rotation counter uint16_t volatile macs_total = 0, macs_wifi = 0, macs_ble = 0, batt_voltage = 0; // globals for display -hw_timer_t *channelSwitch, *sendCycle, *homeCycle, *displaytimer; // irq tasks +hw_timer_t *channelSwitch = NULL, *sendCycle = NULL, *homeCycle = NULL, *displaytimer = NULL; // irq tasks TaskHandle_t irqHandlerTask, wifiSwitchTask; std::set macs; // container holding unique MAC adress hashes From 0cc98a2e243a33fa26f94c78d3b22c5b1dd67e09 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sat, 3 Nov 2018 20:29:02 +0100 Subject: [PATCH 07/36] SPI slave integration --- include/lorawan.h | 4 +++ src/lorawan.cpp | 68 ++++++++++++++++++++++++++++++++++++++++++++++- src/main.cpp | 35 ++---------------------- src/senddata.cpp | 16 +++-------- src/spislave.cpp | 2 +- 5 files changed, 78 insertions(+), 47 deletions(-) diff --git a/include/lorawan.h b/include/lorawan.h index 66d77f5bd..94957c252 100644 --- a/include/lorawan.h +++ b/include/lorawan.h @@ -26,5 +26,9 @@ void os_getDevEui(u1_t *buf); void showLoraKeys(void); void switch_lora(uint8_t sf, uint8_t tx); void lora_send(osjob_t *job); +void lora_enqueuedata(uint8_t messageType, MessageBuffer_t *message); +void lora_queuereset(void); +void lora_housekeeping(void); +esp_err_t lora_stack_init(); #endif \ No newline at end of file diff --git a/src/lorawan.cpp b/src/lorawan.cpp index 35c9d9448..ae0f08c05 100644 --- a/src/lorawan.cpp +++ b/src/lorawan.cpp @@ -341,4 +341,70 @@ void lora_send(osjob_t *job) { lora_send); } -#endif // HAS_LORA \ No newline at end of file +esp_err_t lora_stack_init() { +#ifndef HAS_LORA + return ESP_OK; // continue main program +#else + LoraSendQueue = xQueueCreate(SEND_QUEUE_SIZE, sizeof(MessageBuffer_t)); + if (LoraSendQueue == 0) { + ESP_LOGE(TAG, "Could not create LORA send queue. Aborting."); + return ESP_FAIL; + } + ESP_LOGI(TAG, "LORA send queue created, size %d Bytes", + SEND_QUEUE_SIZE * PAYLOAD_BUFFER_SIZE); + + ESP_LOGI(TAG, "Starting LMIC..."); + os_init(); // initialize lmic run-time environment on core 1 + LMIC_reset(); // initialize lmic MAC + LMIC_setLinkCheckMode(0); + // 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. + LMIC_setClockError(MAX_CLOCK_ERROR * CLOCK_ERROR_PROCENTAGE / 100); + // Set the data rate to Spreading Factor 7. This is the fastest supported + // rate for 125 kHz channels, and it minimizes air time and battery power. Set + // the transmission power to 14 dBi (25 mW). + LMIC_setDrTxpow(DR_SF7, 14); + +#if defined(CFG_US915) || defined(CFG_au921) + // in the US, with TTN, it saves join time if we start on subband 1 (channels + // 8-15). This will get overridden after the join by parameters from the + // network. If working with other networks or in other regions, this will need + // to be changed. + LMIC_selectSubBand(1); +#endif + + LMIC_startJoining(); // start joining + return ESP_OK; // continue main program +#endif +} + +#endif // HAS_LORA + +void lora_enqueuedata(uint8_t messageType, MessageBuffer_t *message) { + // enqueue message in LORA send queue +#ifdef HAS_LORA + BaseType_t ret = + xQueueSendToBack(LoraSendQueue, (void *)message, (TickType_t)0); + if (ret == pdTRUE) { + ESP_LOGI(TAG, "%d bytes enqueued for LORA interface", + message->MessageSize); + } else { + ESP_LOGW(TAG, "LORA sendqueue is full"); + } +#endif +} + +void lora_queuereset(void) { +#ifdef HAS_LORA + xQueueReset(LoraSendQueue); +#endif +} + +void lora_housekeeping(void) { +#ifdef HAS_LORA +// ESP_LOGD(TAG, "loraloop %d bytes left", +// uxTaskGetStackHighWaterMark(LoraTask)); +#endif +} diff --git a/src/main.cpp b/src/main.cpp index de80e7186..46bf6ddf4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -56,7 +56,7 @@ uint8_t volatile channel = 0; // channel rotation counter uint16_t volatile macs_total = 0, macs_wifi = 0, macs_ble = 0, batt_voltage = 0; // globals for display -hw_timer_t *channelSwitch, *sendCycle, *homeCycle, *displaytimer; // irq tasks +hw_timer_t *channelSwitch = NULL, *sendCycle = NULL, *homeCycle = NULL, *displaytimer = NULL; // irq tasks TaskHandle_t irqHandlerTask, wifiSwitchTask; std::set macs; // container holding unique MAC adress hashes @@ -161,39 +161,8 @@ void setup() { // initialize LoRa #ifdef HAS_LORA strcat_P(features, " LORA"); - LoraSendQueue = xQueueCreate(SEND_QUEUE_SIZE, sizeof(MessageBuffer_t)); - if (LoraSendQueue == 0) { - ESP_LOGE(TAG, "Could not create LORA send queue. Aborting."); - exit(0); - } else - ESP_LOGI(TAG, "LORA send queue created, size %d Bytes", - SEND_QUEUE_SIZE * PAYLOAD_BUFFER_SIZE); - - ESP_LOGI(TAG, "Starting LMIC..."); - os_init(); // initialize lmic run-time environment on core 1 - LMIC_reset(); // initialize lmic MAC - LMIC_setLinkCheckMode(0); - // 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. - LMIC_setClockError(MAX_CLOCK_ERROR * CLOCK_ERROR_PROCENTAGE / 100); - // Set the data rate to Spreading Factor 7. This is the fastest supported - // rate for 125 kHz channels, and it minimizes air time and battery power. Set - // the transmission power to 14 dBi (25 mW). - LMIC_setDrTxpow(DR_SF7, 14); - -#if defined(CFG_US915) || defined(CFG_au921) - // in the US, with TTN, it saves join time if we start on subband 1 (channels - // 8-15). This will get overridden after the join by parameters from the - // network. If working with other networks or in other regions, this will need - // to be changed. - LMIC_selectSubBand(1); -#endif - - LMIC_startJoining(); // start joining - #endif + assert(lora_stack_init() == ESP_OK); // initialize SPI #ifdef HAS_SPI diff --git a/src/senddata.cpp b/src/senddata.cpp index 896571142..b8edda34a 100644 --- a/src/senddata.cpp +++ b/src/senddata.cpp @@ -13,19 +13,14 @@ void SendData(uint8_t port) { : (PAYLOAD_ENCODER == 4 ? LPP2PORT : LPP1PORT); memcpy(SendBuffer.Message, payload.getBuffer(), payload.getSize()); - // enqueue message in LoRa send queue -#ifdef HAS_LORA - if (xQueueSendToBack(LoraSendQueue, (void *)&SendBuffer, (TickType_t)0) == - pdTRUE) - ESP_LOGI(TAG, "%d bytes enqueued to send on LoRa", payload.getSize()); -#endif - + // enqueue message in device's send queues + lora_enqueuedata(port, &SendBuffer); spi_enqueuedata(port, &SendBuffer); // clear counter if not in cumulative counter mode if ((port == COUNTERPORT) && (cfg.countermode != 1)) { reset_counters(); // clear macs container and reset all counters - get_salt(); // get new salt for salting hashes + get_salt(); // get new salt for salting hashes ESP_LOGI(TAG, "Counter cleared"); } } // SendData @@ -59,9 +54,6 @@ void sendPayload() { } // sendpayload() void flushQueues() { -#ifdef HAS_LORA - xQueueReset(LoraSendQueue); -#endif - + lora_queuereset(); spi_queuereset(); } \ No newline at end of file diff --git a/src/spislave.cpp b/src/spislave.cpp index 7cd8d7292..c6268d815 100644 --- a/src/spislave.cpp +++ b/src/spislave.cpp @@ -131,7 +131,7 @@ void spi_enqueuedata(uint8_t messageType, MessageBuffer_t *message) { BaseType_t ret = xQueueSendToBack(SPISendQueue, (void *)message, (TickType_t)0); if (ret == pdTRUE) { - ESP_LOGI(TAG, "%d bytes enqueued for SPI consumption", + ESP_LOGI(TAG, "%d bytes enqueued for SPI interface", message->MessageSize); } else { ESP_LOGW(TAG, "SPI sendqueue is full"); From 8e3805a63b98fa52d7039df677deb8ae8797d095 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sat, 3 Nov 2018 20:44:54 +0100 Subject: [PATCH 08/36] SPI slave integration (experimental) --- include/lorawan.h | 1 + include/main.h | 2 ++ include/senddata.h | 3 +++ include/spislave.h | 1 + platformio.ini | 2 +- src/hal/ebox.h | 1 - src/hal/eboxtube.h | 1 - src/hal/fipy.h | 1 - src/hal/heltec.h | 1 - src/hal/heltecv2.h | 1 - src/hal/lolin32lite.h | 2 -- src/hal/lolin32litelora.h | 1 - src/hal/lolin32lora.h | 1 - src/hal/lopy.h | 1 - src/hal/octopus32.h | 1 - src/hal/ttgobeam.h | 1 - src/hal/ttgov1.h | 1 - src/hal/ttgov2.h | 1 - src/hal/ttgov21new.h | 1 - src/hal/ttgov21old.h | 1 - src/lorawan.cpp | 4 ++-- src/main.cpp | 1 - src/senddata.cpp | 3 +-- 23 files changed, 11 insertions(+), 22 deletions(-) diff --git a/include/lorawan.h b/include/lorawan.h index 94957c252..551597b5b 100644 --- a/include/lorawan.h +++ b/include/lorawan.h @@ -29,6 +29,7 @@ void lora_send(osjob_t *job); void lora_enqueuedata(uint8_t messageType, MessageBuffer_t *message); void lora_queuereset(void); void lora_housekeeping(void); + esp_err_t lora_stack_init(); #endif \ No newline at end of file diff --git a/include/main.h b/include/main.h index f7284720e..6bc1b3774 100644 --- a/include/main.h +++ b/include/main.h @@ -13,5 +13,7 @@ #include "ota.h" #include "irqhandler.h" #include "led.h" +#include "spislave.h" +#include "lorawan.h" #endif \ No newline at end of file diff --git a/include/senddata.h b/include/senddata.h index 078196092..b0e470dc5 100644 --- a/include/senddata.h +++ b/include/senddata.h @@ -1,6 +1,9 @@ #ifndef _SENDDATA_H #define _SENDDATA_H +#include "spislave.h" +#include "lorawan.h" + void SendData(uint8_t port); void sendPayload(void); void checkSendQueues(void); diff --git a/include/spislave.h b/include/spislave.h index 526203b95..cb342f76c 100644 --- a/include/spislave.h +++ b/include/spislave.h @@ -25,6 +25,7 @@ licenses. Refer to LICENSE.txt file in repository for more details. #define _SPISLAVE_H #include "globals.h" +#include "spislave.h" esp_err_t spi_init(); diff --git a/platformio.ini b/platformio.ini index 8d08dbb2c..ccdc695b4 100644 --- a/platformio.ini +++ b/platformio.ini @@ -29,7 +29,7 @@ description = Paxcounter is a proof-of-concept ESP32 device for metering passeng [common] ; for release_version use max. 10 chars total, use any decimal format like "a.b.c" -release_version = 1.6.54 +release_version = 1.6.6 ; DEBUG LEVEL: For production run set to 0, otherwise device will leak RAM while running! ; 0=None, 1=Error, 2=Warn, 3=Info, 4=Debug, 5=Verbose debug_level = 0 diff --git a/src/hal/ebox.h b/src/hal/ebox.h index 1f6fe3ad2..201d81a7f 100644 --- a/src/hal/ebox.h +++ b/src/hal/ebox.h @@ -6,7 +6,6 @@ // Hardware related definitions for ebox ESP32-bit with external connected RFM95 LoRa #define HAS_LORA 1 // comment out if device shall not send data via LoRa -#define HAS_SPI 1 // comment out if device shall not send data via SPI #define CFG_sx1276_radio 1 #define HAS_LED (23) // blue LED on board diff --git a/src/hal/eboxtube.h b/src/hal/eboxtube.h index 858b7b16a..35e1c6493 100644 --- a/src/hal/eboxtube.h +++ b/src/hal/eboxtube.h @@ -6,7 +6,6 @@ // Hardware related definitions for ebox ESP32-bit with external connected RFM95 LoRa #define HAS_LORA 1 // comment out if device shall not send data via LoRa -#define HAS_SPI 1 // comment out if device shall not send data via SPI #define CFG_sx1276_radio 1 #define HAS_LED (22) // Green LED on board diff --git a/src/hal/fipy.h b/src/hal/fipy.h index 173c1bee1..fd2341d3b 100644 --- a/src/hal/fipy.h +++ b/src/hal/fipy.h @@ -6,7 +6,6 @@ // Hardware related definitions for Pycom FiPy Board #define HAS_LORA 1 // comment out if device shall not send data via LoRa -#define HAS_SPI 1 // comment out if device shall not send data via SPI #define CFG_sx1272_radio 1 #define HAS_LED NOT_A_PIN // FiPy has no on board LED, so we use RGB LED diff --git a/src/hal/heltec.h b/src/hal/heltec.h index e33f1e34d..82942dbbb 100644 --- a/src/hal/heltec.h +++ b/src/hal/heltec.h @@ -6,7 +6,6 @@ // Hardware related definitions for Heltec LoRa-32 Board #define HAS_LORA 1 // comment out if device shall not send data via LoRa -#define HAS_SPI 1 // comment out if device shall not send data via SPI #define CFG_sx1276_radio 1 #define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C // OLED-Display on board diff --git a/src/hal/heltecv2.h b/src/hal/heltecv2.h index 6d48f05f0..6b8f83d67 100644 --- a/src/hal/heltecv2.h +++ b/src/hal/heltecv2.h @@ -6,7 +6,6 @@ // Hardware related definitions for Heltec V2 LoRa-32 Board #define HAS_LORA 1 // comment out if device shall not send data via LoRa -#define HAS_SPI 1 // comment out if device shall not send data via SPI #define CFG_sx1276_radio 1 #define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C // OLED-Display on board diff --git a/src/hal/lolin32lite.h b/src/hal/lolin32lite.h index 9e9f8551c..f916bc77b 100644 --- a/src/hal/lolin32lite.h +++ b/src/hal/lolin32lite.h @@ -10,6 +10,4 @@ #define HAS_LED 22 // on board LED on GPIO22 #define LED_ACTIVE_LOW 1 // Onboard LED is active when pin is LOW -#define HAS_SPI 1 // comment out if device shall not send data via SPI - #endif \ No newline at end of file diff --git a/src/hal/lolin32litelora.h b/src/hal/lolin32litelora.h index cdb925f93..55b7e10ee 100644 --- a/src/hal/lolin32litelora.h +++ b/src/hal/lolin32litelora.h @@ -18,7 +18,6 @@ #define BUTTON_PULLUP 1 // Button need pullup instead of default pulldown #define HAS_LORA 1 // comment out if device shall not send data via LoRa -#define HAS_SPI 1 // comment out if device shall not send data via SPI #define CFG_sx1276_radio 1 // RFM95 module // Pins for LORA chip SPI interface, reset line and interrupt lines diff --git a/src/hal/lolin32lora.h b/src/hal/lolin32lora.h index 9d2d5af67..62d184125 100644 --- a/src/hal/lolin32lora.h +++ b/src/hal/lolin32lora.h @@ -19,7 +19,6 @@ #define BUTTON_PULLUP 1 // Button need pullup instead of default pulldown #define HAS_LORA 1 // comment out if device shall not send data via LoRa -#define HAS_SPI 1 // comment out if device shall not send data via SPI #define CFG_sx1276_radio 1 // RFM95 module // Pins for LORA chip SPI interface, reset line and interrupt lines diff --git a/src/hal/lopy.h b/src/hal/lopy.h index bf759ec87..1f061d39e 100644 --- a/src/hal/lopy.h +++ b/src/hal/lopy.h @@ -6,7 +6,6 @@ // Hardware related definitions for Pycom LoPy Board (NOT LoPy4) #define HAS_LORA 1 // comment out if device shall not send data via LoRa -#define HAS_SPI 1 // comment out if device shall not send data via SPI #define CFG_sx1272_radio 1 #define HAS_LED NOT_A_PIN // LoPy4 has no on board mono LED, we use on board RGB LED #define HAS_RGB_LED (0) // WS2812B RGB LED on GPIO0 diff --git a/src/hal/octopus32.h b/src/hal/octopus32.h index 5bf96f315..3ab6b5254 100644 --- a/src/hal/octopus32.h +++ b/src/hal/octopus32.h @@ -17,7 +17,6 @@ //#define BUTTON_PULLUP 1 // Button need pullup instead of default pulldown #define HAS_LORA 1 // comment out if device shall not send data via LoRa -#define HAS_SPI 1 // comment out if device shall not send data via SPI #define CFG_sx1276_radio 1 // RFM95 module // Pins for LORA chip SPI interface, reset line and interrupt lines diff --git a/src/hal/ttgobeam.h b/src/hal/ttgobeam.h index 3924d4697..46411eb03 100644 --- a/src/hal/ttgobeam.h +++ b/src/hal/ttgobeam.h @@ -6,7 +6,6 @@ // Hardware related definitions for TTGO T-Beam board #define HAS_LORA 1 // comment out if device shall not send data via LoRa -#define HAS_SPI 1 // comment out if device shall not send data via SPI #define CFG_sx1276_radio 1 // HPD13A LoRa SoC #define BOARD_HAS_PSRAM // use extra 4MB external RAM diff --git a/src/hal/ttgov1.h b/src/hal/ttgov1.h index d90adef39..d9bcd8474 100644 --- a/src/hal/ttgov1.h +++ b/src/hal/ttgov1.h @@ -6,7 +6,6 @@ // Hardware related definitions for TTGOv1 board #define HAS_LORA 1 // comment out if device shall not send data via LoRa -#define HAS_SPI 1 // comment out if device shall not send data via SPI #define CFG_sx1276_radio 1 #define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C // OLED-Display on board diff --git a/src/hal/ttgov2.h b/src/hal/ttgov2.h index 62fc2493a..afe6c3e6c 100644 --- a/src/hal/ttgov2.h +++ b/src/hal/ttgov2.h @@ -6,7 +6,6 @@ // Hardware related definitions for TTGO V2 Board #define HAS_LORA 1 // comment out if device shall not send data via LoRa -#define HAS_SPI 1 // comment out if device shall not send data via SPI #define CFG_sx1276_radio 1 // HPD13A LoRa SoC #define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C diff --git a/src/hal/ttgov21new.h b/src/hal/ttgov21new.h index 2345ea19b..6ef93285b 100644 --- a/src/hal/ttgov21new.h +++ b/src/hal/ttgov21new.h @@ -9,7 +9,6 @@ */ #define HAS_LORA 1 // comment out if device shall not send data via LoRa -#define HAS_SPI 1 // comment out if device shall not send data via SPI #define CFG_sx1276_radio 1 // HPD13A LoRa SoC #define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C diff --git a/src/hal/ttgov21old.h b/src/hal/ttgov21old.h index 76c855a36..523a967d7 100644 --- a/src/hal/ttgov21old.h +++ b/src/hal/ttgov21old.h @@ -10,7 +10,6 @@ */ #define HAS_LORA 1 // comment out if device shall not send data via LoRa -#define HAS_SPI 1 // comment out if device shall not send data via SPI #define CFG_sx1276_radio 1 // HPD13A LoRa SoC #define HAS_LED NOT_A_PIN // no usable LED on board #define DISABLE_BROWNOUT 1 // comment out if you want to keep brownout feature diff --git a/src/lorawan.cpp b/src/lorawan.cpp index ae0f08c05..9974663d7 100644 --- a/src/lorawan.cpp +++ b/src/lorawan.cpp @@ -1,11 +1,11 @@ -#ifdef HAS_LORA - // Basic Config #include "lorawan.h" // Local logging Tag static const char TAG[] = "lora"; +#ifdef HAS_LORA + osjob_t sendjob; QueueHandle_t LoraSendQueue; diff --git a/src/main.cpp b/src/main.cpp index 46bf6ddf4..96ba79ea3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -48,7 +48,6 @@ ESP32 hardware timers // Basic Config #include "main.h" -#include "spislave.h" configData_t cfg; // struct holds current device configuration char display_line6[16], display_line7[16]; // display buffers diff --git a/src/senddata.cpp b/src/senddata.cpp index b8edda34a..782156436 100644 --- a/src/senddata.cpp +++ b/src/senddata.cpp @@ -1,6 +1,5 @@ // Basic Config -#include "globals.h" -#include "spislave.h" +#include "senddata.h" // put data to send in RTos Queues used for transmit over channels Lora and SPI void SendData(uint8_t port) { From 8373f9107b9109177c694d95533c9879e03cc51c Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sat, 3 Nov 2018 20:49:45 +0100 Subject: [PATCH 09/36] spislave.h corrected --- include/spislave.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/spislave.h b/include/spislave.h index cb342f76c..526203b95 100644 --- a/include/spislave.h +++ b/include/spislave.h @@ -25,7 +25,6 @@ licenses. Refer to LICENSE.txt file in repository for more details. #define _SPISLAVE_H #include "globals.h" -#include "spislave.h" esp_err_t spi_init(); From 02b2bf2d4f75558623e0c8783e27cec8bb30baea Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sun, 4 Nov 2018 11:55:25 +0100 Subject: [PATCH 10/36] spislave.cpp: processing of rx data added --- platformio.ini | 4 ++-- src/hal/lopy.h | 6 +++--- src/lorawan.cpp | 24 +++++++++++++++--------- src/spislave.cpp | 22 +++++++++++++++++----- 4 files changed, 37 insertions(+), 19 deletions(-) diff --git a/platformio.ini b/platformio.ini index ccdc695b4..23291c06d 100644 --- a/platformio.ini +++ b/platformio.ini @@ -6,7 +6,7 @@ ; ---> SELECT TARGET PLATFORM HERE! <--- [platformio] -env_default = generic +;env_default = generic ;env_default = ebox ;env_default = eboxtube ;env_default = heltec @@ -17,7 +17,7 @@ env_default = generic ;env_default = ttgov21new ;env_default = ttgobeam ;env_default = lopy -;env_default = lopy4 +env_default = lopy4 ;env_default = fipy ;env_default = lolin32litelora ;env_default = lolin32lora diff --git a/src/hal/lopy.h b/src/hal/lopy.h index 1f061d39e..feaf90245 100644 --- a/src/hal/lopy.h +++ b/src/hal/lopy.h @@ -25,9 +25,9 @@ #define WIFI_ANTENNA 0 // 0 = internal, 1 = external // uncomment this only if your LoPy runs on a PYTRACK BOARD -//#define HAS_GPS 1 -//#define GPS_I2C GPIO_NUM_25, GPIO_NUM_26 // SDA (P22), SCL (P21) -//#define GPS_ADDR 0x10 +#define HAS_GPS 1 +#define GPS_I2C GPIO_NUM_25, GPIO_NUM_26 // SDA (P22), SCL (P21) +#define GPS_ADDR 0x10 // uncomment this only if your LoPy runs on a EXPANSION BOARD //#define HAS_LED (12) // use if LoPy is on Expansion Board, this has a user LED diff --git a/src/lorawan.cpp b/src/lorawan.cpp index 9974663d7..b9c496239 100644 --- a/src/lorawan.cpp +++ b/src/lorawan.cpp @@ -329,9 +329,13 @@ void lora_send(osjob_t *job) { } else { if (xQueueReceive(LoraSendQueue, &SendBuffer, (TickType_t)0) == pdTRUE) { // SendBuffer gets struct MessageBuffer with next payload from queue - LMIC_setTxData2(SendBuffer.MessagePort, SendBuffer.Message, - SendBuffer.MessageSize, (cfg.countermode & 0x02)); - ESP_LOGI(TAG, "%d bytes sent to LoRa", SendBuffer.MessageSize); + if (LMIC_setTxData2(SendBuffer.MessagePort, SendBuffer.Message, + SendBuffer.MessageSize, (cfg.countermode & 0x02))) { + ESP_LOGI(TAG, "%d bytes sent to LoRa", SendBuffer.MessageSize); + } else { + ESP_LOGE(TAG, "coult not send %d bytes to LoRa", + SendBuffer.MessageSize); + } // sprintf(display_line7, "PACKET QUEUED"); } } @@ -341,6 +345,8 @@ void lora_send(osjob_t *job) { lora_send); } +#endif // HAS_LORA + esp_err_t lora_stack_init() { #ifndef HAS_LORA return ESP_OK; // continue main program @@ -375,21 +381,21 @@ esp_err_t lora_stack_init() { LMIC_selectSubBand(1); #endif - LMIC_startJoining(); // start joining - return ESP_OK; // continue main program + if (!LMIC_startJoining()) { // start joining + ESP_LOGI(TAG, "Already joined"); + } + + return ESP_OK; // continue main program #endif } -#endif // HAS_LORA - void lora_enqueuedata(uint8_t messageType, MessageBuffer_t *message) { // enqueue message in LORA send queue #ifdef HAS_LORA BaseType_t ret = xQueueSendToBack(LoraSendQueue, (void *)message, (TickType_t)0); if (ret == pdTRUE) { - ESP_LOGI(TAG, "%d bytes enqueued for LORA interface", - message->MessageSize); + ESP_LOGI(TAG, "%d bytes enqueued for LORA interface", message->MessageSize); } else { ESP_LOGW(TAG, "LORA sendqueue is full"); } diff --git a/src/spislave.cpp b/src/spislave.cpp index c6268d815..7657a9248 100644 --- a/src/spislave.cpp +++ b/src/spislave.cpp @@ -48,31 +48,37 @@ void spi_slave_task(void *param) { MessageBuffer_t msg; size_t transaction_size; + // clear rx + tx buffers memset(txbuf, 0, sizeof(txbuf)); memset(rxbuf, 0, sizeof(rxbuf)); + // wait until data to send arrivey if (xQueueReceive(SPISendQueue, &msg, portMAX_DELAY) != pdTRUE) { ESP_LOGE(TAG, "Premature return from xQueueReceive() with no data!"); continue; } + // fill tx buffer with data to send from queue and calculate crc16 cheksum uint8_t *messageType = txbuf + 2; *messageType = msg.MessagePort; uint8_t *messageSize = txbuf + 3; *messageSize = msg.MessageSize; memcpy(txbuf + HEADER_SIZE, &msg.Message, msg.MessageSize); + // calculate crc16 checksum, not used yet + // uint16_t *crc = (uint16_t *)txbuf; + //*crc = crc16_be(0, messageType, msg.MessageSize + HEADER_SIZE - 2); + // set length for spi slave driver transaction_size = HEADER_SIZE + msg.MessageSize; transaction_size += (4 - transaction_size % 4); - uint16_t *crc = (uint16_t *)txbuf; - *crc = crc16_be(0, messageType, msg.MessageSize + HEADER_SIZE - 2); - + // prepare spi transaction spi_slave_transaction_t spi_transaction = {0}; spi_transaction.length = transaction_size * 8; spi_transaction.tx_buffer = txbuf; spi_transaction.rx_buffer = rxbuf; + // wait until spi master clocks out the data, and read results in rx buffer ESP_LOGI(TAG, "Prepared SPI transaction for %zu bytes", transaction_size); ESP_LOG_BUFFER_HEXDUMP(TAG, txbuf, transaction_size, ESP_LOG_DEBUG); esp_err_t ret = @@ -80,6 +86,11 @@ void spi_slave_task(void *param) { ESP_LOG_BUFFER_HEXDUMP(TAG, rxbuf, transaction_size, ESP_LOG_DEBUG); ESP_LOGI(TAG, "Transaction finished with size %zu bits", spi_transaction.trans_len); + + // 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); + }; } } @@ -111,6 +122,8 @@ esp_err_t spi_init() { .post_setup_cb = NULL, .post_trans_cb = NULL}; + // Enable pull-ups on SPI lines so we don't detect rogue pulses when no master + // is connected gpio_set_pull_mode(SPI_MOSI, GPIO_PULLUP_ONLY); gpio_set_pull_mode(SPI_SCLK, GPIO_PULLUP_ONLY); gpio_set_pull_mode(SPI_CS, GPIO_PULLUP_ONLY); @@ -131,8 +144,7 @@ void spi_enqueuedata(uint8_t messageType, MessageBuffer_t *message) { BaseType_t ret = xQueueSendToBack(SPISendQueue, (void *)message, (TickType_t)0); if (ret == pdTRUE) { - ESP_LOGI(TAG, "%d bytes enqueued for SPI interface", - message->MessageSize); + ESP_LOGI(TAG, "%d bytes enqueued for SPI interface", message->MessageSize); } else { ESP_LOGW(TAG, "SPI sendqueue is full"); } From e8afc10a93b0e6298c904898005142339a690ea7 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sun, 4 Nov 2018 12:25:50 +0100 Subject: [PATCH 11/36] lopy4.h sanitized --- src/hal/lopy4.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/hal/lopy4.h b/src/hal/lopy4.h index 6b93baad6..e98408b12 100644 --- a/src/hal/lopy4.h +++ b/src/hal/lopy4.h @@ -6,12 +6,13 @@ // Hardware related definitions for Pycom LoPy4 Board #define HAS_LORA 1 // comment out if device shall not send data via LoRa + #define HAS_SPI 1 // comment out if device shall not send data via SPI -// pin definitions for SPI slave interface -#define SPI_MOSI GPIO_NUM_22 -#define SPI_MISO GPIO_NUM_33 -#define SPI_SCLK GPIO_NUM_26 -#define SPI_CS GPIO_NUM_36 +// pin definitions for local wired SPI slave interface +#define SPI_MOSI (22) +#define SPI_MISO (33) +#define SPI_SCLK (26) +#define SPI_CS (36) #define CFG_sx1276_radio 1 //#define HAS_LED NOT_A_PIN // LoPy4 has no on board mono LED, we use on board RGB LED From 577cdc949726660048b638f1c39a7199785d85c1 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sun, 4 Nov 2018 13:22:03 +0100 Subject: [PATCH 12/36] lolin32lite.h: LED pin corrected --- src/hal/lolin32lite.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hal/lolin32lite.h b/src/hal/lolin32lite.h index f916bc77b..f353ee1af 100644 --- a/src/hal/lolin32lite.h +++ b/src/hal/lolin32lite.h @@ -7,7 +7,7 @@ #define CFG_sx1272_radio 1 // dummy -#define HAS_LED 22 // on board LED on GPIO22 +#define HAS_LED (5) // on board LED on GPIO5 #define LED_ACTIVE_LOW 1 // Onboard LED is active when pin is LOW #endif \ No newline at end of file From 7ae82d18816b7498666ebd299eea71cf665869bd Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sun, 4 Nov 2018 13:58:35 +0100 Subject: [PATCH 13/36] spislave.cpp: small fixes --- src/hal/generic.h | 2 +- src/hal/lopy4.h | 8 ++++---- src/spislave.cpp | 11 ++++++++--- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/hal/generic.h b/src/hal/generic.h index a8a5555d0..6f1e42301 100644 --- a/src/hal/generic.h +++ b/src/hal/generic.h @@ -11,7 +11,7 @@ #define SPI_MOSI GPIO_NUM_23 #define SPI_MISO GPIO_NUM_19 #define SPI_SCLK GPIO_NUM_18 -#define SPI_CS GPIO_NUM_5 +#define SPI_CS GPIO_NUM_5 #define CFG_sx1276_radio 1 // select LoRa chip //#define CFG_sx1272_radio 1 // select LoRa chip diff --git a/src/hal/lopy4.h b/src/hal/lopy4.h index e98408b12..5e68c78cc 100644 --- a/src/hal/lopy4.h +++ b/src/hal/lopy4.h @@ -9,10 +9,10 @@ #define HAS_SPI 1 // comment out if device shall not send data via SPI // pin definitions for local wired SPI slave interface -#define SPI_MOSI (22) -#define SPI_MISO (33) -#define SPI_SCLK (26) -#define SPI_CS (36) +#define SPI_MOSI GPIO_NUM_22 +#define SPI_MISO GPIO_NUM_33 +#define SPI_SCLK GPIO_NUM_26 +#define SPI_CS GPIO_NUM_36 #define CFG_sx1276_radio 1 //#define HAS_LED NOT_A_PIN // LoPy4 has no on board mono LED, we use on board RGB LED diff --git a/src/spislave.cpp b/src/spislave.cpp index 7657a9248..67d544ebc 100644 --- a/src/spislave.cpp +++ b/src/spislave.cpp @@ -128,11 +128,16 @@ esp_err_t spi_init() { gpio_set_pull_mode(SPI_SCLK, GPIO_PULLUP_ONLY); gpio_set_pull_mode(SPI_CS, GPIO_PULLUP_ONLY); - ESP_LOGI(TAG, "Starting SPIloop..."); - xTaskCreate(spi_slave_task, "spiloop", 4096, (void *)NULL, 2, &spiTask); - esp_err_t ret = spi_slave_initialize(HSPI_HOST, &spi_bus_cfg, &spi_slv_cfg, 1); + + if (ret == ESP_OK) { + ESP_LOGI(TAG, "Starting SPIloop..."); + xTaskCreate(spi_slave_task, "spiloop", 4096, (void *)NULL, 2, &spiTask); + } else { + ESP_LOGE(TAG, "SPI interface initialization failed"); + } + return ret; #endif From 5d5531e3af911e946d84c1c01adf98dea8f14799 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sun, 4 Nov 2018 14:55:30 +0100 Subject: [PATCH 14/36] lorawan.cpp: bugfix logging --- src/lorawan.cpp | 6 +++--- src/spislave.cpp | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/lorawan.cpp b/src/lorawan.cpp index b9c496239..41d5f8847 100644 --- a/src/lorawan.cpp +++ b/src/lorawan.cpp @@ -329,11 +329,11 @@ void lora_send(osjob_t *job) { } else { if (xQueueReceive(LoraSendQueue, &SendBuffer, (TickType_t)0) == pdTRUE) { // SendBuffer gets struct MessageBuffer with next payload from queue - if (LMIC_setTxData2(SendBuffer.MessagePort, SendBuffer.Message, + if (!LMIC_setTxData2(SendBuffer.MessagePort, SendBuffer.Message, SendBuffer.MessageSize, (cfg.countermode & 0x02))) { - ESP_LOGI(TAG, "%d bytes sent to LoRa", SendBuffer.MessageSize); + ESP_LOGI(TAG, "%d byte(s) sent to LoRa", SendBuffer.MessageSize); } else { - ESP_LOGE(TAG, "coult not send %d bytes to LoRa", + ESP_LOGE(TAG, "could not send %d byte(s) to LoRa", SendBuffer.MessageSize); } // sprintf(display_line7, "PACKET QUEUED"); diff --git a/src/spislave.cpp b/src/spislave.cpp index 67d544ebc..6df563b15 100644 --- a/src/spislave.cpp +++ b/src/spislave.cpp @@ -79,7 +79,7 @@ void spi_slave_task(void *param) { spi_transaction.rx_buffer = rxbuf; // wait until spi master clocks out the data, and read results in rx buffer - ESP_LOGI(TAG, "Prepared SPI transaction for %zu bytes", transaction_size); + ESP_LOGI(TAG, "Prepared SPI transaction for %zu byte(s)", transaction_size); ESP_LOG_BUFFER_HEXDUMP(TAG, txbuf, transaction_size, ESP_LOG_DEBUG); esp_err_t ret = spi_slave_transmit(HSPI_HOST, &spi_transaction, portMAX_DELAY); @@ -149,7 +149,7 @@ void spi_enqueuedata(uint8_t messageType, MessageBuffer_t *message) { BaseType_t ret = xQueueSendToBack(SPISendQueue, (void *)message, (TickType_t)0); if (ret == pdTRUE) { - ESP_LOGI(TAG, "%d bytes enqueued for SPI interface", message->MessageSize); + ESP_LOGI(TAG, "%d byte(s) enqueued for SPI interface", message->MessageSize); } else { ESP_LOGW(TAG, "SPI sendqueue is full"); } From 5793b3c81133cd756e40cafc9137aa78bc5aa8c8 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sun, 4 Nov 2018 15:12:39 +0100 Subject: [PATCH 15/36] paxcounter.conf: reduced WIFI_MAX_TRY --- src/paxcounter.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/paxcounter.conf b/src/paxcounter.conf index e048043f4..e15ea9419 100644 --- a/src/paxcounter.conf +++ b/src/paxcounter.conf @@ -67,7 +67,7 @@ // OTA settings #define USE_OTA 1 // Comment out to disable OTA update -#define WIFI_MAX_TRY 20 // maximum number of wifi connect attempts for OTA update [default = 20] +#define WIFI_MAX_TRY 5 // maximum number of wifi connect attempts for OTA update [default = 20] #define FLASH_MAX_TRY 3 // maximum number of attempts for writing update binary to flash [default = 3] #define OTA_MIN_BATT 3700 // minimum battery level vor OTA [millivolt] From 3aa8a88d3a0a6bb9c2d4bdac0e227db52ead9576 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sun, 4 Nov 2018 19:25:11 +0100 Subject: [PATCH 16/36] ota.cpp restructured; .h file sanitization --- include/globals.h | 21 ++--- include/gpsread.h | 8 -- include/led.h | 2 - include/ota.h | 2 +- include/payload.h | 4 - include/rcommand.h | 1 + include/senddata.h | 1 + src/led.cpp | 6 +- src/ota.cpp | 190 ++++++++++++++++++++------------------------ src/paxcounter.conf | 5 +- src/payload.cpp | 29 ++++--- 11 files changed, 120 insertions(+), 149 deletions(-) diff --git a/include/globals.h b/include/globals.h index d946b2df9..f8ec8a130 100644 --- a/include/globals.h +++ b/include/globals.h @@ -38,6 +38,14 @@ typedef struct { uint8_t Message[PAYLOAD_BUFFER_SIZE]; } MessageBuffer_t; +typedef struct { + uint32_t latitude; + uint32_t longitude; + uint8_t satellites; + uint16_t hdop; + uint16_t altitude; +} gpsStatus_t; + // global variables extern configData_t cfg; // current device configuration extern char display_line6[], display_line7[]; // screen buffers @@ -52,16 +60,13 @@ extern std::array beacons; extern TaskHandle_t irqHandlerTask, wifiSwitchTask; +#include "led.h" +#include "payload.h" + #ifdef HAS_GPS #include "gpsread.h" #endif -#if (HAS_LED != NOT_A_PIN) || defined(HAS_RGB_LED) -#include "led.h" -#endif - -#include "payload.h" - #ifdef HAS_LORA #include "lorawan.h" #endif @@ -86,8 +91,4 @@ extern TaskHandle_t irqHandlerTask, wifiSwitchTask; #include "antenna.h" #endif -void reset_counters(void); -void blink_LED(uint16_t set_color, uint16_t set_blinkduration); -uint64_t uptime(); - #endif \ No newline at end of file diff --git a/include/gpsread.h b/include/gpsread.h index 6f5ed584f..484aa9fb4 100644 --- a/include/gpsread.h +++ b/include/gpsread.h @@ -8,14 +8,6 @@ #include #endif -typedef struct { - uint32_t latitude; - uint32_t longitude; - uint8_t satellites; - uint16_t hdop; - uint16_t altitude; -} gpsStatus_t; - extern TinyGPSPlus gps; // Make TinyGPS++ instance globally availabe extern gpsStatus_t gps_status; // Make struct for storing gps data globally available diff --git a/include/led.h b/include/led.h index 6527e8798..b39a65056 100644 --- a/include/led.h +++ b/include/led.h @@ -37,8 +37,6 @@ extern TaskHandle_t ledLoopTask; void rgb_set_color(uint16_t hue); void blink_LED(uint16_t set_color, uint16_t set_blinkduration); void ledLoop(void *parameter); -#if (HAS_LED != NOT_A_PIN) void switch_LED(uint8_t state); -#endif #endif \ No newline at end of file diff --git a/include/ota.h b/include/ota.h index 14f63eb0f..bcffb106c 100644 --- a/include/ota.h +++ b/include/ota.h @@ -11,7 +11,7 @@ #include #include -void do_ota_update(); +bool do_ota_update(); void start_ota_update(); int version_compare(const String v1, const String v2); void display(const uint8_t row, const std::string status, diff --git a/include/payload.h b/include/payload.h index 5973bdd90..57bb89641 100644 --- a/include/payload.h +++ b/include/payload.h @@ -38,12 +38,8 @@ class PayloadConvert { void addStatus(uint16_t voltage, uint64_t uptime, float cputemp, uint32_t mem, uint8_t reset1, uint8_t reset2); void addAlarm(int8_t rssi, uint8_t message); -#ifdef HAS_GPS void addGPS(gpsStatus_t value); -#endif -#ifdef HAS_BUTTON void addButton(uint8_t value); -#endif #if PAYLOAD_ENCODER == 1 // format plain diff --git a/include/rcommand.h b/include/rcommand.h index bde9a151d..806f911a8 100644 --- a/include/rcommand.h +++ b/include/rcommand.h @@ -2,6 +2,7 @@ #define _RCOMMAND_H #include "senddata.h" +#include "cyclic.h" #include "configmanager.h" #include "lorawan.h" #include "macsniff.h" diff --git a/include/senddata.h b/include/senddata.h index b0e470dc5..d2e2641df 100644 --- a/include/senddata.h +++ b/include/senddata.h @@ -3,6 +3,7 @@ #include "spislave.h" #include "lorawan.h" +#include "cyclic.h" void SendData(uint8_t port); void sendPayload(void); diff --git a/src/led.cpp b/src/led.cpp index 8e3b7ed88..c67f18699 100644 --- a/src/led.cpp +++ b/src/led.cpp @@ -87,9 +87,8 @@ void rgb_set_color(uint16_t hue) {} #endif -#if (HAS_LED != NOT_A_PIN) - void switch_LED(uint8_t state) { +#if (HAS_LED != NOT_A_PIN) if (state == LED_ON) { // switch LED on #ifdef LED_ACTIVE_LOW @@ -105,9 +104,8 @@ void switch_LED(uint8_t state) { digitalWrite(HAS_LED, LOW); #endif } -} - #endif +} #if (HAS_LED != NOT_A_PIN) || defined(HAS_RGB_LED) diff --git a/src/ota.cpp b/src/ota.cpp index 465838f5d..71f6b34ee 100644 --- a/src/ota.cpp +++ b/src/ota.cpp @@ -26,9 +26,6 @@ const BintrayClient bintray(BINTRAY_USER, BINTRAY_REPO, BINTRAY_PACKAGE); // Connection port (HTTPS) const int port = 443; -// Connection timeout -const uint32_t RESPONSE_TIMEOUT_MS = 5000; - // Variables to validate firmware content int volatile contentLength = 0; bool volatile isValidContentType = false; @@ -43,24 +40,17 @@ inline String getHeaderValue(String header, String headerName) { void start_ota_update() { -/* -// check battery status if we can before doing ota -#ifdef HAS_BATTERY_PROBE - if (!batt_sufficient()) { - ESP_LOGW(TAG, "Battery voltage %dmV too low for OTA", batt_voltage); - return; - } -#endif -*/ + /* + // check battery status if we can before doing ota + #ifdef HAS_BATTERY_PROBE + if (!batt_sufficient()) { + ESP_LOGW(TAG, "Battery voltage %dmV too low for OTA", batt_voltage); + return; + } + #endif + */ -// turn on LED -#if (HAS_LED != NOT_A_PIN) -#ifdef LED_ACTIVE_LOW - digitalWrite(HAS_LED, LOW); -#else - digitalWrite(HAS_LED, HIGH); -#endif -#endif + switch_LED(LED_ON); #ifdef HAS_DISPLAY u8x8.begin(); @@ -84,42 +74,45 @@ void start_ota_update() { WiFi.begin(WIFI_SSID, WIFI_PASS); - int i = WIFI_MAX_TRY; + int i = WIFI_MAX_TRY, j = OTA_MAX_TRY; while (i--) { ESP_LOGI(TAG, "Trying to connect to %s", WIFI_SSID); - if (WiFi.status() == WL_CONNECTED) - break; - vTaskDelay(5000 / portTICK_PERIOD_MS); - } - - if (i >= 0) { - ESP_LOGI(TAG, "Connected to %s", WIFI_SSID); - display(1, "OK", "WiFi connected"); - do_ota_update(); // gets and flashes new firmware - } else { - ESP_LOGI(TAG, "Could not connect to %s, rebooting.", WIFI_SSID); - display(1, " E", "no WiFi connect"); + if (WiFi.status() == WL_CONNECTED) { + // we now have wifi connection and try to do an OTA over wifi update + ESP_LOGI(TAG, "Connected to %s", WIFI_SSID); + display(1, "OK", "WiFi connected"); + // do a number of tries limited by OTA_MAX_TRY + while (j--) { + ESP_LOGI(TAG, + "Starting OTA update, attempt %u of %u. This will take some " + "time to complete...", + OTA_MAX_TRY - j, OTA_MAX_TRY); + if (do_ota_update()) + goto end; + } + } else { + vTaskDelay(5000 / portTICK_PERIOD_MS); + } } - display(5, "**", ""); // mark line rebooting + ESP_LOGI(TAG, "Could not connect to %s, rebooting.", WIFI_SSID); + display(1, " E", "no WiFi connect"); -// turn off LED -#if (HAS_LED != NOT_A_PIN) -#ifdef LED_ACTIVE_LOW - digitalWrite(HAS_LED, HIGH); -#else - digitalWrite(HAS_LED, LOW); -#endif -#endif +end: + switch_LED(LED_OFF); + display(5, "**", ""); // mark line rebooting vTaskDelay(5000 / portTICK_PERIOD_MS); ESP.restart(); } // start_ota_update -void do_ota_update() { +bool do_ota_update() { + char buf[17]; + bool redirect = true; + size_t written = 0; // Fetch the latest firmware version ESP_LOGI(TAG, "Checking latest firmware version on server..."); @@ -131,11 +124,11 @@ void do_ota_update() { TAG, "Could not load info about the latest firmware. Rebooting to runmode."); display(2, " E", "file not found"); - return; + return false; } else if (version_compare(latest, cfg.version) <= 0) { ESP_LOGI(TAG, "Current firmware is up to date. Rebooting to runmode."); display(2, "NO", "no update found"); - return; + return false; } ESP_LOGI(TAG, "New firmware version v%s available. Downloading...", latest.c_str()); @@ -146,7 +139,7 @@ void do_ota_update() { if (!firmwarePath.endsWith(".bin")) { ESP_LOGI(TAG, "Unsupported binary format, OTA update cancelled."); display(3, " E", "file type error"); - return; + return false; } String currentHost = bintray.getStorageHost(); @@ -158,10 +151,9 @@ void do_ota_update() { if (!client.connect(currentHost.c_str(), port)) { ESP_LOGI(TAG, "Cannot connect to %s", currentHost.c_str()); display(3, " E", "connection lost"); - return; + goto failure; } - bool redirect = true; while (redirect) { if (currentHost != prevHost) { client.stop(); @@ -170,7 +162,7 @@ void do_ota_update() { ESP_LOGI(TAG, "Redirect detected, but cannot connect to %s", currentHost.c_str()); display(3, " E", "server error"); - return; + goto failure; } } @@ -186,8 +178,7 @@ void do_ota_update() { if (millis() - timeout > RESPONSE_TIMEOUT_MS) { ESP_LOGI(TAG, "Client Timeout."); display(3, " E", "client timeout"); - client.stop(); - return; + goto failure; } } @@ -243,79 +234,66 @@ void do_ota_update() { } } } - } + } // while (redirect) display(3, "OK", ""); // line download // check whether we have everything for OTA update - if (contentLength && isValidContentType) { + if (!(contentLength && isValidContentType)) { + ESP_LOGI(TAG, + "There was no valid content in the response from the OTA server!"); + display(4, " E", "response error"); + goto failure; + } - size_t written = 0; + if (!Update.begin(contentLength)) { + ESP_LOGI(TAG, "There isn't enough space to start OTA update"); + display(4, " E", "disk full"); + goto failure; + } - if (Update.begin(contentLength)) { #ifdef HAS_DISPLAY - // register callback function for showing progress while streaming data - Update.onProgress(&show_progress); + // register callback function for showing progress while streaming data + Update.onProgress(&show_progress); #endif - int i = FLASH_MAX_TRY; - while ((i--) && (written != contentLength)) { - - ESP_LOGI(TAG, - "Starting OTA update, attempt %u of %u. This will take some " - "time to complete...", - FLASH_MAX_TRY - i, FLASH_MAX_TRY); - display(4, "**", "writing..."); - written = Update.writeStream(client); + display(4, "**", "writing..."); - if (written == contentLength) { - ESP_LOGI(TAG, "Written %u bytes successfully", written); - snprintf(buf, 17, "%ukB Done!", (uint16_t)(written / 1024)); - display(4, "OK", buf); - break; - } else { - ESP_LOGI(TAG, - "Written only %u of %u bytes, OTA update attempt cancelled.", - written, contentLength); - } - } - - if (Update.end()) { + written = Update.writeStream(client); - if (Update.isFinished()) { - ESP_LOGI( - TAG, - "OTA update completed. Rebooting to runmode with new version."); - client.stop(); - return; - } else { - ESP_LOGI(TAG, "Something went wrong! OTA update hasn't been finished " - "properly."); - } - } else { - ESP_LOGI(TAG, "An error occurred. Error #: %d", Update.getError()); - snprintf(buf, 17, "Error #: %d", Update.getError()); - display(4, " E", buf); - } + if (written == contentLength) { + ESP_LOGI(TAG, "Written %u bytes successfully", written); + snprintf(buf, 17, "%ukB Done!", (uint16_t)(written / 1024)); + display(4, "OK", buf); + } else { + ESP_LOGI(TAG, "Written only %u of %u bytes, OTA update attempt cancelled.", + written, contentLength); + } - } else { - ESP_LOGI(TAG, "There isn't enough space to start OTA update"); - display(4, " E", "disk full"); - client.flush(); - } + if (Update.end()) { + goto finished; } else { - ESP_LOGI(TAG, - "There was no valid content in the response from the OTA server!"); - display(4, " E", "response error"); - client.flush(); + ESP_LOGI(TAG, "An error occurred. Error #: %d", Update.getError()); + snprintf(buf, 17, "Error #: %d", Update.getError()); + display(4, " E", buf); + goto failure; } + +finished: + client.stop(); + ESP_LOGI(TAG, "OTA update completed. Rebooting to runmode with new version."); + return true; + +failure: + client.stop(); ESP_LOGI(TAG, "OTA update failed. Rebooting to runmode with current version."); - client.stop(); + return false; + } // do_ota_update void display(const uint8_t row, const std::string status, - const std::string msg) { + const std::string msg) { #ifdef HAS_DISPLAY u8x8.setCursor(14, row); u8x8.print((status.substr(0, 2)).c_str()); @@ -329,7 +307,7 @@ void display(const uint8_t row, const std::string status, #ifdef HAS_DISPLAY // callback function to show download progress while streaming data -void show_progress (unsigned long current, unsigned long size) { +void show_progress(unsigned long current, unsigned long size) { char buf[17]; snprintf(buf, 17, "%-9lu (%3lu%%)", current, current * 100 / size); display(4, "**", buf); diff --git a/src/paxcounter.conf b/src/paxcounter.conf index e15ea9419..1069b8be7 100644 --- a/src/paxcounter.conf +++ b/src/paxcounter.conf @@ -68,8 +68,9 @@ // OTA settings #define USE_OTA 1 // Comment out to disable OTA update #define WIFI_MAX_TRY 5 // maximum number of wifi connect attempts for OTA update [default = 20] -#define FLASH_MAX_TRY 3 // maximum number of attempts for writing update binary to flash [default = 3] -#define OTA_MIN_BATT 3700 // minimum battery level vor OTA [millivolt] +#define OTA_MAX_TRY 3 // maximum number of attempts for OTA download and write to flash [default = 3] +#define OTA_MIN_BATT 3700 // minimum battery level for OTA [millivolt] +#define RESPONSE_TIMEOUT_MS 30000 // firmware binary server connection timeout [milliseconds] // LMIC settings // moved to src/lmic_config.h \ No newline at end of file diff --git a/src/payload.cpp b/src/payload.cpp index a1d6e5807..ba7e2f06e 100644 --- a/src/payload.cpp +++ b/src/payload.cpp @@ -75,8 +75,8 @@ void PayloadConvert::addStatus(uint16_t voltage, uint64_t uptime, float cputemp, buffer[cursor++] = (byte)(reset2); } -#ifdef HAS_GPS void PayloadConvert::addGPS(gpsStatus_t value) { +#ifdef HAS_GPS buffer[cursor++] = (byte)((value.latitude & 0xFF000000) >> 24); buffer[cursor++] = (byte)((value.latitude & 0x00FF0000) >> 16); buffer[cursor++] = (byte)((value.latitude & 0x0000FF00) >> 8); @@ -90,14 +90,17 @@ void PayloadConvert::addGPS(gpsStatus_t value) { buffer[cursor++] = lowByte(value.hdop); buffer[cursor++] = highByte(value.altitude); buffer[cursor++] = lowByte(value.altitude); -} #endif +} +void PayloadConvert::addButton(uint8_t value) { #ifdef HAS_BUTTON -void PayloadConvert::addButton(uint8_t value) { buffer[cursor++] = value; } + buffer[cursor++] = value; #endif +} -/* ---------------- packed format with LoRa serialization Encoder ---------- */ +/* ---------------- packed format with LoRa serialization Encoder ---------- + */ // derived from // https://github.com/thesolarnomad/lora-serialization/blob/master/src/LoraEncoder.cpp @@ -138,18 +141,20 @@ void PayloadConvert::addStatus(uint16_t voltage, uint64_t uptime, float cputemp, writeUint8(reset2); } -#ifdef HAS_GPS void PayloadConvert::addGPS(gpsStatus_t value) { +#ifdef HAS_GPS writeLatLng(value.latitude, value.longitude); writeUint8(value.satellites); writeUint16(value.hdop); writeUint16(value.altitude); -} #endif +} +void PayloadConvert::addButton(uint8_t value) { #ifdef HAS_BUTTON -void PayloadConvert::addButton(uint8_t value) { writeUint8(value); } + writeUint8(value); #endif +} void PayloadConvert::intToBytes(uint8_t pos, int32_t i, uint8_t byteSize) { for (uint8_t x = 0; x < byteSize; x++) { @@ -162,7 +167,7 @@ void PayloadConvert::writeUptime(uint64_t uptime) { intToBytes(cursor, uptime, 8); } -void PayloadConvert::writeVersion(char * version) { +void PayloadConvert::writeVersion(char *version) { memcpy(buffer + cursor, version, 10); cursor += 10; } @@ -273,8 +278,8 @@ void PayloadConvert::addStatus(uint16_t voltage, uint64_t uptime, float celsius, buffer[cursor++] = lowByte(temp); } -#ifdef HAS_GPS void PayloadConvert::addGPS(gpsStatus_t value) { +#ifdef HAS_GPS int32_t lat = value.latitude / 100; int32_t lon = value.longitude / 100; int32_t alt = value.altitude * 100; @@ -291,18 +296,18 @@ void PayloadConvert::addGPS(gpsStatus_t value) { buffer[cursor++] = (byte)((alt & 0xFF0000) >> 16); buffer[cursor++] = (byte)((alt & 0x00FF00) >> 8); buffer[cursor++] = (byte)((alt & 0x0000FF)); -} #endif +} -#ifdef HAS_BUTTON void PayloadConvert::addButton(uint8_t value) { +#ifdef HAS_BUTTON #if (PAYLOAD_ENCODER == 3) buffer[cursor++] = LPP_BUTTON_CHANNEL; #endif buffer[cursor++] = LPP_DIGITAL_INPUT; buffer[cursor++] = value; -} #endif +} #else #error "No valid payload converter defined" From 26ea8621c2aa69c8ef925afa6351685c27f05fb2 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sun, 4 Nov 2018 19:54:09 +0100 Subject: [PATCH 17/36] ota.cpp: bugfix --- src/ota.cpp | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/ota.cpp b/src/ota.cpp index 71f6b34ee..0843c1cf2 100644 --- a/src/ota.cpp +++ b/src/ota.cpp @@ -75,6 +75,7 @@ void start_ota_update() { WiFi.begin(WIFI_SSID, WIFI_PASS); int i = WIFI_MAX_TRY, j = OTA_MAX_TRY; + bool ret = false; while (i--) { ESP_LOGI(TAG, "Trying to connect to %s", WIFI_SSID); @@ -82,26 +83,29 @@ void start_ota_update() { // we now have wifi connection and try to do an OTA over wifi update ESP_LOGI(TAG, "Connected to %s", WIFI_SSID); display(1, "OK", "WiFi connected"); - // do a number of tries limited by OTA_MAX_TRY - while (j--) { + // do a number of tries to update firmware limited by OTA_MAX_TRY + while ( j--) { ESP_LOGI(TAG, "Starting OTA update, attempt %u of %u. This will take some " "time to complete...", OTA_MAX_TRY - j, OTA_MAX_TRY); - if (do_ota_update()) - goto end; + ret = do_ota_update(); + if (ret) + goto end; // update successful } - } else { - vTaskDelay(5000 / portTICK_PERIOD_MS); + goto end; // update not successful } } - ESP_LOGI(TAG, "Could not connect to %s, rebooting.", WIFI_SSID); + // wifi did not connect + ESP_LOGI(TAG, "Could not connect to %s", WIFI_SSID); display(1, " E", "no WiFi connect"); + vTaskDelay(5000 / portTICK_PERIOD_MS); end: - switch_LED(LED_OFF); + ESP_LOGI(TAG, "Rebooting to runmode using %s firmware", + ret ? "new" : "current"); display(5, "**", ""); // mark line rebooting vTaskDelay(5000 / portTICK_PERIOD_MS); ESP.restart(); @@ -281,13 +285,12 @@ bool do_ota_update() { finished: client.stop(); - ESP_LOGI(TAG, "OTA update completed. Rebooting to runmode with new version."); + ESP_LOGI(TAG, "OTA update completed."); return true; failure: client.stop(); - ESP_LOGI(TAG, - "OTA update failed. Rebooting to runmode with current version."); + ESP_LOGI(TAG, "OTA update failed."); return false; } // do_ota_update From 3d93a44c96ac050186e8cdc90792eba467826189 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sun, 4 Nov 2018 20:30:03 +0100 Subject: [PATCH 18/36] further ota code sanitization (delete update.cpp/.h) --- include/ota.h | 2 +- include/update.h | 181 ------------------------ src/ota.cpp | 8 +- src/update.cpp | 354 ----------------------------------------------- 4 files changed, 6 insertions(+), 539 deletions(-) delete mode 100644 include/update.h delete mode 100644 src/update.cpp diff --git a/include/ota.h b/include/ota.h index bcffb106c..bcdb0410f 100644 --- a/include/ota.h +++ b/include/ota.h @@ -4,8 +4,8 @@ #ifdef USE_OTA #include "globals.h" -#include "update.h" #include "battery.h" +#include #include #include #include diff --git a/include/update.h b/include/update.h deleted file mode 100644 index 2bf4dc461..000000000 --- a/include/update.h +++ /dev/null @@ -1,181 +0,0 @@ -#ifndef ESP8266UPDATER_H -#define ESP8266UPDATER_H - -#include -#include -#include -#include "esp_partition.h" - -#define UPDATE_ERROR_OK (0) -#define UPDATE_ERROR_WRITE (1) -#define UPDATE_ERROR_ERASE (2) -#define UPDATE_ERROR_READ (3) -#define UPDATE_ERROR_SPACE (4) -#define UPDATE_ERROR_SIZE (5) -#define UPDATE_ERROR_STREAM (6) -#define UPDATE_ERROR_MD5 (7) -#define UPDATE_ERROR_MAGIC_BYTE (8) -#define UPDATE_ERROR_ACTIVATE (9) -#define UPDATE_ERROR_NO_PARTITION (10) -#define UPDATE_ERROR_BAD_ARGUMENT (11) -#define UPDATE_ERROR_ABORT (12) - -#define UPDATE_SIZE_UNKNOWN 0xFFFFFFFF - -#define U_FLASH 0 -#define U_SPIFFS 100 -#define U_AUTH 200 - -class UpdateClass { - public: - typedef std::function THandlerFunction_Progress; - - UpdateClass(); - - /* - This callback will be called when Update is receiving data - */ - UpdateClass& onProgress(THandlerFunction_Progress fn); - - /* - Call this to check the space needed for the update - Will return false if there is not enough space - */ - bool begin(size_t size=UPDATE_SIZE_UNKNOWN, int command = U_FLASH); - - /* - Writes a buffer to the flash and increments the address - Returns the amount written - */ - size_t write(uint8_t *data, size_t len); - - /* - Writes the remaining bytes from the Stream to the flash - Uses readBytes() and sets UPDATE_ERROR_STREAM on timeout - Returns the bytes written - Should be equal to the remaining bytes when called - Usable for slow streams like Serial - */ - size_t writeStream(Stream &data); - - /* - If all bytes are written - this call will write the config to eboot - and return true - If there is already an update running but is not finished and !evenIfRemainanig - or there is an error - this will clear everything and return false - the last error is available through getError() - evenIfRemaining is helpfull when you update without knowing the final size first - */ - bool end(bool evenIfRemaining = false); - - /* - Aborts the running update - */ - void abort(); - - /* - Prints the last error to an output stream - */ - void printError(Stream &out); - - /* - sets the expected MD5 for the firmware (hexString) - */ - bool setMD5(const char * expected_md5); - - /* - returns the MD5 String of the sucessfully ended firmware - */ - String md5String(void){ return _md5.toString(); } - - /* - populated the result with the md5 bytes of the sucessfully ended firmware - */ - void md5(uint8_t * result){ return _md5.getBytes(result); } - - //Helpers - uint8_t getError(){ return _error; } - void clearError(){ _error = UPDATE_ERROR_OK; } - bool hasError(){ return _error != UPDATE_ERROR_OK; } - bool isRunning(){ return _size > 0; } - bool isFinished(){ return _progress == _size; } - size_t size(){ return _size; } - size_t progress(){ return _progress; } - size_t remaining(){ return _size - _progress; } - - /* - Template to write from objects that expose - available() and read(uint8_t*, size_t) methods - faster than the writeStream method - writes only what is available - */ - template - size_t write(T &data){ - size_t written = 0; - if (hasError() || !isRunning()) - return 0; - - size_t available = data.available(); - while(available) { - if(_bufferLen + available > remaining()){ - available = remaining() - _bufferLen; - } - if(_bufferLen + available > 4096) { - size_t toBuff = 4096 - _bufferLen; - data.read(_buffer + _bufferLen, toBuff); - _bufferLen += toBuff; - if(!_writeBuffer()) - return written; - written += toBuff; - } else { - data.read(_buffer + _bufferLen, available); - _bufferLen += available; - written += available; - if(_bufferLen == remaining()) { - if(!_writeBuffer()) { - return written; - } - } - } - if(remaining() == 0) - return written; - available = data.available(); - } - return written; - } - - /* - check if there is a firmware on the other OTA partition that you can bootinto - */ - bool canRollBack(); - /* - set the other OTA partition as bootable (reboot to enable) - */ - bool rollBack(); - - private: - void _reset(); - void _abort(uint8_t err); - bool _writeBuffer(); - bool _verifyHeader(uint8_t data); - bool _verifyEnd(); - - - uint8_t _error; - uint8_t *_buffer; - size_t _bufferLen; - size_t _size; - THandlerFunction_Progress _progress_callback; - uint32_t _progress; - uint32_t _command; - const esp_partition_t* _partition; - - String _target_md5; - MD5Builder _md5; -}; - -extern UpdateClass Update; - -#endif diff --git a/src/ota.cpp b/src/ota.cpp index 0843c1cf2..b02c15bd8 100644 --- a/src/ota.cpp +++ b/src/ota.cpp @@ -84,7 +84,7 @@ void start_ota_update() { ESP_LOGI(TAG, "Connected to %s", WIFI_SSID); display(1, "OK", "WiFi connected"); // do a number of tries to update firmware limited by OTA_MAX_TRY - while ( j--) { + while (j--) { ESP_LOGI(TAG, "Starting OTA update, attempt %u of %u. This will take some " "time to complete...", @@ -92,8 +92,8 @@ void start_ota_update() { ret = do_ota_update(); if (ret) goto end; // update successful - } - goto end; // update not successful + } // update not successful + goto end; } } @@ -263,6 +263,8 @@ bool do_ota_update() { display(4, "**", "writing..."); + // set server connection timeout and open server connection + client.setTimeout(RESPONSE_TIMEOUT_MS); written = Update.writeStream(client); if (written == contentLength) { diff --git a/src/update.cpp b/src/update.cpp deleted file mode 100644 index a43a98099..000000000 --- a/src/update.cpp +++ /dev/null @@ -1,354 +0,0 @@ -/* - -this file copied from esp32-arduino library and patched, see PR -https://github.com/espressif/arduino-esp32/pull/1886 - -*/ - -#include "update.h" -#include "Arduino.h" -#include "esp_spi_flash.h" -#include "esp_ota_ops.h" -#include "esp_image_format.h" - -static const char * _err2str(uint8_t _error){ - if(_error == UPDATE_ERROR_OK){ - return ("No Error"); - } else if(_error == UPDATE_ERROR_WRITE){ - return ("Flash Write Failed"); - } else if(_error == UPDATE_ERROR_ERASE){ - return ("Flash Erase Failed"); - } else if(_error == UPDATE_ERROR_READ){ - return ("Flash Read Failed"); - } else if(_error == UPDATE_ERROR_SPACE){ - return ("Not Enough Space"); - } else if(_error == UPDATE_ERROR_SIZE){ - return ("Bad Size Given"); - } else if(_error == UPDATE_ERROR_STREAM){ - return ("Stream Read Timeout"); - } else if(_error == UPDATE_ERROR_MD5){ - return ("MD5 Check Failed"); - } else if(_error == UPDATE_ERROR_MAGIC_BYTE){ - return ("Wrong Magic Byte"); - } else if(_error == UPDATE_ERROR_ACTIVATE){ - return ("Could Not Activate The Firmware"); - } else if(_error == UPDATE_ERROR_NO_PARTITION){ - return ("Partition Could Not be Found"); - } else if(_error == UPDATE_ERROR_BAD_ARGUMENT){ - return ("Bad Argument"); - } else if(_error == UPDATE_ERROR_ABORT){ - return ("Aborted"); - } - return ("UNKNOWN"); -} - -static bool _partitionIsBootable(const esp_partition_t* partition){ - uint8_t buf[4]; - if(!partition){ - return false; - } - if(!ESP.flashRead(partition->address, (uint32_t*)buf, 4)) { - return false; - } - - if(buf[0] != ESP_IMAGE_HEADER_MAGIC) { - return false; - } - return true; -} - -static bool _enablePartition(const esp_partition_t* partition){ - uint8_t buf[4]; - if(!partition){ - return false; - } - if(!ESP.flashRead(partition->address, (uint32_t*)buf, 4)) { - return false; - } - buf[0] = ESP_IMAGE_HEADER_MAGIC; - - return ESP.flashWrite(partition->address, (uint32_t*)buf, 4); -} - -UpdateClass::UpdateClass() -: _error(0) -, _buffer(0) -, _bufferLen(0) -, _size(0) -, _progress_callback(NULL) -, _progress(0) -, _command(U_FLASH) -, _partition(NULL) -{ -} - -UpdateClass& UpdateClass::onProgress(THandlerFunction_Progress fn) { - _progress_callback = fn; - return *this; -} - -void UpdateClass::_reset() { - if (_buffer) - delete[] _buffer; - _buffer = 0; - _bufferLen = 0; - _progress = 0; - _size = 0; - _command = U_FLASH; -} - -bool UpdateClass::canRollBack(){ - if(_buffer){ //Update is running - return false; - } - const esp_partition_t* partition = esp_ota_get_next_update_partition(NULL); - return _partitionIsBootable(partition); -} - -bool UpdateClass::rollBack(){ - if(_buffer){ //Update is running - return false; - } - const esp_partition_t* partition = esp_ota_get_next_update_partition(NULL); - return _partitionIsBootable(partition) && !esp_ota_set_boot_partition(partition); -} - -bool UpdateClass::begin(size_t size, int command) { - if(_size > 0){ - log_w("already running"); - return false; - } - - _reset(); - _error = 0; - - if(size == 0) { - _error = UPDATE_ERROR_SIZE; - return false; - } - - if (command == U_FLASH) { - _partition = esp_ota_get_next_update_partition(NULL); - if(!_partition){ - _error = UPDATE_ERROR_NO_PARTITION; - return false; - } - log_d("OTA Partition: %s", _partition->label); - } - else if (command == U_SPIFFS) { - _partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_SPIFFS, NULL); - if(!_partition){ - _error = UPDATE_ERROR_NO_PARTITION; - return false; - } - } - else { - _error = UPDATE_ERROR_BAD_ARGUMENT; - log_e("bad command %u", command); - return false; - } - - if(size == UPDATE_SIZE_UNKNOWN){ - size = _partition->size; - } else if(size > _partition->size){ - _error = UPDATE_ERROR_SIZE; - log_e("too large %u > %u", size, _partition->size); - return false; - } - - //initialize - _buffer = (uint8_t*)malloc(SPI_FLASH_SEC_SIZE); - if(!_buffer){ - log_e("malloc failed"); - return false; - } - _size = size; - _command = command; - _md5.begin(); - return true; -} - -void UpdateClass::_abort(uint8_t err){ - _reset(); - _error = err; -} - -void UpdateClass::abort(){ - _abort(UPDATE_ERROR_ABORT); -} - -bool UpdateClass::_writeBuffer(){ - //first bytes of new firmware - if(!_progress && _command == U_FLASH){ - //check magic - if(_buffer[0] != ESP_IMAGE_HEADER_MAGIC){ - _abort(UPDATE_ERROR_MAGIC_BYTE); - return false; - } - //remove magic byte from the firmware now and write it upon success - //this ensures that partially written firmware will not be bootable - _buffer[0] = 0xFF; - } - if(!ESP.flashEraseSector((_partition->address + _progress)/SPI_FLASH_SEC_SIZE)){ - _abort(UPDATE_ERROR_ERASE); - return false; - } - if (!ESP.flashWrite(_partition->address + _progress, (uint32_t*)_buffer, _bufferLen)) { - _abort(UPDATE_ERROR_WRITE); - return false; - } - //restore magic or md5 will fail - if(!_progress && _command == U_FLASH){ - _buffer[0] = ESP_IMAGE_HEADER_MAGIC; - } - _md5.add(_buffer, _bufferLen); - _progress += _bufferLen; - _bufferLen = 0; - return true; -} - -bool UpdateClass::_verifyHeader(uint8_t data) { - if(_command == U_FLASH) { - if(data != ESP_IMAGE_HEADER_MAGIC) { - _abort(UPDATE_ERROR_MAGIC_BYTE); - return false; - } - return true; - } else if(_command == U_SPIFFS) { - return true; - } - return false; -} - -bool UpdateClass::_verifyEnd() { - if(_command == U_FLASH) { - if(!_enablePartition(_partition) || !_partitionIsBootable(_partition)) { - _abort(UPDATE_ERROR_READ); - return false; - } - - if(esp_ota_set_boot_partition(_partition)){ - _abort(UPDATE_ERROR_ACTIVATE); - return false; - } - _reset(); - return true; - } else if(_command == U_SPIFFS) { - _reset(); - return true; - } - return false; -} - -bool UpdateClass::setMD5(const char * expected_md5){ - if(strlen(expected_md5) != 32) - { - return false; - } - _target_md5 = expected_md5; - return true; -} - -bool UpdateClass::end(bool evenIfRemaining){ - if(hasError() || _size == 0){ - return false; - } - - if(!isFinished() && !evenIfRemaining){ - log_e("premature end: res:%u, pos:%u/%u\n", getError(), progress(), _size); - _abort(UPDATE_ERROR_ABORT); - return false; - } - - if(evenIfRemaining) { - if(_bufferLen > 0) { - _writeBuffer(); - } - _size = progress(); - } - - _md5.calculate(); - if(_target_md5.length()) { - if(_target_md5 != _md5.toString()){ - _abort(UPDATE_ERROR_MD5); - return false; - } - } - - return _verifyEnd(); -} - -size_t UpdateClass::write(uint8_t *data, size_t len) { - if(hasError() || !isRunning()){ - return 0; - } - - if(len > remaining()){ - _abort(UPDATE_ERROR_SPACE); - return 0; - } - - size_t left = len; - - while((_bufferLen + left) > SPI_FLASH_SEC_SIZE) { - size_t toBuff = SPI_FLASH_SEC_SIZE - _bufferLen; - memcpy(_buffer + _bufferLen, data + (len - left), toBuff); - _bufferLen += toBuff; - if(!_writeBuffer()){ - return len - left; - } - left -= toBuff; - } - memcpy(_buffer + _bufferLen, data + (len - left), left); - _bufferLen += left; - if(_bufferLen == remaining()){ - if(!_writeBuffer()){ - return len - left; - } - } - return len; -} - -size_t UpdateClass::writeStream(Stream &data) { - data.setTimeout(20000); - size_t written = 0; - size_t toRead = 0; - if(hasError() || !isRunning()) - return 0; - - if(!_verifyHeader(data.peek())) { - _reset(); - return 0; - } - if (_progress_callback) { - _progress_callback(0, _size); - } - while(remaining()) { - toRead = data.readBytes(_buffer + _bufferLen, (SPI_FLASH_SEC_SIZE - _bufferLen)); - if(toRead == 0) { //Timeout - delay(100); - toRead = data.readBytes(_buffer + _bufferLen, (SPI_FLASH_SEC_SIZE - _bufferLen)); - if(toRead == 0) { //Timeout - _abort(UPDATE_ERROR_STREAM); - return written; - } - } - _bufferLen += toRead; - if((_bufferLen == remaining() || _bufferLen == SPI_FLASH_SEC_SIZE) && !_writeBuffer()) - return written; - written += toRead; - if(_progress_callback) { - _progress_callback(_progress, _size); - } - } - if(_progress_callback) { - _progress_callback(_size, _size); - } - return written; -} - -void UpdateClass::printError(Stream &out){ - out.println(_err2str(_error)); -} - -UpdateClass Update; From 7ff537bb34e450a2ff724ef53d8493b1d42b456d Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sun, 4 Nov 2018 20:35:41 +0100 Subject: [PATCH 19/36] readme.md updated --- README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 223c0408b..b4b6a61fd 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Paxcounter is a proof-of-concept device for metering passenger flows in realtime Intention of this project is to do this without intrusion in privacy: You don't need to track people owned devices, if you just want to count them. Therefore, Paxcounter does not persistenly store MAC adresses and does no kind of fingerprinting the scanned devices. -Metered counts are transferred to a server via a LoRaWAN network, and/or a local SPI cable interface. +Data is transferred to a server via a LoRaWAN network, and/or a wired SPI slave interface. You can build this project battery powered and reach a full day uptime with a single 18650 Li-Ion cell. @@ -33,15 +33,16 @@ This can all be done with a single small and cheap ESP32 board for less than $20 LoLin32lite + [LoraNode32-Lite shield](https://github.com/hallard/LoLin32-Lite-Lora) - Adafruit ESP32 Feather + LoRa Wing + OLED Wing, #IoT Octopus32 (Octopus + ESP32 Feather) -*SPI only*: (code yet to come) +*SPI only*: - Pyom: WiPy - WeMos: LoLin32, LoLin32 Lite, WeMos D32 +- Generic ESP32 Depending on board hardware following features are supported: -- LED -- OLED Display -- RGB LED +- LED (power/status) +- OLED Display (detailed status) +- RGB LED (colorized status) - Button - Silicon unique ID - Battery voltage monitoring From c061f3f5860f2b337fd84587356d3baa86a306f2 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sun, 4 Nov 2018 20:51:48 +0100 Subject: [PATCH 20/36] ota.cpp small fixes --- src/ota.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/ota.cpp b/src/ota.cpp index b02c15bd8..12fcd6e72 100644 --- a/src/ota.cpp +++ b/src/ota.cpp @@ -84,16 +84,14 @@ void start_ota_update() { ESP_LOGI(TAG, "Connected to %s", WIFI_SSID); display(1, "OK", "WiFi connected"); // do a number of tries to update firmware limited by OTA_MAX_TRY - while (j--) { + while ((j--) && (!ret)) { ESP_LOGI(TAG, "Starting OTA update, attempt %u of %u. This will take some " "time to complete...", OTA_MAX_TRY - j, OTA_MAX_TRY); ret = do_ota_update(); - if (ret) - goto end; // update successful - } // update not successful - goto end; + } + goto end; } } From 4a9db7a4c069883d25e79b6ae04cd3c09d7634a9 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sun, 4 Nov 2018 21:02:37 +0100 Subject: [PATCH 21/36] ota.cpp: shortened log texts --- src/ota.cpp | 39 ++++++++++++++++----------------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/src/ota.cpp b/src/ota.cpp index 12fcd6e72..831f9c088 100644 --- a/src/ota.cpp +++ b/src/ota.cpp @@ -85,10 +85,8 @@ void start_ota_update() { display(1, "OK", "WiFi connected"); // do a number of tries to update firmware limited by OTA_MAX_TRY while ((j--) && (!ret)) { - ESP_LOGI(TAG, - "Starting OTA update, attempt %u of %u. This will take some " - "time to complete...", - OTA_MAX_TRY - j, OTA_MAX_TRY); + ESP_LOGI(TAG, "Starting OTA update, attempt %u of %u", OTA_MAX_TRY - j, + OTA_MAX_TRY); ret = do_ota_update(); } goto end; @@ -102,8 +100,7 @@ void start_ota_update() { end: switch_LED(LED_OFF); - ESP_LOGI(TAG, "Rebooting to runmode using %s firmware", - ret ? "new" : "current"); + ESP_LOGI(TAG, "Rebooting to %s firmware", ret ? "new" : "current"); display(5, "**", ""); // mark line rebooting vTaskDelay(5000 / portTICK_PERIOD_MS); ESP.restart(); @@ -117,29 +114,26 @@ bool do_ota_update() { size_t written = 0; // Fetch the latest firmware version - ESP_LOGI(TAG, "Checking latest firmware version on server..."); + ESP_LOGI(TAG, "Checking latest firmware version on server"); display(2, "**", "checking version"); const String latest = bintray.getLatestVersion(); if (latest.length() == 0) { - ESP_LOGI( - TAG, - "Could not load info about the latest firmware. Rebooting to runmode."); + ESP_LOGI(TAG, "Could not fetch info on latest firmware"); display(2, " E", "file not found"); return false; } else if (version_compare(latest, cfg.version) <= 0) { - ESP_LOGI(TAG, "Current firmware is up to date. Rebooting to runmode."); + ESP_LOGI(TAG, "Current firmware is up to date"); display(2, "NO", "no update found"); return false; } - ESP_LOGI(TAG, "New firmware version v%s available. Downloading...", - latest.c_str()); + ESP_LOGI(TAG, "New firmware version v%s available", latest.c_str()); display(2, "OK", latest.c_str()); display(3, "**", ""); String firmwarePath = bintray.getBinaryPath(latest); if (!firmwarePath.endsWith(".bin")) { - ESP_LOGI(TAG, "Unsupported binary format, OTA update cancelled."); + ESP_LOGI(TAG, "Unsupported binary format"); display(3, " E", "file type error"); return false; } @@ -178,7 +172,7 @@ bool do_ota_update() { unsigned long timeout = millis(); while (client.available() == 0) { if (millis() - timeout > RESPONSE_TIMEOUT_MS) { - ESP_LOGI(TAG, "Client Timeout."); + ESP_LOGI(TAG, "Client timeout"); display(3, " E", "client timeout"); goto failure; } @@ -200,11 +194,11 @@ bool do_ota_update() { "firmware flashing"); redirect = false; } else if (line.indexOf("302") > 0) { - ESP_LOGI(TAG, "Got 302 status code from server. Redirecting to the " + ESP_LOGI(TAG, "Got 302 status code from server. Redirecting to " "new address"); redirect = true; } else { - ESP_LOGI(TAG, "Could not get a valid firmware url."); + ESP_LOGI(TAG, "Could not get firmware download URL"); // Unexptected HTTP response. Retry or skip update? redirect = false; } @@ -242,14 +236,13 @@ bool do_ota_update() { // check whether we have everything for OTA update if (!(contentLength && isValidContentType)) { - ESP_LOGI(TAG, - "There was no valid content in the response from the OTA server!"); + ESP_LOGI(TAG, "Invalid OTA server response"); display(4, " E", "response error"); goto failure; } if (!Update.begin(contentLength)) { - ESP_LOGI(TAG, "There isn't enough space to start OTA update"); + ESP_LOGI(TAG, "Not enough space to start OTA update"); display(4, " E", "disk full"); goto failure; } @@ -270,7 +263,7 @@ bool do_ota_update() { snprintf(buf, 17, "%ukB Done!", (uint16_t)(written / 1024)); display(4, "OK", buf); } else { - ESP_LOGI(TAG, "Written only %u of %u bytes, OTA update attempt cancelled.", + ESP_LOGI(TAG, "Written only %u of %u bytes, OTA update attempt cancelled", written, contentLength); } @@ -285,12 +278,12 @@ bool do_ota_update() { finished: client.stop(); - ESP_LOGI(TAG, "OTA update completed."); + ESP_LOGI(TAG, "OTA update finished"); return true; failure: client.stop(); - ESP_LOGI(TAG, "OTA update failed."); + ESP_LOGI(TAG, "OTA update failed"); return false; } // do_ota_update From f2513584e21b6a2c3fe57fcd6aa62ca218dcff12 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sun, 4 Nov 2018 21:10:33 +0100 Subject: [PATCH 22/36] ota.cpp: stream timeout changed --- src/ota.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/ota.cpp b/src/ota.cpp index 831f9c088..c1489371b 100644 --- a/src/ota.cpp +++ b/src/ota.cpp @@ -142,6 +142,8 @@ bool do_ota_update() { String prevHost = currentHost; WiFiClientSecure client; + // set server connection timeout and open server connection + client.setTimeout(RESPONSE_TIMEOUT_MS); client.setCACert(bintray.getCertificate(currentHost)); if (!client.connect(currentHost.c_str(), port)) { @@ -253,9 +255,6 @@ bool do_ota_update() { #endif display(4, "**", "writing..."); - - // set server connection timeout and open server connection - client.setTimeout(RESPONSE_TIMEOUT_MS); written = Update.writeStream(client); if (written == contentLength) { From 26f4bd8f0987046e631389335ec00df20cd1f789 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Sun, 4 Nov 2018 21:12:19 +0100 Subject: [PATCH 23/36] ota.cpp: streaming timeout changed --- src/ota.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ota.cpp b/src/ota.cpp index c1489371b..60c07dca6 100644 --- a/src/ota.cpp +++ b/src/ota.cpp @@ -155,6 +155,7 @@ bool do_ota_update() { while (redirect) { if (currentHost != prevHost) { client.stop(); + client.setTimeout(RESPONSE_TIMEOUT_MS); client.setCACert(bintray.getCertificate(currentHost)); if (!client.connect(currentHost.c_str(), port)) { ESP_LOGI(TAG, "Redirect detected, but cannot connect to %s", From cbc846d30b40a856d5b9956d83bb479538869df2 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Mon, 5 Nov 2018 00:03:47 +0100 Subject: [PATCH 24/36] ota.cpp: fixed timeout --- src/ota.cpp | 16 +++++++++------- src/paxcounter.conf | 4 ++-- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/ota.cpp b/src/ota.cpp index 60c07dca6..2e406a427 100644 --- a/src/ota.cpp +++ b/src/ota.cpp @@ -77,8 +77,8 @@ void start_ota_update() { int i = WIFI_MAX_TRY, j = OTA_MAX_TRY; bool ret = false; + ESP_LOGI(TAG, "Trying to connect to %s", WIFI_SSID); while (i--) { - ESP_LOGI(TAG, "Trying to connect to %s", WIFI_SSID); if (WiFi.status() == WL_CONNECTED) { // we now have wifi connection and try to do an OTA over wifi update ESP_LOGI(TAG, "Connected to %s", WIFI_SSID); @@ -91,6 +91,7 @@ void start_ota_update() { } goto end; } + vTaskDelay(5000 / portTICK_PERIOD_MS); } // wifi did not connect @@ -142,8 +143,7 @@ bool do_ota_update() { String prevHost = currentHost; WiFiClientSecure client; - // set server connection timeout and open server connection - client.setTimeout(RESPONSE_TIMEOUT_MS); + client.setCACert(bintray.getCertificate(currentHost)); if (!client.connect(currentHost.c_str(), port)) { @@ -151,11 +151,11 @@ bool do_ota_update() { display(3, " E", "connection lost"); goto failure; } + // client.setTimeout(RESPONSE_TIMEOUT); while (redirect) { if (currentHost != prevHost) { client.stop(); - client.setTimeout(RESPONSE_TIMEOUT_MS); client.setCACert(bintray.getCertificate(currentHost)); if (!client.connect(currentHost.c_str(), port)) { ESP_LOGI(TAG, "Redirect detected, but cannot connect to %s", @@ -163,6 +163,7 @@ bool do_ota_update() { display(3, " E", "server error"); goto failure; } + // client.setTimeout(RESPONSE_TIMEOUT); } ESP_LOGI(TAG, "Requesting %s", firmwarePath.c_str()); @@ -174,7 +175,7 @@ bool do_ota_update() { unsigned long timeout = millis(); while (client.available() == 0) { - if (millis() - timeout > RESPONSE_TIMEOUT_MS) { + if ((millis() - timeout) > (RESPONSE_TIMEOUT * 1000)) { ESP_LOGI(TAG, "Client timeout"); display(3, " E", "client timeout"); goto failure; @@ -257,6 +258,7 @@ bool do_ota_update() { display(4, "**", "writing..."); written = Update.writeStream(client); + client.setTimeout(RESPONSE_TIMEOUT); if (written == contentLength) { ESP_LOGI(TAG, "Written %u bytes successfully", written); @@ -270,8 +272,8 @@ bool do_ota_update() { if (Update.end()) { goto finished; } else { - ESP_LOGI(TAG, "An error occurred. Error #: %d", Update.getError()); - snprintf(buf, 17, "Error #: %d", Update.getError()); + ESP_LOGI(TAG, "An error occurred. Error#: %d", Update.getError()); + snprintf(buf, 17, "Error#: %d", Update.getError()); display(4, " E", buf); goto failure; } diff --git a/src/paxcounter.conf b/src/paxcounter.conf index 1069b8be7..5c47a9558 100644 --- a/src/paxcounter.conf +++ b/src/paxcounter.conf @@ -68,9 +68,9 @@ // OTA settings #define USE_OTA 1 // Comment out to disable OTA update #define WIFI_MAX_TRY 5 // maximum number of wifi connect attempts for OTA update [default = 20] -#define OTA_MAX_TRY 3 // maximum number of attempts for OTA download and write to flash [default = 3] +#define OTA_MAX_TRY 5 // maximum number of attempts for OTA download and write to flash [default = 3] #define OTA_MIN_BATT 3700 // minimum battery level for OTA [millivolt] -#define RESPONSE_TIMEOUT_MS 30000 // firmware binary server connection timeout [milliseconds] +#define RESPONSE_TIMEOUT 60 // firmware binary server connection timeout [seconds] // LMIC settings // moved to src/lmic_config.h \ No newline at end of file From d17638ad900e5291852885d436abd4553d06d76b Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Mon, 5 Nov 2018 00:30:32 +0100 Subject: [PATCH 25/36] ota.cpp: control flow --- src/ota.cpp | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/src/ota.cpp b/src/ota.cpp index 2e406a427..83a067026 100644 --- a/src/ota.cpp +++ b/src/ota.cpp @@ -75,7 +75,7 @@ void start_ota_update() { WiFi.begin(WIFI_SSID, WIFI_PASS); int i = WIFI_MAX_TRY, j = OTA_MAX_TRY; - bool ret = false; + bool ret = 1; ESP_LOGI(TAG, "Trying to connect to %s", WIFI_SSID); while (i--) { @@ -84,7 +84,7 @@ void start_ota_update() { ESP_LOGI(TAG, "Connected to %s", WIFI_SSID); display(1, "OK", "WiFi connected"); // do a number of tries to update firmware limited by OTA_MAX_TRY - while ((j--) && (!ret)) { + while ((j--) && (ret > 0)) { ESP_LOGI(TAG, "Starting OTA update, attempt %u of %u", OTA_MAX_TRY - j, OTA_MAX_TRY); ret = do_ota_update(); @@ -101,7 +101,7 @@ void start_ota_update() { end: switch_LED(LED_OFF); - ESP_LOGI(TAG, "Rebooting to %s firmware", ret ? "new" : "current"); + ESP_LOGI(TAG, "Rebooting to %s firmware", (ret < 0) ? "current" : "new"); display(5, "**", ""); // mark line rebooting vTaskDelay(5000 / portTICK_PERIOD_MS); ESP.restart(); @@ -122,11 +122,11 @@ bool do_ota_update() { if (latest.length() == 0) { ESP_LOGI(TAG, "Could not fetch info on latest firmware"); display(2, " E", "file not found"); - return false; + return -1; } else if (version_compare(latest, cfg.version) <= 0) { ESP_LOGI(TAG, "Current firmware is up to date"); display(2, "NO", "no update found"); - return false; + return -2; } ESP_LOGI(TAG, "New firmware version v%s available", latest.c_str()); display(2, "OK", latest.c_str()); @@ -136,7 +136,7 @@ bool do_ota_update() { if (!firmwarePath.endsWith(".bin")) { ESP_LOGI(TAG, "Unsupported binary format"); display(3, " E", "file type error"); - return false; + return -1; } String currentHost = bintray.getStorageHost(); @@ -149,7 +149,7 @@ bool do_ota_update() { if (!client.connect(currentHost.c_str(), port)) { ESP_LOGI(TAG, "Cannot connect to %s", currentHost.c_str()); display(3, " E", "connection lost"); - goto failure; + goto abort; } // client.setTimeout(RESPONSE_TIMEOUT); @@ -161,7 +161,7 @@ bool do_ota_update() { ESP_LOGI(TAG, "Redirect detected, but cannot connect to %s", currentHost.c_str()); display(3, " E", "server error"); - goto failure; + goto abort; } // client.setTimeout(RESPONSE_TIMEOUT); } @@ -178,7 +178,7 @@ bool do_ota_update() { if ((millis() - timeout) > (RESPONSE_TIMEOUT * 1000)) { ESP_LOGI(TAG, "Client timeout"); display(3, " E", "client timeout"); - goto failure; + goto abort; } } @@ -242,13 +242,13 @@ bool do_ota_update() { if (!(contentLength && isValidContentType)) { ESP_LOGI(TAG, "Invalid OTA server response"); display(4, " E", "response error"); - goto failure; + goto retry; } if (!Update.begin(contentLength)) { ESP_LOGI(TAG, "Not enough space to start OTA update"); display(4, " E", "disk full"); - goto failure; + goto abort; } #ifdef HAS_DISPLAY @@ -275,18 +275,21 @@ bool do_ota_update() { ESP_LOGI(TAG, "An error occurred. Error#: %d", Update.getError()); snprintf(buf, 17, "Error#: %d", Update.getError()); display(4, " E", buf); - goto failure; + goto retry; } finished: client.stop(); ESP_LOGI(TAG, "OTA update finished"); - return true; + return 0; -failure: +abort: client.stop(); ESP_LOGI(TAG, "OTA update failed"); - return false; + return -1; + +retry: + return 1; } // do_ota_update From 9c1be4c5572ba3a50b1ccbb56ec4d5581da0a794 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Mon, 5 Nov 2018 00:32:38 +0100 Subject: [PATCH 26/36] ota.cpp: bugfix --- src/ota.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ota.cpp b/src/ota.cpp index 83a067026..4b0d13f3f 100644 --- a/src/ota.cpp +++ b/src/ota.cpp @@ -101,7 +101,7 @@ void start_ota_update() { end: switch_LED(LED_OFF); - ESP_LOGI(TAG, "Rebooting to %s firmware", (ret < 0) ? "current" : "new"); + ESP_LOGI(TAG, "Rebooting to %s firmware", (ret == 0) ? "new" : "current"); display(5, "**", ""); // mark line rebooting vTaskDelay(5000 / portTICK_PERIOD_MS); ESP.restart(); From 9fa2f974c34a6a6bc3371e90ac26c01a7fcbe0ed Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Mon, 5 Nov 2018 13:13:31 +0100 Subject: [PATCH 27/36] OTA timeout problem fixed by workaround --- include/ota.h | 2 +- include/update.h | 181 +++++++++++++++++++++++ src/ota.cpp | 16 +- src/paxcounter.conf | 2 +- src/update.cpp | 352 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 544 insertions(+), 9 deletions(-) create mode 100644 include/update.h create mode 100644 src/update.cpp diff --git a/include/ota.h b/include/ota.h index bcdb0410f..174e7a037 100644 --- a/include/ota.h +++ b/include/ota.h @@ -5,7 +5,7 @@ #include "globals.h" #include "battery.h" -#include +#include "update.h" #include #include #include diff --git a/include/update.h b/include/update.h new file mode 100644 index 000000000..5b0c8d4b1 --- /dev/null +++ b/include/update.h @@ -0,0 +1,181 @@ +#ifndef ESP8266UPDATER_H +#define ESP8266UPDATER_H + +#include +#include +#include +#include "esp_partition.h" + +#define UPDATE_ERROR_OK (0) +#define UPDATE_ERROR_WRITE (1) +#define UPDATE_ERROR_ERASE (2) +#define UPDATE_ERROR_READ (3) +#define UPDATE_ERROR_SPACE (4) +#define UPDATE_ERROR_SIZE (5) +#define UPDATE_ERROR_STREAM (6) +#define UPDATE_ERROR_MD5 (7) +#define UPDATE_ERROR_MAGIC_BYTE (8) +#define UPDATE_ERROR_ACTIVATE (9) +#define UPDATE_ERROR_NO_PARTITION (10) +#define UPDATE_ERROR_BAD_ARGUMENT (11) +#define UPDATE_ERROR_ABORT (12) + +#define UPDATE_SIZE_UNKNOWN 0xFFFFFFFF + +#define U_FLASH 0 +#define U_SPIFFS 100 +#define U_AUTH 200 + +class UpdateClass { + public: + typedef std::function THandlerFunction_Progress; + + UpdateClass(); + + /* + This callback will be called when Update is receiving data + */ + UpdateClass& onProgress(THandlerFunction_Progress fn); + + /* + Call this to check the space needed for the update + Will return false if there is not enough space + */ + bool begin(size_t size=UPDATE_SIZE_UNKNOWN, int command = U_FLASH); + + /* + Writes a buffer to the flash and increments the address + Returns the amount written + */ + size_t write(uint8_t *data, size_t len); + + /* + Writes the remaining bytes from the Stream to the flash + Uses readBytes() and sets UPDATE_ERROR_STREAM on timeout + Returns the bytes written + Should be equal to the remaining bytes when called + Usable for slow streams like Serial + */ + size_t writeStream(Stream &data); + + /* + If all bytes are written + this call will write the config to eboot + and return true + If there is already an update running but is not finished and !evenIfRemainanig + or there is an error + this will clear everything and return false + the last error is available through getError() + evenIfRemaining is helpfull when you update without knowing the final size first + */ + bool end(bool evenIfRemaining = false); + + /* + Aborts the running update + */ + void abort(); + + /* + Prints the last error to an output stream + */ + void printError(Stream &out); + + /* + sets the expected MD5 for the firmware (hexString) + */ + bool setMD5(const char * expected_md5); + + /* + returns the MD5 String of the sucessfully ended firmware + */ + String md5String(void){ return _md5.toString(); } + + /* + populated the result with the md5 bytes of the sucessfully ended firmware + */ + void md5(uint8_t * result){ return _md5.getBytes(result); } + + //Helpers + uint8_t getError(){ return _error; } + void clearError(){ _error = UPDATE_ERROR_OK; } + bool hasError(){ return _error != UPDATE_ERROR_OK; } + bool isRunning(){ return _size > 0; } + bool isFinished(){ return _progress == _size; } + size_t size(){ return _size; } + size_t progress(){ return _progress; } + size_t remaining(){ return _size - _progress; } + + /* + Template to write from objects that expose + available() and read(uint8_t*, size_t) methods + faster than the writeStream method + writes only what is available + */ + template + size_t write(T &data){ + size_t written = 0; + if (hasError() || !isRunning()) + return 0; + + size_t available = data.available(); + while(available) { + if(_bufferLen + available > remaining()){ + available = remaining() - _bufferLen; + } + if(_bufferLen + available > 4096) { + size_t toBuff = 4096 - _bufferLen; + data.read(_buffer + _bufferLen, toBuff); + _bufferLen += toBuff; + if(!_writeBuffer()) + return written; + written += toBuff; + } else { + data.read(_buffer + _bufferLen, available); + _bufferLen += available; + written += available; + if(_bufferLen == remaining()) { + if(!_writeBuffer()) { + return written; + } + } + } + if(remaining() == 0) + return written; + available = data.available(); + } + return written; + } + + /* + check if there is a firmware on the other OTA partition that you can bootinto + */ + bool canRollBack(); + /* + set the other OTA partition as bootable (reboot to enable) + */ + bool rollBack(); + + private: + void _reset(); + void _abort(uint8_t err); + bool _writeBuffer(); + bool _verifyHeader(uint8_t data); + bool _verifyEnd(); + + + uint8_t _error; + uint8_t *_buffer; + size_t _bufferLen; + size_t _size; + THandlerFunction_Progress _progress_callback; + uint32_t _progress; + uint32_t _command; + const esp_partition_t* _partition; + + String _target_md5; + MD5Builder _md5; +}; + +extern UpdateClass Update; + +#endif \ No newline at end of file diff --git a/src/ota.cpp b/src/ota.cpp index 4b0d13f3f..8ede3aed3 100644 --- a/src/ota.cpp +++ b/src/ota.cpp @@ -26,6 +26,8 @@ const BintrayClient bintray(BINTRAY_USER, BINTRAY_REPO, BINTRAY_PACKAGE); // Connection port (HTTPS) const int port = 443; +const unsigned long STREAM_TIMEOUT = 30000; + // Variables to validate firmware content int volatile contentLength = 0; bool volatile isValidContentType = false; @@ -145,13 +147,15 @@ bool do_ota_update() { WiFiClientSecure client; client.setCACert(bintray.getCertificate(currentHost)); + //client.setTimeout(RESPONSE_TIMEOUT_MS); + // --> causing error [E][WiFiClient.cpp:236] setSocketOption(): 1006 : 9 + // so we unfortunately need patched update.cpp which sets the stream timeout if (!client.connect(currentHost.c_str(), port)) { ESP_LOGI(TAG, "Cannot connect to %s", currentHost.c_str()); display(3, " E", "connection lost"); goto abort; } - // client.setTimeout(RESPONSE_TIMEOUT); while (redirect) { if (currentHost != prevHost) { @@ -163,7 +167,6 @@ bool do_ota_update() { display(3, " E", "server error"); goto abort; } - // client.setTimeout(RESPONSE_TIMEOUT); } ESP_LOGI(TAG, "Requesting %s", firmwarePath.c_str()); @@ -175,7 +178,7 @@ bool do_ota_update() { unsigned long timeout = millis(); while (client.available() == 0) { - if ((millis() - timeout) > (RESPONSE_TIMEOUT * 1000)) { + if ((millis() - timeout) > (RESPONSE_TIMEOUT_MS)) { ESP_LOGI(TAG, "Client timeout"); display(3, " E", "client timeout"); goto abort; @@ -233,8 +236,8 @@ bool do_ota_update() { isValidContentType = true; } } - } - } // while (redirect) + } // while (client.available()) + } // while (redirect) display(3, "OK", ""); // line download @@ -257,8 +260,7 @@ bool do_ota_update() { #endif display(4, "**", "writing..."); - written = Update.writeStream(client); - client.setTimeout(RESPONSE_TIMEOUT); + written = Update.writeStream(client); // this is a blocking call if (written == contentLength) { ESP_LOGI(TAG, "Written %u bytes successfully", written); diff --git a/src/paxcounter.conf b/src/paxcounter.conf index 5c47a9558..a4bb32ad4 100644 --- a/src/paxcounter.conf +++ b/src/paxcounter.conf @@ -70,7 +70,7 @@ #define WIFI_MAX_TRY 5 // maximum number of wifi connect attempts for OTA update [default = 20] #define OTA_MAX_TRY 5 // maximum number of attempts for OTA download and write to flash [default = 3] #define OTA_MIN_BATT 3700 // minimum battery level for OTA [millivolt] -#define RESPONSE_TIMEOUT 60 // firmware binary server connection timeout [seconds] +#define RESPONSE_TIMEOUT_MS 60000 // firmware binary server connection timeout [milliseconds] // LMIC settings // moved to src/lmic_config.h \ No newline at end of file diff --git a/src/update.cpp b/src/update.cpp new file mode 100644 index 000000000..b59ec2844 --- /dev/null +++ b/src/update.cpp @@ -0,0 +1,352 @@ +/* +this file copied from esp32-arduino library and patched, see PR +https://github.com/espressif/arduino-esp32/pull/1886 +*/ + +#include "update.h" +#include "Arduino.h" +#include "esp_spi_flash.h" +#include "esp_ota_ops.h" +#include "esp_image_format.h" + +static const char * _err2str(uint8_t _error){ + if(_error == UPDATE_ERROR_OK){ + return ("No Error"); + } else if(_error == UPDATE_ERROR_WRITE){ + return ("Flash Write Failed"); + } else if(_error == UPDATE_ERROR_ERASE){ + return ("Flash Erase Failed"); + } else if(_error == UPDATE_ERROR_READ){ + return ("Flash Read Failed"); + } else if(_error == UPDATE_ERROR_SPACE){ + return ("Not Enough Space"); + } else if(_error == UPDATE_ERROR_SIZE){ + return ("Bad Size Given"); + } else if(_error == UPDATE_ERROR_STREAM){ + return ("Stream Read Timeout"); + } else if(_error == UPDATE_ERROR_MD5){ + return ("MD5 Check Failed"); + } else if(_error == UPDATE_ERROR_MAGIC_BYTE){ + return ("Wrong Magic Byte"); + } else if(_error == UPDATE_ERROR_ACTIVATE){ + return ("Could Not Activate The Firmware"); + } else if(_error == UPDATE_ERROR_NO_PARTITION){ + return ("Partition Could Not be Found"); + } else if(_error == UPDATE_ERROR_BAD_ARGUMENT){ + return ("Bad Argument"); + } else if(_error == UPDATE_ERROR_ABORT){ + return ("Aborted"); + } + return ("UNKNOWN"); +} + +static bool _partitionIsBootable(const esp_partition_t* partition){ + uint8_t buf[4]; + if(!partition){ + return false; + } + if(!ESP.flashRead(partition->address, (uint32_t*)buf, 4)) { + return false; + } + + if(buf[0] != ESP_IMAGE_HEADER_MAGIC) { + return false; + } + return true; +} + +static bool _enablePartition(const esp_partition_t* partition){ + uint8_t buf[4]; + if(!partition){ + return false; + } + if(!ESP.flashRead(partition->address, (uint32_t*)buf, 4)) { + return false; + } + buf[0] = ESP_IMAGE_HEADER_MAGIC; + + return ESP.flashWrite(partition->address, (uint32_t*)buf, 4); +} + +UpdateClass::UpdateClass() +: _error(0) +, _buffer(0) +, _bufferLen(0) +, _size(0) +, _progress_callback(NULL) +, _progress(0) +, _command(U_FLASH) +, _partition(NULL) +{ +} + +UpdateClass& UpdateClass::onProgress(THandlerFunction_Progress fn) { + _progress_callback = fn; + return *this; +} + +void UpdateClass::_reset() { + if (_buffer) + delete[] _buffer; + _buffer = 0; + _bufferLen = 0; + _progress = 0; + _size = 0; + _command = U_FLASH; +} + +bool UpdateClass::canRollBack(){ + if(_buffer){ //Update is running + return false; + } + const esp_partition_t* partition = esp_ota_get_next_update_partition(NULL); + return _partitionIsBootable(partition); +} + +bool UpdateClass::rollBack(){ + if(_buffer){ //Update is running + return false; + } + const esp_partition_t* partition = esp_ota_get_next_update_partition(NULL); + return _partitionIsBootable(partition) && !esp_ota_set_boot_partition(partition); +} + +bool UpdateClass::begin(size_t size, int command) { + if(_size > 0){ + log_w("already running"); + return false; + } + + _reset(); + _error = 0; + + if(size == 0) { + _error = UPDATE_ERROR_SIZE; + return false; + } + + if (command == U_FLASH) { + _partition = esp_ota_get_next_update_partition(NULL); + if(!_partition){ + _error = UPDATE_ERROR_NO_PARTITION; + return false; + } + log_d("OTA Partition: %s", _partition->label); + } + else if (command == U_SPIFFS) { + _partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_SPIFFS, NULL); + if(!_partition){ + _error = UPDATE_ERROR_NO_PARTITION; + return false; + } + } + else { + _error = UPDATE_ERROR_BAD_ARGUMENT; + log_e("bad command %u", command); + return false; + } + + if(size == UPDATE_SIZE_UNKNOWN){ + size = _partition->size; + } else if(size > _partition->size){ + _error = UPDATE_ERROR_SIZE; + log_e("too large %u > %u", size, _partition->size); + return false; + } + + //initialize + _buffer = (uint8_t*)malloc(SPI_FLASH_SEC_SIZE); + if(!_buffer){ + log_e("malloc failed"); + return false; + } + _size = size; + _command = command; + _md5.begin(); + return true; +} + +void UpdateClass::_abort(uint8_t err){ + _reset(); + _error = err; +} + +void UpdateClass::abort(){ + _abort(UPDATE_ERROR_ABORT); +} + +bool UpdateClass::_writeBuffer(){ + //first bytes of new firmware + if(!_progress && _command == U_FLASH){ + //check magic + if(_buffer[0] != ESP_IMAGE_HEADER_MAGIC){ + _abort(UPDATE_ERROR_MAGIC_BYTE); + return false; + } + //remove magic byte from the firmware now and write it upon success + //this ensures that partially written firmware will not be bootable + _buffer[0] = 0xFF; + } + if(!ESP.flashEraseSector((_partition->address + _progress)/SPI_FLASH_SEC_SIZE)){ + _abort(UPDATE_ERROR_ERASE); + return false; + } + if (!ESP.flashWrite(_partition->address + _progress, (uint32_t*)_buffer, _bufferLen)) { + _abort(UPDATE_ERROR_WRITE); + return false; + } + //restore magic or md5 will fail + if(!_progress && _command == U_FLASH){ + _buffer[0] = ESP_IMAGE_HEADER_MAGIC; + } + _md5.add(_buffer, _bufferLen); + _progress += _bufferLen; + _bufferLen = 0; + return true; +} + +bool UpdateClass::_verifyHeader(uint8_t data) { + if(_command == U_FLASH) { + if(data != ESP_IMAGE_HEADER_MAGIC) { + _abort(UPDATE_ERROR_MAGIC_BYTE); + return false; + } + return true; + } else if(_command == U_SPIFFS) { + return true; + } + return false; +} + +bool UpdateClass::_verifyEnd() { + if(_command == U_FLASH) { + if(!_enablePartition(_partition) || !_partitionIsBootable(_partition)) { + _abort(UPDATE_ERROR_READ); + return false; + } + + if(esp_ota_set_boot_partition(_partition)){ + _abort(UPDATE_ERROR_ACTIVATE); + return false; + } + _reset(); + return true; + } else if(_command == U_SPIFFS) { + _reset(); + return true; + } + return false; +} + +bool UpdateClass::setMD5(const char * expected_md5){ + if(strlen(expected_md5) != 32) + { + return false; + } + _target_md5 = expected_md5; + return true; +} + +bool UpdateClass::end(bool evenIfRemaining){ + if(hasError() || _size == 0){ + return false; + } + + if(!isFinished() && !evenIfRemaining){ + log_e("premature end: res:%u, pos:%u/%u\n", getError(), progress(), _size); + _abort(UPDATE_ERROR_ABORT); + return false; + } + + if(evenIfRemaining) { + if(_bufferLen > 0) { + _writeBuffer(); + } + _size = progress(); + } + + _md5.calculate(); + if(_target_md5.length()) { + if(_target_md5 != _md5.toString()){ + _abort(UPDATE_ERROR_MD5); + return false; + } + } + + return _verifyEnd(); +} + +size_t UpdateClass::write(uint8_t *data, size_t len) { + if(hasError() || !isRunning()){ + return 0; + } + + if(len > remaining()){ + _abort(UPDATE_ERROR_SPACE); + return 0; + } + + size_t left = len; + + while((_bufferLen + left) > SPI_FLASH_SEC_SIZE) { + size_t toBuff = SPI_FLASH_SEC_SIZE - _bufferLen; + memcpy(_buffer + _bufferLen, data + (len - left), toBuff); + _bufferLen += toBuff; + if(!_writeBuffer()){ + return len - left; + } + left -= toBuff; + } + memcpy(_buffer + _bufferLen, data + (len - left), left); + _bufferLen += left; + if(_bufferLen == remaining()){ + if(!_writeBuffer()){ + return len - left; + } + } + return len; +} + +size_t UpdateClass::writeStream(Stream &data) { + data.setTimeout(RESPONSE_TIMEOUT_MS); + size_t written = 0; + size_t toRead = 0; + if(hasError() || !isRunning()) + return 0; + + if(!_verifyHeader(data.peek())) { + _reset(); + return 0; + } + if (_progress_callback) { + _progress_callback(0, _size); + } + while(remaining()) { + toRead = data.readBytes(_buffer + _bufferLen, (SPI_FLASH_SEC_SIZE - _bufferLen)); + if(toRead == 0) { //Timeout + delay(100); + toRead = data.readBytes(_buffer + _bufferLen, (SPI_FLASH_SEC_SIZE - _bufferLen)); + if(toRead == 0) { //Timeout + _abort(UPDATE_ERROR_STREAM); + return written; + } + } + _bufferLen += toRead; + if((_bufferLen == remaining() || _bufferLen == SPI_FLASH_SEC_SIZE) && !_writeBuffer()) + return written; + written += toRead; + if(_progress_callback) { + _progress_callback(_progress, _size); + } + } + if(_progress_callback) { + _progress_callback(_size, _size); + } + return written; +} + +void UpdateClass::printError(Stream &out){ + out.println(_err2str(_error)); +} + +UpdateClass Update; \ No newline at end of file From af0f3a78fdb8c7a82c8956286dc6b80ca62564c4 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Mon, 5 Nov 2018 15:28:26 +0100 Subject: [PATCH 28/36] OTA improved (LED flashing, faster buffer closing at end of write) --- include/ota.h | 2 +- include/update.h | 5 ++++- src/ota.cpp | 23 +++++++++++++++-------- src/update.cpp | 33 ++++++++++++++++++++++++++++----- 4 files changed, 48 insertions(+), 15 deletions(-) diff --git a/include/ota.h b/include/ota.h index 174e7a037..3c953ac06 100644 --- a/include/ota.h +++ b/include/ota.h @@ -11,7 +11,7 @@ #include #include -bool do_ota_update(); +int do_ota_update(); void start_ota_update(); int version_compare(const String v1, const String v2); void display(const uint8_t row, const std::string status, diff --git a/include/update.h b/include/update.h index 5b0c8d4b1..87c6f35c3 100644 --- a/include/update.h +++ b/include/update.h @@ -41,7 +41,7 @@ class UpdateClass { Call this to check the space needed for the update Will return false if there is not enough space */ - bool begin(size_t size=UPDATE_SIZE_UNKNOWN, int command = U_FLASH); + bool begin(size_t size=UPDATE_SIZE_UNKNOWN, int command = U_FLASH, int ledPin = -1, uint8_t ledOn = LOW); /* Writes a buffer to the flash and increments the address @@ -174,6 +174,9 @@ class UpdateClass { String _target_md5; MD5Builder _md5; + + int _ledPin; + uint8_t _ledOn; }; extern UpdateClass Update; diff --git a/src/ota.cpp b/src/ota.cpp index 8ede3aed3..778e7cf2c 100644 --- a/src/ota.cpp +++ b/src/ota.cpp @@ -26,8 +26,6 @@ const BintrayClient bintray(BINTRAY_USER, BINTRAY_REPO, BINTRAY_PACKAGE); // Connection port (HTTPS) const int port = 443; -const unsigned long STREAM_TIMEOUT = 30000; - // Variables to validate firmware content int volatile contentLength = 0; bool volatile isValidContentType = false; @@ -77,7 +75,7 @@ void start_ota_update() { WiFi.begin(WIFI_SSID, WIFI_PASS); int i = WIFI_MAX_TRY, j = OTA_MAX_TRY; - bool ret = 1; + int ret = 1; // 0 = finished, 1 = retry, -1 = abort ESP_LOGI(TAG, "Trying to connect to %s", WIFI_SSID); while (i--) { @@ -110,7 +108,9 @@ void start_ota_update() { } // start_ota_update -bool do_ota_update() { +// Reads data vom wifi client and flashes it to ota partition +// returns: 0 = finished, 1 = retry, -1 = abort +int do_ota_update() { char buf[17]; bool redirect = true; @@ -128,7 +128,7 @@ bool do_ota_update() { } else if (version_compare(latest, cfg.version) <= 0) { ESP_LOGI(TAG, "Current firmware is up to date"); display(2, "NO", "no update found"); - return -2; + return -1; } ESP_LOGI(TAG, "New firmware version v%s available", latest.c_str()); display(2, "OK", latest.c_str()); @@ -147,7 +147,7 @@ bool do_ota_update() { WiFiClientSecure client; client.setCACert(bintray.getCertificate(currentHost)); - //client.setTimeout(RESPONSE_TIMEOUT_MS); + // client.setTimeout(RESPONSE_TIMEOUT_MS); // --> causing error [E][WiFiClient.cpp:236] setSocketOption(): 1006 : 9 // so we unfortunately need patched update.cpp which sets the stream timeout @@ -206,8 +206,7 @@ bool do_ota_update() { redirect = true; } else { ESP_LOGI(TAG, "Could not get firmware download URL"); - // Unexptected HTTP response. Retry or skip update? - redirect = false; + goto retry; } } @@ -248,7 +247,15 @@ bool do_ota_update() { goto retry; } +#ifdef HAS_LED +#ifndef LED_ACTIVE_LOW + if (!Update.begin(contentLength, U_FLASH, HAS_LED, HIGH)) { +#else + if (!Update.begin(contentLength, U_FLASH, HAS_LED, LOW)) { +#endif +#else if (!Update.begin(contentLength)) { +#endif ESP_LOGI(TAG, "Not enough space to start OTA update"); display(4, " E", "disk full"); goto abort; diff --git a/src/update.cpp b/src/update.cpp index b59ec2844..618720f5b 100644 --- a/src/update.cpp +++ b/src/update.cpp @@ -1,9 +1,9 @@ /* this file copied from esp32-arduino library and patched, see PR -https://github.com/espressif/arduino-esp32/pull/1886 +https://github.com/espressif/arduino-esp32/pull/1979 */ -#include "update.h" +#include "Update.h" #include "Arduino.h" #include "esp_spi_flash.h" #include "esp_ota_ops.h" @@ -93,6 +93,10 @@ void UpdateClass::_reset() { _progress = 0; _size = 0; _command = U_FLASH; + + if(_ledPin != -1) { + digitalWrite(_ledPin, !_ledOn); // off + } } bool UpdateClass::canRollBack(){ @@ -111,12 +115,15 @@ bool UpdateClass::rollBack(){ return _partitionIsBootable(partition) && !esp_ota_set_boot_partition(partition); } -bool UpdateClass::begin(size_t size, int command) { +bool UpdateClass::begin(size_t size, int command, int ledPin, uint8_t ledOn) { if(_size > 0){ log_w("already running"); return false; } + _ledPin = ledPin; + _ledOn = !!ledOn; // 0(LOW) or 1(HIGH) + _reset(); _error = 0; @@ -321,16 +328,32 @@ size_t UpdateClass::writeStream(Stream &data) { if (_progress_callback) { _progress_callback(0, _size); } + + if(_ledPin != -1) { + pinMode(_ledPin, OUTPUT); + } + while(remaining()) { - toRead = data.readBytes(_buffer + _bufferLen, (SPI_FLASH_SEC_SIZE - _bufferLen)); + if(_ledPin != -1) { + digitalWrite(_ledPin, _ledOn); // Switch LED on + } + size_t bytesToRead = SPI_FLASH_SEC_SIZE - _bufferLen; + if(bytesToRead > remaining()) { + bytesToRead = remaining(); + } + + toRead = data.readBytes(_buffer + _bufferLen, bytesToRead); if(toRead == 0) { //Timeout delay(100); - toRead = data.readBytes(_buffer + _bufferLen, (SPI_FLASH_SEC_SIZE - _bufferLen)); + toRead = data.readBytes(_buffer + _bufferLen, bytesToRead); if(toRead == 0) { //Timeout _abort(UPDATE_ERROR_STREAM); return written; } } + if(_ledPin != -1) { + digitalWrite(_ledPin, !_ledOn); // Switch LED off + } _bufferLen += toRead; if((_bufferLen == remaining() || _bufferLen == SPI_FLASH_SEC_SIZE) && !_writeBuffer()) return written; From bfd91f45453a03df4dcdcf837f47334de74f6cf4 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Mon, 5 Nov 2018 16:06:17 +0100 Subject: [PATCH 29/36] ota.cpp: wifi reconnect improved --- src/ota.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ota.cpp b/src/ota.cpp index 778e7cf2c..b318506b0 100644 --- a/src/ota.cpp +++ b/src/ota.cpp @@ -72,12 +72,14 @@ void start_ota_update() { ESP_LOGI(TAG, "Starting Wifi OTA update"); display(1, "**", WIFI_SSID); + WiFi.mode(WIFI_AP_STA); WiFi.begin(WIFI_SSID, WIFI_PASS); int i = WIFI_MAX_TRY, j = OTA_MAX_TRY; int ret = 1; // 0 = finished, 1 = retry, -1 = abort ESP_LOGI(TAG, "Trying to connect to %s", WIFI_SSID); + while (i--) { if (WiFi.status() == WL_CONNECTED) { // we now have wifi connection and try to do an OTA over wifi update @@ -92,6 +94,7 @@ void start_ota_update() { goto end; } vTaskDelay(5000 / portTICK_PERIOD_MS); + WiFi.reconnect(); } // wifi did not connect From 4370abe824ed5b64c6554630ae44b393f3b34507 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Mon, 5 Nov 2018 17:27:17 +0100 Subject: [PATCH 30/36] v1.6.6 --- platformio.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platformio.ini b/platformio.ini index 23291c06d..ccdc695b4 100644 --- a/platformio.ini +++ b/platformio.ini @@ -6,7 +6,7 @@ ; ---> SELECT TARGET PLATFORM HERE! <--- [platformio] -;env_default = generic +env_default = generic ;env_default = ebox ;env_default = eboxtube ;env_default = heltec @@ -17,7 +17,7 @@ ;env_default = ttgov21new ;env_default = ttgobeam ;env_default = lopy -env_default = lopy4 +;env_default = lopy4 ;env_default = fipy ;env_default = lolin32litelora ;env_default = lolin32lora From 8ae5b6e9708af901b5bd6ff1122437c17e95593b Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Mon, 5 Nov 2018 21:27:28 +0100 Subject: [PATCH 31/36] ota.cpp: improved software version comparision function --- include/ota.h | 1 + src/ota.cpp | 40 ++++++++++++---------------------------- 2 files changed, 13 insertions(+), 28 deletions(-) diff --git a/include/ota.h b/include/ota.h index 3c953ac06..542307624 100644 --- a/include/ota.h +++ b/include/ota.h @@ -10,6 +10,7 @@ #include #include #include +#include int do_ota_update(); void start_ota_update(); diff --git a/src/ota.cpp b/src/ota.cpp index b318506b0..434bfaa5a 100644 --- a/src/ota.cpp +++ b/src/ota.cpp @@ -327,38 +327,22 @@ void show_progress(unsigned long current, unsigned long size) { } #endif -// helper function to compare two versions. Returns 1 if v2 is -// smaller, -1 if v1 is smaller, 0 if equal +// helper function to convert strings into lower case +bool comp(char s1, char s2) { return tolower(s1) < tolower(s2); } +// helper function to lexicographically compare two versions. Returns 1 if v2 is +// smaller, -1 if v1 is smaller, 0 if equal int version_compare(const String v1, const String v2) { - // vnum stores each numeric part of version - int vnum1 = 0, vnum2 = 0; - - // loop until both string are processed - for (int i = 0, j = 0; (i < v1.length() || j < v2.length());) { - // storing numeric part of version 1 in vnum1 - while (i < v1.length() && v1[i] != '.') { - vnum1 = vnum1 * 10 + (v1[i] - '0'); - i++; - } - // storing numeric part of version 2 in vnum2 - while (j < v2.length() && v2[j] != '.') { - vnum2 = vnum2 * 10 + (v2[j] - '0'); - j++; - } + if (v1 == v2) + return 0; - if (vnum1 > vnum2) - return 1; - if (vnum2 > vnum1) - return -1; + const char *a1 = v1.c_str(), *a2 = v2.c_str(); - // if equal, reset variables and go for next numeric - // part - vnum1 = vnum2 = 0; - i++; - j++; - } - return 0; + if (lexicographical_compare(a1, a1 + strlen(a1), a2, a2 + strlen(a2), comp)) + return -1; + else + return 1; } + #endif // USE_OTA \ No newline at end of file From b0fa5e9021d8134930fbb513b493fdfd22e4bbc0 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Mon, 5 Nov 2018 21:40:07 +0100 Subject: [PATCH 32/36] OTA battery check --- src/battery.cpp | 7 ++++++- src/ota.cpp | 12 ++++-------- src/paxcounter.conf | 2 +- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/battery.cpp b/src/battery.cpp index 0e8949656..367a4678c 100644 --- a/src/battery.cpp +++ b/src/battery.cpp @@ -50,8 +50,13 @@ uint16_t read_voltage() { } bool batt_sufficient() { +#ifdef HAS_BATTERY_PROBE uint16_t volts = read_voltage(); - return (( volts < 1000 ) || (volts > OTA_MIN_BATT)); // no battery or battery sufficient + return ((volts < 1000) || + (volts > OTA_MIN_BATT)); // no battery or battery sufficient +#else + return true; +#endif } #endif // HAS_BATTERY_PROBE \ No newline at end of file diff --git a/src/ota.cpp b/src/ota.cpp index 434bfaa5a..ae9dab05a 100644 --- a/src/ota.cpp +++ b/src/ota.cpp @@ -40,15 +40,11 @@ inline String getHeaderValue(String header, String headerName) { void start_ota_update() { - /* // check battery status if we can before doing ota - #ifdef HAS_BATTERY_PROBE - if (!batt_sufficient()) { - ESP_LOGW(TAG, "Battery voltage %dmV too low for OTA", batt_voltage); - return; - } - #endif - */ + if (!batt_sufficient()) { + ESP_LOGE(TAG, "Battery voltage %dmV too low for OTA", batt_voltage); + return; + } switch_LED(LED_ON); diff --git a/src/paxcounter.conf b/src/paxcounter.conf index a4bb32ad4..629954942 100644 --- a/src/paxcounter.conf +++ b/src/paxcounter.conf @@ -69,7 +69,7 @@ #define USE_OTA 1 // Comment out to disable OTA update #define WIFI_MAX_TRY 5 // maximum number of wifi connect attempts for OTA update [default = 20] #define OTA_MAX_TRY 5 // maximum number of attempts for OTA download and write to flash [default = 3] -#define OTA_MIN_BATT 3700 // minimum battery level for OTA [millivolt] +#define OTA_MIN_BATT 3600 // minimum battery level for OTA [millivolt] #define RESPONSE_TIMEOUT_MS 60000 // firmware binary server connection timeout [milliseconds] // LMIC settings From 22577ea92a2425d36b31476aac8e1e45a8b16910 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Mon, 5 Nov 2018 21:43:22 +0100 Subject: [PATCH 33/36] battery.cpp sanitized --- src/battery.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/battery.cpp b/src/battery.cpp index 367a4678c..bb2ffce79 100644 --- a/src/battery.cpp +++ b/src/battery.cpp @@ -1,5 +1,3 @@ -#ifdef HAS_BATTERY_PROBE - #include "globals.h" // Local logging tag @@ -14,6 +12,7 @@ static const adc_atten_t atten = ADC_ATTEN_DB_11; static const adc_unit_t unit = ADC_UNIT_1; void calibrate_voltage(void) { +#ifdef HAS_BATTERY_PROBE // configure ADC ESP_ERROR_CHECK(adc1_config_width(ADC_WIDTH_BIT_12)); ESP_ERROR_CHECK(adc1_config_channel_atten(adc_channel, atten)); @@ -30,9 +29,11 @@ void calibrate_voltage(void) { } else { ESP_LOGI(TAG, "ADC characterization based on default reference voltage"); } +#endif } uint16_t read_voltage() { +#ifdef HAS_BATTERY_PROBE // multisample ADC uint32_t adc_reading = 0; for (int i = 0; i < NO_OF_SAMPLES; i++) { @@ -47,6 +48,9 @@ uint16_t read_voltage() { #endif ESP_LOGD(TAG, "Raw: %d / Voltage: %dmV", adc_reading, voltage); return voltage; +#else + return 0; +#endif } bool batt_sufficient() { @@ -57,6 +61,4 @@ bool batt_sufficient() { #else return true; #endif -} - -#endif // HAS_BATTERY_PROBE \ No newline at end of file +} \ No newline at end of file From bb9da23905327b706bfd57efd3047fe519da7306 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Mon, 5 Nov 2018 22:00:01 +0100 Subject: [PATCH 34/36] v1.6.62 --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index ccdc695b4..249fb87a0 100644 --- a/platformio.ini +++ b/platformio.ini @@ -29,7 +29,7 @@ description = Paxcounter is a proof-of-concept ESP32 device for metering passeng [common] ; for release_version use max. 10 chars total, use any decimal format like "a.b.c" -release_version = 1.6.6 +release_version = 1.6.62 ; DEBUG LEVEL: For production run set to 0, otherwise device will leak RAM while running! ; 0=None, 1=Error, 2=Warn, 3=Info, 4=Debug, 5=Verbose debug_level = 0 From a66021a84817a95a5815d8a8d29a61330bfa1b0c Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Mon, 5 Nov 2018 22:15:15 +0100 Subject: [PATCH 35/36] battery.cpp: bugfix compiler directives --- src/battery.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/battery.cpp b/src/battery.cpp index bb2ffce79..c7a43070c 100644 --- a/src/battery.cpp +++ b/src/battery.cpp @@ -3,6 +3,7 @@ // Local logging tag static const char TAG[] = "main"; +#ifdef HAS_BATTERY_PROBE esp_adc_cal_characteristics_t *adc_characs = (esp_adc_cal_characteristics_t *)calloc( 1, sizeof(esp_adc_cal_characteristics_t)); @@ -10,6 +11,7 @@ esp_adc_cal_characteristics_t *adc_characs = static const adc1_channel_t adc_channel = HAS_BATTERY_PROBE; static const adc_atten_t atten = ADC_ATTEN_DB_11; static const adc_unit_t unit = ADC_UNIT_1; +#endif void calibrate_voltage(void) { #ifdef HAS_BATTERY_PROBE From 8d2aeaca9f8b0095593181323c34894866b73722 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Mon, 5 Nov 2018 23:09:26 +0100 Subject: [PATCH 36/36] update platformio-espressif32 v1.5.0 --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 249fb87a0..026c56f29 100644 --- a/platformio.ini +++ b/platformio.ini @@ -38,7 +38,7 @@ upload_protocol = esptool ;upload_protocol = custom extra_scripts = pre:build.py keyfile = ota.conf -platform_espressif32 = espressif32@1.4.0 +platform_espressif32 = espressif32@1.5.0 board_build.partitions = min_spiffs.csv monitor_speed = 115200 lib_deps_all =