From 62b9b1255f9f9a6ab0b701819905413d4052641e Mon Sep 17 00:00:00 2001 From: localhorst Date: Sat, 16 Jan 2021 00:23:02 +0100 Subject: [PATCH 01/21] added app demo code --- .gitignore | 3 + components/mesh_ota/CMakeLists.txt | 2 +- components/mesh_ota/https_client.c | 292 +++++++++++++++++++++ components/mesh_ota/include/Mesh_network.h | 7 +- components/mesh_ota/include/https_client.h | 75 ++++++ main/Blinky_LED.c | 124 +++++++++ main/Blinky_LED.h | 35 +++ main/CMakeLists.txt | 2 +- main/Main.c | 2 + 9 files changed, 537 insertions(+), 5 deletions(-) create mode 100644 components/mesh_ota/https_client.c create mode 100644 components/mesh_ota/include/https_client.h create mode 100644 main/Blinky_LED.c create mode 100644 main/Blinky_LED.h diff --git a/.gitignore b/.gitignore index 37d7f21..19e3a2a 100644 --- a/.gitignore +++ b/.gitignore @@ -57,3 +57,6 @@ build/ test/build/ *.old + +*.orig + diff --git a/components/mesh_ota/CMakeLists.txt b/components/mesh_ota/CMakeLists.txt index c524a09..5484c68 100644 --- a/components/mesh_ota/CMakeLists.txt +++ b/components/mesh_ota/CMakeLists.txt @@ -1,4 +1,4 @@ -idf_component_register(SRCS "Mesh_network_handler.c" "Mesh_network.c" "Mesh_OTA.c" +idf_component_register(SRCS "https_client.c" "Mesh_network_handler.c" "Mesh_network.c" "Mesh_OTA.c" INCLUDE_DIRS "include" REQUIRES nvs_flash esp_http_client diff --git a/components/mesh_ota/https_client.c b/components/mesh_ota/https_client.c new file mode 100644 index 0000000..cb4d204 --- /dev/null +++ b/components/mesh_ota/https_client.c @@ -0,0 +1,292 @@ +#include "https_client.h" + +static const char *TAG = "https_client"; + +static const char *REQUEST = "GET " CONFIG_OTA_HTTPS_URL " HTTP/1.1\r\n" + "Host: "CONFIG_OTA_HTTPS_SERVER_COMMON_NAME"\r\n" + "User-Agent: esp-idf/1.0 esp32\r\n" + "Authorization: Basic " CONFIG_OTA_HTTPS_AUTH "\r\n" + "\r\n"; + + +static HTTPS_Client_t sHTTPS_ClientConfig; + +https_client_ret_t https_clientInitEmbedTLS(); +https_client_ret_t https_clientConnectToServer(); +https_client_ret_t https_clientValidateServer(); +https_client_ret_t https_clientSendRequest(); + +https_client_ret_t https_clientInitialize() +{ + https_client_ret_t i32RetHTTPClient = HTTPS_CLIENT_OK; + + i32RetHTTPClient = https_clientInitEmbedTLS(); + + if(i32RetHTTPClient == HTTPS_CLIENT_OK) + { + i32RetHTTPClient = https_clientConnectToServer(); + } + + if(i32RetHTTPClient == HTTPS_CLIENT_OK) + { + i32RetHTTPClient = https_clientValidateServer(); + } + + if(i32RetHTTPClient == HTTPS_CLIENT_OK) + { + i32RetHTTPClient = https_clientSendRequest(); + } + + switch (i32RetHTTPClient) + { + case HTTPS_CLIENT_ERROR_INIT_EMBEDTLS: + ESP_LOGE(TAG, "Unable to initialize EmbedTLS"); + i32RetHTTPClient = HTTPS_CLIENT_ERROR; + break; + case HTTPS_CLIENT_ERROR_INIT_CONNECT_TWO_SERVER: + ESP_LOGE(TAG, "Unable to connect to server"); + i32RetHTTPClient = HTTPS_CLIENT_ERROR; + break; + case HTTPS_CLIENT_ERROR_INIT_VALIDATE_SERVER: + ESP_LOGE(TAG, "Unable to validate the server"); + i32RetHTTPClient = HTTPS_CLIENT_ERROR; + break; + case HTTPS_CLIENT_ERROR_INIT_SEND_REQUEST: + ESP_LOGE(TAG, "Unable to send request to server"); + i32RetHTTPClient = HTTPS_CLIENT_ERROR; + break; + case HTTPS_CLIENT_OK: + ESP_LOGI(TAG, "HTTPS Client successfully initialized"); + i32RetHTTPClient = HTTPS_CLIENT_OK; + break; + default: + i32RetHTTPClient = HTTPS_CLIENT_ERROR; + ESP_LOGE(TAG, "Unknown error while init https client"); + break; + } + return i32RetHTTPClient; +} + +https_client_ret_t https_clientRetrieveData(char* pu8Data, uint32_t* pu32DataLenght, uint32_t* pu32BytesRead) +{ + https_client_ret_t i32RetHTTPClient = HTTPS_CLIENT_OK; + int32_t i32RetRetrieveData = ESP_OK; + bool bRetriveData = true; + + bzero(pu8Data, *pu32DataLenght); + *pu32BytesRead = 0U; + + while (bRetriveData) + { + //Reading HTTP response + i32RetRetrieveData = mbedtls_ssl_read(&sHTTPS_ClientConfig.ssl, (unsigned char *)(pu8Data+(*pu32BytesRead)), ((*pu32DataLenght)-(*pu32BytesRead))); + + if(i32RetRetrieveData > 0) + { + //Data received + *pu32BytesRead = *pu32BytesRead + i32RetRetrieveData; + + if(*pu32DataLenght > 0) + { + //buffer not full yet --> read some more + bRetriveData = true; + } + else + { + //buffer full --> stop reading + bRetriveData = false; + } + } + + if(i32RetRetrieveData == 0) + { + //all data read --> stop reading + bRetriveData = false; + pu32BytesRead = 0; + } + + if(i32RetRetrieveData == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) + { + //connection is going to be closed + i32RetHTTPClient = HTTPS_CLIENT_ERROR; + bRetriveData = false; + } + } + return i32RetHTTPClient; +} + +https_client_ret_t https_clientDeinitialize() +{ + https_client_ret_t i32RetHTTPClient = HTTPS_CLIENT_OK; + + i32RetHTTPClient = mbedtls_ssl_close_notify(&sHTTPS_ClientConfig.ssl); //close session + + if(i32RetHTTPClient != ESP_OK) + { + ESP_LOGE(TAG, "mbedtls_ssl_close_notify returned 0x%x", i32RetHTTPClient); + } + + mbedtls_ssl_session_reset(&sHTTPS_ClientConfig.ssl); //reset embedssl + mbedtls_net_free(&sHTTPS_ClientConfig.server_fd); //free ram + + return i32RetHTTPClient; +} + +https_client_ret_t https_clientInitEmbedTLS() { + + https_client_ret_t i32RetHTTPClient = HTTPS_CLIENT_OK; + int32_t i32RetEmbedTLS = ESP_OK; + + mbedtls_ssl_init(&sHTTPS_ClientConfig.ssl); + mbedtls_x509_crt_init(&sHTTPS_ClientConfig.cacert); + mbedtls_ctr_drbg_init(&sHTTPS_ClientConfig.ctr_drbg); + mbedtls_ssl_config_init(&sHTTPS_ClientConfig.conf); + mbedtls_entropy_init(&sHTTPS_ClientConfig.entropy); + + i32RetEmbedTLS = mbedtls_ctr_drbg_seed(&sHTTPS_ClientConfig.ctr_drbg, mbedtls_entropy_func, &sHTTPS_ClientConfig.entropy, NULL, 0); + + if(i32RetEmbedTLS!= ESP_OK) + { + ESP_LOGE(TAG, "mbedtls_ctr_drbg_seed returned %d", i32RetEmbedTLS); + } + + if(i32RetEmbedTLS == ESP_OK) + { + //Attaching the certificate bundle + i32RetEmbedTLS = esp_crt_bundle_attach(&sHTTPS_ClientConfig.conf); + if(i32RetEmbedTLS != ESP_OK) + { + ESP_LOGE(TAG, "esp_crt_bundle_attach returned 0x%x\n\n", i32RetEmbedTLS); + } + } + + if(i32RetEmbedTLS == ESP_OK) + { + //Setting hostname for TLS session. + i32RetEmbedTLS = mbedtls_ssl_set_hostname(&sHTTPS_ClientConfig.ssl, CONFIG_OTA_HTTPS_SERVER_COMMON_NAME); + // Hostname set here should match CN in server certificate + if(i32RetEmbedTLS != ESP_OK) + { + ESP_LOGE(TAG, "mbedtls_ssl_set_hostname returned 0x%x", i32RetEmbedTLS); + } + } + if(i32RetEmbedTLS == ESP_OK) + { + //Setting up the SSL/TLS structure + i32RetEmbedTLS = mbedtls_ssl_config_defaults(&sHTTPS_ClientConfig.conf, + MBEDTLS_SSL_IS_CLIENT, + MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT); + + if(i32RetEmbedTLS != ESP_OK) + { + ESP_LOGE(TAG, "mbedtls_ssl_config_defaults returned %d", i32RetEmbedTLS); + } + } + + if(i32RetEmbedTLS == ESP_OK) + { + mbedtls_ssl_conf_authmode(&sHTTPS_ClientConfig.conf, MBEDTLS_SSL_VERIFY_REQUIRED); + mbedtls_ssl_conf_ca_chain(&sHTTPS_ClientConfig.conf, &sHTTPS_ClientConfig.cacert, NULL); + mbedtls_ssl_conf_rng(&sHTTPS_ClientConfig.conf, mbedtls_ctr_drbg_random, &sHTTPS_ClientConfig.ctr_drbg); + + i32RetEmbedTLS = mbedtls_ssl_setup(&sHTTPS_ClientConfig.ssl, &sHTTPS_ClientConfig.conf); + if(i32RetEmbedTLS != ESP_OK) + { + ESP_LOGE(TAG, "mbedtls_ssl_setup returned -0x%x\n\n", i32RetEmbedTLS); + } + } + + if(i32RetEmbedTLS == ESP_OK) + { + mbedtls_net_init(&sHTTPS_ClientConfig.server_fd); + } + + if (i32RetEmbedTLS != ESP_OK) + { + i32RetHTTPClient = HTTPS_CLIENT_ERROR_INIT_EMBEDTLS; + } + + return i32RetHTTPClient; +} + +https_client_ret_t https_clientConnectToServer() +{ + https_client_ret_t i32RetHTTPClient = HTTPS_CLIENT_OK; + int32_t i32RetServerConnect = ESP_OK; + + //Connecting to server + i32RetServerConnect = mbedtls_net_connect(&sHTTPS_ClientConfig.server_fd, CONFIG_OTA_HTTPS_SERVER_COMMON_NAME, CONFIG_OTA_HTTPS_SERVER_PORT, MBEDTLS_NET_PROTO_TCP); + if (i32RetServerConnect != ESP_OK) + { + ESP_LOGE(TAG, "mbedtls_net_connect returned %x", i32RetServerConnect); + } + + if(i32RetServerConnect == ESP_OK) + { + mbedtls_ssl_set_bio(&sHTTPS_ClientConfig.ssl, &sHTTPS_ClientConfig.server_fd, mbedtls_net_send, mbedtls_net_recv, NULL); + + //Performing the SSL/TLS handshake + while ((i32RetServerConnect = mbedtls_ssl_handshake(&sHTTPS_ClientConfig.ssl)) != 0) + { + if ((i32RetServerConnect != MBEDTLS_ERR_SSL_WANT_READ) && (i32RetServerConnect != MBEDTLS_ERR_SSL_WANT_WRITE)) + { + ESP_LOGE(TAG, "mbedtls_ssl_handshake returned 0x%x", i32RetServerConnect); + } + } + } + + if(i32RetServerConnect != ESP_OK) + { + i32RetHTTPClient = HTTPS_CLIENT_ERROR_INIT_CONNECT_TWO_SERVER; + } + return i32RetHTTPClient; +} + +https_client_ret_t https_clientValidateServer() +{ + https_client_ret_t i32RetHTTPClient = HTTPS_CLIENT_OK; + int32_t i32RetValidateServer = ESP_OK; + + //Verifying peer X.509 certificate + if ((i32RetValidateServer = mbedtls_ssl_get_verify_result(&sHTTPS_ClientConfig.ssl)) != 0) + { + ESP_LOGE(TAG, "Failed to verify peer certificate!"); + } + + if(i32RetValidateServer != ESP_OK) + { + i32RetHTTPClient = HTTPS_CLIENT_ERROR_INIT_VALIDATE_SERVER; + } + return i32RetHTTPClient; +} + +https_client_ret_t https_clientSendRequest() +{ + https_client_ret_t i32RetHTTPClient = HTTPS_CLIENT_OK; + int32_t i32RetSendRequest = ESP_OK; + uint32_t u32WrittenBytes = 0; + bool bWrite = true; //flag to stop loop + + //Writing HTTP request + while((u32WrittenBytes < strlen(REQUEST)) && bWrite) + { + i32RetSendRequest = mbedtls_ssl_write(&sHTTPS_ClientConfig.ssl, + (const unsigned char *)REQUEST + u32WrittenBytes, + strlen(REQUEST) - u32WrittenBytes); + if (i32RetSendRequest >= 0) + { + //bytes written + u32WrittenBytes += i32RetSendRequest; + } else if (i32RetSendRequest != MBEDTLS_ERR_SSL_WANT_WRITE && i32RetSendRequest != MBEDTLS_ERR_SSL_WANT_READ) { + ESP_LOGE(TAG, "mbedtls_ssl_write returned 0x%x", i32RetSendRequest); + bWrite = false; + } + } + + if(bWrite == false) + { + i32RetHTTPClient = HTTPS_CLIENT_ERROR_INIT_SEND_REQUEST; + } + return i32RetHTTPClient; +} diff --git a/components/mesh_ota/include/Mesh_network.h b/components/mesh_ota/include/Mesh_network.h index bb303c0..7c60526 100644 --- a/components/mesh_ota/include/Mesh_network.h +++ b/components/mesh_ota/include/Mesh_network.h @@ -47,9 +47,10 @@ #endif -struct mesh_packet +struct meshPacket { - enum ota_mesh_packet_type { + enum otaMeshPacketType + { APP_Data, //data for application OTA_Version_Request, //send own version in payload OTA_Version_Respone, //send own version in payload @@ -60,7 +61,7 @@ struct mesh_packet uint8_t au8Payload[1024]; }; -typedef struct mesh_packet MESH_PACKET_t; +typedef struct meshPacket MESH_PACKET_t; extern bool bIsMeshConnected; extern int32_t i32MeshLayer; diff --git a/components/mesh_ota/include/https_client.h b/components/mesh_ota/include/https_client.h new file mode 100644 index 0000000..60d192b --- /dev/null +++ b/components/mesh_ota/include/https_client.h @@ -0,0 +1,75 @@ +#ifndef H_HTTPS_CLIENT +#define H_HTTPS_CLIENT + +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_wifi.h" +#include "esp_event.h" +#include "esp_log.h" +#include "esp_system.h" +#include "nvs_flash.h" +#include "esp_netif.h" + +#include "lwip/err.h" +#include "lwip/sockets.h" +#include "lwip/sys.h" +#include "lwip/netdb.h" +#include "lwip/dns.h" + +#include "mbedtls/platform.h" +#include "mbedtls/net_sockets.h" +#include "mbedtls/esp_debug.h" +#include "mbedtls/ssl.h" +#include "mbedtls/entropy.h" +#include "mbedtls/ctr_drbg.h" +#include "mbedtls/error.h" +#include "mbedtls/certs.h" +#include "esp_crt_bundle.h" + +#ifndef CONFIG_OTA_HTTPS_URL +#define CONFIG_OTA_HTTPS_URL "https://exmaple.com/theImage.bin" +#endif + +#ifndef CONFIG_OTA_HTTPS_SERVER_PORT +#define CONFIG_OTA_HTTPS_SERVER_PORT "443" +#endif + +#ifndef CONFIG_OTA_HTTPS_AUTH +#define CONFIG_OTA_HTTPS_AUTH "base64(user:password)" +#endif + +#ifndef CONFIG_OTA_HTTPS_SERVER_COMMON_NAME +#define CONFIG_OTA_HTTPS_SERVER_COMMON_NAME "exmaple.com" +#endif + +#define HTTPS_CLIENT_OK 0 +#define HTTPS_CLIENT_ERROR -1 +#define HTTPS_CLIENT_ERROR_INIT_EMBEDTLS -2 +#define HTTPS_CLIENT_ERROR_INIT_CONNECT_TWO_SERVER -3 +#define HTTPS_CLIENT_ERROR_INIT_VALIDATE_SERVER -4 +#define HTTPS_CLIENT_ERROR_INIT_SEND_REQUEST -5 + +struct HTTPS_Client +{ + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; + mbedtls_ssl_context ssl; + mbedtls_x509_crt cacert; + mbedtls_ssl_config conf; + mbedtls_net_context server_fd; +}; + +typedef int32_t https_client_ret_t; +typedef struct HTTPS_Client HTTPS_Client_t; + +https_client_ret_t https_clientInitialize(); +https_client_ret_t https_clientRetrieveData(char* pu8Data, uint32_t* pu32DataLenght, uint32_t* pu32BytesRead); +https_client_ret_t https_clientDeinitialize(); + +#endif /* H_HTTPS_CLIENT */ + + + + diff --git a/main/Blinky_LED.c b/main/Blinky_LED.c new file mode 100644 index 0000000..95e262c --- /dev/null +++ b/main/Blinky_LED.c @@ -0,0 +1,124 @@ + + +#include "Blinky_LED.h" + +static const char *LOG_TAG = "blinky_led"; +static bool bLEDisOn = true; + +xQueueHandle queueBlinkyLEDPackets; + +esp_err_t errBlinkyLEDInitialize() +{ + esp_err_t err = ESP_OK; + BaseType_t xReturned; + + vGPIOInitialize(); + + queueBlinkyLEDPackets = xQueueCreate(5, sizeof (BLINKY_PACKET_t)); + if (queueBlinkyLEDPackets == 0) // Queue not created + { + ESP_LOGE(LOG_TAG, "Unable to create Queue for Application Packets"); + err = ESP_FAIL; + } + + if(err == ESP_OK) + { + xReturned = xTaskCreate(vTaskReadUserInput, "vTaskReadUserInput", 2048, NULL, 5, NULL); + if(xReturned != pdPASS) + { + err = ESP_FAIL; + } + } + + if(err == ESP_OK) + { + xReturned = xTaskCreate(vTaskReceiveData, "vTaskReceiveData", 2048, NULL, 5, NULL); + if(xReturned != pdPASS) + { + err = ESP_FAIL; + } + } + return err; +} + +void vGPIOInitialize() +{ + gpio_config_t gpioConf; + + //LED as Output + gpio_reset_pin(GPIO_LED); + gpio_set_direction(GPIO_LED, GPIO_MODE_OUTPUT); + + //BTN as Input + gpioConf.intr_type = GPIO_INTR_DISABLE; + gpioConf.mode = GPIO_MODE_INPUT; + gpioConf.pin_bit_mask = GPIO_INPUT_PIN_SEL; + gpioConf.pull_down_en = 0; + gpioConf.pull_up_en = 1; + gpio_config(&gpioConf); +} + +void vTaskReadUserInput(void *arg) +{ + BLINKY_PACKET_t bTmpStateLED = LED_OFF; + while(true) + { + if(gpio_get_level(GPIO_BOOT_BTN) == 0) + { + if(bLEDisOn == false) + { + ESP_LOGI(LOG_TAG,"switch ON"); + bTmpStateLED = LED_ON; + } + else + { + ESP_LOGI(LOG_TAG,"switch OFF"); + bTmpStateLED = LED_OFF; + } + + if (xQueueSend(queueBlinkyLEDPackets, &bTmpStateLED, portMAX_DELAY) != pdPASS) + { + ESP_LOGE(LOG_TAG, "Unable to push packet into Queue"); + } + vTaskDelay(200 / portTICK_PERIOD_MS); + } + vTaskDelay(50 / portTICK_PERIOD_MS); + } +} + +void vTaskReceiveData(void *arg) +{ + BLINKY_PACKET_t bTmpStateLED = LED_OFF; + + while (1) + { + if (xQueueReceive(queueBlinkyLEDPackets, &bTmpStateLED, portMAX_DELAY) != pdTRUE) + { + ESP_LOGE(LOG_TAG, "Unable to receive packet from Queue"); + } + else + { + //Successfully RECEIVED the packet + switch (bTmpStateLED) + { + case LED_ON: + bLEDisOn = true; + gpio_set_level(GPIO_LED, 1); //switch on + ESP_LOGI(LOG_TAG,"rec ON"); + break; + + case LED_OFF: + bLEDisOn = false; + gpio_set_level(GPIO_LED, 0); //switch off + ESP_LOGI(LOG_TAG,"rec OFF"); + break; + + default: + bLEDisOn = false; + gpio_set_level(GPIO_LED, 0); //switch off + break; + } + } + vTaskDelay(200 / portTICK_PERIOD_MS); + } +} \ No newline at end of file diff --git a/main/Blinky_LED.h b/main/Blinky_LED.h new file mode 100644 index 0000000..ab6b5e2 --- /dev/null +++ b/main/Blinky_LED.h @@ -0,0 +1,35 @@ +#ifndef H_BLINKY_LED +#define H_BLINKY_LED + +#include +#include "esp_wifi.h" +#include "esp_system.h" +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "driver/gpio.h" + +#include "Mesh_OTA.h" + +#define GPIO_BOOT_BTN 0 +#define GPIO_LED 2 + +#define GPIO_INPUT_PIN_SEL (1ULL< Date: Sat, 16 Jan 2021 18:23:10 +0100 Subject: [PATCH 02/21] completed demo app blinky_led --- components/mesh_ota/Mesh_OTA.c | 10 +- components/mesh_ota/Mesh_network.c | 79 +++-- components/mesh_ota/Mesh_network_handler.c | 344 ++++++++++----------- components/mesh_ota/include/Mesh_OTA.h | 4 +- components/mesh_ota/include/Mesh_network.h | 23 +- components/mesh_ota/include/https_client.h | 4 +- main/Blinky_LED.c | 102 ++++-- main/Blinky_LED.h | 26 +- main/Main.c | 4 +- sdkconfig | 2 +- 10 files changed, 348 insertions(+), 250 deletions(-) diff --git a/components/mesh_ota/Mesh_OTA.c b/components/mesh_ota/Mesh_OTA.c index 4f7b221..1bad54c 100644 --- a/components/mesh_ota/Mesh_OTA.c +++ b/components/mesh_ota/Mesh_OTA.c @@ -4,12 +4,12 @@ * 999.999.999 * Return true if remote version is newer (higher) than local version */ -bool bNewerVersion(const char* pu8Local, const char* pu8Remote) +bool bNewerVersion(const char* pu8Local, const char* pu8Remote) { char u8LocalTmp[12]; //local version char u8RemoteTmp[12]; //remote version - char* pu8saveptrLocal; //context for strok_r - char* pu8saveptrRemote; //context for strok_r + char* pu8saveptrLocal; //context for strok_r + char* pu8saveptrRemote; //context for strok_r bool bReturn = false; //flag to stop loop uint8_t u8Index = 0; //numbers counter in version string @@ -49,7 +49,7 @@ esp_err_t errFindImageStart(const char* pu8Data, uint32_t* pu32DataLenght, uint3 uint8_t u8SecondDotIndex = 0; *pu32StartOffset = 0U; //reset offset to zero - + while((u32DataIndex < *pu32DataLenght) && (bImageStartOffsetFound == false)) { //search for magic byte @@ -67,7 +67,7 @@ esp_err_t errFindImageStart(const char* pu8Data, uint32_t* pu32DataLenght, uint3 u32FirstDotOffset = (u32DataIndex+49+u8FirstDotIndex); } } - u8FirstDotIndex++; + u8FirstDotIndex++; } while ((u8SecondDotIndex < 3) && (u32SecondDotOffset == 0) && (u32FirstDotOffset != 0)) diff --git a/components/mesh_ota/Mesh_network.c b/components/mesh_ota/Mesh_network.c index 96f22ef..3cf3ac3 100644 --- a/components/mesh_ota/Mesh_network.c +++ b/components/mesh_ota/Mesh_network.c @@ -4,11 +4,13 @@ static const char *LOG_TAG = "mesh_network"; static uint8_t tx_buf[CONFIG_MESH_MESSAGE_SIZE] = { 0, }; static uint8_t rx_buf[CONFIG_MESH_MESSAGE_SIZE] = { 0, }; -static uint8_t u8NodeMAC[6]; +uint8_t u8ownMAC[6]; esp_netif_t* netif_sta; bool bIsMeshConnected; int32_t i32MeshLayer; -mesh_addr_t mesh_parent_addr; +mesh_addr_t meshParentAddr; +void (*pAppRxHandle)(uint8_t*, uint8_t* ); + esp_err_t errMeshNetworkInitialize() { @@ -74,7 +76,7 @@ esp_err_t errMeshNetworkInitialize() /* mesh start */ ERROR_CHECK(esp_mesh_start()); - ERROR_CHECK(esp_base_mac_addr_get(u8NodeMAC)) + ERROR_CHECK(esp_base_mac_addr_get(u8ownMAC)) //debug info ESP_LOGD(LOG_TAG, "mesh starts successfully, heap:%d, %s<%d>%s, ps:%d\n", esp_get_minimum_free_heap_size(), @@ -82,7 +84,7 @@ esp_err_t errMeshNetworkInitialize() esp_mesh_get_topology(), esp_mesh_get_topology() ? "(chain)":"(tree)", esp_mesh_is_ps_enabled()); - ESP_LOGI(LOG_TAG, "Node MAC: \"%x:%x:%x:%x:%x:%x\" ", u8NodeMAC[0], u8NodeMAC[1], u8NodeMAC[2], u8NodeMAC[3], u8NodeMAC[4], u8NodeMAC[5]); + ESP_LOGI(LOG_TAG, "Node MAC: \"%x:%x:%x:%x:%x:%x\" ", u8ownMAC[0], u8ownMAC[1], u8ownMAC[2], u8ownMAC[3], u8ownMAC[4], u8ownMAC[5]); return ESP_OK; } @@ -97,7 +99,6 @@ esp_err_t errMeshNetworkInitializeWiFi() ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_FLASH)); ERROR_CHECK(esp_wifi_start()); return err; - } esp_err_t errMeshNetworkInitializeRouter(mesh_cfg_t* cfg) @@ -141,7 +142,7 @@ esp_err_t errGetChildren(mesh_addr_t* pChildren, uint16_t* pu16ChildrenSize) { for(uint16_t index = 0; index < esp_mesh_get_routing_table_size(); index++) { - if(! (bCheckMACEquality(u8NodeMAC, route_table[index].addr)) ) + if(! (bCheckMACEquality(u8ownMAC, route_table[index].addr)) ) { //child node //ESP_LOGI(MESH_TAG, "adding Node: \"0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\" ", route_table[index].addr[0], route_table[index].addr[1], route_table[index].addr[2], route_table[index].addr[3], route_table[index].addr[4], route_table[index].addr[5]); @@ -153,6 +154,37 @@ esp_err_t errGetChildren(mesh_addr_t* pChildren, uint16_t* pu16ChildrenSize) return err; } +esp_err_t errGetParentNode(mesh_addr_t* pMeshParentAddr) +{ + esp_err_t err = ESP_OK; + + if(bIsMeshConnected == false) + { + err = ESP_FAIL; + } + else + { + memcpy(pMeshParentAddr, &meshParentAddr, sizeof(mesh_addr_t)); + } + return err; +} + +void vGetOwnAddr(mesh_addr_t* pMeshOwnAddr) +{ + memcpy(pMeshOwnAddr->addr, u8ownMAC, 6); +} + +bool bIsRootNode() +{ + return esp_mesh_is_root(); +} + +esp_err_t errMeshNetworkSetAppReceiveHandle(void (*pAppRxHandleTmp)(uint8_t * pu8Data, uint8_t* pu8Sender)) +{ + pAppRxHandle = pAppRxHandleTmp; //set handle from app as receive handle if an app packet is received + return ESP_OK; +} + esp_err_t errSendMeshPacket(mesh_addr_t* pAddrDest, MESH_PACKET_t* pPacket) { esp_err_t err; @@ -162,11 +194,12 @@ esp_err_t errSendMeshPacket(mesh_addr_t* pAddrDest, MESH_PACKET_t* pPacket) data.proto = MESH_PROTO_BIN; data.tos = MESH_TOS_P2P; memcpy(tx_buf, (uint8_t *)pPacket, sizeof(MESH_PACKET_t)); + err = esp_mesh_send(pAddrDest, &data, MESH_DATA_P2P, NULL, 0); + return err; } - esp_err_t errStartReceiveTask() { esp_err_t err = ESP_OK; @@ -199,34 +232,27 @@ void vTaskReceiveMeshData(void *arg) ESP_LOGE(LOG_TAG, "err:0x%x, size:%d", err, data.size); continue; } - - -/* - struct ota_mesh_packet packet; - memcpy(&packet, (uint8_t *)rx_buf, sizeof(struct ota_mesh_packet)); + MESH_PACKET_t packet; + memcpy(&packet, (uint8_t *)rx_buf, sizeof(MESH_PACKET_t)); switch (packet.type) { - case APP_Version_Request: - ESP_LOGI(LOG_TAG, "recv: APP_Version_Request"); - packet.type=APP_Version_Response; - packet.au8Payload[0] = 42; //TODO get current running version - // ESP_ERROR_CHECK (esp_mesh_send_packet(&from, &packet)); //send back to parent + case APP_Data: + ESP_LOGD(LOG_TAG, "recv: APP_Data"); + //call the rx handle from app + pAppRxHandle(packet.au8Payload, from.addr); //hand over payload and sender of this mesh packet break; - case APP_Version_Response: - ESP_LOGI(LOG_TAG, "recv: APP_Version_Response - App Version %i: ", packet.au8Payload[0]); - //check if node is out-dated - // esp_mesh_ota_send(&from); + case OTA_Version_Request: + ESP_LOGI(LOG_TAG, "recv: OTA_Version_Request"); + break; + case OTA_Version_Respone: + ESP_LOGI(LOG_TAG, "recv: OTA_Version_Respone"); break; case OTA_Data: ESP_LOGI(LOG_TAG, "recv: OTA_Data"); - //esp_mesh_ota_receive(&from, &packet); - packet.type=OTA_ACK; - //ESP_ERROR_CHECK (esp_mesh_send_packet(&from, &packet)); //send back to parent break; case OTA_ACK: ESP_LOGI(LOG_TAG, "recv: OTA_ACK"); - //esp_mesh_ota_send(&from); break; case OTA_Complete: ESP_LOGI(LOG_TAG, "recv: OTA_Complete"); @@ -235,9 +261,6 @@ void vTaskReceiveMeshData(void *arg) ESP_LOGE(LOG_TAG, "recv: something"); break; }//end switch - - */ - } //end while } diff --git a/components/mesh_ota/Mesh_network_handler.c b/components/mesh_ota/Mesh_network_handler.c index 22e198a..f23c991 100644 --- a/components/mesh_ota/Mesh_network_handler.c +++ b/components/mesh_ota/Mesh_network_handler.c @@ -15,205 +15,205 @@ void vMeshEventHandler(void *arg, esp_event_base_t event_base, int32_t i32EventI static uint16_t last_layer = 0; switch (i32EventID) - { - case MESH_EVENT_STARTED: - { - esp_mesh_get_id(&id); - ESP_LOGI(LOG_TAG, "ID:"MACSTR"", MAC2STR(id.addr)); - bIsMeshConnected = false; - i32MeshLayer = esp_mesh_get_layer(); - } - break; + { + case MESH_EVENT_STARTED: + { + esp_mesh_get_id(&id); + ESP_LOGI(LOG_TAG, "ID:"MACSTR"", MAC2STR(id.addr)); + bIsMeshConnected = false; + i32MeshLayer = esp_mesh_get_layer(); + } + break; case MESH_EVENT_STOPPED: - { - ESP_LOGI(LOG_TAG, ""); - bIsMeshConnected = false; - i32MeshLayer = esp_mesh_get_layer(); - } - break; + { + ESP_LOGI(LOG_TAG, ""); + bIsMeshConnected = false; + i32MeshLayer = esp_mesh_get_layer(); + } + break; case MESH_EVENT_CHILD_CONNECTED: - { - mesh_event_child_connected_t *child_connected = (mesh_event_child_connected_t *)vpEventData; - ESP_LOGI(LOG_TAG, "aid:%d, "MACSTR"", - child_connected->aid, - MAC2STR(child_connected->mac)); - } - break; + { + mesh_event_child_connected_t *child_connected = (mesh_event_child_connected_t *)vpEventData; + ESP_LOGI(LOG_TAG, "aid:%d, "MACSTR"", + child_connected->aid, + MAC2STR(child_connected->mac)); + } + break; case MESH_EVENT_CHILD_DISCONNECTED: - { - mesh_event_child_disconnected_t *child_disconnected = (mesh_event_child_disconnected_t *)vpEventData; - ESP_LOGI(LOG_TAG, "aid:%d, "MACSTR"", - child_disconnected->aid, - MAC2STR(child_disconnected->mac)); - } - break; + { + mesh_event_child_disconnected_t *child_disconnected = (mesh_event_child_disconnected_t *)vpEventData; + ESP_LOGI(LOG_TAG, "aid:%d, "MACSTR"", + child_disconnected->aid, + MAC2STR(child_disconnected->mac)); + } + break; case MESH_EVENT_ROUTING_TABLE_ADD: - { - mesh_event_routing_table_change_t *routing_table = (mesh_event_routing_table_change_t *)vpEventData; - ESP_LOGW(LOG_TAG, "add %d, new:%d, layer:%d", - routing_table->rt_size_change, - routing_table->rt_size_new, i32MeshLayer); - } - break; + { + mesh_event_routing_table_change_t *routing_table = (mesh_event_routing_table_change_t *)vpEventData; + ESP_LOGW(LOG_TAG, "add %d, new:%d, layer:%d", + routing_table->rt_size_change, + routing_table->rt_size_new, i32MeshLayer); + } + break; case MESH_EVENT_ROUTING_TABLE_REMOVE: - { - mesh_event_routing_table_change_t *routing_table = (mesh_event_routing_table_change_t *)vpEventData; - ESP_LOGW(LOG_TAG, "remove %d, new:%d, layer:%d", - routing_table->rt_size_change, - routing_table->rt_size_new, i32MeshLayer); - } - break; + { + mesh_event_routing_table_change_t *routing_table = (mesh_event_routing_table_change_t *)vpEventData; + ESP_LOGW(LOG_TAG, "remove %d, new:%d, layer:%d", + routing_table->rt_size_change, + routing_table->rt_size_new, i32MeshLayer); + } + break; case MESH_EVENT_NO_PARENT_FOUND: - { - mesh_event_no_parent_found_t *no_parent = (mesh_event_no_parent_found_t *)vpEventData; - ESP_LOGI(LOG_TAG, "scan times:%d", - no_parent->scan_times); - /* TODO handler for the failure, maybe nominate themselves */ - } - break; + { + mesh_event_no_parent_found_t *no_parent = (mesh_event_no_parent_found_t *)vpEventData; + ESP_LOGI(LOG_TAG, "scan times:%d", + no_parent->scan_times); + /* TODO handler for the failure, maybe nominate themselves */ + } + break; case MESH_EVENT_PARENT_CONNECTED: + { + mesh_event_connected_t *connected = (mesh_event_connected_t *)vpEventData; + esp_mesh_get_id(&id); + i32MeshLayer = connected->self_layer; + memcpy(&meshParentAddr.addr, connected->connected.bssid, 6); + ESP_LOGI(LOG_TAG, "layer:%d-->%d, parent:"MACSTR"%s, ID:"MACSTR", duty:%d", + last_layer, i32MeshLayer, MAC2STR(meshParentAddr.addr), + esp_mesh_is_root() ? "" : (i32MeshLayer == 2) ? "" : "", //print own node title + MAC2STR(id.addr), connected->duty); + last_layer = i32MeshLayer; + bIsMeshConnected = true; + if (esp_mesh_is_root()) { - mesh_event_connected_t *connected = (mesh_event_connected_t *)vpEventData; - esp_mesh_get_id(&id); - i32MeshLayer = connected->self_layer; - memcpy(&mesh_parent_addr.addr, connected->connected.bssid, 6); - ESP_LOGI(LOG_TAG, "layer:%d-->%d, parent:"MACSTR"%s, ID:"MACSTR", duty:%d", - last_layer, i32MeshLayer, MAC2STR(mesh_parent_addr.addr), - esp_mesh_is_root() ? "" : (i32MeshLayer == 2) ? "" : "", //print own node title - MAC2STR(id.addr), connected->duty); - last_layer = i32MeshLayer; - bIsMeshConnected = true; - if (esp_mesh_is_root()) - { - ESP_ERROR_CHECK(esp_netif_dhcpc_start(netif_sta)); //get a IP from router - } - errStartReceiveTask();//start receiving + ESP_ERROR_CHECK(esp_netif_dhcpc_start(netif_sta)); //get a IP from router } - break; + errStartReceiveTask();//start receiving + } + break; case MESH_EVENT_PARENT_DISCONNECTED: - { - mesh_event_disconnected_t *disconnected = (mesh_event_disconnected_t *)vpEventData; - ESP_LOGI(LOG_TAG, "reason:%d", disconnected->reason); - bIsMeshConnected = false; - i32MeshLayer = esp_mesh_get_layer(); - } - break; + { + mesh_event_disconnected_t *disconnected = (mesh_event_disconnected_t *)vpEventData; + ESP_LOGI(LOG_TAG, "reason:%d", disconnected->reason); + bIsMeshConnected = false; + i32MeshLayer = esp_mesh_get_layer(); + } + break; case MESH_EVENT_LAYER_CHANGE: - { - mesh_event_layer_change_t *layer_change = (mesh_event_layer_change_t *)vpEventData; - i32MeshLayer = layer_change->new_layer; - ESP_LOGI(LOG_TAG, "layer:%d-->%d%s", - last_layer, i32MeshLayer, - esp_mesh_is_root() ? "" : (i32MeshLayer == 2) ? "" : ""); - last_layer = i32MeshLayer; - } - break; + { + mesh_event_layer_change_t *layer_change = (mesh_event_layer_change_t *)vpEventData; + i32MeshLayer = layer_change->new_layer; + ESP_LOGI(LOG_TAG, "layer:%d-->%d%s", + last_layer, i32MeshLayer, + esp_mesh_is_root() ? "" : (i32MeshLayer == 2) ? "" : ""); + last_layer = i32MeshLayer; + } + break; case MESH_EVENT_ROOT_ADDRESS: - { - mesh_event_root_address_t *root_addr = (mesh_event_root_address_t *)vpEventData; - ESP_LOGI(LOG_TAG, "root address:"MACSTR"", - MAC2STR(root_addr->addr)); - } - break; + { + mesh_event_root_address_t *root_addr = (mesh_event_root_address_t *)vpEventData; + ESP_LOGI(LOG_TAG, "root address:"MACSTR"", + MAC2STR(root_addr->addr)); + } + break; case MESH_EVENT_VOTE_STARTED: - { - mesh_event_vote_started_t *vote_started = (mesh_event_vote_started_t *)vpEventData; - ESP_LOGI(LOG_TAG, "attempts:%d, reason:%d, rc_addr:"MACSTR"", - vote_started->attempts, - vote_started->reason, - MAC2STR(vote_started->rc_addr.addr)); - } - break; + { + mesh_event_vote_started_t *vote_started = (mesh_event_vote_started_t *)vpEventData; + ESP_LOGI(LOG_TAG, "attempts:%d, reason:%d, rc_addr:"MACSTR"", + vote_started->attempts, + vote_started->reason, + MAC2STR(vote_started->rc_addr.addr)); + } + break; case MESH_EVENT_VOTE_STOPPED: - { - ESP_LOGI(LOG_TAG, ""); - } - break; + { + ESP_LOGI(LOG_TAG, ""); + } + break; case MESH_EVENT_ROOT_SWITCH_REQ: - { - mesh_event_root_switch_req_t *switch_req = (mesh_event_root_switch_req_t *)vpEventData; - ESP_LOGI(LOG_TAG, "reason:%d, rc_addr:"MACSTR"", switch_req->reason, - MAC2STR( switch_req->rc_addr.addr)); - } - break; + { + mesh_event_root_switch_req_t *switch_req = (mesh_event_root_switch_req_t *)vpEventData; + ESP_LOGI(LOG_TAG, "reason:%d, rc_addr:"MACSTR"", switch_req->reason, + MAC2STR( switch_req->rc_addr.addr)); + } + break; case MESH_EVENT_ROOT_SWITCH_ACK: - { - //new root - i32MeshLayer = esp_mesh_get_layer(); - esp_mesh_get_parent_bssid(&mesh_parent_addr); - ESP_LOGI(LOG_TAG, "layer:%d, parent:"MACSTR"", i32MeshLayer, MAC2STR(mesh_parent_addr.addr)); - } - break; + { + //new root + i32MeshLayer = esp_mesh_get_layer(); + esp_mesh_get_parent_bssid(&meshParentAddr); + ESP_LOGI(LOG_TAG, "layer:%d, parent:"MACSTR"", i32MeshLayer, MAC2STR(meshParentAddr.addr)); + } + break; case MESH_EVENT_TODS_STATE: - { - mesh_event_toDS_state_t *toDs_state = (mesh_event_toDS_state_t *)vpEventData; - ESP_LOGI(LOG_TAG, "state:%d", *toDs_state); - } - break; + { + mesh_event_toDS_state_t *toDs_state = (mesh_event_toDS_state_t *)vpEventData; + ESP_LOGI(LOG_TAG, "state:%d", *toDs_state); + } + break; case MESH_EVENT_ROOT_FIXED: - { - mesh_event_root_fixed_t *root_fixed = (mesh_event_root_fixed_t *)vpEventData; - ESP_LOGI(LOG_TAG, "%s", - root_fixed->is_fixed ? "fixed" : "not fixed"); - } - break; + { + mesh_event_root_fixed_t *root_fixed = (mesh_event_root_fixed_t *)vpEventData; + ESP_LOGI(LOG_TAG, "%s", + root_fixed->is_fixed ? "fixed" : "not fixed"); + } + break; case MESH_EVENT_ROOT_ASKED_YIELD: - { - mesh_event_root_conflict_t *root_conflict = (mesh_event_root_conflict_t *)vpEventData; - ESP_LOGI(LOG_TAG, ""MACSTR", rssi:%d, capacity:%d", - MAC2STR(root_conflict->addr), root_conflict->rssi, root_conflict->capacity); - } - break; + { + mesh_event_root_conflict_t *root_conflict = (mesh_event_root_conflict_t *)vpEventData; + ESP_LOGI(LOG_TAG, ""MACSTR", rssi:%d, capacity:%d", + MAC2STR(root_conflict->addr), root_conflict->rssi, root_conflict->capacity); + } + break; case MESH_EVENT_CHANNEL_SWITCH: - { - mesh_event_channel_switch_t *channel_switch = (mesh_event_channel_switch_t *)vpEventData; - ESP_LOGI(LOG_TAG, "new channel:%d", channel_switch->channel); - } - break; + { + mesh_event_channel_switch_t *channel_switch = (mesh_event_channel_switch_t *)vpEventData; + ESP_LOGI(LOG_TAG, "new channel:%d", channel_switch->channel); + } + break; case MESH_EVENT_SCAN_DONE: - { - mesh_event_scan_done_t *scan_done = (mesh_event_scan_done_t *)vpEventData; - ESP_LOGI(LOG_TAG, "number:%d", scan_done->number); - } - break; + { + mesh_event_scan_done_t *scan_done = (mesh_event_scan_done_t *)vpEventData; + ESP_LOGI(LOG_TAG, "number:%d", scan_done->number); + } + break; case MESH_EVENT_NETWORK_STATE: - { - mesh_event_network_state_t *network_state = (mesh_event_network_state_t *)vpEventData; - ESP_LOGI(LOG_TAG, "is_rootless:%d", network_state->is_rootless); - } - break; + { + mesh_event_network_state_t *network_state = (mesh_event_network_state_t *)vpEventData; + ESP_LOGI(LOG_TAG, "is_rootless:%d", network_state->is_rootless); + } + break; case MESH_EVENT_STOP_RECONNECTION: - { - ESP_LOGI(LOG_TAG, ""); - } - break; + { + ESP_LOGI(LOG_TAG, ""); + } + break; case MESH_EVENT_FIND_NETWORK: - { - mesh_event_find_network_t *find_network = (mesh_event_find_network_t *)vpEventData; - ESP_LOGI(LOG_TAG, "new channel:%d, router BSSID:"MACSTR"", - find_network->channel, MAC2STR(find_network->router_bssid)); - } - break; + { + mesh_event_find_network_t *find_network = (mesh_event_find_network_t *)vpEventData; + ESP_LOGI(LOG_TAG, "new channel:%d, router BSSID:"MACSTR"", + find_network->channel, MAC2STR(find_network->router_bssid)); + } + break; case MESH_EVENT_ROUTER_SWITCH: - { - mesh_event_router_switch_t *router_switch = (mesh_event_router_switch_t *)vpEventData; - ESP_LOGI(LOG_TAG, "new router:%s, channel:%d, "MACSTR"", - router_switch->ssid, router_switch->channel, MAC2STR(router_switch->bssid)); - } - break; + { + mesh_event_router_switch_t *router_switch = (mesh_event_router_switch_t *)vpEventData; + ESP_LOGI(LOG_TAG, "new router:%s, channel:%d, "MACSTR"", + router_switch->ssid, router_switch->channel, MAC2STR(router_switch->bssid)); + } + break; case MESH_EVENT_PS_PARENT_DUTY: - { - mesh_event_ps_duty_t *ps_duty = (mesh_event_ps_duty_t *)vpEventData; - ESP_LOGI(LOG_TAG, "duty:%d", ps_duty->duty); - } - break; + { + mesh_event_ps_duty_t *ps_duty = (mesh_event_ps_duty_t *)vpEventData; + ESP_LOGI(LOG_TAG, "duty:%d", ps_duty->duty); + } + break; case MESH_EVENT_PS_CHILD_DUTY: - { - mesh_event_ps_duty_t *ps_duty = (mesh_event_ps_duty_t *)vpEventData; - ESP_LOGI(LOG_TAG, "cidx:%d, "MACSTR", duty:%d", ps_duty->child_connected.aid-1, - MAC2STR(ps_duty->child_connected.mac), ps_duty->duty); - } - break; + { + mesh_event_ps_duty_t *ps_duty = (mesh_event_ps_duty_t *)vpEventData; + ESP_LOGI(LOG_TAG, "cidx:%d, "MACSTR", duty:%d", ps_duty->child_connected.aid-1, + MAC2STR(ps_duty->child_connected.mac), ps_duty->duty); + } + break; default: ESP_LOGI(LOG_TAG, "unknown id:%d", i32EventID); break; diff --git a/components/mesh_ota/include/Mesh_OTA.h b/components/mesh_ota/include/Mesh_OTA.h index 608aa79..4c61a60 100644 --- a/components/mesh_ota/include/Mesh_OTA.h +++ b/components/mesh_ota/include/Mesh_OTA.h @@ -33,10 +33,10 @@ enum ota_packet_type err = (x); \ if (err != ESP_OK) \ { \ - ESP_LOGE(LOG_TAG, "%s failed with error: %d -> %s", #x, err, esp_err_to_name(err)); \ + ESP_LOGE(LOG_TAG, "%s failed with error: 0x%x -> %s", #x, err, esp_err_to_name(err)); \ } \ } \ - + bool bNewerVersion(const char* pu8Local, const char* pu8Remote); esp_err_t errExtractVersionNumber(const char* pu8Data, uint32_t* pu32DataLenght, char* pc8RemoteVersionNumber); diff --git a/components/mesh_ota/include/Mesh_network.h b/components/mesh_ota/include/Mesh_network.h index 7c60526..617354d 100644 --- a/components/mesh_ota/include/Mesh_network.h +++ b/components/mesh_ota/include/Mesh_network.h @@ -49,9 +49,9 @@ struct meshPacket { - enum otaMeshPacketType + enum otaMeshPacketType { - APP_Data, //data for application + APP_Data, //data for application OTA_Version_Request, //send own version in payload OTA_Version_Respone, //send own version in payload OTA_Data, //send image segment @@ -65,20 +65,31 @@ typedef struct meshPacket MESH_PACKET_t; extern bool bIsMeshConnected; extern int32_t i32MeshLayer; -extern mesh_addr_t mesh_parent_addr; +extern mesh_addr_t meshParentAddr; extern esp_netif_t* netif_sta; +extern uint8_t u8ownMAC[6]; esp_err_t errMeshNetworkInitialize(); esp_err_t errMeshNetworkInitializeWiFi(); esp_err_t errMeshNetworkInitializeRouter(mesh_cfg_t* cfg); +esp_err_t errMeshNetworkSetAppReceiveHandle(void (*pFuncParam)(uint8_t * pu8Data, uint8_t* pu8Sender)); + bool bCheckMACEquality(uint8_t* pu8aMAC, uint8_t* pu8bMAC); +void vGetOwnAddr(mesh_addr_t* pMeshOwnAddr); +esp_err_t errGetParentNode(mesh_addr_t* pMeshParentAddr); esp_err_t errGetChildren(mesh_addr_t* pChildren, uint16_t* pu16ChildrenSize); -void vMeshEventHandler(void *arg, esp_event_base_t event_base, int32_t i32EventID, void* vpEventData); -void vIPEventHandler(void *arg, esp_event_base_t event_base, int32_t i32EventID, void *event_data); +bool bIsRootNode(); + esp_err_t errStartReceiveTask(); void vTaskReceiveMeshData(void *arg); +void vMeshEventHandler(void *arg, esp_event_base_t event_base, int32_t i32EventID, void* vpEventData); +void vIPEventHandler(void *arg, esp_event_base_t event_base, int32_t i32EventID, void *event_data); + esp_err_t errSendMeshPacket(mesh_addr_t* pAddrDest, MESH_PACKET_t* pPacket); + + + #endif /* H_MESH_NETWORK */ - + diff --git a/components/mesh_ota/include/https_client.h b/components/mesh_ota/include/https_client.h index 60d192b..f2c9252 100644 --- a/components/mesh_ota/include/https_client.h +++ b/components/mesh_ota/include/https_client.h @@ -26,7 +26,7 @@ #include "mbedtls/ctr_drbg.h" #include "mbedtls/error.h" #include "mbedtls/certs.h" -#include "esp_crt_bundle.h" +#include "esp_crt_bundle.h" #ifndef CONFIG_OTA_HTTPS_URL #define CONFIG_OTA_HTTPS_URL "https://exmaple.com/theImage.bin" @@ -63,7 +63,7 @@ struct HTTPS_Client typedef int32_t https_client_ret_t; typedef struct HTTPS_Client HTTPS_Client_t; - + https_client_ret_t https_clientInitialize(); https_client_ret_t https_clientRetrieveData(char* pu8Data, uint32_t* pu32DataLenght, uint32_t* pu32BytesRead); https_client_ret_t https_clientDeinitialize(); diff --git a/main/Blinky_LED.c b/main/Blinky_LED.c index 95e262c..2cfc7c7 100644 --- a/main/Blinky_LED.c +++ b/main/Blinky_LED.c @@ -1,11 +1,11 @@ - - #include "Blinky_LED.h" static const char *LOG_TAG = "blinky_led"; -static bool bLEDisOn = true; - -xQueueHandle queueBlinkyLEDPackets; +static bool bLEDisOn = false; //set led default off +static mesh_addr_t addrParent; //addr of parent node +static mesh_addr_t childrenAddr[CONFIG_MESH_ROUTE_TABLE_SIZE]; //array of children attached to this node +static uint16_t u16ChildrenSize; //number of children attached to this node +xQueueHandle queueBlinkyLEDPackets; //handle for led action queue esp_err_t errBlinkyLEDInitialize() { @@ -14,16 +14,20 @@ esp_err_t errBlinkyLEDInitialize() vGPIOInitialize(); - queueBlinkyLEDPackets = xQueueCreate(5, sizeof (BLINKY_PACKET_t)); + //create queue to store led action created from BTN and mesh network events + queueBlinkyLEDPackets = xQueueCreate(5, sizeof(BLINKY_PACKET_t)); if (queueBlinkyLEDPackets == 0) // Queue not created { ESP_LOGE(LOG_TAG, "Unable to create Queue for Application Packets"); err = ESP_FAIL; } + //register the receiver handle in mesh network + ERROR_CHECK(errMeshNetworkSetAppReceiveHandle(rxHandle)); + if(err == ESP_OK) { - xReturned = xTaskCreate(vTaskReadUserInput, "vTaskReadUserInput", 2048, NULL, 5, NULL); + xReturned = xTaskCreate(vTaskReadUserInput, "vTaskReadUserInput", 4096, NULL, 5, NULL); if(xReturned != pdPASS) { err = ESP_FAIL; @@ -32,7 +36,7 @@ esp_err_t errBlinkyLEDInitialize() if(err == ESP_OK) { - xReturned = xTaskCreate(vTaskReceiveData, "vTaskReceiveData", 2048, NULL, 5, NULL); + xReturned = xTaskCreate(vTaskReceiveData, "vTaskReceiveData", 4096, NULL, 5, NULL); if(xReturned != pdPASS) { err = ESP_FAIL; @@ -58,27 +62,65 @@ void vGPIOInitialize() gpio_config(&gpioConf); } +void rxHandle(uint8_t* pu8Data, uint8_t* pu8Sender) +{ + //send payload to app queue + BLINKY_PACKET_t bTmpPacket; + memcpy(&bTmpPacket, (uint8_t *)pu8Data, sizeof(BLINKY_PACKET_t)); + memcpy(&bTmpPacket.meshSenderAddr, (uint8_t *)pu8Sender, 6); //copy MAC from sender into app packet + if (xQueueSend(queueBlinkyLEDPackets, &bTmpPacket, portMAX_DELAY) != pdPASS) + { + ESP_LOGE(LOG_TAG, "Unable to push packet from mesh into Queue"); + } +} + void vTaskReadUserInput(void *arg) { - BLINKY_PACKET_t bTmpStateLED = LED_OFF; + esp_err_t err = ESP_OK; + BLINKY_PACKET_t bTmpPacket; + MESH_PACKET_t meshPacket; + + bTmpPacket.type = LED_OFF; //default off + meshPacket.type = APP_Data; //this is a app packet + while(true) - { + { //check for BTN press if(gpio_get_level(GPIO_BOOT_BTN) == 0) { + err = ESP_OK; + if(bLEDisOn == false) { - ESP_LOGI(LOG_TAG,"switch ON"); - bTmpStateLED = LED_ON; + bTmpPacket.type = LED_ON; } else { - ESP_LOGI(LOG_TAG,"switch OFF"); - bTmpStateLED = LED_OFF; + bTmpPacket.type = LED_OFF; } - if (xQueueSend(queueBlinkyLEDPackets, &bTmpStateLED, portMAX_DELAY) != pdPASS) + //push led action into queue + if (xQueueSend(queueBlinkyLEDPackets, &bTmpPacket, portMAX_DELAY) != pdPASS) { - ESP_LOGE(LOG_TAG, "Unable to push packet into Queue"); + ESP_LOGE(LOG_TAG, "Unable to push packet into queue"); + } + + memcpy(meshPacket.au8Payload, &bTmpPacket, sizeof(BLINKY_PACKET_t)); + + if(bIsRootNode() == false) + { + //this node is not root --> send led action to parent + ERROR_CHECK(errGetParentNode(&addrParent)); + ERROR_CHECK(errSendMeshPacket(&addrParent, &meshPacket)); + } + else + { + //this node is root --> send led action to children + ERROR_CHECK(errGetChildren(childrenAddr, &u16ChildrenSize)); + + for (uint16_t u16Index = 0; u16Index < u16ChildrenSize; u16Index++) + { + ERROR_CHECK (errSendMeshPacket(&childrenAddr[u16Index], &meshPacket)); + } } vTaskDelay(200 / portTICK_PERIOD_MS); } @@ -88,37 +130,55 @@ void vTaskReadUserInput(void *arg) void vTaskReceiveData(void *arg) { - BLINKY_PACKET_t bTmpStateLED = LED_OFF; + esp_err_t err = ESP_OK; + MESH_PACKET_t meshPacket; + BLINKY_PACKET_t bTmpPacket; + + bTmpPacket.type = LED_OFF; //default off + meshPacket.type = APP_Data; //this is a app packet while (1) { - if (xQueueReceive(queueBlinkyLEDPackets, &bTmpStateLED, portMAX_DELAY) != pdTRUE) + if (xQueueReceive(queueBlinkyLEDPackets, &bTmpPacket, portMAX_DELAY) != pdTRUE) { ESP_LOGE(LOG_TAG, "Unable to receive packet from Queue"); } else { + err = ESP_OK; //Successfully RECEIVED the packet - switch (bTmpStateLED) + switch (bTmpPacket.type) { case LED_ON: bLEDisOn = true; gpio_set_level(GPIO_LED, 1); //switch on - ESP_LOGI(LOG_TAG,"rec ON"); + ESP_LOGI(LOG_TAG,"switch LED ON"); break; case LED_OFF: bLEDisOn = false; gpio_set_level(GPIO_LED, 0); //switch off - ESP_LOGI(LOG_TAG,"rec OFF"); + ESP_LOGI(LOG_TAG,"switch LED OFF"); break; default: bLEDisOn = false; gpio_set_level(GPIO_LED, 0); //switch off + ESP_LOGI(LOG_TAG,"switch LED OFF"); break; } } + + ERROR_CHECK(errGetChildren(childrenAddr, &u16ChildrenSize)); //get all children attached to this node + memcpy(meshPacket.au8Payload, &bTmpPacket, sizeof(BLINKY_PACKET_t)); //copy led action in mesh packet payload + + for (uint16_t u16Index = 0; u16Index < u16ChildrenSize; u16Index++) + { //loop through children + if(bCheckMACEquality(bTmpPacket.meshSenderAddr.addr, childrenAddr[u16Index].addr) == false) //exclude the sender node + { + ERROR_CHECK (errSendMeshPacket(&childrenAddr[u16Index], &meshPacket)); //send to child + } + } vTaskDelay(200 / portTICK_PERIOD_MS); } } \ No newline at end of file diff --git a/main/Blinky_LED.h b/main/Blinky_LED.h index ab6b5e2..a5ec54e 100644 --- a/main/Blinky_LED.h +++ b/main/Blinky_LED.h @@ -11,25 +11,29 @@ #include "Mesh_OTA.h" -#define GPIO_BOOT_BTN 0 -#define GPIO_LED 2 +#define GPIO_BOOT_BTN 0 //GPIO0 (Boot BTN) +#define GPIO_LED 2 //GPIO2 (internal blue LED in DevKit V1.0) -#define GPIO_INPUT_PIN_SEL (1ULL< Date: Sun, 17 Jan 2021 23:27:01 +0100 Subject: [PATCH 03/21] added control for http_ota task --- components/mesh_ota/Mesh_OTA.c | 270 +++++++++++---- components/mesh_ota/Mesh_network.c | 148 +++++---- components/mesh_ota/Mesh_network_handler.c | 369 +++++++++++---------- components/mesh_ota/https_client.c | 301 ++++++++--------- components/mesh_ota/include/Mesh_OTA.h | 28 +- components/mesh_ota/include/Mesh_network.h | 9 +- main/Main.c | 12 +- 7 files changed, 665 insertions(+), 472 deletions(-) diff --git a/components/mesh_ota/Mesh_OTA.c b/components/mesh_ota/Mesh_OTA.c index 1bad54c..2254c5f 100644 --- a/components/mesh_ota/Mesh_OTA.c +++ b/components/mesh_ota/Mesh_OTA.c @@ -1,5 +1,153 @@ #include "Mesh_OTA.h" + +static const char *LOG_TAG = "mesh_ota"; + +xQueueHandle queueNodes; //nodes that should be checked for ota update (contains children and parent) +xQueueHandle queueMessageOTA; //mesh ota controll messages like "OTA_Version_Response" "OTA_ACK" + +SemaphoreHandle_t bsStartStopServerWorker; //binary semaphore + +esp_err_t errMeshOTAInitialize() +{ + esp_err_t err = ESP_OK; + BaseType_t xReturned; + + //create queue to store nodes for ota worker task + queueNodes = xQueueCreate(QUEUE_NODES_SIZE, sizeof(mesh_addr_t)); + if (queueNodes == 0) // Queue not created + { + ESP_LOGE(LOG_TAG, "Unable to create Queue for Nodes"); + err = ESP_FAIL; + } + + if(err == ESP_OK) + { + //create queue to store ota messages + queueMessageOTA = xQueueCreate(QUEUE_MESSAGE_OTA_SIZE, sizeof(MESH_PACKET_t)); + if (queueMessageOTA == 0) // Queue not created + { + ESP_LOGE(LOG_TAG, "Unable to create Queue for OTA Messages"); + err = ESP_FAIL; + } + } + + if(err == ESP_OK) + { + bsStartStopServerWorker = xSemaphoreCreateBinary(); + if( bsStartStopServerWorker == NULL ) + { + ESP_LOGE(LOG_TAG, "Unable to create Mutex to represent state of Server worker"); + err = ESP_FAIL; + } + } + + ERROR_CHECK(errMeshNetworkSetChildConnectedHandle(vAddNodeToPossibleUpdatableQueue)); + ERROR_CHECK(errMeshNetworkSetOTAMessageHandleHandle(vAddOTAControllMessageToQueue)); + ERROR_CHECK(errMeshNetworkSetChangeStateOfServerWorkerHandle(vChangeStateOfServerWorker)); + + if(err == ESP_OK) + { + xReturned = xTaskCreate(vTaskServerWorker, "vTaskServerWorker", 4096, NULL, 5, NULL); + if(xReturned != pdPASS) + { + ESP_LOGE(LOG_TAG, "Unable to create the server worker task"); + err = ESP_FAIL; + } + } + + return err; +} + + +void vAddNodeToPossibleUpdatableQueue(uint8_t* pu8Data) +{ + //send payload to node queue + mesh_addr_t addrNode; + memcpy(&addrNode.addr, (uint8_t *)pu8Data, 6); //copy MAC + + if (xQueueSend(queueNodes, &addrNode, portMAX_DELAY) != pdPASS) + { + ESP_LOGE(LOG_TAG, "Unable to push node into node queue"); + } + else + { + ESP_LOGI(LOG_TAG, "added node \"%x:%x:%x:%x:%x:%x\" to possible updatable queue", addrNode.addr[0], addrNode.addr[1], addrNode.addr[2], addrNode.addr[3], addrNode.addr[4], addrNode.addr[5]); + } +} + + +void vAddOTAControllMessageToQueue(MESH_PACKET_t* puMeshPacket) +{ + //send ota packet to packet queue + if (xQueueSend(queueMessageOTA, puMeshPacket, portMAX_DELAY) != pdPASS) + { + ESP_LOGE(LOG_TAG, "Unable to push ota packet into packet queue"); + } + else + { + ESP_LOGI(LOG_TAG, "added ota controll message to queue"); + } +} + + +void vChangeStateOfServerWorker(bool bState) //allow access via function ptn to networl_handler +{ + static bool bLastState = false; + + if(bState != bLastState) //change only if necessary + { + ESP_LOGI(LOG_TAG, "server worker change handler"); + + if(bState == true) + { + if (xSemaphoreGive(bsStartStopServerWorker) != pdTRUE) + { + ESP_LOGE(LOG_TAG, "Unable to give mutex to activate the server worker"); + } + } + else + { + if (xSemaphoreTake(bsStartStopServerWorker,( TickType_t ) 10 ) != pdTRUE) + { + ESP_LOGE(LOG_TAG, "Unable to obtain mutex to deactivate the server worker"); + } + } + bLastState = bState; + } +} + +void vTaskOTAWorker(void *arg) +{ + + + + + +} + +void vTaskServerWorker(void *arg) +{ + while(true) + { + xSemaphoreTake(bsStartStopServerWorker, portMAX_DELAY); //wait for binary semaphore that allows to start the worker + xSemaphoreGive(bsStartStopServerWorker); //free binary semaphore, this allows the handler to change is to taken + + if (esp_mesh_is_root()) //check again that this node is the root node + { + ESP_LOGI(LOG_TAG, "DEMO HTTP request"); + + //server get version + + //ota update if newer + + //lock ota mutex + + vTaskDelay( (SERVER_CHECK_INTERVAL*1000) / portTICK_PERIOD_MS); //sleep till next server check + } + } +} + /* * 999.999.999 * Return true if remote version is newer (higher) than local version @@ -20,15 +168,15 @@ bool bNewerVersion(const char* pu8Local, const char* pu8Remote) char* pu8TokenRemote = strtok_r(u8RemoteTmp, ".", &pu8saveptrRemote); //split tokens while( (u8Index <= 2) && (bReturn == false)) //loop through tokens - { - u8Index++; - if(atoi(pu8TokenLocal) < atoi(pu8TokenRemote)) { - bReturn = true; //version number difference --> stop loop + u8Index++; + if(atoi(pu8TokenLocal) < atoi(pu8TokenRemote)) + { + bReturn = true; //version number difference --> stop loop + } + pu8TokenLocal = strtok_r(NULL, ".", &pu8saveptrLocal); //split tokens + pu8TokenRemote = strtok_r(NULL, ".", &pu8saveptrRemote); //split tokens } - pu8TokenLocal = strtok_r(NULL, ".", &pu8saveptrLocal); //split tokens - pu8TokenRemote = strtok_r(NULL, ".", &pu8saveptrRemote); //split tokens - } return bReturn; } @@ -51,61 +199,61 @@ esp_err_t errFindImageStart(const char* pu8Data, uint32_t* pu32DataLenght, uint3 *pu32StartOffset = 0U; //reset offset to zero while((u32DataIndex < *pu32DataLenght) && (bImageStartOffsetFound == false)) - { - //search for magic byte - if(pu8Data[u32DataIndex] == 0xe9) { - //magic byte found - while ((u8FirstDotIndex < 3) && (u32FirstDotOffset == 0)) - { - //search first dot in version number - if((u32DataIndex+49+u8FirstDotIndex) < *pu32DataLenght) + //search for magic byte + if(pu8Data[u32DataIndex] == 0xe9) { - if((pu8Data[(u32DataIndex+49+u8FirstDotIndex)] == 0x2e)) - { - //first dot found - u32FirstDotOffset = (u32DataIndex+49+u8FirstDotIndex); - } - } - u8FirstDotIndex++; - } + //magic byte found + while ((u8FirstDotIndex < 3) && (u32FirstDotOffset == 0)) + { + //search first dot in version number + if((u32DataIndex+49+u8FirstDotIndex) < *pu32DataLenght) + { + if((pu8Data[(u32DataIndex+49+u8FirstDotIndex)] == 0x2e)) + { + //first dot found + u32FirstDotOffset = (u32DataIndex+49+u8FirstDotIndex); + } + } + u8FirstDotIndex++; + } - while ((u8SecondDotIndex < 3) && (u32SecondDotOffset == 0) && (u32FirstDotOffset != 0)) - { - //search first dot in version number - if((u32FirstDotOffset+(u8SecondDotIndex+2)) < *pu32DataLenght) - { - if((pu8Data[(u32FirstDotOffset+(u8SecondDotIndex+2))] == 0x2e)) - { - //second dot found - u32SecondDotOffset = (u32FirstDotOffset+(u8SecondDotIndex+2)); - } - } - u8SecondDotIndex++; - } + while ((u8SecondDotIndex < 3) && (u32SecondDotOffset == 0) && (u32FirstDotOffset != 0)) + { + //search first dot in version number + if((u32FirstDotOffset+(u8SecondDotIndex+2)) < *pu32DataLenght) + { + if((pu8Data[(u32FirstDotOffset+(u8SecondDotIndex+2))] == 0x2e)) + { + //second dot found + u32SecondDotOffset = (u32FirstDotOffset+(u8SecondDotIndex+2)); + } + } + u8SecondDotIndex++; + } - if((u32FirstDotOffset != 0) && (u32SecondDotOffset != 0)) - { - //image start found based on magic byte and version number systax - *pu32StartOffset = u32DataIndex; //store image start offset - bImageStartOffsetFound = true; - } - else - { - // this is propably not the magic byte --> reset - u32FirstDotOffset = 0; - u32SecondDotOffset = 0; - u8FirstDotIndex = 0; - u8SecondDotIndex = 0; - } + if((u32FirstDotOffset != 0) && (u32SecondDotOffset != 0)) + { + //image start found based on magic byte and version number systax + *pu32StartOffset = u32DataIndex; //store image start offset + bImageStartOffsetFound = true; + } + else + { + // this is propably not the magic byte --> reset + u32FirstDotOffset = 0; + u32SecondDotOffset = 0; + u8FirstDotIndex = 0; + u8SecondDotIndex = 0; + } + } + u32DataIndex++; } - u32DataIndex++; - } if(bImageStartOffsetFound == false) - { - errReturn = ESP_ERR_NOT_FOUND; - } + { + errReturn = ESP_ERR_NOT_FOUND; + } return errReturn; } @@ -119,17 +267,15 @@ esp_err_t errExtractVersionNumber(const char* pu8Data, uint32_t* pu32DataLenght, err = errFindImageStart(pu8Data, pu32DataLenght, &u32StartOffset); //get image start offset if(err == ESP_OK) - { - //image found - strncpy(pc8RemoteVersionNumber, pu8Data+(u32StartOffset+48), 11); //copy version number - pc8RemoteVersionNumber[12] = '\0'; - } + { + //image found + strncpy(pc8RemoteVersionNumber, pu8Data+(u32StartOffset+48), 11); //copy version number + pc8RemoteVersionNumber[12] = '\0'; + } return err; } /* - - esp_err_t esp_mesh_ota_send(mesh_addr_t* dest) { esp_err_t err = ESP_OK; diff --git a/components/mesh_ota/Mesh_network.c b/components/mesh_ota/Mesh_network.c index 3cf3ac3..6542219 100644 --- a/components/mesh_ota/Mesh_network.c +++ b/components/mesh_ota/Mesh_network.c @@ -10,7 +10,9 @@ bool bIsMeshConnected; int32_t i32MeshLayer; mesh_addr_t meshParentAddr; void (*pAppRxHandle)(uint8_t*, uint8_t* ); - +void (*pOTAChildConnectHandle)(uint8_t* ); +void (*pOTAMessageHandle)(MESH_PACKET_t* ); +void (*pChangeStateOfServerWorkerHandle)(bool ); esp_err_t errMeshNetworkInitialize() { @@ -24,9 +26,9 @@ esp_err_t errMeshNetworkInitialize() #ifdef ERASE_NVS if(err == ESP_ERR_NVS_NO_FREE_PAGES) //check if storage is full - { - ERROR_CHECK(nvs_flash_erase()); - } + { + ERROR_CHECK(nvs_flash_erase()); + } #endif // tcpip initialization @@ -120,13 +122,13 @@ bool bCheckMACEquality(uint8_t* pu8aMAC, uint8_t* pu8bMAC) uint8_t index = 0; while ((index < 6) && (bRet == true)) - { - if(pu8aMAC[index] != pu8bMAC[index]) { - bRet = false; + if(pu8aMAC[index] != pu8bMAC[index]) + { + bRet = false; + } + index++; } - index++; - } return bRet; } @@ -139,18 +141,18 @@ esp_err_t errGetChildren(mesh_addr_t* pChildren, uint16_t* pu16ChildrenSize) ERROR_CHECK(esp_mesh_get_routing_table((mesh_addr_t *) &route_table, (CONFIG_MESH_ROUTE_TABLE_SIZE * 6), &route_table_size)); if (err == ESP_OK) - { - for(uint16_t index = 0; index < esp_mesh_get_routing_table_size(); index++) { - if(! (bCheckMACEquality(u8ownMAC, route_table[index].addr)) ) - { - //child node - //ESP_LOGI(MESH_TAG, "adding Node: \"0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\" ", route_table[index].addr[0], route_table[index].addr[1], route_table[index].addr[2], route_table[index].addr[3], route_table[index].addr[4], route_table[index].addr[5]); - pChildren[*pu16ChildrenSize] = route_table[index]; - *pu16ChildrenSize = (*pu16ChildrenSize)+1; - } + for(uint16_t index = 0; index < esp_mesh_get_routing_table_size(); index++) + { + if(! (bCheckMACEquality(u8ownMAC, route_table[index].addr)) ) + { + //child node + //ESP_LOGI(MESH_TAG, "adding Node: \"0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\" ", route_table[index].addr[0], route_table[index].addr[1], route_table[index].addr[2], route_table[index].addr[3], route_table[index].addr[4], route_table[index].addr[5]); + pChildren[*pu16ChildrenSize] = route_table[index]; + *pu16ChildrenSize = (*pu16ChildrenSize)+1; + } + } } - } return err; } @@ -159,13 +161,13 @@ esp_err_t errGetParentNode(mesh_addr_t* pMeshParentAddr) esp_err_t err = ESP_OK; if(bIsMeshConnected == false) - { - err = ESP_FAIL; - } + { + err = ESP_FAIL; + } else - { - memcpy(pMeshParentAddr, &meshParentAddr, sizeof(mesh_addr_t)); - } + { + memcpy(pMeshParentAddr, &meshParentAddr, sizeof(mesh_addr_t)); + } return err; } @@ -185,6 +187,24 @@ esp_err_t errMeshNetworkSetAppReceiveHandle(void (*pAppRxHandleTmp)(uint8_t * pu return ESP_OK; } +esp_err_t errMeshNetworkSetChildConnectedHandle(void (*pChildConnectHandleTmp)(uint8_t * pu8Data)) +{ + pOTAChildConnectHandle = pChildConnectHandleTmp; + return ESP_OK; +} + +esp_err_t errMeshNetworkSetOTAMessageHandleHandle(void (*pOTAMessageHandleTmp)(MESH_PACKET_t* puMeshPacket)) +{ + pOTAMessageHandle = pOTAMessageHandleTmp; + return ESP_OK; +} + +esp_err_t errMeshNetworkSetChangeStateOfServerWorkerHandle(void (*pChangeStateOfServerWorkerHandleTmp)(bool bState)) +{ + pChangeStateOfServerWorkerHandle = pChangeStateOfServerWorkerHandleTmp; + return ESP_OK; +} + esp_err_t errSendMeshPacket(mesh_addr_t* pAddrDest, MESH_PACKET_t* pPacket) { esp_err_t err; @@ -208,9 +228,9 @@ esp_err_t errStartReceiveTask() xReturned = xTaskCreate(vTaskReceiveMeshData, "ReceiveMeshData", 7000, NULL, 5, NULL); if(xReturned != pdPASS) - { - err = ESP_FAIL; - } + { + err = ESP_FAIL; + } return err; } @@ -224,44 +244,44 @@ void vTaskReceiveMeshData(void *arg) data.size = CONFIG_MESH_MESSAGE_SIZE; while (true) - { - data.size = CONFIG_MESH_MESSAGE_SIZE; - err = esp_mesh_recv(&from, &data, portMAX_DELAY, &flag, NULL, 0); - if (err != ESP_OK || !data.size) { - ESP_LOGE(LOG_TAG, "err:0x%x, size:%d", err, data.size); - continue; - } - MESH_PACKET_t packet; - memcpy(&packet, (uint8_t *)rx_buf, sizeof(MESH_PACKET_t)); + data.size = CONFIG_MESH_MESSAGE_SIZE; + err = esp_mesh_recv(&from, &data, portMAX_DELAY, &flag, NULL, 0); + if (err != ESP_OK || !data.size) + { + ESP_LOGE(LOG_TAG, "err:0x%x, size:%d", err, data.size); + continue; + } + MESH_PACKET_t packet; + memcpy(&packet, (uint8_t *)rx_buf, sizeof(MESH_PACKET_t)); - switch (packet.type) - { - case APP_Data: - ESP_LOGD(LOG_TAG, "recv: APP_Data"); - //call the rx handle from app - pAppRxHandle(packet.au8Payload, from.addr); //hand over payload and sender of this mesh packet - break; - case OTA_Version_Request: - ESP_LOGI(LOG_TAG, "recv: OTA_Version_Request"); - break; - case OTA_Version_Respone: - ESP_LOGI(LOG_TAG, "recv: OTA_Version_Respone"); - break; - case OTA_Data: - ESP_LOGI(LOG_TAG, "recv: OTA_Data"); - break; - case OTA_ACK: - ESP_LOGI(LOG_TAG, "recv: OTA_ACK"); - break; - case OTA_Complete: - ESP_LOGI(LOG_TAG, "recv: OTA_Complete"); - break; - default: - ESP_LOGE(LOG_TAG, "recv: something"); - break; - }//end switch - } //end while + switch (packet.type) + { + case APP_Data: + ESP_LOGD(LOG_TAG, "recv: APP_Data"); + //call the rx handle from app + pAppRxHandle(packet.au8Payload, from.addr); //hand over payload and sender of this mesh packet + break; + case OTA_Version_Request: + ESP_LOGI(LOG_TAG, "recv: OTA_Version_Request"); + break; + case OTA_Version_Respone: + ESP_LOGI(LOG_TAG, "recv: OTA_Version_Respone"); + break; + case OTA_Data: + ESP_LOGI(LOG_TAG, "recv: OTA_Data"); + break; + case OTA_ACK: + ESP_LOGI(LOG_TAG, "recv: OTA_ACK"); + break; + case OTA_Complete: + ESP_LOGI(LOG_TAG, "recv: OTA_Complete"); + break; + default: + ESP_LOGE(LOG_TAG, "recv: something"); + break; + }//end switch + } //end while } diff --git a/components/mesh_ota/Mesh_network_handler.c b/components/mesh_ota/Mesh_network_handler.c index f23c991..3f5e2f7 100644 --- a/components/mesh_ota/Mesh_network_handler.c +++ b/components/mesh_ota/Mesh_network_handler.c @@ -7,6 +7,10 @@ void vIPEventHandler(void *arg, esp_event_base_t event_base, int32_t i32EventID, { ip_event_got_ip_t *event = (ip_event_got_ip_t *) vpEventData; ESP_LOGI(LOG_TAG, "IP:" IPSTR, IP2STR(&event->ip_info.ip)); + if(pChangeStateOfServerWorkerHandle) + { + pChangeStateOfServerWorkerHandle(true); //signal that this node (root node) has access to internet + } } void vMeshEventHandler(void *arg, esp_event_base_t event_base, int32_t i32EventID, void* vpEventData) @@ -15,205 +19,210 @@ void vMeshEventHandler(void *arg, esp_event_base_t event_base, int32_t i32EventI static uint16_t last_layer = 0; switch (i32EventID) - { - case MESH_EVENT_STARTED: - { - esp_mesh_get_id(&id); - ESP_LOGI(LOG_TAG, "ID:"MACSTR"", MAC2STR(id.addr)); - bIsMeshConnected = false; - i32MeshLayer = esp_mesh_get_layer(); - } - break; - case MESH_EVENT_STOPPED: - { - ESP_LOGI(LOG_TAG, ""); - bIsMeshConnected = false; - i32MeshLayer = esp_mesh_get_layer(); - } - break; - case MESH_EVENT_CHILD_CONNECTED: - { - mesh_event_child_connected_t *child_connected = (mesh_event_child_connected_t *)vpEventData; - ESP_LOGI(LOG_TAG, "aid:%d, "MACSTR"", - child_connected->aid, - MAC2STR(child_connected->mac)); - } - break; - case MESH_EVENT_CHILD_DISCONNECTED: - { - mesh_event_child_disconnected_t *child_disconnected = (mesh_event_child_disconnected_t *)vpEventData; - ESP_LOGI(LOG_TAG, "aid:%d, "MACSTR"", - child_disconnected->aid, - MAC2STR(child_disconnected->mac)); - } - break; - case MESH_EVENT_ROUTING_TABLE_ADD: - { - mesh_event_routing_table_change_t *routing_table = (mesh_event_routing_table_change_t *)vpEventData; - ESP_LOGW(LOG_TAG, "add %d, new:%d, layer:%d", - routing_table->rt_size_change, - routing_table->rt_size_new, i32MeshLayer); - } - break; - case MESH_EVENT_ROUTING_TABLE_REMOVE: - { - mesh_event_routing_table_change_t *routing_table = (mesh_event_routing_table_change_t *)vpEventData; - ESP_LOGW(LOG_TAG, "remove %d, new:%d, layer:%d", - routing_table->rt_size_change, - routing_table->rt_size_new, i32MeshLayer); - } - break; - case MESH_EVENT_NO_PARENT_FOUND: - { - mesh_event_no_parent_found_t *no_parent = (mesh_event_no_parent_found_t *)vpEventData; - ESP_LOGI(LOG_TAG, "scan times:%d", - no_parent->scan_times); - /* TODO handler for the failure, maybe nominate themselves */ - } - break; - case MESH_EVENT_PARENT_CONNECTED: - { - mesh_event_connected_t *connected = (mesh_event_connected_t *)vpEventData; - esp_mesh_get_id(&id); - i32MeshLayer = connected->self_layer; - memcpy(&meshParentAddr.addr, connected->connected.bssid, 6); - ESP_LOGI(LOG_TAG, "layer:%d-->%d, parent:"MACSTR"%s, ID:"MACSTR", duty:%d", - last_layer, i32MeshLayer, MAC2STR(meshParentAddr.addr), - esp_mesh_is_root() ? "" : (i32MeshLayer == 2) ? "" : "", //print own node title - MAC2STR(id.addr), connected->duty); - last_layer = i32MeshLayer; - bIsMeshConnected = true; - if (esp_mesh_is_root()) { - ESP_ERROR_CHECK(esp_netif_dhcpc_start(netif_sta)); //get a IP from router - } - errStartReceiveTask();//start receiving - } - break; + case MESH_EVENT_STARTED: + { + esp_mesh_get_id(&id); + ESP_LOGI(LOG_TAG, "ID:"MACSTR"", MAC2STR(id.addr)); +bIsMeshConnected = false; +i32MeshLayer = esp_mesh_get_layer(); +} +break; + case MESH_EVENT_STOPPED: +{ +ESP_LOGI(LOG_TAG, ""); +bIsMeshConnected = false; +i32MeshLayer = esp_mesh_get_layer(); +} +break; + case MESH_EVENT_CHILD_CONNECTED: +{ +mesh_event_child_connected_t *child_connected = (mesh_event_child_connected_t *)vpEventData; +ESP_LOGI(LOG_TAG, "aid:%d, "MACSTR"", child_connected->aid, MAC2STR(child_connected->mac)); + +if(pOTAChildConnectHandle){pOTAChildConnectHandle(child_connected->mac);}//add this child to queue using handle + +} +break; + case MESH_EVENT_CHILD_DISCONNECTED: +{ +mesh_event_child_disconnected_t *child_disconnected = (mesh_event_child_disconnected_t *)vpEventData; +ESP_LOGI(LOG_TAG, "aid:%d, "MACSTR"", +child_disconnected->aid, +MAC2STR(child_disconnected->mac)); +} +break; + case MESH_EVENT_ROUTING_TABLE_ADD: +{ +mesh_event_routing_table_change_t *routing_table = (mesh_event_routing_table_change_t *)vpEventData; +ESP_LOGW(LOG_TAG, "add %d, new:%d, layer:%d", +routing_table->rt_size_change, +routing_table->rt_size_new, i32MeshLayer); +} +break; + case MESH_EVENT_ROUTING_TABLE_REMOVE: +{ +mesh_event_routing_table_change_t *routing_table = (mesh_event_routing_table_change_t *)vpEventData; +ESP_LOGW(LOG_TAG, "remove %d, new:%d, layer:%d", +routing_table->rt_size_change, +routing_table->rt_size_new, i32MeshLayer); +} +break; + case MESH_EVENT_NO_PARENT_FOUND: +{ +mesh_event_no_parent_found_t *no_parent = (mesh_event_no_parent_found_t *)vpEventData; +ESP_LOGI(LOG_TAG, "scan times:%d", +no_parent->scan_times); +/* TODO handler for the failure, maybe nominate themselves */ +} +break; + case MESH_EVENT_PARENT_CONNECTED: +{ +mesh_event_connected_t *connected = (mesh_event_connected_t *)vpEventData; +esp_mesh_get_id(&id); +i32MeshLayer = connected->self_layer; +memcpy(&meshParentAddr.addr, connected->connected.bssid, 6); +ESP_LOGI(LOG_TAG, "layer:%d-->%d, parent:"MACSTR"%s, ID:"MACSTR", duty:%d", +last_layer, i32MeshLayer, MAC2STR(meshParentAddr.addr), +esp_mesh_is_root() ? "" : (i32MeshLayer == 2) ? "" : "", //print own node title +MAC2STR(id.addr), connected->duty); +last_layer = i32MeshLayer; +bIsMeshConnected = true; +if (esp_mesh_is_root()) +{ +if(esp_netif_dhcpc_start(netif_sta) == ESP_ERR_ESP_NETIF_DHCP_ALREADY_STARTED) //get a IP from router +{ +if(pChangeStateOfServerWorkerHandle){pChangeStateOfServerWorkerHandle(true);}// signal reconnect +} +} +errStartReceiveTask();//start receiving +} +break; case MESH_EVENT_PARENT_DISCONNECTED: - { - mesh_event_disconnected_t *disconnected = (mesh_event_disconnected_t *)vpEventData; - ESP_LOGI(LOG_TAG, "reason:%d", disconnected->reason); - bIsMeshConnected = false; - i32MeshLayer = esp_mesh_get_layer(); - } - break; +{ +mesh_event_disconnected_t *disconnected = (mesh_event_disconnected_t *)vpEventData; +ESP_LOGI(LOG_TAG, "reason:%d", disconnected->reason); +bIsMeshConnected = false; +if(pChangeStateOfServerWorkerHandle){pChangeStateOfServerWorkerHandle(false);} +i32MeshLayer = esp_mesh_get_layer(); +} +break; case MESH_EVENT_LAYER_CHANGE: - { - mesh_event_layer_change_t *layer_change = (mesh_event_layer_change_t *)vpEventData; - i32MeshLayer = layer_change->new_layer; - ESP_LOGI(LOG_TAG, "layer:%d-->%d%s", - last_layer, i32MeshLayer, - esp_mesh_is_root() ? "" : (i32MeshLayer == 2) ? "" : ""); - last_layer = i32MeshLayer; - } - break; +{ +mesh_event_layer_change_t *layer_change = (mesh_event_layer_change_t *)vpEventData; +i32MeshLayer = layer_change->new_layer; +ESP_LOGI(LOG_TAG, "layer:%d-->%d%s", +last_layer, i32MeshLayer, +esp_mesh_is_root() ? "" : (i32MeshLayer == 2) ? "" : ""); +last_layer = i32MeshLayer; +} +break; case MESH_EVENT_ROOT_ADDRESS: - { - mesh_event_root_address_t *root_addr = (mesh_event_root_address_t *)vpEventData; - ESP_LOGI(LOG_TAG, "root address:"MACSTR"", - MAC2STR(root_addr->addr)); - } - break; +{ +mesh_event_root_address_t *root_addr = (mesh_event_root_address_t *)vpEventData; +ESP_LOGI(LOG_TAG, "root address:"MACSTR"", +MAC2STR(root_addr->addr)); +} +break; case MESH_EVENT_VOTE_STARTED: - { - mesh_event_vote_started_t *vote_started = (mesh_event_vote_started_t *)vpEventData; - ESP_LOGI(LOG_TAG, "attempts:%d, reason:%d, rc_addr:"MACSTR"", - vote_started->attempts, - vote_started->reason, - MAC2STR(vote_started->rc_addr.addr)); - } - break; +{ +mesh_event_vote_started_t *vote_started = (mesh_event_vote_started_t *)vpEventData; +ESP_LOGI(LOG_TAG, "attempts:%d, reason:%d, rc_addr:"MACSTR"", +vote_started->attempts, +vote_started->reason, +MAC2STR(vote_started->rc_addr.addr)); +} +break; case MESH_EVENT_VOTE_STOPPED: - { - ESP_LOGI(LOG_TAG, ""); - } - break; +{ +ESP_LOGI(LOG_TAG, ""); +} +break; case MESH_EVENT_ROOT_SWITCH_REQ: - { - mesh_event_root_switch_req_t *switch_req = (mesh_event_root_switch_req_t *)vpEventData; - ESP_LOGI(LOG_TAG, "reason:%d, rc_addr:"MACSTR"", switch_req->reason, - MAC2STR( switch_req->rc_addr.addr)); - } - break; +{ +mesh_event_root_switch_req_t *switch_req = (mesh_event_root_switch_req_t *)vpEventData; +ESP_LOGI(LOG_TAG, "reason:%d, rc_addr:"MACSTR"", switch_req->reason, +MAC2STR( switch_req->rc_addr.addr)); +} +break; case MESH_EVENT_ROOT_SWITCH_ACK: - { - //new root - i32MeshLayer = esp_mesh_get_layer(); - esp_mesh_get_parent_bssid(&meshParentAddr); - ESP_LOGI(LOG_TAG, "layer:%d, parent:"MACSTR"", i32MeshLayer, MAC2STR(meshParentAddr.addr)); - } - break; +{ +//new root +i32MeshLayer = esp_mesh_get_layer(); +esp_mesh_get_parent_bssid(&meshParentAddr); +ESP_LOGI(LOG_TAG, "layer:%d, parent:"MACSTR"", i32MeshLayer, MAC2STR(meshParentAddr.addr)); +} +break; case MESH_EVENT_TODS_STATE: - { - mesh_event_toDS_state_t *toDs_state = (mesh_event_toDS_state_t *)vpEventData; - ESP_LOGI(LOG_TAG, "state:%d", *toDs_state); - } - break; +{ +mesh_event_toDS_state_t *toDs_state = (mesh_event_toDS_state_t *)vpEventData; +ESP_LOGI(LOG_TAG, "state:%d", *toDs_state); +} +break; case MESH_EVENT_ROOT_FIXED: - { - mesh_event_root_fixed_t *root_fixed = (mesh_event_root_fixed_t *)vpEventData; - ESP_LOGI(LOG_TAG, "%s", - root_fixed->is_fixed ? "fixed" : "not fixed"); - } - break; +{ +mesh_event_root_fixed_t *root_fixed = (mesh_event_root_fixed_t *)vpEventData; +ESP_LOGI(LOG_TAG, "%s", +root_fixed->is_fixed ? "fixed" : "not fixed"); +} +break; case MESH_EVENT_ROOT_ASKED_YIELD: - { - mesh_event_root_conflict_t *root_conflict = (mesh_event_root_conflict_t *)vpEventData; - ESP_LOGI(LOG_TAG, ""MACSTR", rssi:%d, capacity:%d", - MAC2STR(root_conflict->addr), root_conflict->rssi, root_conflict->capacity); - } - break; +{ +mesh_event_root_conflict_t *root_conflict = (mesh_event_root_conflict_t *)vpEventData; +ESP_LOGI(LOG_TAG, ""MACSTR", rssi:%d, capacity:%d", +MAC2STR(root_conflict->addr), root_conflict->rssi, root_conflict->capacity); +} +break; case MESH_EVENT_CHANNEL_SWITCH: - { - mesh_event_channel_switch_t *channel_switch = (mesh_event_channel_switch_t *)vpEventData; - ESP_LOGI(LOG_TAG, "new channel:%d", channel_switch->channel); - } - break; +{ +mesh_event_channel_switch_t *channel_switch = (mesh_event_channel_switch_t *)vpEventData; +ESP_LOGI(LOG_TAG, "new channel:%d", channel_switch->channel); +} +break; case MESH_EVENT_SCAN_DONE: - { - mesh_event_scan_done_t *scan_done = (mesh_event_scan_done_t *)vpEventData; - ESP_LOGI(LOG_TAG, "number:%d", scan_done->number); - } - break; +{ +mesh_event_scan_done_t *scan_done = (mesh_event_scan_done_t *)vpEventData; +ESP_LOGI(LOG_TAG, "number:%d", scan_done->number); +} +break; case MESH_EVENT_NETWORK_STATE: - { - mesh_event_network_state_t *network_state = (mesh_event_network_state_t *)vpEventData; - ESP_LOGI(LOG_TAG, "is_rootless:%d", network_state->is_rootless); - } - break; +{ +mesh_event_network_state_t *network_state = (mesh_event_network_state_t *)vpEventData; +ESP_LOGI(LOG_TAG, "is_rootless:%d", network_state->is_rootless); +} +break; case MESH_EVENT_STOP_RECONNECTION: - { - ESP_LOGI(LOG_TAG, ""); - } - break; +{ +ESP_LOGI(LOG_TAG, ""); +} +break; case MESH_EVENT_FIND_NETWORK: - { - mesh_event_find_network_t *find_network = (mesh_event_find_network_t *)vpEventData; - ESP_LOGI(LOG_TAG, "new channel:%d, router BSSID:"MACSTR"", - find_network->channel, MAC2STR(find_network->router_bssid)); - } - break; +{ +mesh_event_find_network_t *find_network = (mesh_event_find_network_t *)vpEventData; +ESP_LOGI(LOG_TAG, "new channel:%d, router BSSID:"MACSTR"", +find_network->channel, MAC2STR(find_network->router_bssid)); +} +break; case MESH_EVENT_ROUTER_SWITCH: - { - mesh_event_router_switch_t *router_switch = (mesh_event_router_switch_t *)vpEventData; - ESP_LOGI(LOG_TAG, "new router:%s, channel:%d, "MACSTR"", - router_switch->ssid, router_switch->channel, MAC2STR(router_switch->bssid)); - } - break; +{ +mesh_event_router_switch_t *router_switch = (mesh_event_router_switch_t *)vpEventData; +ESP_LOGI(LOG_TAG, "new router:%s, channel:%d, "MACSTR"", +router_switch->ssid, router_switch->channel, MAC2STR(router_switch->bssid)); +} +break; case MESH_EVENT_PS_PARENT_DUTY: - { - mesh_event_ps_duty_t *ps_duty = (mesh_event_ps_duty_t *)vpEventData; - ESP_LOGI(LOG_TAG, "duty:%d", ps_duty->duty); - } - break; +{ +mesh_event_ps_duty_t *ps_duty = (mesh_event_ps_duty_t *)vpEventData; +ESP_LOGI(LOG_TAG, "duty:%d", ps_duty->duty); +} +break; case MESH_EVENT_PS_CHILD_DUTY: - { - mesh_event_ps_duty_t *ps_duty = (mesh_event_ps_duty_t *)vpEventData; - ESP_LOGI(LOG_TAG, "cidx:%d, "MACSTR", duty:%d", ps_duty->child_connected.aid-1, - MAC2STR(ps_duty->child_connected.mac), ps_duty->duty); - } - break; +{ +mesh_event_ps_duty_t *ps_duty = (mesh_event_ps_duty_t *)vpEventData; +ESP_LOGI(LOG_TAG, "cidx:%d, "MACSTR", duty:%d", ps_duty->child_connected.aid-1, +MAC2STR(ps_duty->child_connected.mac), ps_duty->duty); +} +break; default: ESP_LOGI(LOG_TAG, "unknown id:%d", i32EventID); break; diff --git a/components/mesh_ota/https_client.c b/components/mesh_ota/https_client.c index cb4d204..9c2b075 100644 --- a/components/mesh_ota/https_client.c +++ b/components/mesh_ota/https_client.c @@ -23,47 +23,47 @@ https_client_ret_t https_clientInitialize() i32RetHTTPClient = https_clientInitEmbedTLS(); if(i32RetHTTPClient == HTTPS_CLIENT_OK) - { - i32RetHTTPClient = https_clientConnectToServer(); - } + { + i32RetHTTPClient = https_clientConnectToServer(); + } if(i32RetHTTPClient == HTTPS_CLIENT_OK) - { - i32RetHTTPClient = https_clientValidateServer(); - } + { + i32RetHTTPClient = https_clientValidateServer(); + } if(i32RetHTTPClient == HTTPS_CLIENT_OK) - { - i32RetHTTPClient = https_clientSendRequest(); - } + { + i32RetHTTPClient = https_clientSendRequest(); + } switch (i32RetHTTPClient) - { - case HTTPS_CLIENT_ERROR_INIT_EMBEDTLS: - ESP_LOGE(TAG, "Unable to initialize EmbedTLS"); - i32RetHTTPClient = HTTPS_CLIENT_ERROR; - break; - case HTTPS_CLIENT_ERROR_INIT_CONNECT_TWO_SERVER: - ESP_LOGE(TAG, "Unable to connect to server"); - i32RetHTTPClient = HTTPS_CLIENT_ERROR; - break; - case HTTPS_CLIENT_ERROR_INIT_VALIDATE_SERVER: - ESP_LOGE(TAG, "Unable to validate the server"); - i32RetHTTPClient = HTTPS_CLIENT_ERROR; - break; - case HTTPS_CLIENT_ERROR_INIT_SEND_REQUEST: - ESP_LOGE(TAG, "Unable to send request to server"); - i32RetHTTPClient = HTTPS_CLIENT_ERROR; - break; - case HTTPS_CLIENT_OK: - ESP_LOGI(TAG, "HTTPS Client successfully initialized"); - i32RetHTTPClient = HTTPS_CLIENT_OK; - break; - default: - i32RetHTTPClient = HTTPS_CLIENT_ERROR; - ESP_LOGE(TAG, "Unknown error while init https client"); - break; - } + { + case HTTPS_CLIENT_ERROR_INIT_EMBEDTLS: + ESP_LOGE(TAG, "Unable to initialize EmbedTLS"); + i32RetHTTPClient = HTTPS_CLIENT_ERROR; + break; + case HTTPS_CLIENT_ERROR_INIT_CONNECT_TWO_SERVER: + ESP_LOGE(TAG, "Unable to connect to server"); + i32RetHTTPClient = HTTPS_CLIENT_ERROR; + break; + case HTTPS_CLIENT_ERROR_INIT_VALIDATE_SERVER: + ESP_LOGE(TAG, "Unable to validate the server"); + i32RetHTTPClient = HTTPS_CLIENT_ERROR; + break; + case HTTPS_CLIENT_ERROR_INIT_SEND_REQUEST: + ESP_LOGE(TAG, "Unable to send request to server"); + i32RetHTTPClient = HTTPS_CLIENT_ERROR; + break; + case HTTPS_CLIENT_OK: + ESP_LOGI(TAG, "HTTPS Client successfully initialized"); + i32RetHTTPClient = HTTPS_CLIENT_OK; + break; + default: + i32RetHTTPClient = HTTPS_CLIENT_ERROR; + ESP_LOGE(TAG, "Unknown error while init https client"); + break; + } return i32RetHTTPClient; } @@ -77,41 +77,41 @@ https_client_ret_t https_clientRetrieveData(char* pu8Data, uint32_t* pu32DataLen *pu32BytesRead = 0U; while (bRetriveData) - { - //Reading HTTP response - i32RetRetrieveData = mbedtls_ssl_read(&sHTTPS_ClientConfig.ssl, (unsigned char *)(pu8Data+(*pu32BytesRead)), ((*pu32DataLenght)-(*pu32BytesRead))); - - if(i32RetRetrieveData > 0) { - //Data received - *pu32BytesRead = *pu32BytesRead + i32RetRetrieveData; + //Reading HTTP response + i32RetRetrieveData = mbedtls_ssl_read(&sHTTPS_ClientConfig.ssl, (unsigned char *)(pu8Data+(*pu32BytesRead)), ((*pu32DataLenght)-(*pu32BytesRead))); - if(*pu32DataLenght > 0) - { - //buffer not full yet --> read some more - bRetriveData = true; - } - else - { - //buffer full --> stop reading - bRetriveData = false; - } - } + if(i32RetRetrieveData > 0) + { + //Data received + *pu32BytesRead = *pu32BytesRead + i32RetRetrieveData; - if(i32RetRetrieveData == 0) - { - //all data read --> stop reading - bRetriveData = false; - pu32BytesRead = 0; - } + if(*pu32DataLenght > 0) + { + //buffer not full yet --> read some more + bRetriveData = true; + } + else + { + //buffer full --> stop reading + bRetriveData = false; + } + } - if(i32RetRetrieveData == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) - { - //connection is going to be closed - i32RetHTTPClient = HTTPS_CLIENT_ERROR; - bRetriveData = false; + if(i32RetRetrieveData == 0) + { + //all data read --> stop reading + bRetriveData = false; + pu32BytesRead = 0; + } + + if(i32RetRetrieveData == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) + { + //connection is going to be closed + i32RetHTTPClient = HTTPS_CLIENT_ERROR; + bRetriveData = false; + } } - } return i32RetHTTPClient; } @@ -122,9 +122,9 @@ https_client_ret_t https_clientDeinitialize() i32RetHTTPClient = mbedtls_ssl_close_notify(&sHTTPS_ClientConfig.ssl); //close session if(i32RetHTTPClient != ESP_OK) - { - ESP_LOGE(TAG, "mbedtls_ssl_close_notify returned 0x%x", i32RetHTTPClient); - } + { + ESP_LOGE(TAG, "mbedtls_ssl_close_notify returned 0x%x", i32RetHTTPClient); + } mbedtls_ssl_session_reset(&sHTTPS_ClientConfig.ssl); //reset embedssl mbedtls_net_free(&sHTTPS_ClientConfig.server_fd); //free ram @@ -132,7 +132,8 @@ https_client_ret_t https_clientDeinitialize() return i32RetHTTPClient; } -https_client_ret_t https_clientInitEmbedTLS() { +https_client_ret_t https_clientInitEmbedTLS() +{ https_client_ret_t i32RetHTTPClient = HTTPS_CLIENT_OK; int32_t i32RetEmbedTLS = ESP_OK; @@ -146,66 +147,66 @@ https_client_ret_t https_clientInitEmbedTLS() { i32RetEmbedTLS = mbedtls_ctr_drbg_seed(&sHTTPS_ClientConfig.ctr_drbg, mbedtls_entropy_func, &sHTTPS_ClientConfig.entropy, NULL, 0); if(i32RetEmbedTLS!= ESP_OK) - { - ESP_LOGE(TAG, "mbedtls_ctr_drbg_seed returned %d", i32RetEmbedTLS); - } - - if(i32RetEmbedTLS == ESP_OK) - { - //Attaching the certificate bundle - i32RetEmbedTLS = esp_crt_bundle_attach(&sHTTPS_ClientConfig.conf); - if(i32RetEmbedTLS != ESP_OK) { - ESP_LOGE(TAG, "esp_crt_bundle_attach returned 0x%x\n\n", i32RetEmbedTLS); + ESP_LOGE(TAG, "mbedtls_ctr_drbg_seed returned %d", i32RetEmbedTLS); } - } if(i32RetEmbedTLS == ESP_OK) - { - //Setting hostname for TLS session. - i32RetEmbedTLS = mbedtls_ssl_set_hostname(&sHTTPS_ClientConfig.ssl, CONFIG_OTA_HTTPS_SERVER_COMMON_NAME); - // Hostname set here should match CN in server certificate - if(i32RetEmbedTLS != ESP_OK) { - ESP_LOGE(TAG, "mbedtls_ssl_set_hostname returned 0x%x", i32RetEmbedTLS); + //Attaching the certificate bundle + i32RetEmbedTLS = esp_crt_bundle_attach(&sHTTPS_ClientConfig.conf); + if(i32RetEmbedTLS != ESP_OK) + { + ESP_LOGE(TAG, "esp_crt_bundle_attach returned 0x%x\n\n", i32RetEmbedTLS); + } } - } - if(i32RetEmbedTLS == ESP_OK) - { - //Setting up the SSL/TLS structure - i32RetEmbedTLS = mbedtls_ssl_config_defaults(&sHTTPS_ClientConfig.conf, - MBEDTLS_SSL_IS_CLIENT, - MBEDTLS_SSL_TRANSPORT_STREAM, - MBEDTLS_SSL_PRESET_DEFAULT); - if(i32RetEmbedTLS != ESP_OK) + if(i32RetEmbedTLS == ESP_OK) { - ESP_LOGE(TAG, "mbedtls_ssl_config_defaults returned %d", i32RetEmbedTLS); + //Setting hostname for TLS session. + i32RetEmbedTLS = mbedtls_ssl_set_hostname(&sHTTPS_ClientConfig.ssl, CONFIG_OTA_HTTPS_SERVER_COMMON_NAME); + // Hostname set here should match CN in server certificate + if(i32RetEmbedTLS != ESP_OK) + { + ESP_LOGE(TAG, "mbedtls_ssl_set_hostname returned 0x%x", i32RetEmbedTLS); + } } - } - if(i32RetEmbedTLS == ESP_OK) - { - mbedtls_ssl_conf_authmode(&sHTTPS_ClientConfig.conf, MBEDTLS_SSL_VERIFY_REQUIRED); - mbedtls_ssl_conf_ca_chain(&sHTTPS_ClientConfig.conf, &sHTTPS_ClientConfig.cacert, NULL); - mbedtls_ssl_conf_rng(&sHTTPS_ClientConfig.conf, mbedtls_ctr_drbg_random, &sHTTPS_ClientConfig.ctr_drbg); - - i32RetEmbedTLS = mbedtls_ssl_setup(&sHTTPS_ClientConfig.ssl, &sHTTPS_ClientConfig.conf); - if(i32RetEmbedTLS != ESP_OK) { - ESP_LOGE(TAG, "mbedtls_ssl_setup returned -0x%x\n\n", i32RetEmbedTLS); + //Setting up the SSL/TLS structure + i32RetEmbedTLS = mbedtls_ssl_config_defaults(&sHTTPS_ClientConfig.conf, + MBEDTLS_SSL_IS_CLIENT, + MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT); + + if(i32RetEmbedTLS != ESP_OK) + { + ESP_LOGE(TAG, "mbedtls_ssl_config_defaults returned %d", i32RetEmbedTLS); + } } - } if(i32RetEmbedTLS == ESP_OK) - { - mbedtls_net_init(&sHTTPS_ClientConfig.server_fd); - } + { + mbedtls_ssl_conf_authmode(&sHTTPS_ClientConfig.conf, MBEDTLS_SSL_VERIFY_REQUIRED); + mbedtls_ssl_conf_ca_chain(&sHTTPS_ClientConfig.conf, &sHTTPS_ClientConfig.cacert, NULL); + mbedtls_ssl_conf_rng(&sHTTPS_ClientConfig.conf, mbedtls_ctr_drbg_random, &sHTTPS_ClientConfig.ctr_drbg); + + i32RetEmbedTLS = mbedtls_ssl_setup(&sHTTPS_ClientConfig.ssl, &sHTTPS_ClientConfig.conf); + if(i32RetEmbedTLS != ESP_OK) + { + ESP_LOGE(TAG, "mbedtls_ssl_setup returned -0x%x\n\n", i32RetEmbedTLS); + } + } + + if(i32RetEmbedTLS == ESP_OK) + { + mbedtls_net_init(&sHTTPS_ClientConfig.server_fd); + } if (i32RetEmbedTLS != ESP_OK) - { - i32RetHTTPClient = HTTPS_CLIENT_ERROR_INIT_EMBEDTLS; - } + { + i32RetHTTPClient = HTTPS_CLIENT_ERROR_INIT_EMBEDTLS; + } return i32RetHTTPClient; } @@ -218,28 +219,28 @@ https_client_ret_t https_clientConnectToServer() //Connecting to server i32RetServerConnect = mbedtls_net_connect(&sHTTPS_ClientConfig.server_fd, CONFIG_OTA_HTTPS_SERVER_COMMON_NAME, CONFIG_OTA_HTTPS_SERVER_PORT, MBEDTLS_NET_PROTO_TCP); if (i32RetServerConnect != ESP_OK) - { - ESP_LOGE(TAG, "mbedtls_net_connect returned %x", i32RetServerConnect); - } + { + ESP_LOGE(TAG, "mbedtls_net_connect returned %x", i32RetServerConnect); + } if(i32RetServerConnect == ESP_OK) - { - mbedtls_ssl_set_bio(&sHTTPS_ClientConfig.ssl, &sHTTPS_ClientConfig.server_fd, mbedtls_net_send, mbedtls_net_recv, NULL); - - //Performing the SSL/TLS handshake - while ((i32RetServerConnect = mbedtls_ssl_handshake(&sHTTPS_ClientConfig.ssl)) != 0) { - if ((i32RetServerConnect != MBEDTLS_ERR_SSL_WANT_READ) && (i32RetServerConnect != MBEDTLS_ERR_SSL_WANT_WRITE)) - { - ESP_LOGE(TAG, "mbedtls_ssl_handshake returned 0x%x", i32RetServerConnect); - } + mbedtls_ssl_set_bio(&sHTTPS_ClientConfig.ssl, &sHTTPS_ClientConfig.server_fd, mbedtls_net_send, mbedtls_net_recv, NULL); + + //Performing the SSL/TLS handshake + while ((i32RetServerConnect = mbedtls_ssl_handshake(&sHTTPS_ClientConfig.ssl)) != 0) + { + if ((i32RetServerConnect != MBEDTLS_ERR_SSL_WANT_READ) && (i32RetServerConnect != MBEDTLS_ERR_SSL_WANT_WRITE)) + { + ESP_LOGE(TAG, "mbedtls_ssl_handshake returned 0x%x", i32RetServerConnect); + } + } } - } if(i32RetServerConnect != ESP_OK) - { - i32RetHTTPClient = HTTPS_CLIENT_ERROR_INIT_CONNECT_TWO_SERVER; - } + { + i32RetHTTPClient = HTTPS_CLIENT_ERROR_INIT_CONNECT_TWO_SERVER; + } return i32RetHTTPClient; } @@ -250,14 +251,14 @@ https_client_ret_t https_clientValidateServer() //Verifying peer X.509 certificate if ((i32RetValidateServer = mbedtls_ssl_get_verify_result(&sHTTPS_ClientConfig.ssl)) != 0) - { - ESP_LOGE(TAG, "Failed to verify peer certificate!"); - } + { + ESP_LOGE(TAG, "Failed to verify peer certificate!"); + } if(i32RetValidateServer != ESP_OK) - { - i32RetHTTPClient = HTTPS_CLIENT_ERROR_INIT_VALIDATE_SERVER; - } + { + i32RetHTTPClient = HTTPS_CLIENT_ERROR_INIT_VALIDATE_SERVER; + } return i32RetHTTPClient; } @@ -270,23 +271,25 @@ https_client_ret_t https_clientSendRequest() //Writing HTTP request while((u32WrittenBytes < strlen(REQUEST)) && bWrite) - { - i32RetSendRequest = mbedtls_ssl_write(&sHTTPS_ClientConfig.ssl, - (const unsigned char *)REQUEST + u32WrittenBytes, - strlen(REQUEST) - u32WrittenBytes); - if (i32RetSendRequest >= 0) { - //bytes written - u32WrittenBytes += i32RetSendRequest; - } else if (i32RetSendRequest != MBEDTLS_ERR_SSL_WANT_WRITE && i32RetSendRequest != MBEDTLS_ERR_SSL_WANT_READ) { - ESP_LOGE(TAG, "mbedtls_ssl_write returned 0x%x", i32RetSendRequest); - bWrite = false; + i32RetSendRequest = mbedtls_ssl_write(&sHTTPS_ClientConfig.ssl, + (const unsigned char *)REQUEST + u32WrittenBytes, + strlen(REQUEST) - u32WrittenBytes); + if (i32RetSendRequest >= 0) + { + //bytes written + u32WrittenBytes += i32RetSendRequest; + } + else if (i32RetSendRequest != MBEDTLS_ERR_SSL_WANT_WRITE && i32RetSendRequest != MBEDTLS_ERR_SSL_WANT_READ) + { + ESP_LOGE(TAG, "mbedtls_ssl_write returned 0x%x", i32RetSendRequest); + bWrite = false; + } } - } if(bWrite == false) - { - i32RetHTTPClient = HTTPS_CLIENT_ERROR_INIT_SEND_REQUEST; - } + { + i32RetHTTPClient = HTTPS_CLIENT_ERROR_INIT_SEND_REQUEST; + } return i32RetHTTPClient; } diff --git a/components/mesh_ota/include/Mesh_OTA.h b/components/mesh_ota/include/Mesh_OTA.h index 4c61a60..3c6a99e 100644 --- a/components/mesh_ota/include/Mesh_OTA.h +++ b/components/mesh_ota/include/Mesh_OTA.h @@ -16,30 +16,34 @@ #include "Mesh_network.h" #define ERASE_NVS //erase non volatile storage if full - -/* -enum ota_packet_type - { - APP_Version_Request, - APP_Version_Response, - OTA_Data, - OTA_ACK, - OTA_Complete - }; -*/ +#define QUEUE_NODES_SIZE 10 +#define QUEUE_MESSAGE_OTA_SIZE 10 +#define SERVER_CHECK_INTERVAL 30 //in seconds #define ERROR_CHECK(x) if (err == ESP_OK) \ { \ err = (x); \ if (err != ESP_OK) \ { \ - ESP_LOGE(LOG_TAG, "%s failed with error: 0x%x -> %s", #x, err, esp_err_to_name(err)); \ + ESP_LOGE(LOG_TAG, "%s failed with error: 0x%x -> %s", #x, err, esp_err_to_name(err)); \ } \ } \ +esp_err_t errMeshOTAInitialize(); +//helper functions bool bNewerVersion(const char* pu8Local, const char* pu8Remote); esp_err_t errExtractVersionNumber(const char* pu8Data, uint32_t* pu32DataLenght, char* pc8RemoteVersionNumber); esp_err_t errFindImageStart(const char* pu8Data, uint32_t* pu32DataLenght, uint32_t* pu32StartOffset); +//Handler +void vAddNodeToPossibleUpdatableQueue(uint8_t* pu8Data); +void vAddOTAControllMessageToQueue(MESH_PACKET_t* puMeshPacket); +void vChangeStateOfServerWorker(bool state); + +//Tasks +void vTaskServerWorker(void *arg); + + + #endif /* H_MESH_OTA */ diff --git a/components/mesh_ota/include/Mesh_network.h b/components/mesh_ota/include/Mesh_network.h index 617354d..178dc61 100644 --- a/components/mesh_ota/include/Mesh_network.h +++ b/components/mesh_ota/include/Mesh_network.h @@ -59,6 +59,7 @@ struct meshPacket OTA_Complete //signal end of image } type; uint8_t au8Payload[1024]; + mesh_addr_t meshSenderAddr; }; typedef struct meshPacket MESH_PACKET_t; @@ -68,12 +69,18 @@ extern int32_t i32MeshLayer; extern mesh_addr_t meshParentAddr; extern esp_netif_t* netif_sta; extern uint8_t u8ownMAC[6]; +extern void (*pOTAChildConnectHandle)(uint8_t* ); +extern void (*pChangeStateOfServerWorkerHandle)(bool ); esp_err_t errMeshNetworkInitialize(); esp_err_t errMeshNetworkInitializeWiFi(); esp_err_t errMeshNetworkInitializeRouter(mesh_cfg_t* cfg); -esp_err_t errMeshNetworkSetAppReceiveHandle(void (*pFuncParam)(uint8_t * pu8Data, uint8_t* pu8Sender)); +esp_err_t errMeshNetworkSetAppReceiveHandle(void (*pAppRxHandleTmp)(uint8_t * pu8Data, uint8_t* pu8Sender)); +esp_err_t errMeshNetworkSetChildConnectedHandle(void (*pChildConnectHandleTmp)(uint8_t * pu8Data)); +esp_err_t errMeshNetworkSetOTAMessageHandleHandle(void (*pOTAMessageHandleTmp)(MESH_PACKET_t* puMeshPacket)); + +esp_err_t errMeshNetworkSetChangeStateOfServerWorkerHandle(void (*pChangeStateOfServerWorkerHandleTmp)(bool bState)); bool bCheckMACEquality(uint8_t* pu8aMAC, uint8_t* pu8bMAC); void vGetOwnAddr(mesh_addr_t* pMeshOwnAddr); diff --git a/main/Main.c b/main/Main.c index b00da8b..50164a3 100644 --- a/main/Main.c +++ b/main/Main.c @@ -20,14 +20,18 @@ void app_main(void) { esp_err_t err = ESP_OK; ESP_LOGI(LOG_TAG, "hardcoded: 0.0.1"); + + ESP_LOGI(LOG_TAG, "start mesh network"); err = errMeshNetworkInitialize(); ESP_ERROR_CHECK(err); - //start ota - - //start app - errBlinkyLEDInitialize(); + ESP_LOGI(LOG_TAG, "start ota"); + err = errMeshOTAInitialize(); + ESP_ERROR_CHECK(err); + ESP_LOGI(LOG_TAG, "start app"); + err = errBlinkyLEDInitialize(); + ESP_ERROR_CHECK(err); } From cf99410893bdce61cd7dd9d93b1338f493083902 Mon Sep 17 00:00:00 2001 From: localhorst Date: Sun, 17 Jan 2021 23:47:59 +0100 Subject: [PATCH 04/21] added https ota code in task --- components/mesh_ota/CMakeLists.txt | 2 +- .../{https_client.c => HTTPS_client.c} | 2 +- components/mesh_ota/Mesh_OTA.c | 79 ++++++- .../{https_client.h => HTTPS_client.h} | 0 components/mesh_ota/include/Mesh_OTA.h | 1 + main/Blinky_LED.c | 194 +++++++++--------- style_code.sh | 15 ++ 7 files changed, 194 insertions(+), 99 deletions(-) rename components/mesh_ota/{https_client.c => HTTPS_client.c} (99%) rename components/mesh_ota/include/{https_client.h => HTTPS_client.h} (100%) create mode 100644 style_code.sh diff --git a/components/mesh_ota/CMakeLists.txt b/components/mesh_ota/CMakeLists.txt index 5484c68..8d5c8bc 100644 --- a/components/mesh_ota/CMakeLists.txt +++ b/components/mesh_ota/CMakeLists.txt @@ -1,4 +1,4 @@ -idf_component_register(SRCS "https_client.c" "Mesh_network_handler.c" "Mesh_network.c" "Mesh_OTA.c" +idf_component_register(SRCS "HTTPS_client.c" "Mesh_network_handler.c" "Mesh_network.c" "Mesh_OTA.c" INCLUDE_DIRS "include" REQUIRES nvs_flash esp_http_client diff --git a/components/mesh_ota/https_client.c b/components/mesh_ota/HTTPS_client.c similarity index 99% rename from components/mesh_ota/https_client.c rename to components/mesh_ota/HTTPS_client.c index 9c2b075..40fd597 100644 --- a/components/mesh_ota/https_client.c +++ b/components/mesh_ota/HTTPS_client.c @@ -1,4 +1,4 @@ -#include "https_client.h" +#include "HTTPS_client.h" static const char *TAG = "https_client"; diff --git a/components/mesh_ota/Mesh_OTA.c b/components/mesh_ota/Mesh_OTA.c index 2254c5f..4496bed 100644 --- a/components/mesh_ota/Mesh_OTA.c +++ b/components/mesh_ota/Mesh_OTA.c @@ -48,7 +48,7 @@ esp_err_t errMeshOTAInitialize() if(err == ESP_OK) { - xReturned = xTaskCreate(vTaskServerWorker, "vTaskServerWorker", 4096, NULL, 5, NULL); + xReturned = xTaskCreate(vTaskServerWorker, "vTaskServerWorker", 8192, NULL, 5, NULL); if(xReturned != pdPASS) { ESP_LOGE(LOG_TAG, "Unable to create the server worker task"); @@ -128,6 +128,18 @@ void vTaskOTAWorker(void *arg) void vTaskServerWorker(void *arg) { + + esp_err_t err = ESP_OK; + uint32_t u32BufferLenght = 1024U; + char buffer[1024U]; + uint32_t u32BytesRead = 0; + char pcRemoteVersionNumber[12]; + const esp_partition_t * currentPartition; + const esp_partition_t * otaPartition; + static esp_ota_handle_t otaHandle; + uint32_t u32StartOffset; + esp_app_desc_t otaPartitionDesc; + while(true) { xSemaphoreTake(bsStartStopServerWorker, portMAX_DELAY); //wait for binary semaphore that allows to start the worker @@ -139,6 +151,71 @@ void vTaskServerWorker(void *arg) //server get version + currentPartition = esp_ota_get_boot_partition(); + ESP_LOGI(LOG_TAG, "Type: %d", (*currentPartition).subtype); + ESP_LOGI(LOG_TAG, "Start address: %d", (*currentPartition).address); + ESP_LOGI(LOG_TAG, "Size: %d", (*currentPartition).size); + ESP_LOGI(LOG_TAG, "Encrypted: %d", (*currentPartition).encrypted); + + esp_app_desc_t curPartitionDesc; + err = esp_ota_get_partition_description(currentPartition, &curPartitionDesc); + ESP_ERROR_CHECK(err); + ESP_LOGI(LOG_TAG, "currentPartition project_name: %s", (curPartitionDesc).project_name); + ESP_LOGI(LOG_TAG, "currentPartition version: %s", (curPartitionDesc).version); + ESP_LOGI(LOG_TAG, "currentPartition Timestamp: %s %s", (curPartitionDesc).date, (curPartitionDesc).time); + + https_clientInitialize(); + https_clientRetrieveData(buffer, &u32BufferLenght, &u32BytesRead); + ESP_LOGI(LOG_TAG, "Data received: %i", u32BytesRead); + err = errExtractVersionNumber(buffer, &u32BytesRead, pcRemoteVersionNumber); + + if(err == ESP_OK) + { + if(bNewerVersion((curPartitionDesc).version, pcRemoteVersionNumber)) + { + ESP_LOGI(LOG_TAG, "Newer Version available"); + //write ota + otaPartition= esp_ota_get_next_update_partition(currentPartition); + + err = errFindImageStart(buffer, &u32BufferLenght, &u32StartOffset); + + ESP_LOGI(LOG_TAG, "first byte offset: %i", u32StartOffset); + ESP_LOGI(LOG_TAG, "first byte: %x", buffer[u32StartOffset]); + + err = esp_ota_begin(otaPartition, OTA_SIZE_UNKNOWN, &otaHandle); + ESP_ERROR_CHECK(err); + + do + { + ESP_LOGI(LOG_TAG, "OTA-Data written: %i", u32BytesRead); + err = esp_ota_write(otaHandle, (const void*) buffer+u32StartOffset, (u32BytesRead-u32StartOffset)); + u32StartOffset = 0U; + https_clientRetrieveData(buffer, &u32BufferLenght, &u32BytesRead); + } + while (u32BytesRead > 0); + + err = esp_ota_end(otaHandle); + ESP_ERROR_CHECK(err); + + err = esp_ota_get_partition_description(otaPartition, &otaPartitionDesc); + ESP_ERROR_CHECK(err); + ESP_LOGI(LOG_TAG, "otaPartition project_name: %s", (otaPartitionDesc).project_name); + err = esp_ota_set_boot_partition(otaPartition); + ESP_ERROR_CHECK(err); + //esp_restart(); + } + else + { + ESP_LOGI(LOG_TAG, "NO newer Version available"); + } + } + else + { + ESP_LOGI(LOG_TAG, "errExtractVersionNumber failed: %i", err); + } + + https_clientDeinitialize(); + //ota update if newer //lock ota mutex diff --git a/components/mesh_ota/include/https_client.h b/components/mesh_ota/include/HTTPS_client.h similarity index 100% rename from components/mesh_ota/include/https_client.h rename to components/mesh_ota/include/HTTPS_client.h diff --git a/components/mesh_ota/include/Mesh_OTA.h b/components/mesh_ota/include/Mesh_OTA.h index 3c6a99e..343baec 100644 --- a/components/mesh_ota/include/Mesh_OTA.h +++ b/components/mesh_ota/include/Mesh_OTA.h @@ -14,6 +14,7 @@ #include "esp_partition.h" #include "Mesh_network.h" +#include "HTTPS_client.h" #define ERASE_NVS //erase non volatile storage if full #define QUEUE_NODES_SIZE 10 diff --git a/main/Blinky_LED.c b/main/Blinky_LED.c index 2cfc7c7..384d4bb 100644 --- a/main/Blinky_LED.c +++ b/main/Blinky_LED.c @@ -17,31 +17,31 @@ esp_err_t errBlinkyLEDInitialize() //create queue to store led action created from BTN and mesh network events queueBlinkyLEDPackets = xQueueCreate(5, sizeof(BLINKY_PACKET_t)); if (queueBlinkyLEDPackets == 0) // Queue not created - { - ESP_LOGE(LOG_TAG, "Unable to create Queue for Application Packets"); - err = ESP_FAIL; - } + { + ESP_LOGE(LOG_TAG, "Unable to create Queue for Application Packets"); + err = ESP_FAIL; + } //register the receiver handle in mesh network ERROR_CHECK(errMeshNetworkSetAppReceiveHandle(rxHandle)); if(err == ESP_OK) - { - xReturned = xTaskCreate(vTaskReadUserInput, "vTaskReadUserInput", 4096, NULL, 5, NULL); - if(xReturned != pdPASS) { - err = ESP_FAIL; + xReturned = xTaskCreate(vTaskReadUserInput, "vTaskReadUserInput", 4096, NULL, 5, NULL); + if(xReturned != pdPASS) + { + err = ESP_FAIL; + } } - } if(err == ESP_OK) - { - xReturned = xTaskCreate(vTaskReceiveData, "vTaskReceiveData", 4096, NULL, 5, NULL); - if(xReturned != pdPASS) { - err = ESP_FAIL; + xReturned = xTaskCreate(vTaskReceiveData, "vTaskReceiveData", 4096, NULL, 5, NULL); + if(xReturned != pdPASS) + { + err = ESP_FAIL; + } } - } return err; } @@ -69,9 +69,9 @@ void rxHandle(uint8_t* pu8Data, uint8_t* pu8Sender) memcpy(&bTmpPacket, (uint8_t *)pu8Data, sizeof(BLINKY_PACKET_t)); memcpy(&bTmpPacket.meshSenderAddr, (uint8_t *)pu8Sender, 6); //copy MAC from sender into app packet if (xQueueSend(queueBlinkyLEDPackets, &bTmpPacket, portMAX_DELAY) != pdPASS) - { - ESP_LOGE(LOG_TAG, "Unable to push packet from mesh into Queue"); - } + { + ESP_LOGE(LOG_TAG, "Unable to push packet from mesh into Queue"); + } } void vTaskReadUserInput(void *arg) @@ -84,48 +84,49 @@ void vTaskReadUserInput(void *arg) meshPacket.type = APP_Data; //this is a app packet while(true) - { //check for BTN press - if(gpio_get_level(GPIO_BOOT_BTN) == 0) { - err = ESP_OK; - - if(bLEDisOn == false) - { - bTmpPacket.type = LED_ON; - } - else - { - bTmpPacket.type = LED_OFF; - } - - //push led action into queue - if (xQueueSend(queueBlinkyLEDPackets, &bTmpPacket, portMAX_DELAY) != pdPASS) - { - ESP_LOGE(LOG_TAG, "Unable to push packet into queue"); - } - - memcpy(meshPacket.au8Payload, &bTmpPacket, sizeof(BLINKY_PACKET_t)); - - if(bIsRootNode() == false) - { - //this node is not root --> send led action to parent - ERROR_CHECK(errGetParentNode(&addrParent)); - ERROR_CHECK(errSendMeshPacket(&addrParent, &meshPacket)); - } - else - { - //this node is root --> send led action to children - ERROR_CHECK(errGetChildren(childrenAddr, &u16ChildrenSize)); - - for (uint16_t u16Index = 0; u16Index < u16ChildrenSize; u16Index++) + //check for BTN press + if(gpio_get_level(GPIO_BOOT_BTN) == 0) { - ERROR_CHECK (errSendMeshPacket(&childrenAddr[u16Index], &meshPacket)); + err = ESP_OK; + + if(bLEDisOn == false) + { + bTmpPacket.type = LED_ON; + } + else + { + bTmpPacket.type = LED_OFF; + } + + //push led action into queue + if (xQueueSend(queueBlinkyLEDPackets, &bTmpPacket, portMAX_DELAY) != pdPASS) + { + ESP_LOGE(LOG_TAG, "Unable to push packet into queue"); + } + + memcpy(meshPacket.au8Payload, &bTmpPacket, sizeof(BLINKY_PACKET_t)); + + if(bIsRootNode() == false) + { + //this node is not root --> send led action to parent + ERROR_CHECK(errGetParentNode(&addrParent)); + ERROR_CHECK(errSendMeshPacket(&addrParent, &meshPacket)); + } + else + { + //this node is root --> send led action to children + ERROR_CHECK(errGetChildren(childrenAddr, &u16ChildrenSize)); + + for (uint16_t u16Index = 0; u16Index < u16ChildrenSize; u16Index++) + { + ERROR_CHECK (errSendMeshPacket(&childrenAddr[u16Index], &meshPacket)); + } + } + vTaskDelay(200 / portTICK_PERIOD_MS); } - } - vTaskDelay(200 / portTICK_PERIOD_MS); + vTaskDelay(50 / portTICK_PERIOD_MS); } - vTaskDelay(50 / portTICK_PERIOD_MS); - } } void vTaskReceiveData(void *arg) @@ -138,47 +139,48 @@ void vTaskReceiveData(void *arg) meshPacket.type = APP_Data; //this is a app packet while (1) - { - if (xQueueReceive(queueBlinkyLEDPackets, &bTmpPacket, portMAX_DELAY) != pdTRUE) { - ESP_LOGE(LOG_TAG, "Unable to receive packet from Queue"); + if (xQueueReceive(queueBlinkyLEDPackets, &bTmpPacket, portMAX_DELAY) != pdTRUE) + { + ESP_LOGE(LOG_TAG, "Unable to receive packet from Queue"); + } + else + { + err = ESP_OK; + //Successfully RECEIVED the packet + switch (bTmpPacket.type) + { + case LED_ON: + bLEDisOn = true; + gpio_set_level(GPIO_LED, 1); //switch on + ESP_LOGI(LOG_TAG,"switch LED ON"); + break; + + case LED_OFF: + bLEDisOn = false; + gpio_set_level(GPIO_LED, 0); //switch off + ESP_LOGI(LOG_TAG,"switch LED OFF"); + break; + + default: + bLEDisOn = false; + gpio_set_level(GPIO_LED, 0); //switch off + ESP_LOGI(LOG_TAG,"switch LED OFF"); + break; + } + } + + ERROR_CHECK(errGetChildren(childrenAddr, &u16ChildrenSize)); //get all children attached to this node + memcpy(meshPacket.au8Payload, &bTmpPacket, sizeof(BLINKY_PACKET_t)); //copy led action in mesh packet payload + + for (uint16_t u16Index = 0; u16Index < u16ChildrenSize; u16Index++) + { + //loop through children + if(bCheckMACEquality(bTmpPacket.meshSenderAddr.addr, childrenAddr[u16Index].addr) == false) //exclude the sender node + { + ERROR_CHECK (errSendMeshPacket(&childrenAddr[u16Index], &meshPacket)); //send to child + } + } + vTaskDelay(200 / portTICK_PERIOD_MS); } - else - { - err = ESP_OK; - //Successfully RECEIVED the packet - switch (bTmpPacket.type) - { - case LED_ON: - bLEDisOn = true; - gpio_set_level(GPIO_LED, 1); //switch on - ESP_LOGI(LOG_TAG,"switch LED ON"); - break; - - case LED_OFF: - bLEDisOn = false; - gpio_set_level(GPIO_LED, 0); //switch off - ESP_LOGI(LOG_TAG,"switch LED OFF"); - break; - - default: - bLEDisOn = false; - gpio_set_level(GPIO_LED, 0); //switch off - ESP_LOGI(LOG_TAG,"switch LED OFF"); - break; - } - } - - ERROR_CHECK(errGetChildren(childrenAddr, &u16ChildrenSize)); //get all children attached to this node - memcpy(meshPacket.au8Payload, &bTmpPacket, sizeof(BLINKY_PACKET_t)); //copy led action in mesh packet payload - - for (uint16_t u16Index = 0; u16Index < u16ChildrenSize; u16Index++) - { //loop through children - if(bCheckMACEquality(bTmpPacket.meshSenderAddr.addr, childrenAddr[u16Index].addr) == false) //exclude the sender node - { - ERROR_CHECK (errSendMeshPacket(&childrenAddr[u16Index], &meshPacket)); //send to child - } - } - vTaskDelay(200 / portTICK_PERIOD_MS); - } } \ No newline at end of file diff --git a/style_code.sh b/style_code.sh new file mode 100644 index 0000000..2857fb3 --- /dev/null +++ b/style_code.sh @@ -0,0 +1,15 @@ +#! /bin/bash + +cd main +astyle --style=gnu *.c +astyle --style=gnu *.h + +cd .. + +cd components/mesh_ota +astyle --style=gnu *.c +cd include +astyle --style=gnu *.h + + + From c542dc05abddac1487a1f4ed25dbcd5684ffa9d6 Mon Sep 17 00:00:00 2001 From: localhorst Date: Mon, 18 Jan 2021 12:49:52 +0100 Subject: [PATCH 05/21] cleanup https ota --- components/mesh_ota/HTTPS_client.c | 31 +++- components/mesh_ota/Mesh_OTA.c | 198 +++++++++++++-------- components/mesh_ota/include/HTTPS_client.h | 1 + components/mesh_ota/include/Mesh_OTA.h | 2 + 4 files changed, 152 insertions(+), 80 deletions(-) diff --git a/components/mesh_ota/HTTPS_client.c b/components/mesh_ota/HTTPS_client.c index 40fd597..d273704 100644 --- a/components/mesh_ota/HTTPS_client.c +++ b/components/mesh_ota/HTTPS_client.c @@ -111,10 +111,20 @@ https_client_ret_t https_clientRetrieveData(char* pu8Data, uint32_t* pu32DataLen i32RetHTTPClient = HTTPS_CLIENT_ERROR; bRetriveData = false; } + } return i32RetHTTPClient; } +https_client_ret_t https_clientReset() +{ + https_client_ret_t i32RetHTTPClient = HTTPS_CLIENT_OK; + + i32RetHTTPClient = https_clientSendRequest(); + + return i32RetHTTPClient; +} + https_client_ret_t https_clientDeinitialize() { https_client_ret_t i32RetHTTPClient = HTTPS_CLIENT_OK; @@ -137,6 +147,7 @@ https_client_ret_t https_clientInitEmbedTLS() https_client_ret_t i32RetHTTPClient = HTTPS_CLIENT_OK; int32_t i32RetEmbedTLS = ESP_OK; + static bool bAlreadySetup = false; mbedtls_ssl_init(&sHTTPS_ClientConfig.ssl); mbedtls_x509_crt_init(&sHTTPS_ClientConfig.cacert); @@ -191,11 +202,25 @@ https_client_ret_t https_clientInitEmbedTLS() mbedtls_ssl_conf_ca_chain(&sHTTPS_ClientConfig.conf, &sHTTPS_ClientConfig.cacert, NULL); mbedtls_ssl_conf_rng(&sHTTPS_ClientConfig.conf, mbedtls_ctr_drbg_random, &sHTTPS_ClientConfig.ctr_drbg); - i32RetEmbedTLS = mbedtls_ssl_setup(&sHTTPS_ClientConfig.ssl, &sHTTPS_ClientConfig.conf); - if(i32RetEmbedTLS != ESP_OK) + if (bAlreadySetup == false) //check if mbedtls_ssl_setup was called before { - ESP_LOGE(TAG, "mbedtls_ssl_setup returned -0x%x\n\n", i32RetEmbedTLS); + i32RetEmbedTLS = mbedtls_ssl_setup(&sHTTPS_ClientConfig.ssl, &sHTTPS_ClientConfig.conf); //call this only once + if(i32RetEmbedTLS != ESP_OK) + { + ESP_LOGE(TAG, "mbedtls_ssl_setup returned 0x%x\n\n", i32RetEmbedTLS); + + // uint8_t buffer[20]; + //mbedtls_strerror(i32RetEmbedTLS, buffer, 20); + //ESP_LOGE(TAG, "%s", buffer); + } + else + { + bAlreadySetup = true; + } + } + + } if(i32RetEmbedTLS == ESP_OK) diff --git a/components/mesh_ota/Mesh_OTA.c b/components/mesh_ota/Mesh_OTA.c index 4496bed..5ec0713 100644 --- a/components/mesh_ota/Mesh_OTA.c +++ b/components/mesh_ota/Mesh_OTA.c @@ -128,105 +128,149 @@ void vTaskOTAWorker(void *arg) void vTaskServerWorker(void *arg) { - - esp_err_t err = ESP_OK; - uint32_t u32BufferLenght = 1024U; - char buffer[1024U]; - uint32_t u32BytesRead = 0; - char pcRemoteVersionNumber[12]; - const esp_partition_t * currentPartition; - const esp_partition_t * otaPartition; - static esp_ota_handle_t otaHandle; - uint32_t u32StartOffset; - esp_app_desc_t otaPartitionDesc; + esp_err_t err; + bool bNewOTAImage = false; // true if a new ota image was downloaded and validated + // bool bFirstRun = true; while(true) { + err = ESP_OK; xSemaphoreTake(bsStartStopServerWorker, portMAX_DELAY); //wait for binary semaphore that allows to start the worker xSemaphoreGive(bsStartStopServerWorker); //free binary semaphore, this allows the handler to change is to taken if (esp_mesh_is_root()) //check again that this node is the root node { - ESP_LOGI(LOG_TAG, "DEMO HTTP request"); + // if(bFirstRun == true) + // { + ERROR_CHECK(https_clientInitialize()); + // bFirstRun = false; + //} - //server get version + ERROR_CHECK(errOTAHTTPS(&bNewOTAImage)); + https_clientDeinitialize(); - currentPartition = esp_ota_get_boot_partition(); - ESP_LOGI(LOG_TAG, "Type: %d", (*currentPartition).subtype); - ESP_LOGI(LOG_TAG, "Start address: %d", (*currentPartition).address); - ESP_LOGI(LOG_TAG, "Size: %d", (*currentPartition).size); - ESP_LOGI(LOG_TAG, "Encrypted: %d", (*currentPartition).encrypted); + // https_clientReset(); - esp_app_desc_t curPartitionDesc; - err = esp_ota_get_partition_description(currentPartition, &curPartitionDesc); - ESP_ERROR_CHECK(err); - ESP_LOGI(LOG_TAG, "currentPartition project_name: %s", (curPartitionDesc).project_name); - ESP_LOGI(LOG_TAG, "currentPartition version: %s", (curPartitionDesc).version); - ESP_LOGI(LOG_TAG, "currentPartition Timestamp: %s %s", (curPartitionDesc).date, (curPartitionDesc).time); - - https_clientInitialize(); - https_clientRetrieveData(buffer, &u32BufferLenght, &u32BytesRead); - ESP_LOGI(LOG_TAG, "Data received: %i", u32BytesRead); - err = errExtractVersionNumber(buffer, &u32BytesRead, pcRemoteVersionNumber); - - if(err == ESP_OK) + if(bNewOTAImage == true) { - if(bNewerVersion((curPartitionDesc).version, pcRemoteVersionNumber)) - { - ESP_LOGI(LOG_TAG, "Newer Version available"); - //write ota - otaPartition= esp_ota_get_next_update_partition(currentPartition); - - err = errFindImageStart(buffer, &u32BufferLenght, &u32StartOffset); - - ESP_LOGI(LOG_TAG, "first byte offset: %i", u32StartOffset); - ESP_LOGI(LOG_TAG, "first byte: %x", buffer[u32StartOffset]); - - err = esp_ota_begin(otaPartition, OTA_SIZE_UNKNOWN, &otaHandle); - ESP_ERROR_CHECK(err); - - do - { - ESP_LOGI(LOG_TAG, "OTA-Data written: %i", u32BytesRead); - err = esp_ota_write(otaHandle, (const void*) buffer+u32StartOffset, (u32BytesRead-u32StartOffset)); - u32StartOffset = 0U; - https_clientRetrieveData(buffer, &u32BufferLenght, &u32BytesRead); - } - while (u32BytesRead > 0); - - err = esp_ota_end(otaHandle); - ESP_ERROR_CHECK(err); - - err = esp_ota_get_partition_description(otaPartition, &otaPartitionDesc); - ESP_ERROR_CHECK(err); - ESP_LOGI(LOG_TAG, "otaPartition project_name: %s", (otaPartitionDesc).project_name); - err = esp_ota_set_boot_partition(otaPartition); - ESP_ERROR_CHECK(err); - //esp_restart(); - } - else - { - ESP_LOGI(LOG_TAG, "NO newer Version available"); - } - } - else - { - ESP_LOGI(LOG_TAG, "errExtractVersionNumber failed: %i", err); + //set want reboot + ESP_LOGI(LOG_TAG, "Updated successfully via HTTPS, will reboot if possible"); } - https_clientDeinitialize(); - //ota update if newer - - //lock ota mutex vTaskDelay( (SERVER_CHECK_INTERVAL*1000) / portTICK_PERIOD_MS); //sleep till next server check } } } +esp_err_t errOTAHTTPS(bool* pbNewOTAImage) +{ + esp_err_t err = ESP_OK; + char buffer[1024U]; + uint32_t u32BufferLenght = 1024U; + uint32_t u32BytesRead = 0; + char pcRemoteVersionNumber[12]; + const esp_partition_t * currentPartition; + const esp_partition_t * otaPartition; + static esp_ota_handle_t otaHandle; + uint32_t u32StartOffset; + //esp_app_desc_t otaPartitionDesc; + esp_app_desc_t curPartitionDesc; + + + currentPartition = esp_ota_get_boot_partition(); + ESP_LOGI(LOG_TAG, "Type: %d", (*currentPartition).subtype); + ESP_LOGI(LOG_TAG, "Start address: %d", (*currentPartition).address); + ESP_LOGI(LOG_TAG, "Size: %d", (*currentPartition).size); + ESP_LOGI(LOG_TAG, "Encrypted: %d", (*currentPartition).encrypted); + + + ERROR_CHECK(esp_ota_get_partition_description(currentPartition, &curPartitionDesc)); + //ESP_LOGI(LOG_TAG, "currentPartition project_name: %s", (curPartitionDesc).project_name); + //ESP_LOGI(LOG_TAG, "currentPartition version: %s", (curPartitionDesc).version); + //ESP_LOGI(LOG_TAG, "currentPartition Timestamp: %s %s", (curPartitionDesc).date, (curPartitionDesc).time); + + + + ERROR_CHECK(https_clientRetrieveData(buffer, &u32BufferLenght, &u32BytesRead)); //read first bytes if image, including the version + + //ESP_LOGI(LOG_TAG, "Data received: %i", u32BytesRead); + + ERROR_CHECK(errExtractVersionNumber(buffer, &u32BytesRead, pcRemoteVersionNumber)); + + if(err == ESP_OK) + { + if(bNewerVersion((curPartitionDesc).version, pcRemoteVersionNumber)) //compare local and remote version + { + // server image is newer --> OTA update required + ESP_LOGI(LOG_TAG, "server image is newer --> OTA update required"); + + otaPartition = esp_ota_get_next_update_partition(currentPartition); + + if(otaPartition == NULL) + { + err = ESP_FAIL; + ESP_LOGE(LOG_TAG, "unable to get next ota partition"); + } + + ERROR_CHECK(errFindImageStart(buffer, &u32BufferLenght, &u32StartOffset)); //get image start offset + + //ESP_LOGI(LOG_TAG, "first byte offset: %i", u32StartOffset); + //ESP_LOGI(LOG_TAG, "first byte: %x", buffer[u32StartOffset]); + + //TODO lock ota mutex + + ERROR_CHECK(esp_ota_begin(otaPartition, OTA_SIZE_UNKNOWN, &otaHandle)); + + if(err == ESP_OK) + { + //image download and ota partition write + do + { + ESP_LOGI(LOG_TAG, "OTA-Data written: %i", u32BytesRead); + ERROR_CHECK(esp_ota_write(otaHandle, (const void*) buffer+u32StartOffset, (u32BytesRead-u32StartOffset))); + + if(err == ESP_OK) + { + //write was succsesfull + u32StartOffset = 0U; //reset the offset for next download + https_clientRetrieveData(buffer, &u32BufferLenght, &u32BytesRead); //download next data segment + } + } + while ((u32BytesRead > 0) && (err == ESP_OK)); + } + + if(err == ESP_OK) + { + //no error occurred --> finish ota update process + ERROR_CHECK(esp_ota_end(otaHandle)); //finish process + ERROR_CHECK(esp_ota_set_boot_partition(otaPartition)); //set new image as boot + if(err == ESP_OK) + { + *pbNewOTAImage = true; //image validated + } + } + else + { + // error occurred --> abort ota update process + ESP_LOGE(LOG_TAG, "abort ota process"); + ERROR_CHECK(esp_ota_abort(otaHandle)); + *pbNewOTAImage = false; //ota update failed + } + + //TODO unlock ota mutex + + } //end newer version on server + } //end version number extracted + + + + return err; +} + + /* - * 999.999.999 * Return true if remote version is newer (higher) than local version */ bool bNewerVersion(const char* pu8Local, const char* pu8Remote) diff --git a/components/mesh_ota/include/HTTPS_client.h b/components/mesh_ota/include/HTTPS_client.h index f2c9252..889363a 100644 --- a/components/mesh_ota/include/HTTPS_client.h +++ b/components/mesh_ota/include/HTTPS_client.h @@ -66,6 +66,7 @@ typedef struct HTTPS_Client HTTPS_Client_t; https_client_ret_t https_clientInitialize(); https_client_ret_t https_clientRetrieveData(char* pu8Data, uint32_t* pu32DataLenght, uint32_t* pu32BytesRead); +https_client_ret_t https_clientReset(); https_client_ret_t https_clientDeinitialize(); #endif /* H_HTTPS_CLIENT */ diff --git a/components/mesh_ota/include/Mesh_OTA.h b/components/mesh_ota/include/Mesh_OTA.h index 343baec..fece273 100644 --- a/components/mesh_ota/include/Mesh_OTA.h +++ b/components/mesh_ota/include/Mesh_OTA.h @@ -32,6 +32,8 @@ esp_err_t errMeshOTAInitialize(); +esp_err_t errOTAHTTPS(bool* pbNewOTAImage); + //helper functions bool bNewerVersion(const char* pu8Local, const char* pu8Remote); esp_err_t errExtractVersionNumber(const char* pu8Data, uint32_t* pu32DataLenght, char* pc8RemoteVersionNumber); From a0546aa3efd5916806faa7568626f578fe8abc24 Mon Sep 17 00:00:00 2001 From: localhorst Date: Mon, 18 Jan 2021 17:38:08 +0100 Subject: [PATCH 06/21] completet https ota --- components/mesh_ota/HTTPS_client.c | 58 ++------- components/mesh_ota/Mesh_OTA.c | 132 +++++++++------------ components/mesh_ota/include/HTTPS_client.h | 6 +- components/mesh_ota/include/Mesh_OTA.h | 1 + 4 files changed, 72 insertions(+), 125 deletions(-) diff --git a/components/mesh_ota/HTTPS_client.c b/components/mesh_ota/HTTPS_client.c index d273704..6c390f6 100644 --- a/components/mesh_ota/HTTPS_client.c +++ b/components/mesh_ota/HTTPS_client.c @@ -22,47 +22,10 @@ https_client_ret_t https_clientInitialize() i32RetHTTPClient = https_clientInitEmbedTLS(); - if(i32RetHTTPClient == HTTPS_CLIENT_OK) + if (i32RetHTTPClient == HTTPS_CLIENT_ERROR_INIT_EMBEDTLS) { - i32RetHTTPClient = https_clientConnectToServer(); - } - - if(i32RetHTTPClient == HTTPS_CLIENT_OK) - { - i32RetHTTPClient = https_clientValidateServer(); - } - - if(i32RetHTTPClient == HTTPS_CLIENT_OK) - { - i32RetHTTPClient = https_clientSendRequest(); - } - - switch (i32RetHTTPClient) - { - case HTTPS_CLIENT_ERROR_INIT_EMBEDTLS: ESP_LOGE(TAG, "Unable to initialize EmbedTLS"); i32RetHTTPClient = HTTPS_CLIENT_ERROR; - break; - case HTTPS_CLIENT_ERROR_INIT_CONNECT_TWO_SERVER: - ESP_LOGE(TAG, "Unable to connect to server"); - i32RetHTTPClient = HTTPS_CLIENT_ERROR; - break; - case HTTPS_CLIENT_ERROR_INIT_VALIDATE_SERVER: - ESP_LOGE(TAG, "Unable to validate the server"); - i32RetHTTPClient = HTTPS_CLIENT_ERROR; - break; - case HTTPS_CLIENT_ERROR_INIT_SEND_REQUEST: - ESP_LOGE(TAG, "Unable to send request to server"); - i32RetHTTPClient = HTTPS_CLIENT_ERROR; - break; - case HTTPS_CLIENT_OK: - ESP_LOGI(TAG, "HTTPS Client successfully initialized"); - i32RetHTTPClient = HTTPS_CLIENT_OK; - break; - default: - i32RetHTTPClient = HTTPS_CLIENT_ERROR; - ESP_LOGE(TAG, "Unknown error while init https client"); - break; } return i32RetHTTPClient; } @@ -78,6 +41,7 @@ https_client_ret_t https_clientRetrieveData(char* pu8Data, uint32_t* pu32DataLen while (bRetriveData) { + mbedtls_ssl_conf_read_timeout(&sHTTPS_ClientConfig.conf, HTTPS_READ_TIMEOUT); //set timeout //Reading HTTP response i32RetRetrieveData = mbedtls_ssl_read(&sHTTPS_ClientConfig.ssl, (unsigned char *)(pu8Data+(*pu32BytesRead)), ((*pu32DataLenght)-(*pu32BytesRead))); @@ -105,13 +69,18 @@ https_client_ret_t https_clientRetrieveData(char* pu8Data, uint32_t* pu32DataLen pu32BytesRead = 0; } + if(i32RetRetrieveData == MBEDTLS_ERR_SSL_TIMEOUT ) + { + //timeout --> stop reading + bRetriveData = false; + } + if(i32RetRetrieveData == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { //connection is going to be closed i32RetHTTPClient = HTTPS_CLIENT_ERROR; bRetriveData = false; } - } return i32RetHTTPClient; } @@ -120,15 +89,6 @@ https_client_ret_t https_clientReset() { https_client_ret_t i32RetHTTPClient = HTTPS_CLIENT_OK; - i32RetHTTPClient = https_clientSendRequest(); - - return i32RetHTTPClient; -} - -https_client_ret_t https_clientDeinitialize() -{ - https_client_ret_t i32RetHTTPClient = HTTPS_CLIENT_OK; - i32RetHTTPClient = mbedtls_ssl_close_notify(&sHTTPS_ClientConfig.ssl); //close session if(i32RetHTTPClient != ESP_OK) @@ -250,7 +210,7 @@ https_client_ret_t https_clientConnectToServer() if(i32RetServerConnect == ESP_OK) { - mbedtls_ssl_set_bio(&sHTTPS_ClientConfig.ssl, &sHTTPS_ClientConfig.server_fd, mbedtls_net_send, mbedtls_net_recv, NULL); + mbedtls_ssl_set_bio(&sHTTPS_ClientConfig.ssl, &sHTTPS_ClientConfig.server_fd, mbedtls_net_send, mbedtls_net_recv, mbedtls_net_recv_timeout); //Performing the SSL/TLS handshake while ((i32RetServerConnect = mbedtls_ssl_handshake(&sHTTPS_ClientConfig.ssl)) != 0) diff --git a/components/mesh_ota/Mesh_OTA.c b/components/mesh_ota/Mesh_OTA.c index 5ec0713..212c905 100644 --- a/components/mesh_ota/Mesh_OTA.c +++ b/components/mesh_ota/Mesh_OTA.c @@ -8,6 +8,8 @@ xQueueHandle queueMessageOTA; //mesh ota controll messages like "OTA_Version_Res SemaphoreHandle_t bsStartStopServerWorker; //binary semaphore +const esp_partition_t* pOTAPartition; //pointer to ota partition + esp_err_t errMeshOTAInitialize() { esp_err_t err = ESP_OK; @@ -46,6 +48,17 @@ esp_err_t errMeshOTAInitialize() ERROR_CHECK(errMeshNetworkSetOTAMessageHandleHandle(vAddOTAControllMessageToQueue)); ERROR_CHECK(errMeshNetworkSetChangeStateOfServerWorkerHandle(vChangeStateOfServerWorker)); + if(err == ESP_OK) + { + pOTAPartition = esp_ota_get_next_update_partition(NULL); //get ota partition + + if(pOTAPartition == NULL) + { + err = ESP_FAIL; + ESP_LOGE(LOG_TAG, "unable to get next ota partition"); + } + } + if(err == ESP_OK) { xReturned = xTaskCreate(vTaskServerWorker, "vTaskServerWorker", 8192, NULL, 5, NULL); @@ -130,7 +143,7 @@ void vTaskServerWorker(void *arg) { esp_err_t err; bool bNewOTAImage = false; // true if a new ota image was downloaded and validated - // bool bFirstRun = true; + bool bFirstRun = true; while(true) { @@ -140,16 +153,18 @@ void vTaskServerWorker(void *arg) if (esp_mesh_is_root()) //check again that this node is the root node { - // if(bFirstRun == true) - // { + if(bFirstRun == true) + { ERROR_CHECK(https_clientInitialize()); - // bFirstRun = false; - //} + bFirstRun = false; + } + + ERROR_CHECK(https_clientConnectToServer()); + ERROR_CHECK(https_clientValidateServer()); + ERROR_CHECK(https_clientSendRequest()); ERROR_CHECK(errOTAHTTPS(&bNewOTAImage)); - https_clientDeinitialize(); - - // https_clientReset(); + https_clientReset(); if(bNewOTAImage == true) { @@ -167,85 +182,58 @@ void vTaskServerWorker(void *arg) esp_err_t errOTAHTTPS(bool* pbNewOTAImage) { esp_err_t err = ESP_OK; - char buffer[1024U]; - uint32_t u32BufferLenght = 1024U; - uint32_t u32BytesRead = 0; - char pcRemoteVersionNumber[12]; - const esp_partition_t * currentPartition; - const esp_partition_t * otaPartition; - static esp_ota_handle_t otaHandle; - uint32_t u32StartOffset; - //esp_app_desc_t otaPartitionDesc; - esp_app_desc_t curPartitionDesc; + char u8OTABuffer[OTA_HTTPS_SEGMENT_SIZE]; //store image segment from server before ota write + uint32_t u32BufferLenght = OTA_HTTPS_SEGMENT_SIZE; //size of buffer + uint32_t u32BytesRead = 0; //number of bytes that are read from server, <= u32BufferLenght + char pcRemoteVersionNumber[12]; //string for version number in server image + const esp_partition_t* pBootPartition; //pointer to boot partition (that will booted after reset) + static esp_ota_handle_t otaHandle; //OTA process handle + uint32_t u32StartOffset = 0U; //start offset for image (exclude the http response data) + esp_app_desc_t bootPartitionDesc; //Metadate from boot partition + pBootPartition = esp_ota_get_boot_partition(); //get boot partition (that will booted after reset), not the running partition + ERROR_CHECK(esp_ota_get_partition_description(pBootPartition, &bootPartitionDesc)); //get metadate of partition - currentPartition = esp_ota_get_boot_partition(); - ESP_LOGI(LOG_TAG, "Type: %d", (*currentPartition).subtype); - ESP_LOGI(LOG_TAG, "Start address: %d", (*currentPartition).address); - ESP_LOGI(LOG_TAG, "Size: %d", (*currentPartition).size); - ESP_LOGI(LOG_TAG, "Encrypted: %d", (*currentPartition).encrypted); + ERROR_CHECK(https_clientRetrieveData(u8OTABuffer, &u32BufferLenght, &u32BytesRead)); //read first bytes if image, including the version + ERROR_CHECK(errExtractVersionNumber(u8OTABuffer, &u32BytesRead, pcRemoteVersionNumber)); //extract version numbers - ERROR_CHECK(esp_ota_get_partition_description(currentPartition, &curPartitionDesc)); - //ESP_LOGI(LOG_TAG, "currentPartition project_name: %s", (curPartitionDesc).project_name); - //ESP_LOGI(LOG_TAG, "currentPartition version: %s", (curPartitionDesc).version); - //ESP_LOGI(LOG_TAG, "currentPartition Timestamp: %s %s", (curPartitionDesc).date, (curPartitionDesc).time); - - - - ERROR_CHECK(https_clientRetrieveData(buffer, &u32BufferLenght, &u32BytesRead)); //read first bytes if image, including the version - - //ESP_LOGI(LOG_TAG, "Data received: %i", u32BytesRead); - - ERROR_CHECK(errExtractVersionNumber(buffer, &u32BytesRead, pcRemoteVersionNumber)); - - if(err == ESP_OK) + if(err == ESP_OK) //check if version number is found { - if(bNewerVersion((curPartitionDesc).version, pcRemoteVersionNumber)) //compare local and remote version + if(bNewerVersion((bootPartitionDesc).version, pcRemoteVersionNumber)) //compare local and remote version { // server image is newer --> OTA update required ESP_LOGI(LOG_TAG, "server image is newer --> OTA update required"); - otaPartition = esp_ota_get_next_update_partition(currentPartition); - - if(otaPartition == NULL) - { - err = ESP_FAIL; - ESP_LOGE(LOG_TAG, "unable to get next ota partition"); - } - - ERROR_CHECK(errFindImageStart(buffer, &u32BufferLenght, &u32StartOffset)); //get image start offset - - //ESP_LOGI(LOG_TAG, "first byte offset: %i", u32StartOffset); - //ESP_LOGI(LOG_TAG, "first byte: %x", buffer[u32StartOffset]); + ERROR_CHECK(errFindImageStart(u8OTABuffer, &u32BufferLenght, &u32StartOffset)); //get image start offset //TODO lock ota mutex - ERROR_CHECK(esp_ota_begin(otaPartition, OTA_SIZE_UNKNOWN, &otaHandle)); - + ERROR_CHECK(esp_ota_begin(pOTAPartition, OTA_SIZE_UNKNOWN, &otaHandle)); //start ota update process if(err == ESP_OK) { //image download and ota partition write + ESP_LOGI(LOG_TAG, "start ota https download"); do { - ESP_LOGI(LOG_TAG, "OTA-Data written: %i", u32BytesRead); - ERROR_CHECK(esp_ota_write(otaHandle, (const void*) buffer+u32StartOffset, (u32BytesRead-u32StartOffset))); + //TODO progress log + ERROR_CHECK(esp_ota_write(otaHandle, (const void*) u8OTABuffer+u32StartOffset, (u32BytesRead-u32StartOffset))); if(err == ESP_OK) { //write was succsesfull u32StartOffset = 0U; //reset the offset for next download - https_clientRetrieveData(buffer, &u32BufferLenght, &u32BytesRead); //download next data segment + ERROR_CHECK(https_clientRetrieveData(u8OTABuffer, &u32BufferLenght, &u32BytesRead)); //download next data segment } } - while ((u32BytesRead > 0) && (err == ESP_OK)); + while ((u32BytesRead > 0) && (err == ESP_OK)); //loop until error or complete image downloaded } if(err == ESP_OK) { //no error occurred --> finish ota update process ERROR_CHECK(esp_ota_end(otaHandle)); //finish process - ERROR_CHECK(esp_ota_set_boot_partition(otaPartition)); //set new image as boot + ERROR_CHECK(esp_ota_set_boot_partition(pOTAPartition)); //set new image as boot if(err == ESP_OK) { *pbNewOTAImage = true; //image validated @@ -253,23 +241,17 @@ esp_err_t errOTAHTTPS(bool* pbNewOTAImage) } else { - // error occurred --> abort ota update process - ESP_LOGE(LOG_TAG, "abort ota process"); + //error occurred --> abort ota update process + ESP_LOGE(LOG_TAG, "abort ota process due to error 0x%x -> %s", err, esp_err_to_name(err)); ERROR_CHECK(esp_ota_abort(otaHandle)); *pbNewOTAImage = false; //ota update failed } - //TODO unlock ota mutex - } //end newer version on server } //end version number extracted - - - return err; } - /* * Return true if remote version is newer (higher) than local version */ @@ -403,9 +385,9 @@ esp_err_t esp_mesh_ota_send(mesh_addr_t* dest) static uint32_t u32index; - const esp_partition_t * currentPartition = esp_ota_get_boot_partition(); + const esp_partition_t * pBootPartition = esp_ota_get_boot_partition(); - if((*currentPartition).subtype == 0) + if((*pBootPartition).subtype == 0) { int data_read = 0; @@ -422,7 +404,7 @@ esp_err_t esp_mesh_ota_send(mesh_addr_t* dest) else { ESP_LOGI(MESH_TAG, "OTA-Data read: %i", u32index); - err = esp_partition_read(currentPartition, (1024*u32index), packet.au8Payload, 1024 ); + err = esp_partition_read(pBootPartition, (1024*u32index), packet.au8Payload, 1024 ); ESP_ERROR_CHECK(err); data_read = 1024; u32index++; @@ -438,7 +420,7 @@ esp_err_t esp_mesh_ota_send(mesh_addr_t* dest) } else { - ESP_LOGI(MESH_TAG, "Subtype: %d", (*currentPartition).subtype); + ESP_LOGI(MESH_TAG, "Subtype: %d", (*pBootPartition).subtype); } return err; } @@ -449,14 +431,14 @@ esp_err_t esp_mesh_ota_receive(mesh_addr_t* dest, struct ota_mesh_packet* packet static esp_ota_handle_t otaHandle; static uint32_t u32index; - const esp_partition_t * currentPartition = esp_ota_get_boot_partition(); - const esp_partition_t * otaPartition = esp_ota_get_next_update_partition(currentPartition); + const esp_partition_t * pBootPartition = esp_ota_get_boot_partition(); + const esp_partition_t * pOTAPartition = esp_ota_get_next_update_partition(pBootPartition); if(u32index == 0) { //first run - err = esp_ota_begin(otaPartition, OTA_SIZE_UNKNOWN, &otaHandle); + err = esp_ota_begin(pOTAPartition, OTA_SIZE_UNKNOWN, &otaHandle); ESP_ERROR_CHECK(err); } @@ -480,11 +462,11 @@ esp_err_t esp_mesh_ota_receive(mesh_addr_t* dest, struct ota_mesh_packet* packet err = esp_ota_end(otaHandle); ESP_ERROR_CHECK(err); esp_app_desc_t otaPartitionDesc; - err = esp_ota_get_partition_description(otaPartition, &otaPartitionDesc); + err = esp_ota_get_partition_description(pOTAPartition, &otaPartitionDesc); ESP_ERROR_CHECK(err); - ESP_LOGI(MESH_TAG, "otaPartition project_name: %s", (otaPartitionDesc).project_name); + ESP_LOGI(MESH_TAG, "pOTAPartition project_name: %s", (otaPartitionDesc).project_name); - err = esp_ota_set_boot_partition(otaPartition); + err = esp_ota_set_boot_partition(pOTAPartition); ESP_ERROR_CHECK(err); struct ota_mesh_packet retPacket; diff --git a/components/mesh_ota/include/HTTPS_client.h b/components/mesh_ota/include/HTTPS_client.h index 889363a..a1c464f 100644 --- a/components/mesh_ota/include/HTTPS_client.h +++ b/components/mesh_ota/include/HTTPS_client.h @@ -51,6 +51,8 @@ #define HTTPS_CLIENT_ERROR_INIT_VALIDATE_SERVER -4 #define HTTPS_CLIENT_ERROR_INIT_SEND_REQUEST -5 +#define HTTPS_READ_TIMEOUT 1000 //ms + struct HTTPS_Client { mbedtls_entropy_context entropy; @@ -65,9 +67,11 @@ typedef int32_t https_client_ret_t; typedef struct HTTPS_Client HTTPS_Client_t; https_client_ret_t https_clientInitialize(); +https_client_ret_t https_clientConnectToServer(); +https_client_ret_t https_clientValidateServer(); +https_client_ret_t https_clientSendRequest(); https_client_ret_t https_clientRetrieveData(char* pu8Data, uint32_t* pu32DataLenght, uint32_t* pu32BytesRead); https_client_ret_t https_clientReset(); -https_client_ret_t https_clientDeinitialize(); #endif /* H_HTTPS_CLIENT */ diff --git a/components/mesh_ota/include/Mesh_OTA.h b/components/mesh_ota/include/Mesh_OTA.h index fece273..c42f0bb 100644 --- a/components/mesh_ota/include/Mesh_OTA.h +++ b/components/mesh_ota/include/Mesh_OTA.h @@ -20,6 +20,7 @@ #define QUEUE_NODES_SIZE 10 #define QUEUE_MESSAGE_OTA_SIZE 10 #define SERVER_CHECK_INTERVAL 30 //in seconds +#define OTA_HTTPS_SEGMENT_SIZE 2048U #define ERROR_CHECK(x) if (err == ESP_OK) \ { \ From 88fd2c69a916194471ccb390280c334187f398f3 Mon Sep 17 00:00:00 2001 From: localhorst Date: Mon, 18 Jan 2021 19:03:32 +0100 Subject: [PATCH 07/21] added OTA process mutex; progress log; reboot flag --- components/mesh_ota/HTTPS_client.c | 18 ++--- components/mesh_ota/Mesh_OTA.c | 89 +++++++++++++++++----- components/mesh_ota/include/HTTPS_client.h | 12 +-- components/mesh_ota/include/Mesh_OTA.h | 4 +- components/mesh_ota/include/Mesh_network.h | 3 - 5 files changed, 86 insertions(+), 40 deletions(-) diff --git a/components/mesh_ota/HTTPS_client.c b/components/mesh_ota/HTTPS_client.c index 6c390f6..6518925 100644 --- a/components/mesh_ota/HTTPS_client.c +++ b/components/mesh_ota/HTTPS_client.c @@ -12,11 +12,11 @@ static const char *REQUEST = "GET " CONFIG_OTA_HTTPS_URL " HTTP/1.1\r\n" static HTTPS_Client_t sHTTPS_ClientConfig; https_client_ret_t https_clientInitEmbedTLS(); -https_client_ret_t https_clientConnectToServer(); -https_client_ret_t https_clientValidateServer(); -https_client_ret_t https_clientSendRequest(); +https_client_ret_t errHTTPSClientConnectToServer(); +https_client_ret_t errHTTPSClientValidateServer(); +https_client_ret_t errHTTPSClientSendRequest(); -https_client_ret_t https_clientInitialize() +https_client_ret_t errHTTPSClientInitialize() { https_client_ret_t i32RetHTTPClient = HTTPS_CLIENT_OK; @@ -30,7 +30,7 @@ https_client_ret_t https_clientInitialize() return i32RetHTTPClient; } -https_client_ret_t https_clientRetrieveData(char* pu8Data, uint32_t* pu32DataLenght, uint32_t* pu32BytesRead) +https_client_ret_t errHTTPSClientRetrieveData(char* pu8Data, uint32_t* pu32DataLenght, uint32_t* pu32BytesRead) { https_client_ret_t i32RetHTTPClient = HTTPS_CLIENT_OK; int32_t i32RetRetrieveData = ESP_OK; @@ -85,7 +85,7 @@ https_client_ret_t https_clientRetrieveData(char* pu8Data, uint32_t* pu32DataLen return i32RetHTTPClient; } -https_client_ret_t https_clientReset() +https_client_ret_t errHTTPSClientReset() { https_client_ret_t i32RetHTTPClient = HTTPS_CLIENT_OK; @@ -196,7 +196,7 @@ https_client_ret_t https_clientInitEmbedTLS() return i32RetHTTPClient; } -https_client_ret_t https_clientConnectToServer() +https_client_ret_t errHTTPSClientConnectToServer() { https_client_ret_t i32RetHTTPClient = HTTPS_CLIENT_OK; int32_t i32RetServerConnect = ESP_OK; @@ -229,7 +229,7 @@ https_client_ret_t https_clientConnectToServer() return i32RetHTTPClient; } -https_client_ret_t https_clientValidateServer() +https_client_ret_t errHTTPSClientValidateServer() { https_client_ret_t i32RetHTTPClient = HTTPS_CLIENT_OK; int32_t i32RetValidateServer = ESP_OK; @@ -247,7 +247,7 @@ https_client_ret_t https_clientValidateServer() return i32RetHTTPClient; } -https_client_ret_t https_clientSendRequest() +https_client_ret_t errHTTPSClientSendRequest() { https_client_ret_t i32RetHTTPClient = HTTPS_CLIENT_OK; int32_t i32RetSendRequest = ESP_OK; diff --git a/components/mesh_ota/Mesh_OTA.c b/components/mesh_ota/Mesh_OTA.c index 212c905..4851bcb 100644 --- a/components/mesh_ota/Mesh_OTA.c +++ b/components/mesh_ota/Mesh_OTA.c @@ -1,19 +1,21 @@ #include "Mesh_OTA.h" - static const char *LOG_TAG = "mesh_ota"; xQueueHandle queueNodes; //nodes that should be checked for ota update (contains children and parent) xQueueHandle queueMessageOTA; //mesh ota controll messages like "OTA_Version_Response" "OTA_ACK" SemaphoreHandle_t bsStartStopServerWorker; //binary semaphore +SemaphoreHandle_t bsOTAProcess; //binary semaphore const esp_partition_t* pOTAPartition; //pointer to ota partition +bool bWantReboot; //flag to signal pending reboot esp_err_t errMeshOTAInitialize() { esp_err_t err = ESP_OK; BaseType_t xReturned; + bWantReboot = false; //create queue to store nodes for ota worker task queueNodes = xQueueCreate(QUEUE_NODES_SIZE, sizeof(mesh_addr_t)); @@ -44,6 +46,26 @@ esp_err_t errMeshOTAInitialize() } } + if(err == ESP_OK) + { + bsOTAProcess = xSemaphoreCreateBinary(); + if( bsOTAProcess == NULL ) + { + ESP_LOGE(LOG_TAG, "Unable to create Mutex to grant access to OTA Process"); + err = ESP_FAIL; + } + } + + if(err == ESP_OK) + { + xSemaphoreGive(bsOTAProcess); //unlock binary semaphore + if( bsOTAProcess == NULL ) + { + ESP_LOGE(LOG_TAG, "Unable to unlock Mutex to grant access to OTA Process"); + err = ESP_FAIL; + } + } + ERROR_CHECK(errMeshNetworkSetChildConnectedHandle(vAddNodeToPossibleUpdatableQueue)); ERROR_CHECK(errMeshNetworkSetOTAMessageHandleHandle(vAddOTAControllMessageToQueue)); ERROR_CHECK(errMeshNetworkSetChangeStateOfServerWorkerHandle(vChangeStateOfServerWorker)); @@ -72,7 +94,6 @@ esp_err_t errMeshOTAInitialize() return err; } - void vAddNodeToPossibleUpdatableQueue(uint8_t* pu8Data) { //send payload to node queue @@ -89,7 +110,6 @@ void vAddNodeToPossibleUpdatableQueue(uint8_t* pu8Data) } } - void vAddOTAControllMessageToQueue(MESH_PACKET_t* puMeshPacket) { //send ota packet to packet queue @@ -103,7 +123,6 @@ void vAddOTAControllMessageToQueue(MESH_PACKET_t* puMeshPacket) } } - void vChangeStateOfServerWorker(bool bState) //allow access via function ptn to networl_handler { static bool bLastState = false; @@ -142,38 +161,39 @@ void vTaskOTAWorker(void *arg) void vTaskServerWorker(void *arg) { esp_err_t err; - bool bNewOTAImage = false; // true if a new ota image was downloaded and validated + bool bNewOTAImage; //true if a new ota image was downloaded and validated bool bFirstRun = true; while(true) { err = ESP_OK; + bNewOTAImage = false; xSemaphoreTake(bsStartStopServerWorker, portMAX_DELAY); //wait for binary semaphore that allows to start the worker xSemaphoreGive(bsStartStopServerWorker); //free binary semaphore, this allows the handler to change is to taken if (esp_mesh_is_root()) //check again that this node is the root node { + ESP_LOGI(LOG_TAG, "Checking firmware image on server"); + if(bFirstRun == true) { - ERROR_CHECK(https_clientInitialize()); + ERROR_CHECK(errHTTPSClientInitialize()); bFirstRun = false; } - ERROR_CHECK(https_clientConnectToServer()); - ERROR_CHECK(https_clientValidateServer()); - ERROR_CHECK(https_clientSendRequest()); + ERROR_CHECK(errHTTPSClientConnectToServer()); + ERROR_CHECK(errHTTPSClientValidateServer()); + ERROR_CHECK(errHTTPSClientSendRequest()); ERROR_CHECK(errOTAHTTPS(&bNewOTAImage)); - https_clientReset(); + errHTTPSClientReset(); if(bNewOTAImage == true) { //set want reboot - ESP_LOGI(LOG_TAG, "Updated successfully via HTTPS, will reboot if possible"); + ESP_LOGI(LOG_TAG, "Updated successfully via HTTPS, set pending reboot"); + bWantReboot = true; } - - - vTaskDelay( (SERVER_CHECK_INTERVAL*1000) / portTICK_PERIOD_MS); //sleep till next server check } } @@ -190,11 +210,12 @@ esp_err_t errOTAHTTPS(bool* pbNewOTAImage) static esp_ota_handle_t otaHandle; //OTA process handle uint32_t u32StartOffset = 0U; //start offset for image (exclude the http response data) esp_app_desc_t bootPartitionDesc; //Metadate from boot partition + uint32_t u32OTABytesWritten = 0U; //counter unsed for progress log pBootPartition = esp_ota_get_boot_partition(); //get boot partition (that will booted after reset), not the running partition ERROR_CHECK(esp_ota_get_partition_description(pBootPartition, &bootPartitionDesc)); //get metadate of partition - ERROR_CHECK(https_clientRetrieveData(u8OTABuffer, &u32BufferLenght, &u32BytesRead)); //read first bytes if image, including the version + ERROR_CHECK(errHTTPSClientRetrieveData(u8OTABuffer, &u32BufferLenght, &u32BytesRead)); //read first bytes if image, including the version ERROR_CHECK(errExtractVersionNumber(u8OTABuffer, &u32BytesRead, pcRemoteVersionNumber)); //extract version numbers @@ -207,23 +228,24 @@ esp_err_t errOTAHTTPS(bool* pbNewOTAImage) ERROR_CHECK(errFindImageStart(u8OTABuffer, &u32BufferLenght, &u32StartOffset)); //get image start offset - //TODO lock ota mutex + xSemaphoreTake(bsOTAProcess, portMAX_DELAY); //wait for binary semaphore that allows to start the OTA process ERROR_CHECK(esp_ota_begin(pOTAPartition, OTA_SIZE_UNKNOWN, &otaHandle)); //start ota update process if(err == ESP_OK) { //image download and ota partition write - ESP_LOGI(LOG_TAG, "start ota https download"); + ESP_LOGI(LOG_TAG, "start OTA download via HTTPS"); do { - //TODO progress log + vPrintOTAProgress(&(pOTAPartition->size), &u32OTABytesWritten); ERROR_CHECK(esp_ota_write(otaHandle, (const void*) u8OTABuffer+u32StartOffset, (u32BytesRead-u32StartOffset))); if(err == ESP_OK) { //write was succsesfull u32StartOffset = 0U; //reset the offset for next download - ERROR_CHECK(https_clientRetrieveData(u8OTABuffer, &u32BufferLenght, &u32BytesRead)); //download next data segment + ERROR_CHECK(errHTTPSClientRetrieveData(u8OTABuffer, &u32BufferLenght, &u32BytesRead)); //download next data segment + u32OTABytesWritten = u32OTABytesWritten + u32BytesRead; //update counter } } while ((u32BytesRead > 0) && (err == ESP_OK)); //loop until error or complete image downloaded @@ -246,8 +268,12 @@ esp_err_t errOTAHTTPS(bool* pbNewOTAImage) ERROR_CHECK(esp_ota_abort(otaHandle)); *pbNewOTAImage = false; //ota update failed } - //TODO unlock ota mutex - } //end newer version on server + xSemaphoreGive(bsOTAProcess); //free binary semaphore, this allows other tasks to start the OTA process + } + else + { + ESP_LOGI(LOG_TAG, "server image is NOT newer --> OTA update NOT required"); + } } //end version number extracted return err; } @@ -378,6 +404,27 @@ esp_err_t errExtractVersionNumber(const char* pu8Data, uint32_t* pu32DataLenght, return err; } +inline void vPrintOTAProgress(const uint32_t* const pu32TotalImageSize, const uint32_t* const pu32BytesWritten) +{ + uint32_t u32Percentage = 0U; + static uint32_t u32LastPercentage = 0U; + + if((*pu32BytesWritten) >= (*pu32TotalImageSize)) + { + u32Percentage = 100; + } + else + { + u32Percentage = (uint32_t) (((float) (*pu32BytesWritten)/(float) (*pu32TotalImageSize)) * 100.0); + } + + if((u32Percentage-u32LastPercentage) >= OTA_PROGRESS_LOG_INTERVAL) + { + ESP_LOGI(LOG_TAG, "OTA update progress: %i %%", u32Percentage); + u32LastPercentage = u32Percentage; + } +} + /* esp_err_t esp_mesh_ota_send(mesh_addr_t* dest) { diff --git a/components/mesh_ota/include/HTTPS_client.h b/components/mesh_ota/include/HTTPS_client.h index a1c464f..0150363 100644 --- a/components/mesh_ota/include/HTTPS_client.h +++ b/components/mesh_ota/include/HTTPS_client.h @@ -66,12 +66,12 @@ struct HTTPS_Client typedef int32_t https_client_ret_t; typedef struct HTTPS_Client HTTPS_Client_t; -https_client_ret_t https_clientInitialize(); -https_client_ret_t https_clientConnectToServer(); -https_client_ret_t https_clientValidateServer(); -https_client_ret_t https_clientSendRequest(); -https_client_ret_t https_clientRetrieveData(char* pu8Data, uint32_t* pu32DataLenght, uint32_t* pu32BytesRead); -https_client_ret_t https_clientReset(); +https_client_ret_t errHTTPSClientInitialize(); +https_client_ret_t errHTTPSClientConnectToServer(); +https_client_ret_t errHTTPSClientValidateServer(); +https_client_ret_t errHTTPSClientSendRequest(); +https_client_ret_t errHTTPSClientRetrieveData(char* pu8Data, uint32_t* pu32DataLenght, uint32_t* pu32BytesRead); +https_client_ret_t errHTTPSClientReset(); #endif /* H_HTTPS_CLIENT */ diff --git a/components/mesh_ota/include/Mesh_OTA.h b/components/mesh_ota/include/Mesh_OTA.h index c42f0bb..d6df8fb 100644 --- a/components/mesh_ota/include/Mesh_OTA.h +++ b/components/mesh_ota/include/Mesh_OTA.h @@ -21,6 +21,7 @@ #define QUEUE_MESSAGE_OTA_SIZE 10 #define SERVER_CHECK_INTERVAL 30 //in seconds #define OTA_HTTPS_SEGMENT_SIZE 2048U +#define OTA_PROGRESS_LOG_INTERVAL 7U #define ERROR_CHECK(x) if (err == ESP_OK) \ { \ @@ -39,6 +40,7 @@ esp_err_t errOTAHTTPS(bool* pbNewOTAImage); bool bNewerVersion(const char* pu8Local, const char* pu8Remote); esp_err_t errExtractVersionNumber(const char* pu8Data, uint32_t* pu32DataLenght, char* pc8RemoteVersionNumber); esp_err_t errFindImageStart(const char* pu8Data, uint32_t* pu32DataLenght, uint32_t* pu32StartOffset); +void vPrintOTAProgress(const uint32_t* const pu32TotalImageSize, const uint32_t* const pu32BytesWritten); //Handler void vAddNodeToPossibleUpdatableQueue(uint8_t* pu8Data); @@ -46,7 +48,7 @@ void vAddOTAControllMessageToQueue(MESH_PACKET_t* puMeshPacket); void vChangeStateOfServerWorker(bool state); //Tasks -void vTaskServerWorker(void *arg); +inline void vTaskServerWorker(void *arg); diff --git a/components/mesh_ota/include/Mesh_network.h b/components/mesh_ota/include/Mesh_network.h index 178dc61..0bbd5f4 100644 --- a/components/mesh_ota/include/Mesh_network.h +++ b/components/mesh_ota/include/Mesh_network.h @@ -95,8 +95,5 @@ void vIPEventHandler(void *arg, esp_event_base_t event_base, int32_t i32EventID, esp_err_t errSendMeshPacket(mesh_addr_t* pAddrDest, MESH_PACKET_t* pPacket); - - - #endif /* H_MESH_NETWORK */ From 64460498768113dbbbe6f28ca6918341752acead Mon Sep 17 00:00:00 2001 From: localhorst Date: Mon, 18 Jan 2021 22:56:42 +0100 Subject: [PATCH 08/21] OTA message handle call and vAddAllNeighboursToQueue() --- components/mesh_ota/Mesh_OTA.c | 73 ++++++++++++++++++++-- components/mesh_ota/Mesh_network.c | 21 +++---- components/mesh_ota/include/Mesh_OTA.h | 6 +- components/mesh_ota/include/Mesh_network.h | 3 + 4 files changed, 84 insertions(+), 19 deletions(-) diff --git a/components/mesh_ota/Mesh_OTA.c b/components/mesh_ota/Mesh_OTA.c index 4851bcb..afd93f9 100644 --- a/components/mesh_ota/Mesh_OTA.c +++ b/components/mesh_ota/Mesh_OTA.c @@ -91,14 +91,25 @@ esp_err_t errMeshOTAInitialize() } } + + if(err == ESP_OK) + { + xReturned = xTaskCreate(vTaskOTAWorker, "vTaskOTAWorker", 8192, NULL, 5, NULL); + if(xReturned != pdPASS) + { + ESP_LOGE(LOG_TAG, "Unable to create the OTA worker task"); + err = ESP_FAIL; + } + } + return err; } -void vAddNodeToPossibleUpdatableQueue(uint8_t* pu8Data) +void vAddNodeToPossibleUpdatableQueue(uint8_t* pu8MAC) { - //send payload to node queue + //send payload to node queues mesh_addr_t addrNode; - memcpy(&addrNode.addr, (uint8_t *)pu8Data, 6); //copy MAC + memcpy(&addrNode.addr, (uint8_t *)pu8MAC, 6); //copy MAC if (xQueueSend(queueNodes, &addrNode, portMAX_DELAY) != pdPASS) { @@ -151,11 +162,37 @@ void vChangeStateOfServerWorker(bool bState) //allow access via function ptn to void vTaskOTAWorker(void *arg) { + while(true) + { + + if((uxQueueSpacesAvailable(queueNodes) - QUEUE_NODES_SIZE) == 0) + { + //nodes queue is empty + ESP_LOGI(LOG_TAG, "nodes queue is empty"); + + if(bWantReboot == true) + { + ESP_LOGI(LOG_TAG, "ESP32 Reboot ..."); + //vTaskDelay( (1000) / portTICK_PERIOD_MS); + //esp_restart(); + } + + //read OTAMessages queue + //if OTA_Version_Response + // --> send OTA_Version_Request + // --> this version older --> start OTA_Rx --> vAddAllNeighboursToQueue(); //add all existing neighbours to queues + // --> this version newer --> start OTA_Tx + + //if not OTA_Version_Response --> do nothing + + + } - + vTaskDelay( (1000) / portTICK_PERIOD_MS); + } } void vTaskServerWorker(void *arg) @@ -193,8 +230,9 @@ void vTaskServerWorker(void *arg) //set want reboot ESP_LOGI(LOG_TAG, "Updated successfully via HTTPS, set pending reboot"); bWantReboot = true; + vAddAllNeighboursToQueue(); //add all existing neighbours to queue (aparent will not be added because this node is the root) } - vTaskDelay( (SERVER_CHECK_INTERVAL*1000) / portTICK_PERIOD_MS); //sleep till next server check + vTaskDelay( (SERVER_CHECK_INTERVAL*1000) / portTICK_PERIOD_MS); //sleep till next server checks } } } @@ -404,7 +442,7 @@ esp_err_t errExtractVersionNumber(const char* pu8Data, uint32_t* pu32DataLenght, return err; } -inline void vPrintOTAProgress(const uint32_t* const pu32TotalImageSize, const uint32_t* const pu32BytesWritten) +void vPrintOTAProgress(const uint32_t* const pu32TotalImageSize, const uint32_t* const pu32BytesWritten) { uint32_t u32Percentage = 0U; static uint32_t u32LastPercentage = 0U; @@ -425,6 +463,29 @@ inline void vPrintOTAProgress(const uint32_t* const pu32TotalImageSize, const ui } } +void vAddAllNeighboursToQueue(void) +{ + esp_err_t err = ESP_OK; + + mesh_addr_t addrParent; //addr of parent node + mesh_addr_t childrenAddr[CONFIG_MESH_ROUTE_TABLE_SIZE]; //array of children attached to this node + uint16_t u16ChildrenSize; //number of children attached to this node + + err = errGetParentNode(&addrParent); + + if(err == ESP_OK) + { + vAddNodeToPossibleUpdatableQueue(addrParent.addr); + } + + ERROR_CHECK(errGetChildren(childrenAddr, &u16ChildrenSize)); //get all children + + for (uint16_t u16Index = 0; u16Index < u16ChildrenSize; u16Index++) + { + vAddNodeToPossibleUpdatableQueue(childrenAddr[u16Index].addr); + } +} + /* esp_err_t esp_mesh_ota_send(mesh_addr_t* dest) { diff --git a/components/mesh_ota/Mesh_network.c b/components/mesh_ota/Mesh_network.c index 6542219..f8fec8f 100644 --- a/components/mesh_ota/Mesh_network.c +++ b/components/mesh_ota/Mesh_network.c @@ -160,12 +160,14 @@ esp_err_t errGetParentNode(mesh_addr_t* pMeshParentAddr) { esp_err_t err = ESP_OK; - if(bIsMeshConnected == false) + if((bIsMeshConnected == false) || (esp_mesh_is_root())) { + //this node is not connected or is the root --> this node has no parent err = ESP_FAIL; } else { + //node has parent memcpy(pMeshParentAddr, &meshParentAddr, sizeof(mesh_addr_t)); } return err; @@ -253,7 +255,8 @@ void vTaskReceiveMeshData(void *arg) continue; } MESH_PACKET_t packet; - memcpy(&packet, (uint8_t *)rx_buf, sizeof(MESH_PACKET_t)); + memcpy(&packet, (uint8_t *)rx_buf, sizeof(MESH_PACKET_t)); //parse MESH_PACKET_t + memcpy(&packet.meshSenderAddr, &from, sizeof(mesh_addr_t)); //copy sender into packet switch (packet.type) { @@ -263,19 +266,15 @@ void vTaskReceiveMeshData(void *arg) pAppRxHandle(packet.au8Payload, from.addr); //hand over payload and sender of this mesh packet break; case OTA_Version_Request: - ESP_LOGI(LOG_TAG, "recv: OTA_Version_Request"); - break; case OTA_Version_Respone: - ESP_LOGI(LOG_TAG, "recv: OTA_Version_Respone"); - break; case OTA_Data: - ESP_LOGI(LOG_TAG, "recv: OTA_Data"); - break; case OTA_ACK: - ESP_LOGI(LOG_TAG, "recv: OTA_ACK"); - break; case OTA_Complete: - ESP_LOGI(LOG_TAG, "recv: OTA_Complete"); + //call the rx handle from OTA + if(pOTAMessageHandle) + { + pOTAMessageHandle(&packet); + } break; default: ESP_LOGE(LOG_TAG, "recv: something"); diff --git a/components/mesh_ota/include/Mesh_OTA.h b/components/mesh_ota/include/Mesh_OTA.h index d6df8fb..7a75f1c 100644 --- a/components/mesh_ota/include/Mesh_OTA.h +++ b/components/mesh_ota/include/Mesh_OTA.h @@ -41,14 +41,16 @@ bool bNewerVersion(const char* pu8Local, const char* pu8Remote); esp_err_t errExtractVersionNumber(const char* pu8Data, uint32_t* pu32DataLenght, char* pc8RemoteVersionNumber); esp_err_t errFindImageStart(const char* pu8Data, uint32_t* pu32DataLenght, uint32_t* pu32StartOffset); void vPrintOTAProgress(const uint32_t* const pu32TotalImageSize, const uint32_t* const pu32BytesWritten); +void vAddAllNeighboursToQueue(void); //Handler -void vAddNodeToPossibleUpdatableQueue(uint8_t* pu8Data); +void vAddNodeToPossibleUpdatableQueue(uint8_t* pu8MAC); void vAddOTAControllMessageToQueue(MESH_PACKET_t* puMeshPacket); void vChangeStateOfServerWorker(bool state); //Tasks -inline void vTaskServerWorker(void *arg); +void vTaskServerWorker(void *arg); +void vTaskOTAWorker(void *arg); diff --git a/components/mesh_ota/include/Mesh_network.h b/components/mesh_ota/include/Mesh_network.h index 0bbd5f4..178dc61 100644 --- a/components/mesh_ota/include/Mesh_network.h +++ b/components/mesh_ota/include/Mesh_network.h @@ -95,5 +95,8 @@ void vIPEventHandler(void *arg, esp_event_base_t event_base, int32_t i32EventID, esp_err_t errSendMeshPacket(mesh_addr_t* pAddrDest, MESH_PACKET_t* pPacket); + + + #endif /* H_MESH_NETWORK */ From b274d939c4f4aa0faa616ef4cea05c2cd63bab67 Mon Sep 17 00:00:00 2001 From: localhorst Date: Tue, 19 Jan 2021 12:36:21 +0100 Subject: [PATCH 09/21] OTA mesh worker --- components/mesh_ota/Mesh_OTA.c | 199 ++++++++++++++++----- components/mesh_ota/Mesh_network.c | 4 +- components/mesh_ota/include/Mesh_OTA.h | 3 + components/mesh_ota/include/Mesh_network.h | 2 +- 4 files changed, 159 insertions(+), 49 deletions(-) diff --git a/components/mesh_ota/Mesh_OTA.c b/components/mesh_ota/Mesh_OTA.c index afd93f9..8610180 100644 --- a/components/mesh_ota/Mesh_OTA.c +++ b/components/mesh_ota/Mesh_OTA.c @@ -160,41 +160,6 @@ void vChangeStateOfServerWorker(bool bState) //allow access via function ptn to } } -void vTaskOTAWorker(void *arg) -{ - while(true) - { - - if((uxQueueSpacesAvailable(queueNodes) - QUEUE_NODES_SIZE) == 0) - { - //nodes queue is empty - ESP_LOGI(LOG_TAG, "nodes queue is empty"); - - if(bWantReboot == true) - { - ESP_LOGI(LOG_TAG, "ESP32 Reboot ..."); - //vTaskDelay( (1000) / portTICK_PERIOD_MS); - //esp_restart(); - } - - //read OTAMessages queue - //if OTA_Version_Response - // --> send OTA_Version_Request - // --> this version older --> start OTA_Rx --> vAddAllNeighboursToQueue(); //add all existing neighbours to queues - // --> this version newer --> start OTA_Tx - - //if not OTA_Version_Response --> do nothing - - - } - - - - - vTaskDelay( (1000) / portTICK_PERIOD_MS); - } -} - void vTaskServerWorker(void *arg) { esp_err_t err; @@ -237,6 +202,61 @@ void vTaskServerWorker(void *arg) } } +void vTaskOTAWorker(void *arg) +{ + esp_err_t err = ESP_OK; + bool bNewOTAImage; //true if a new ota image was downloaded and validated + mesh_addr_t meshNodeAddr; //node that should be checked for ota update + + while(true) + { + err = ESP_OK; + bNewOTAImage = false; + + if((uxQueueSpacesAvailable(queueNodes) - QUEUE_NODES_SIZE) == 0) + { + //nodes queue is empty + ESP_LOGI(LOG_TAG, "nodes queue is empty"); + + if(bWantReboot == true) + { + ESP_LOGI(LOG_TAG, "ESP32 Reboot ..."); + //vTaskDelay( (1000) / portTICK_PERIOD_MS); + //esp_restart(); + } + + ERROR_CHECK(errOTAMeshSlave(&bNewOTAImage)); + } + else + { + //queue not empty + ESP_LOGI(LOG_TAG, "nodes queue not empty: %i", (QUEUE_NODES_SIZE - uxQueueSpacesAvailable(queueNodes))); + + if (xQueueReceive(queueNodes, &meshNodeAddr, ((100) / portTICK_PERIOD_MS)) != pdTRUE) + { + ESP_LOGE(LOG_TAG, "Unable to receive OTA Messages from Queue"); + err = ESP_FAIL; + } + + ERROR_CHECK(errOTAMeshMaster(&bNewOTAImage, &meshNodeAddr)); + } + + if(bNewOTAImage == true) + { + //set want reboot + ESP_LOGI(LOG_TAG, "Updated successfully via Mesh, set pending reboot"); + bWantReboot = true; + vAddAllNeighboursToQueue(); //add all existing neighbours to queue + } + + + + + vTaskDelay( (1000) / portTICK_PERIOD_MS); + } +} + + esp_err_t errOTAHTTPS(bool* pbNewOTAImage) { esp_err_t err = ESP_OK; @@ -250,15 +270,17 @@ esp_err_t errOTAHTTPS(bool* pbNewOTAImage) esp_app_desc_t bootPartitionDesc; //Metadate from boot partition uint32_t u32OTABytesWritten = 0U; //counter unsed for progress log - pBootPartition = esp_ota_get_boot_partition(); //get boot partition (that will booted after reset), not the running partition - ERROR_CHECK(esp_ota_get_partition_description(pBootPartition, &bootPartitionDesc)); //get metadate of partition - ERROR_CHECK(errHTTPSClientRetrieveData(u8OTABuffer, &u32BufferLenght, &u32BytesRead)); //read first bytes if image, including the version ERROR_CHECK(errExtractVersionNumber(u8OTABuffer, &u32BytesRead, pcRemoteVersionNumber)); //extract version numbers if(err == ESP_OK) //check if version number is found { + xSemaphoreTake(bsOTAProcess, portMAX_DELAY); //wait for binary semaphore that allows to start the OTA process + + pBootPartition = esp_ota_get_boot_partition(); //get boot partition (that will booted after reset), not the running partition + ERROR_CHECK(esp_ota_get_partition_description(pBootPartition, &bootPartitionDesc)); //get metadata of partition + if(bNewerVersion((bootPartitionDesc).version, pcRemoteVersionNumber)) //compare local and remote version { // server image is newer --> OTA update required @@ -266,8 +288,6 @@ esp_err_t errOTAHTTPS(bool* pbNewOTAImage) ERROR_CHECK(errFindImageStart(u8OTABuffer, &u32BufferLenght, &u32StartOffset)); //get image start offset - xSemaphoreTake(bsOTAProcess, portMAX_DELAY); //wait for binary semaphore that allows to start the OTA process - ERROR_CHECK(esp_ota_begin(pOTAPartition, OTA_SIZE_UNKNOWN, &otaHandle)); //start ota update process if(err == ESP_OK) { @@ -306,16 +326,83 @@ esp_err_t errOTAHTTPS(bool* pbNewOTAImage) ERROR_CHECK(esp_ota_abort(otaHandle)); *pbNewOTAImage = false; //ota update failed } - xSemaphoreGive(bsOTAProcess); //free binary semaphore, this allows other tasks to start the OTA process } else { ESP_LOGI(LOG_TAG, "server image is NOT newer --> OTA update NOT required"); } + xSemaphoreGive(bsOTAProcess); //free binary semaphore, this allows other tasks to start the OTA process } //end version number extracted return err; } +esp_err_t errOTAMeshSlave(bool* pbNewOTAImage) +{ + esp_err_t err = ESP_OK; + MESH_PACKET_t sOTAMessage; + const esp_partition_t* pBootPartition; //pointer to boot partition (that will booted after reset) + esp_app_desc_t bootPartitionDesc; //Metadate from boot partition + *pbNewOTAImage = false; //set default false + + //read OTAMessages queue + if(uxQueueSpacesAvailable(queueMessageOTA) < QUEUE_MESSAGE_OTA_SIZE) + { + //queue not empty + if (xQueueReceive(queueMessageOTA, &sOTAMessage, ((100) / portTICK_PERIOD_MS)) != pdTRUE) + { + ESP_LOGE(LOG_TAG, "Unable to receive OTA Messages from Queue"); + err = ESP_FAIL; + } + + if((err == ESP_OK) && (sOTAMessage.type == OTA_Version_Request)) //if OTA_Version_Request + { + xSemaphoreTake(bsOTAProcess, portMAX_DELAY); //wait for binary semaphore that allows to start the OTA process + + pBootPartition = esp_ota_get_boot_partition(); //get boot partition (that will booted after reset), not the running partition + ERROR_CHECK(esp_ota_get_partition_description(pBootPartition, &bootPartitionDesc)); //get metadata of partition + + //send OTA_Version_Response to sender of OTA_Version_Request packet + ERROR_CHECK(errSendOTAVersionResponse(&sOTAMessage.meshSenderAddr)); + + if((bNewerVersion((bootPartitionDesc).version, (char*) sOTAMessage.au8Payload)) && (err == ESP_OK)) //compare local and remote version + { + //remote newer as local + ESP_LOGI(LOG_TAG, "remote image on node is newer --> OTA update required"); + // --> this version older --> start OTA_Rx --> set pbNewOTAImage true + } + + if((bNewerVersion((char*) sOTAMessage.au8Payload, (bootPartitionDesc).version)) && (err == ESP_OK)) //compare remote and local version + { + //local newer as remote + ESP_LOGI(LOG_TAG, "remote image on node is older --> OTA send required"); + // --> this version newer --> start OTA_Tx + } + xSemaphoreGive(bsOTAProcess); //free binary semaphore, this allows other tasks to start the OTA process + } + } + return err; +} + +esp_err_t errOTAMeshMaster(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr) +{ + esp_err_t err = ESP_OK; + MESH_PACKET_t sOTAMessage; + const esp_partition_t* pBootPartition; //pointer to boot partition (that will booted after reset) + esp_app_desc_t bootPartitionDesc; //Metadate from boot partition + *pbNewOTAImage = false; //set default false + + //get node + //check if node is still connected + // --> send OTA_Version_Request + // --> read OTA_Version_Response (if from this node) (all other OTA message add again) + // --> this version older --> start OTA_Rx --> vAddAllNeighboursToQueue(); //add all existing neighbours to queues + // --> this version newer --> start OTA_Tx + + + return err; +} + + /* * Return true if remote version is newer (higher) than local version */ @@ -328,8 +415,8 @@ bool bNewerVersion(const char* pu8Local, const char* pu8Remote) bool bReturn = false; //flag to stop loop uint8_t u8Index = 0; //numbers counter in version string - strcpy(u8LocalTmp, pu8Local); //copy in tmp - strcpy(u8RemoteTmp, pu8Remote); //copy in tmp + strncpy(u8LocalTmp, pu8Local, 12); //copy in tmp + strncpy(u8RemoteTmp, pu8Remote, 12); //copy in tmp char* pu8TokenLocal = strtok_r(u8LocalTmp, ".", &pu8saveptrLocal); //split tokens char* pu8TokenRemote = strtok_r(u8RemoteTmp, ".", &pu8saveptrRemote); //split tokens @@ -469,23 +556,43 @@ void vAddAllNeighboursToQueue(void) mesh_addr_t addrParent; //addr of parent node mesh_addr_t childrenAddr[CONFIG_MESH_ROUTE_TABLE_SIZE]; //array of children attached to this node - uint16_t u16ChildrenSize; //number of children attached to this node + uint16_t u16ChildrenSize = 0U; //number of children attached to this node err = errGetParentNode(&addrParent); if(err == ESP_OK) { vAddNodeToPossibleUpdatableQueue(addrParent.addr); + ESP_LOGI(LOG_TAG, "added parent"); } + err = ESP_OK; //reset error code + ERROR_CHECK(errGetChildren(childrenAddr, &u16ChildrenSize)); //get all children - for (uint16_t u16Index = 0; u16Index < u16ChildrenSize; u16Index++) + for (uint16_t u16Index = 0; ((u16Index < u16ChildrenSize) && (err == ESP_OK)); u16Index++) { vAddNodeToPossibleUpdatableQueue(childrenAddr[u16Index].addr); + ESP_LOGI(LOG_TAG, "added child"); } } +esp_err_t errSendOTAVersionResponse(mesh_addr_t* pMeshReceiverAddr) +{ + esp_err_t err = ESP_OK; + MESH_PACKET_t packet; + packet.type = OTA_Version_Response; + + const esp_partition_t* pBootPartition; //pointer to boot partition (that will booted after reset) + esp_app_desc_t bootPartitionDesc; //Metadata from boot partition + + pBootPartition = esp_ota_get_boot_partition(); //get boot partition (that will booted after reset), not the running partition + ERROR_CHECK(esp_ota_get_partition_description(pBootPartition, &bootPartitionDesc)); //get metadate of partition + memcpy(&packet.au8Payload, &bootPartitionDesc.version, 12); //copy local version to OTA_Version_Response packet + err = errSendMeshPacket(pMeshReceiverAddr, &packet); + return err; +} + /* esp_err_t esp_mesh_ota_send(mesh_addr_t* dest) { @@ -591,4 +698,4 @@ esp_err_t esp_mesh_ota_receive(mesh_addr_t* dest, struct ota_mesh_packet* packet return err; } -*/ \ No newline at end of file +*/ diff --git a/components/mesh_ota/Mesh_network.c b/components/mesh_ota/Mesh_network.c index f8fec8f..bb008c6 100644 --- a/components/mesh_ota/Mesh_network.c +++ b/components/mesh_ota/Mesh_network.c @@ -147,7 +147,7 @@ esp_err_t errGetChildren(mesh_addr_t* pChildren, uint16_t* pu16ChildrenSize) if(! (bCheckMACEquality(u8ownMAC, route_table[index].addr)) ) { //child node - //ESP_LOGI(MESH_TAG, "adding Node: \"0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\" ", route_table[index].addr[0], route_table[index].addr[1], route_table[index].addr[2], route_table[index].addr[3], route_table[index].addr[4], route_table[index].addr[5]); + //ESP_LOGI(LOG_TAG, "adding Node: \"0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\" ", route_table[index].addr[0], route_table[index].addr[1], route_table[index].addr[2], route_table[index].addr[3], route_table[index].addr[4], route_table[index].addr[5]); pChildren[*pu16ChildrenSize] = route_table[index]; *pu16ChildrenSize = (*pu16ChildrenSize)+1; } @@ -266,7 +266,7 @@ void vTaskReceiveMeshData(void *arg) pAppRxHandle(packet.au8Payload, from.addr); //hand over payload and sender of this mesh packet break; case OTA_Version_Request: - case OTA_Version_Respone: + case OTA_Version_Response: case OTA_Data: case OTA_ACK: case OTA_Complete: diff --git a/components/mesh_ota/include/Mesh_OTA.h b/components/mesh_ota/include/Mesh_OTA.h index 7a75f1c..0983e8f 100644 --- a/components/mesh_ota/include/Mesh_OTA.h +++ b/components/mesh_ota/include/Mesh_OTA.h @@ -35,6 +35,8 @@ esp_err_t errMeshOTAInitialize(); esp_err_t errOTAHTTPS(bool* pbNewOTAImage); +esp_err_t errOTAMeshSlave(bool* pbNewOTAImage); +esp_err_t errOTAMeshMaster(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr); //helper functions bool bNewerVersion(const char* pu8Local, const char* pu8Remote); @@ -42,6 +44,7 @@ esp_err_t errExtractVersionNumber(const char* pu8Data, uint32_t* pu32DataLenght esp_err_t errFindImageStart(const char* pu8Data, uint32_t* pu32DataLenght, uint32_t* pu32StartOffset); void vPrintOTAProgress(const uint32_t* const pu32TotalImageSize, const uint32_t* const pu32BytesWritten); void vAddAllNeighboursToQueue(void); +esp_err_t errSendOTAVersionResponse(mesh_addr_t* meshReceiverAddr); //Handler void vAddNodeToPossibleUpdatableQueue(uint8_t* pu8MAC); diff --git a/components/mesh_ota/include/Mesh_network.h b/components/mesh_ota/include/Mesh_network.h index 178dc61..93c2cf2 100644 --- a/components/mesh_ota/include/Mesh_network.h +++ b/components/mesh_ota/include/Mesh_network.h @@ -53,7 +53,7 @@ struct meshPacket { APP_Data, //data for application OTA_Version_Request, //send own version in payload - OTA_Version_Respone, //send own version in payload + OTA_Version_Response, //send own version in payload OTA_Data, //send image segment OTA_ACK, //ack image segment OTA_Complete //signal end of image From 94aa8751cb51af12afa08c9f6c51c2e5564e9c39 Mon Sep 17 00:00:00 2001 From: localhorst Date: Tue, 19 Jan 2021 17:20:16 +0100 Subject: [PATCH 10/21] Mesh OTA Master & Slave --- components/mesh_ota/Mesh_OTA.c | 100 +++++++++++++++++---- components/mesh_ota/Mesh_network.c | 35 ++++++++ components/mesh_ota/include/Mesh_OTA.h | 1 + components/mesh_ota/include/Mesh_network.h | 1 + 4 files changed, 118 insertions(+), 19 deletions(-) diff --git a/components/mesh_ota/Mesh_OTA.c b/components/mesh_ota/Mesh_OTA.c index 8610180..fe2f2d8 100644 --- a/components/mesh_ota/Mesh_OTA.c +++ b/components/mesh_ota/Mesh_OTA.c @@ -248,15 +248,10 @@ void vTaskOTAWorker(void *arg) bWantReboot = true; vAddAllNeighboursToQueue(); //add all existing neighbours to queue } - - - - vTaskDelay( (1000) / portTICK_PERIOD_MS); } } - esp_err_t errOTAHTTPS(bool* pbNewOTAImage) { esp_err_t err = ESP_OK; @@ -284,7 +279,7 @@ esp_err_t errOTAHTTPS(bool* pbNewOTAImage) if(bNewerVersion((bootPartitionDesc).version, pcRemoteVersionNumber)) //compare local and remote version { // server image is newer --> OTA update required - ESP_LOGI(LOG_TAG, "server image is newer --> OTA update required"); + ESP_LOGI(LOG_TAG, "Server: image is newer --> OTA update required"); ERROR_CHECK(errFindImageStart(u8OTABuffer, &u32BufferLenght, &u32StartOffset)); //get image start offset @@ -306,7 +301,7 @@ esp_err_t errOTAHTTPS(bool* pbNewOTAImage) u32OTABytesWritten = u32OTABytesWritten + u32BytesRead; //update counter } } - while ((u32BytesRead > 0) && (err == ESP_OK)); //loop until error or complete image downloaded + while ((u32BytesRead > 0) && (err == ESP_OK) && (u32OTABytesWritten <= pOTAPartition->size)); //loop until error or complete image downloaded } if(err == ESP_OK) @@ -361,7 +356,7 @@ esp_err_t errOTAMeshSlave(bool* pbNewOTAImage) pBootPartition = esp_ota_get_boot_partition(); //get boot partition (that will booted after reset), not the running partition ERROR_CHECK(esp_ota_get_partition_description(pBootPartition, &bootPartitionDesc)); //get metadata of partition - //send OTA_Version_Response to sender of OTA_Version_Request packet + //send OTA_Version_Response to sender of OTA_Version_Request packet wirh version in payload ERROR_CHECK(errSendOTAVersionResponse(&sOTAMessage.meshSenderAddr)); if((bNewerVersion((bootPartitionDesc).version, (char*) sOTAMessage.au8Payload)) && (err == ESP_OK)) //compare local and remote version @@ -388,26 +383,77 @@ esp_err_t errOTAMeshMaster(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr) esp_err_t err = ESP_OK; MESH_PACKET_t sOTAMessage; const esp_partition_t* pBootPartition; //pointer to boot partition (that will booted after reset) - esp_app_desc_t bootPartitionDesc; //Metadate from boot partition + esp_app_desc_t bootPartitionDesc; //Metadata from boot partition + bool bNodeIsConnected = false; + bool bNodeIsResponding = false; + *pbNewOTAImage = false; //set default false - //get node - //check if node is still connected - // --> send OTA_Version_Request - // --> read OTA_Version_Response (if from this node) (all other OTA message add again) - // --> this version older --> start OTA_Rx --> vAddAllNeighboursToQueue(); //add all existing neighbours to queues - // --> this version newer --> start OTA_Tx + if(bIsNodeNeighbour(pMeshNodeAddr) == true) //check if node is still connected + { + bNodeIsConnected = true; //node is one of the neighbours + xSemaphoreTake(bsOTAProcess, portMAX_DELAY); //wait for binary semaphore that allows to start the OTA process + ERROR_CHECK(errSendOTAVersionRequest(pMeshNodeAddr)); //send OTA_VERSION_REQUEST with local version in payload + //read OTA_Version_Response (if from this node) (all other OTA message add again) + // if(uxQueueSpacesAvailable(queueMessageOTA) < QUEUE_MESSAGE_OTA_SIZE) + //{ + + for (uint32_t u32Index = 0; u32Index < QUEUE_MESSAGE_OTA_SIZE; u32Index++) //loop through all OTA messages + { + if(uxQueueSpacesAvailable(queueMessageOTA) < QUEUE_MESSAGE_OTA_SIZE) + { + //queue not empty + if (xQueueReceive(queueMessageOTA, &sOTAMessage, ((3000) / portTICK_PERIOD_MS)) != pdTRUE) + { + ESP_LOGE(LOG_TAG, "Unable to receive OTA Messages from queue"); + err = ESP_FAIL; + } + + if((err == ESP_OK) && (sOTAMessage.type == OTA_Version_Response) && (bCheckMACEquality(sOTAMessage.meshSenderAddr.addr, pMeshNodeAddr->addr))) //if OTA_Version_Request + { + bNodeIsResponding = true; + pBootPartition = esp_ota_get_boot_partition(); //get boot partition (that will booted after reset), not the running partition + ERROR_CHECK(esp_ota_get_partition_description(pBootPartition, &bootPartitionDesc)); //get metadata of partition + + if((bNewerVersion((bootPartitionDesc).version, (char*) sOTAMessage.au8Payload)) && (err == ESP_OK)) //compare local and remote version + { + //remote newer as local + ESP_LOGI(LOG_TAG, "Mesh: remote image on node is newer --> OTA update required"); + // --> this version older --> start OTA_Rx --> set pbNewOTAImage true + } + + if((bNewerVersion((char*) sOTAMessage.au8Payload, (bootPartitionDesc).version)) && (err == ESP_OK)) //compare remote and local version + { + //local newer as remote + ESP_LOGI(LOG_TAG, "Mesh: remote image on node is older --> OTA send required"); + // --> this version newer --> start OTA_Tx + } + } + else + { + //send wrong OTA message back to queue + vAddOTAControllMessageToQueue(&sOTAMessage); + } + } + }//end loop + xSemaphoreGive(bsOTAProcess); //free binary semaphore, this allows other tasks to start the OTA process + } + + if((bNodeIsResponding == false) && (bNodeIsConnected == true)) + { + //add node back to queue if connected and NOT responding + vAddNodeToPossibleUpdatableQueue(pMeshNodeAddr->addr); + } return err; } - -/* - * Return true if remote version is newer (higher) than local version -*/ bool bNewerVersion(const char* pu8Local, const char* pu8Remote) { + /* + * Return true if remote version is newer (higher) than local version + */ char u8LocalTmp[12]; //local version char u8RemoteTmp[12]; //remote version char* pu8saveptrLocal; //context for strok_r @@ -593,6 +639,22 @@ esp_err_t errSendOTAVersionResponse(mesh_addr_t* pMeshReceiverAddr) return err; } +esp_err_t errSendOTAVersionRequest(mesh_addr_t* pMeshReceiverAddr) +{ + esp_err_t err = ESP_OK; + MESH_PACKET_t packet; + packet.type = OTA_Version_Request; + + const esp_partition_t* pBootPartition; //pointer to boot partition (that will booted after reset) + esp_app_desc_t bootPartitionDesc; //Metadata from boot partition + + pBootPartition = esp_ota_get_boot_partition(); //get boot partition (that will booted after reset), not the running partition + ERROR_CHECK(esp_ota_get_partition_description(pBootPartition, &bootPartitionDesc)); //get metadate of partition + memcpy(&packet.au8Payload, &bootPartitionDesc.version, 12); //copy local version to OTA_Version_Request packet + err = errSendMeshPacket(pMeshReceiverAddr, &packet); + return err; +} + /* esp_err_t esp_mesh_ota_send(mesh_addr_t* dest) { diff --git a/components/mesh_ota/Mesh_network.c b/components/mesh_ota/Mesh_network.c index bb008c6..054b8b6 100644 --- a/components/mesh_ota/Mesh_network.c +++ b/components/mesh_ota/Mesh_network.c @@ -183,6 +183,41 @@ bool bIsRootNode() return esp_mesh_is_root(); } +bool bIsNodeNeighbour(mesh_addr_t* pNode) +{ + esp_err_t err = ESP_OK; + bool bReturn = false; + mesh_addr_t addrParent; //addr of parent node + mesh_addr_t childrenAddr[CONFIG_MESH_ROUTE_TABLE_SIZE]; //array of children attached to this node + uint16_t u16ChildrenSize = 0U; //number of children attached to this node + + err = errGetParentNode(&addrParent); + + if(err == ESP_OK) + { + if(bCheckMACEquality(pNode->addr, addrParent.addr) == true) + { + bReturn = true; //node was found + } + } + + if(bReturn == false) + { + err = ESP_OK; //reset error code + + ERROR_CHECK(errGetChildren(childrenAddr, &u16ChildrenSize)); //get all children + + for (uint16_t u16Index = 0; ((u16Index < u16ChildrenSize) && (err == ESP_OK) && (bReturn == false)); u16Index++) + { + if(bCheckMACEquality(pNode->addr, childrenAddr[u16Index].addr) == true) + { + bReturn = true; //node was found + } + } + } + return bReturn; +} + esp_err_t errMeshNetworkSetAppReceiveHandle(void (*pAppRxHandleTmp)(uint8_t * pu8Data, uint8_t* pu8Sender)) { pAppRxHandle = pAppRxHandleTmp; //set handle from app as receive handle if an app packet is received diff --git a/components/mesh_ota/include/Mesh_OTA.h b/components/mesh_ota/include/Mesh_OTA.h index 0983e8f..7883271 100644 --- a/components/mesh_ota/include/Mesh_OTA.h +++ b/components/mesh_ota/include/Mesh_OTA.h @@ -45,6 +45,7 @@ esp_err_t errFindImageStart(const char* pu8Data, uint32_t* pu32DataLenght, uint void vPrintOTAProgress(const uint32_t* const pu32TotalImageSize, const uint32_t* const pu32BytesWritten); void vAddAllNeighboursToQueue(void); esp_err_t errSendOTAVersionResponse(mesh_addr_t* meshReceiverAddr); +esp_err_t errSendOTAVersionRequest(mesh_addr_t* meshReceiverAddr); //Handler void vAddNodeToPossibleUpdatableQueue(uint8_t* pu8MAC); diff --git a/components/mesh_ota/include/Mesh_network.h b/components/mesh_ota/include/Mesh_network.h index 93c2cf2..f69706f 100644 --- a/components/mesh_ota/include/Mesh_network.h +++ b/components/mesh_ota/include/Mesh_network.h @@ -87,6 +87,7 @@ void vGetOwnAddr(mesh_addr_t* pMeshOwnAddr); esp_err_t errGetParentNode(mesh_addr_t* pMeshParentAddr); esp_err_t errGetChildren(mesh_addr_t* pChildren, uint16_t* pu16ChildrenSize); bool bIsRootNode(); +bool bIsNodeNeighbour(mesh_addr_t* pNode); esp_err_t errStartReceiveTask(); void vTaskReceiveMeshData(void *arg); From 57c71c401c2ae2173848a07757d76c3392d09aea Mon Sep 17 00:00:00 2001 From: localhorst Date: Tue, 19 Jan 2021 22:19:30 +0100 Subject: [PATCH 11/21] OTA Tx and Rx over Mesh --- components/mesh_ota/Mesh_OTA.c | 341 ++++++++++++++------- components/mesh_ota/Mesh_network.c | 1 + components/mesh_ota/include/Mesh_OTA.h | 14 +- components/mesh_ota/include/Mesh_network.h | 6 +- 4 files changed, 253 insertions(+), 109 deletions(-) diff --git a/components/mesh_ota/Mesh_OTA.c b/components/mesh_ota/Mesh_OTA.c index fe2f2d8..4bc55d3 100644 --- a/components/mesh_ota/Mesh_OTA.c +++ b/components/mesh_ota/Mesh_OTA.c @@ -130,7 +130,7 @@ void vAddOTAControllMessageToQueue(MESH_PACKET_t* puMeshPacket) } else { - ESP_LOGI(LOG_TAG, "added ota controll message to queue"); + ESP_LOGI(LOG_TAG, "added ota message to queue: %i (type)", puMeshPacket->type); } } @@ -239,6 +239,12 @@ void vTaskOTAWorker(void *arg) } ERROR_CHECK(errOTAMeshMaster(&bNewOTAImage, &meshNodeAddr)); + + if (err != ESP_OK) + { + //OTA process faild --> add back to queue + vAddNodeToPossibleUpdatableQueue(meshNodeAddr.addr); + } } if(bNewOTAImage == true) @@ -290,7 +296,7 @@ esp_err_t errOTAHTTPS(bool* pbNewOTAImage) ESP_LOGI(LOG_TAG, "start OTA download via HTTPS"); do { - vPrintOTAProgress(&(pOTAPartition->size), &u32OTABytesWritten); + vPrintOTAProgress(&(pOTAPartition->size), &u32OTABytesWritten, Receiver); ERROR_CHECK(esp_ota_write(otaHandle, (const void*) u8OTABuffer+u32StartOffset, (u32BytesRead-u32StartOffset))); if(err == ESP_OK) @@ -364,6 +370,7 @@ esp_err_t errOTAMeshSlave(bool* pbNewOTAImage) //remote newer as local ESP_LOGI(LOG_TAG, "remote image on node is newer --> OTA update required"); // --> this version older --> start OTA_Rx --> set pbNewOTAImage true + ERROR_CHECK(errOTAMeshReceive(pbNewOTAImage, &sOTAMessage.meshSenderAddr)); } if((bNewerVersion((char*) sOTAMessage.au8Payload, (bootPartitionDesc).version)) && (err == ESP_OK)) //compare remote and local version @@ -371,6 +378,7 @@ esp_err_t errOTAMeshSlave(bool* pbNewOTAImage) //local newer as remote ESP_LOGI(LOG_TAG, "remote image on node is older --> OTA send required"); // --> this version newer --> start OTA_Tx + ERROR_CHECK(errOTAMeshTransmit(&sOTAMessage.meshSenderAddr)); } xSemaphoreGive(bsOTAProcess); //free binary semaphore, this allows other tasks to start the OTA process } @@ -396,10 +404,6 @@ esp_err_t errOTAMeshMaster(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr) ERROR_CHECK(errSendOTAVersionRequest(pMeshNodeAddr)); //send OTA_VERSION_REQUEST with local version in payload - //read OTA_Version_Response (if from this node) (all other OTA message add again) - // if(uxQueueSpacesAvailable(queueMessageOTA) < QUEUE_MESSAGE_OTA_SIZE) - //{ - for (uint32_t u32Index = 0; u32Index < QUEUE_MESSAGE_OTA_SIZE; u32Index++) //loop through all OTA messages { if(uxQueueSpacesAvailable(queueMessageOTA) < QUEUE_MESSAGE_OTA_SIZE) @@ -422,6 +426,7 @@ esp_err_t errOTAMeshMaster(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr) //remote newer as local ESP_LOGI(LOG_TAG, "Mesh: remote image on node is newer --> OTA update required"); // --> this version older --> start OTA_Rx --> set pbNewOTAImage true + ERROR_CHECK(errOTAMeshReceive(pbNewOTAImage, &sOTAMessage.meshSenderAddr)); } if((bNewerVersion((char*) sOTAMessage.au8Payload, (bootPartitionDesc).version)) && (err == ESP_OK)) //compare remote and local version @@ -429,14 +434,20 @@ esp_err_t errOTAMeshMaster(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr) //local newer as remote ESP_LOGI(LOG_TAG, "Mesh: remote image on node is older --> OTA send required"); // --> this version newer --> start OTA_Tx + ERROR_CHECK(errOTAMeshTransmit(&sOTAMessage.meshSenderAddr)); } } - else + else if (err == ESP_OK) { - //send wrong OTA message back to queue + //received from wrong node or type --> back to queue vAddOTAControllMessageToQueue(&sOTAMessage); } } + else + { + // OTA Message queue is empty --> wait some time + vTaskDelay( (1000/QUEUE_MESSAGE_OTA_SIZE) / portTICK_PERIOD_MS); + } }//end loop xSemaphoreGive(bsOTAProcess); //free binary semaphore, this allows other tasks to start the OTA process } @@ -575,7 +586,7 @@ esp_err_t errExtractVersionNumber(const char* pu8Data, uint32_t* pu32DataLenght, return err; } -void vPrintOTAProgress(const uint32_t* const pu32TotalImageSize, const uint32_t* const pu32BytesWritten) +void vPrintOTAProgress(const uint32_t* const pu32TotalImageSize, const uint32_t* const pu32BytesWritten, OTA_MESH_ROLE_t eRole) { uint32_t u32Percentage = 0U; static uint32_t u32LastPercentage = 0U; @@ -591,7 +602,18 @@ void vPrintOTAProgress(const uint32_t* const pu32TotalImageSize, const uint32_t* if((u32Percentage-u32LastPercentage) >= OTA_PROGRESS_LOG_INTERVAL) { - ESP_LOGI(LOG_TAG, "OTA update progress: %i %%", u32Percentage); + if(eRole == Transmitter) + { + ESP_LOGI(LOG_TAG, "Transmitting OTA update: %i %%", u32Percentage); + } + + if(eRole == Receiver) + { + ESP_LOGI(LOG_TAG, "Receiving OTA update: %i %%", u32Percentage); + } + + + u32LastPercentage = u32Percentage; } } @@ -655,109 +677,216 @@ esp_err_t errSendOTAVersionRequest(mesh_addr_t* pMeshReceiverAddr) return err; } -/* -esp_err_t esp_mesh_ota_send(mesh_addr_t* dest) +esp_err_t errOTAMeshTransmit(mesh_addr_t* pMeshNodeAddr) { esp_err_t err = ESP_OK; + const esp_partition_t* pBootPartition; //pointer to boot partition (that will booted after reset) + MESH_PACKET_t sMeshPacket; //packet for sending and receiving + uint32_t u32Index = 0U; //index for partition read offset + bool bAbort = false; //abort the OTA process + bool bNodeIsResponding = false; //remote node is still active + uint32_t u32OTABytesWritten = 0U; - static uint32_t u32index; + pBootPartition = esp_ota_get_boot_partition(); //get boot partition (that will booted after reset), not the running partition - const esp_partition_t * pBootPartition = esp_ota_get_boot_partition(); - - if((*pBootPartition).subtype == 0) - { - - int data_read = 0; - - struct ota_mesh_packet packet; - packet.type=OTA_Data; - - if(u32index == 1024) + //loop through partition to read in segmensts until end or error or abort called + while( ((OTA_MESH_SEGMENT_SIZE * u32Index) < pBootPartition->size) && (err == ESP_OK) && (bAbort == false)) { - //all data read - data_read = 0; - u32index = 0; - } - else - { - ESP_LOGI(MESH_TAG, "OTA-Data read: %i", u32index); - err = esp_partition_read(pBootPartition, (1024*u32index), packet.au8Payload, 1024 ); - ESP_ERROR_CHECK(err); - data_read = 1024; - u32index++; - } + bNodeIsResponding = false; //reset to default - if (data_read > 0) - { - //send ota fragemnt to node - esp_mesh_send_packet(dest, &packet); - } + // read partition with offset based in index + ERROR_CHECK(esp_partition_read(pBootPartition, (OTA_MESH_SEGMENT_SIZE * u32Index), sMeshPacket.au8Payload, OTA_MESH_SEGMENT_SIZE)); + u32OTABytesWritten = ((u32Index+1) * OTA_MESH_SEGMENT_SIZE); + vPrintOTAProgress(&(pBootPartition->size), &u32OTABytesWritten, Transmitter); - ESP_ERROR_CHECK(err); - } + if(err == ESP_OK) + { + //no error while read --> send OTA_DATA packet + sMeshPacket.type = OTA_Data; + + if((OTA_MESH_SEGMENT_SIZE * (u32Index+1)) >= pBootPartition->size) //check if last segment + { + //last partition image segment --> send OTA_Complete + sMeshPacket.type = OTA_Complete; + } + + err = errSendMeshPacket(pMeshNodeAddr, &sMeshPacket); + } + else + { + // error while read --> send OTA_ABORT and abort this OTA process + sMeshPacket.type = OTA_Abort; + bAbort = true; + errSendMeshPacket(pMeshNodeAddr, &sMeshPacket); + } + + // loop through all OTA messages or until abort is called or error + for (uint32_t u32Index = 0; ((u32Index < QUEUE_MESSAGE_OTA_SIZE) && (bAbort == false) && (err == ESP_OK)); u32Index++) //loop through all OTA messages + { + if(uxQueueSpacesAvailable(queueMessageOTA) < QUEUE_MESSAGE_OTA_SIZE) + { + //queue not empty + if (xQueueReceive(queueMessageOTA, &sMeshPacket, ((3000) / portTICK_PERIOD_MS)) != pdTRUE) + { + ESP_LOGE(LOG_TAG, "Unable to receive OTA Messages from queue"); + err = ESP_FAIL; + } + + if((err == ESP_OK) && (bCheckMACEquality(sMeshPacket.meshSenderAddr.addr, pMeshNodeAddr->addr))) //if OTA_Version_Request + { + //packet from node received + switch (sMeshPacket.type) + { + case OTA_ACK: //increase index for next round + u32Index++; + bNodeIsResponding = true; + break; + case OTA_Abort: //abort this OTA process + bAbort = true; + bNodeIsResponding = true; + break; + default: + //receives wrong OTA message type from node --> back to queue + vAddOTAControllMessageToQueue(&sMeshPacket); + break; + } + } + else if (err == ESP_OK) + { + //received from wrong node --> back to queue + vAddOTAControllMessageToQueue(&sMeshPacket); + } + } + else + { + // OTA Message queue is empty --> wait some time + vTaskDelay( (1000/QUEUE_MESSAGE_OTA_SIZE) / portTICK_PERIOD_MS); + } + + }//end OTA message loop + + if(bNodeIsResponding == false) + { + //no abort was called but node didn’t responded + bAbort = true; + err = ESP_FAIL; //this OTA process failed with error + } + }//end of partition segment loop + return err; +} + +esp_err_t errOTAMeshReceive(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr) +{ + esp_err_t err = ESP_OK; + MESH_PACKET_t sMeshPacket; //packet for sending and receiving + bool bComplete = false; //complete the OTA process + bool bAbort = false; //abort the OTA process + bool bNodeIsResponding = false; //remote node is still active + uint32_t u32OTABytesWritten = 0U; //counter unsed for progress log + static esp_ota_handle_t otaHandle; //OTA process handle + *pbNewOTAImage = false; + + ERROR_CHECK(esp_ota_begin(pOTAPartition, OTA_SIZE_UNKNOWN, &otaHandle)); //start ota update process + + //partition segement loop through partition to read in segmensts until end or error or abort called + while((bComplete == false) && (err == ESP_OK) && (bAbort == false) && (u32OTABytesWritten <= pOTAPartition->size)) + { + bNodeIsResponding = false; //reset to default + + // loop through all OTA messages or until abort is called + for (uint32_t u32Index = 0; ((u32Index < QUEUE_MESSAGE_OTA_SIZE) && (bAbort == false)); u32Index++) //loop through all OTA messages + { + if(uxQueueSpacesAvailable(queueMessageOTA) < QUEUE_MESSAGE_OTA_SIZE) + { + //queue not empty + if (xQueueReceive(queueMessageOTA, &sMeshPacket, ((3000) / portTICK_PERIOD_MS)) != pdTRUE) + { + ESP_LOGE(LOG_TAG, "Unable to receive OTA Messages from queue"); + err = ESP_FAIL; + } + + if((err == ESP_OK) && (bCheckMACEquality(sMeshPacket.meshSenderAddr.addr, pMeshNodeAddr->addr))) //if OTA_Version_Request + { + //packet from node received + switch (sMeshPacket.type) + { + case OTA_Complete: //signal end of this OTA process, fall through because same behavior as OTA_Data + bComplete = true; + //fall through + case OTA_Data: //data segement received + bNodeIsResponding = true; + ERROR_CHECK(esp_ota_write(otaHandle, sMeshPacket.au8Payload, OTA_MESH_SEGMENT_SIZE)); + u32OTABytesWritten = ((u32Index+1) * OTA_MESH_SEGMENT_SIZE); + vPrintOTAProgress(&(pOTAPartition->size), &u32OTABytesWritten, Receiver); + break; + case OTA_Abort: //abort this OTA process + bAbort = true; + bNodeIsResponding = true; + break; + default: + //receives wrong OTA message type from node --> back to queue + vAddOTAControllMessageToQueue(&sMeshPacket); + break; + } + } + else if (err == ESP_OK) + { + //received from wrong node --> back to queue + vAddOTAControllMessageToQueue(&sMeshPacket); + } + } + else + { + // OTA Message queue is empty --> wait some time + vTaskDelay( (1000/QUEUE_MESSAGE_OTA_SIZE) / portTICK_PERIOD_MS); + } + + }//end of OTA message loop + + if(bNodeIsResponding == false) + { + //no abort was called but node didn’t responded --> error + bAbort = true; //this will stop the partition segement loop + err = ESP_FAIL; //this OTA process failed with error + } + else + { + //node has responded with OTA_DATA or OTA_Complete or OTA_ABORT + if(err == ESP_OK) + { + + if(bAbort == false) + { + //no error while ota write --> send OTA_ACK packet + sMeshPacket.type = OTA_ACK; + err = errSendMeshPacket(pMeshNodeAddr, &sMeshPacket); + } + } + else + { + // error while read --> send OTA_ABORT and abort this OTA process + sMeshPacket.type = OTA_Abort; + bAbort = true; + errSendMeshPacket(pMeshNodeAddr, &sMeshPacket); + } + } + }//end of partition segement loop + + if(bComplete == true) + { + //all OTA segments received --> validate + ERROR_CHECK(esp_ota_end(otaHandle)); + ERROR_CHECK(esp_ota_set_boot_partition(pOTAPartition)); + if(err == ESP_OK) + { + //successfully updated OTA partition + *pbNewOTAImage = true; + } + } else - { - ESP_LOGI(MESH_TAG, "Subtype: %d", (*pBootPartition).subtype); - } + { + //not all OTA segments received --> abort this OTA process + ERROR_CHECK(esp_ota_abort(otaHandle)); + } return err; } - -esp_err_t esp_mesh_ota_receive(mesh_addr_t* dest, struct ota_mesh_packet* packet) -{ - esp_err_t err = ESP_OK; - static esp_ota_handle_t otaHandle; - static uint32_t u32index; - - const esp_partition_t * pBootPartition = esp_ota_get_boot_partition(); - const esp_partition_t * pOTAPartition = esp_ota_get_next_update_partition(pBootPartition); - - if(u32index == 0) - { - //first run - - err = esp_ota_begin(pOTAPartition, OTA_SIZE_UNKNOWN, &otaHandle); - ESP_ERROR_CHECK(err); - } - - ESP_LOGI(MESH_TAG, "OTA-Data write: %i", u32index); - err = esp_ota_write(otaHandle, packet->au8Payload, 1024); - - if(err != ESP_OK) - { - ESP_LOGE(MESH_TAG, "OTA-Data write error: %i at %i", err, u32index); - } - - ESP_ERROR_CHECK(err); - - - - if(u32index >= 1023) - { - //ota update complete - - ESP_LOGI(MESH_TAG, "OTA-Data complete arrived: %i", u32index); - err = esp_ota_end(otaHandle); - ESP_ERROR_CHECK(err); - esp_app_desc_t otaPartitionDesc; - err = esp_ota_get_partition_description(pOTAPartition, &otaPartitionDesc); - ESP_ERROR_CHECK(err); - ESP_LOGI(MESH_TAG, "pOTAPartition project_name: %s", (otaPartitionDesc).project_name); - - err = esp_ota_set_boot_partition(pOTAPartition); - ESP_ERROR_CHECK(err); - - struct ota_mesh_packet retPacket; - retPacket.type=OTA_Complete; - ESP_ERROR_CHECK (esp_mesh_send_packet(dest, &retPacket)); //send back to parent - - //check if this node has children --> Update them - - esp_restart(); - } - - u32index++; - - - return err; -} -*/ diff --git a/components/mesh_ota/Mesh_network.c b/components/mesh_ota/Mesh_network.c index 054b8b6..e28c1c8 100644 --- a/components/mesh_ota/Mesh_network.c +++ b/components/mesh_ota/Mesh_network.c @@ -305,6 +305,7 @@ void vTaskReceiveMeshData(void *arg) case OTA_Data: case OTA_ACK: case OTA_Complete: + case OTA_Abort: //call the rx handle from OTA if(pOTAMessageHandle) { diff --git a/components/mesh_ota/include/Mesh_OTA.h b/components/mesh_ota/include/Mesh_OTA.h index 7883271..d83710d 100644 --- a/components/mesh_ota/include/Mesh_OTA.h +++ b/components/mesh_ota/include/Mesh_OTA.h @@ -22,6 +22,7 @@ #define SERVER_CHECK_INTERVAL 30 //in seconds #define OTA_HTTPS_SEGMENT_SIZE 2048U #define OTA_PROGRESS_LOG_INTERVAL 7U +#define OTA_MESH_SEGMENT_SIZE MESH_NETWORK_PAYLOAD_SIZE #define ERROR_CHECK(x) if (err == ESP_OK) \ { \ @@ -32,17 +33,28 @@ } \ } \ +enum otaMeshRole +{ + Transmitter, + Receiver +}; + +typedef enum otaMeshRole OTA_MESH_ROLE_t; + esp_err_t errMeshOTAInitialize(); esp_err_t errOTAHTTPS(bool* pbNewOTAImage); esp_err_t errOTAMeshSlave(bool* pbNewOTAImage); esp_err_t errOTAMeshMaster(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr); +esp_err_t errOTAMeshTransmit(mesh_addr_t* pMeshNodeAddr); +esp_err_t errOTAMeshReceive(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr); + //helper functions bool bNewerVersion(const char* pu8Local, const char* pu8Remote); esp_err_t errExtractVersionNumber(const char* pu8Data, uint32_t* pu32DataLenght, char* pc8RemoteVersionNumber); esp_err_t errFindImageStart(const char* pu8Data, uint32_t* pu32DataLenght, uint32_t* pu32StartOffset); -void vPrintOTAProgress(const uint32_t* const pu32TotalImageSize, const uint32_t* const pu32BytesWritten); +void vPrintOTAProgress(const uint32_t* const pu32TotalImageSize, const uint32_t* const pu32BytesWritten, OTA_MESH_ROLE_t eRole); void vAddAllNeighboursToQueue(void); esp_err_t errSendOTAVersionResponse(mesh_addr_t* meshReceiverAddr); esp_err_t errSendOTAVersionRequest(mesh_addr_t* meshReceiverAddr); diff --git a/components/mesh_ota/include/Mesh_network.h b/components/mesh_ota/include/Mesh_network.h index f69706f..b4c2d13 100644 --- a/components/mesh_ota/include/Mesh_network.h +++ b/components/mesh_ota/include/Mesh_network.h @@ -46,6 +46,7 @@ #define CONFIG_MESH_ROUTE_TABLE_SIZE 50 #endif +#define MESH_NETWORK_PAYLOAD_SIZE 1024U struct meshPacket { @@ -56,9 +57,10 @@ struct meshPacket OTA_Version_Response, //send own version in payload OTA_Data, //send image segment OTA_ACK, //ack image segment - OTA_Complete //signal end of image + OTA_Complete, //signal end of image + OTA_Abort //abort OTA process } type; - uint8_t au8Payload[1024]; + uint8_t au8Payload[MESH_NETWORK_PAYLOAD_SIZE]; mesh_addr_t meshSenderAddr; }; From f74985da4c6a5d3dadb92f188980bf5dfdda9368 Mon Sep 17 00:00:00 2001 From: localhorst Date: Wed, 20 Jan 2021 11:20:35 +0100 Subject: [PATCH 12/21] fixed mesh OTA process --- components/mesh_ota/Mesh_OTA.c | 60 ++++++++++++++++++-------- components/mesh_ota/include/Mesh_OTA.h | 1 + 2 files changed, 42 insertions(+), 19 deletions(-) diff --git a/components/mesh_ota/Mesh_OTA.c b/components/mesh_ota/Mesh_OTA.c index 4bc55d3..9d1f4b0 100644 --- a/components/mesh_ota/Mesh_OTA.c +++ b/components/mesh_ota/Mesh_OTA.c @@ -130,7 +130,7 @@ void vAddOTAControllMessageToQueue(MESH_PACKET_t* puMeshPacket) } else { - ESP_LOGI(LOG_TAG, "added ota message to queue: %i (type)", puMeshPacket->type); + //ESP_LOGI(LOG_TAG, "added ota message to queue: %i (type)", puMeshPacket->type); } } @@ -216,11 +216,11 @@ void vTaskOTAWorker(void *arg) if((uxQueueSpacesAvailable(queueNodes) - QUEUE_NODES_SIZE) == 0) { //nodes queue is empty - ESP_LOGI(LOG_TAG, "nodes queue is empty"); + // ESP_LOGI(LOG_TAG, "nodes queue is empty"); if(bWantReboot == true) { - ESP_LOGI(LOG_TAG, "ESP32 Reboot ..."); + //ESP_LOGI(LOG_TAG, "ESP32 Reboot ..."); //vTaskDelay( (1000) / portTICK_PERIOD_MS); //esp_restart(); } @@ -682,21 +682,22 @@ esp_err_t errOTAMeshTransmit(mesh_addr_t* pMeshNodeAddr) esp_err_t err = ESP_OK; const esp_partition_t* pBootPartition; //pointer to boot partition (that will booted after reset) MESH_PACKET_t sMeshPacket; //packet for sending and receiving - uint32_t u32Index = 0U; //index for partition read offset + // uint32_t u32Index = 0U; //index for partition read offset bool bAbort = false; //abort the OTA process bool bNodeIsResponding = false; //remote node is still active uint32_t u32OTABytesWritten = 0U; + uint32_t u32SegmentCounter = 0U; pBootPartition = esp_ota_get_boot_partition(); //get boot partition (that will booted after reset), not the running partition //loop through partition to read in segmensts until end or error or abort called - while( ((OTA_MESH_SEGMENT_SIZE * u32Index) < pBootPartition->size) && (err == ESP_OK) && (bAbort == false)) + while( ((OTA_MESH_SEGMENT_SIZE * u32SegmentCounter) < pBootPartition->size) && (err == ESP_OK) && (bAbort == false)) { bNodeIsResponding = false; //reset to default // read partition with offset based in index - ERROR_CHECK(esp_partition_read(pBootPartition, (OTA_MESH_SEGMENT_SIZE * u32Index), sMeshPacket.au8Payload, OTA_MESH_SEGMENT_SIZE)); - u32OTABytesWritten = ((u32Index+1) * OTA_MESH_SEGMENT_SIZE); + ERROR_CHECK(esp_partition_read(pBootPartition, (OTA_MESH_SEGMENT_SIZE * u32SegmentCounter), sMeshPacket.au8Payload, OTA_MESH_SEGMENT_SIZE)); + u32OTABytesWritten = ((u32SegmentCounter+1) * OTA_MESH_SEGMENT_SIZE); vPrintOTAProgress(&(pBootPartition->size), &u32OTABytesWritten, Transmitter); if(err == ESP_OK) @@ -704,12 +705,13 @@ esp_err_t errOTAMeshTransmit(mesh_addr_t* pMeshNodeAddr) //no error while read --> send OTA_DATA packet sMeshPacket.type = OTA_Data; - if((OTA_MESH_SEGMENT_SIZE * (u32Index+1)) >= pBootPartition->size) //check if last segment + if((OTA_MESH_SEGMENT_SIZE * (u32SegmentCounter+1)) >= pBootPartition->size) //check if last segment { //last partition image segment --> send OTA_Complete + ESP_LOGI(LOG_TAG, "OTA-TX: last segment--> send Complete"); sMeshPacket.type = OTA_Complete; } - + ESP_LOGI(LOG_TAG, "OTA-TX: send packet"); err = errSendMeshPacket(pMeshNodeAddr, &sMeshPacket); } else @@ -717,14 +719,15 @@ esp_err_t errOTAMeshTransmit(mesh_addr_t* pMeshNodeAddr) // error while read --> send OTA_ABORT and abort this OTA process sMeshPacket.type = OTA_Abort; bAbort = true; + ESP_LOGI(LOG_TAG, "OTA-TX: error while read --> send ABORT"); errSendMeshPacket(pMeshNodeAddr, &sMeshPacket); } // loop through all OTA messages or until abort is called or error for (uint32_t u32Index = 0; ((u32Index < QUEUE_MESSAGE_OTA_SIZE) && (bAbort == false) && (err == ESP_OK)); u32Index++) //loop through all OTA messages { - if(uxQueueSpacesAvailable(queueMessageOTA) < QUEUE_MESSAGE_OTA_SIZE) - { + // if(uxQueueSpacesAvailable(queueMessageOTA) < QUEUE_MESSAGE_OTA_SIZE) + // { //queue not empty if (xQueueReceive(queueMessageOTA, &sMeshPacket, ((3000) / portTICK_PERIOD_MS)) != pdTRUE) { @@ -740,6 +743,7 @@ esp_err_t errOTAMeshTransmit(mesh_addr_t* pMeshNodeAddr) case OTA_ACK: //increase index for next round u32Index++; bNodeIsResponding = true; + u32Index = QUEUE_MESSAGE_OTA_SIZE;//this will end the loop through all OTA messages break; case OTA_Abort: //abort this OTA process bAbort = true; @@ -747,7 +751,7 @@ esp_err_t errOTAMeshTransmit(mesh_addr_t* pMeshNodeAddr) break; default: //receives wrong OTA message type from node --> back to queue - vAddOTAControllMessageToQueue(&sMeshPacket); + //vAddOTAControllMessageToQueue(&sMeshPacket); break; } } @@ -756,21 +760,26 @@ esp_err_t errOTAMeshTransmit(mesh_addr_t* pMeshNodeAddr) //received from wrong node --> back to queue vAddOTAControllMessageToQueue(&sMeshPacket); } + /* } else { // OTA Message queue is empty --> wait some time - vTaskDelay( (1000/QUEUE_MESSAGE_OTA_SIZE) / portTICK_PERIOD_MS); + ESP_LOGI(LOG_TAG, "OTA-TX: ota message queue empty --> wait"); + vTaskDelay( (OTA_MESH_TIMEOUT) / portTICK_PERIOD_MS); } + */ }//end OTA message loop if(bNodeIsResponding == false) { //no abort was called but node didn’t responded + ESP_LOGE(LOG_TAG, "OTA-TX: no abort was called but node didn’t responded --> error"); bAbort = true; err = ESP_FAIL; //this OTA process failed with error } + u32SegmentCounter++; }//end of partition segment loop return err; } @@ -785,6 +794,7 @@ esp_err_t errOTAMeshReceive(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr) uint32_t u32OTABytesWritten = 0U; //counter unsed for progress log static esp_ota_handle_t otaHandle; //OTA process handle *pbNewOTAImage = false; + uint32_t u32SegmentCounter = 0U; ERROR_CHECK(esp_ota_begin(pOTAPartition, OTA_SIZE_UNKNOWN, &otaHandle)); //start ota update process @@ -796,8 +806,8 @@ esp_err_t errOTAMeshReceive(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr) // loop through all OTA messages or until abort is called for (uint32_t u32Index = 0; ((u32Index < QUEUE_MESSAGE_OTA_SIZE) && (bAbort == false)); u32Index++) //loop through all OTA messages { - if(uxQueueSpacesAvailable(queueMessageOTA) < QUEUE_MESSAGE_OTA_SIZE) - { + //if(uxQueueSpacesAvailable(queueMessageOTA) < QUEUE_MESSAGE_OTA_SIZE) + // { //queue not empty if (xQueueReceive(queueMessageOTA, &sMeshPacket, ((3000) / portTICK_PERIOD_MS)) != pdTRUE) { @@ -812,20 +822,24 @@ esp_err_t errOTAMeshReceive(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr) { case OTA_Complete: //signal end of this OTA process, fall through because same behavior as OTA_Data bComplete = true; + ESP_LOGI(LOG_TAG, "OTA-RX: rec Complete --> last segment"); //fall through case OTA_Data: //data segement received bNodeIsResponding = true; ERROR_CHECK(esp_ota_write(otaHandle, sMeshPacket.au8Payload, OTA_MESH_SEGMENT_SIZE)); - u32OTABytesWritten = ((u32Index+1) * OTA_MESH_SEGMENT_SIZE); + u32OTABytesWritten = ((u32SegmentCounter+1) * OTA_MESH_SEGMENT_SIZE); vPrintOTAProgress(&(pOTAPartition->size), &u32OTABytesWritten, Receiver); + u32Index = QUEUE_MESSAGE_OTA_SIZE; //this will end the loop through all OTA messages break; case OTA_Abort: //abort this OTA process bAbort = true; bNodeIsResponding = true; + ESP_LOGI(LOG_TAG, "OTA-RX: rec Abort"); + //this will end the loop through all OTA messages break; default: //receives wrong OTA message type from node --> back to queue - vAddOTAControllMessageToQueue(&sMeshPacket); + //vAddOTAControllMessageToQueue(&sMeshPacket); break; } } @@ -834,18 +848,22 @@ esp_err_t errOTAMeshReceive(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr) //received from wrong node --> back to queue vAddOTAControllMessageToQueue(&sMeshPacket); } - } + + /* } else { + ESP_LOGI(LOG_TAG, "OTA-RX: ota message queue empty --> wait"); // OTA Message queue is empty --> wait some time - vTaskDelay( (1000/QUEUE_MESSAGE_OTA_SIZE) / portTICK_PERIOD_MS); + vTaskDelay( (OTA_MESH_TIMEOUT) / portTICK_PERIOD_MS); } + */ }//end of OTA message loop if(bNodeIsResponding == false) { //no abort was called but node didn’t responded --> error + ESP_LOGI(LOG_TAG, "OTA-RX: no abort was called but node didn’t responded --> error"); bAbort = true; //this will stop the partition segement loop err = ESP_FAIL; //this OTA process failed with error } @@ -858,6 +876,7 @@ esp_err_t errOTAMeshReceive(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr) if(bAbort == false) { //no error while ota write --> send OTA_ACK packet + ESP_LOGI(LOG_TAG, "OTA-RX: no error while ota write --> send OTA_ACK packet"); sMeshPacket.type = OTA_ACK; err = errSendMeshPacket(pMeshNodeAddr, &sMeshPacket); } @@ -867,14 +886,17 @@ esp_err_t errOTAMeshReceive(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr) // error while read --> send OTA_ABORT and abort this OTA process sMeshPacket.type = OTA_Abort; bAbort = true; + ESP_LOGI(LOG_TAG, "OTA-RX: abort --> send ABORT"); errSendMeshPacket(pMeshNodeAddr, &sMeshPacket); } } + u32SegmentCounter++; }//end of partition segement loop if(bComplete == true) { //all OTA segments received --> validate + ESP_LOGI(LOG_TAG, "OTA-RX: validate image "); ERROR_CHECK(esp_ota_end(otaHandle)); ERROR_CHECK(esp_ota_set_boot_partition(pOTAPartition)); if(err == ESP_OK) diff --git a/components/mesh_ota/include/Mesh_OTA.h b/components/mesh_ota/include/Mesh_OTA.h index d83710d..cbf5630 100644 --- a/components/mesh_ota/include/Mesh_OTA.h +++ b/components/mesh_ota/include/Mesh_OTA.h @@ -23,6 +23,7 @@ #define OTA_HTTPS_SEGMENT_SIZE 2048U #define OTA_PROGRESS_LOG_INTERVAL 7U #define OTA_MESH_SEGMENT_SIZE MESH_NETWORK_PAYLOAD_SIZE +#define OTA_MESH_TIMEOUT 400U //in ms #define ERROR_CHECK(x) if (err == ESP_OK) \ { \ From 05dfe8528b8317dc514163c05343470e79fa3754 Mon Sep 17 00:00:00 2001 From: localhorst Date: Wed, 20 Jan 2021 13:43:41 +0100 Subject: [PATCH 13/21] fixed update of all neighbours after update --- components/mesh_ota/Mesh_OTA.c | 209 +++++++++++---------- components/mesh_ota/Mesh_network.c | 10 + components/mesh_ota/include/Mesh_network.h | 1 + 3 files changed, 124 insertions(+), 96 deletions(-) diff --git a/components/mesh_ota/Mesh_OTA.c b/components/mesh_ota/Mesh_OTA.c index 9d1f4b0..1772af0 100644 --- a/components/mesh_ota/Mesh_OTA.c +++ b/components/mesh_ota/Mesh_OTA.c @@ -130,7 +130,21 @@ void vAddOTAControllMessageToQueue(MESH_PACKET_t* puMeshPacket) } else { - //ESP_LOGI(LOG_TAG, "added ota message to queue: %i (type)", puMeshPacket->type); + switch (puMeshPacket->type) + { + case OTA_Abort: + ESP_LOGI(LOG_TAG, "added ota message to queue: OTA_Abort from 0x%x", puMeshPacket->meshSenderAddr.addr[5]); + break; + case OTA_Version_Request: + ESP_LOGI(LOG_TAG, "added ota message to queue: OTA_Version_Request from 0x%x", puMeshPacket->meshSenderAddr.addr[5]); + break; + + case OTA_Version_Response: + ESP_LOGI(LOG_TAG, "added ota message to queue: OTA_Version Response from 0x%x", puMeshPacket->meshSenderAddr.addr[5]); + break; + default: + break; + } } } @@ -216,7 +230,7 @@ void vTaskOTAWorker(void *arg) if((uxQueueSpacesAvailable(queueNodes) - QUEUE_NODES_SIZE) == 0) { //nodes queue is empty - // ESP_LOGI(LOG_TAG, "nodes queue is empty"); + ESP_LOGI(LOG_TAG, "nodes queue is empty"); if(bWantReboot == true) { @@ -402,6 +416,7 @@ esp_err_t errOTAMeshMaster(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr) bNodeIsConnected = true; //node is one of the neighbours xSemaphoreTake(bsOTAProcess, portMAX_DELAY); //wait for binary semaphore that allows to start the OTA process + ESP_LOGI(LOG_TAG, "Mesh-Master: send Version_Request to 0x%x", pMeshNodeAddr->addr[5]); ERROR_CHECK(errSendOTAVersionRequest(pMeshNodeAddr)); //send OTA_VERSION_REQUEST with local version in payload for (uint32_t u32Index = 0; u32Index < QUEUE_MESSAGE_OTA_SIZE; u32Index++) //loop through all OTA messages @@ -446,6 +461,7 @@ esp_err_t errOTAMeshMaster(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr) else { // OTA Message queue is empty --> wait some time + ESP_LOGI(LOG_TAG, "OTA-Master: OTA Message queue is empty --> wait some time"); vTaskDelay( (1000/QUEUE_MESSAGE_OTA_SIZE) / portTICK_PERIOD_MS); } }//end loop @@ -455,6 +471,7 @@ esp_err_t errOTAMeshMaster(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr) if((bNodeIsResponding == false) && (bNodeIsConnected == true)) { //add node back to queue if connected and NOT responding + ESP_LOGI(LOG_TAG, "OTA-Master: connected and NOT responding --> add node back to queue "); vAddNodeToPossibleUpdatableQueue(pMeshNodeAddr->addr); } return err; @@ -682,7 +699,7 @@ esp_err_t errOTAMeshTransmit(mesh_addr_t* pMeshNodeAddr) esp_err_t err = ESP_OK; const esp_partition_t* pBootPartition; //pointer to boot partition (that will booted after reset) MESH_PACKET_t sMeshPacket; //packet for sending and receiving - // uint32_t u32Index = 0U; //index for partition read offset + // uint32_t u32Index = 0U; //index for partition read offset bool bAbort = false; //abort the OTA process bool bNodeIsResponding = false; //remote node is still active uint32_t u32OTABytesWritten = 0U; @@ -711,7 +728,7 @@ esp_err_t errOTAMeshTransmit(mesh_addr_t* pMeshNodeAddr) ESP_LOGI(LOG_TAG, "OTA-TX: last segment--> send Complete"); sMeshPacket.type = OTA_Complete; } - ESP_LOGI(LOG_TAG, "OTA-TX: send packet"); + //ESP_LOGI(LOG_TAG, "OTA-TX: send packet"); err = errSendMeshPacket(pMeshNodeAddr, &sMeshPacket); } else @@ -726,49 +743,49 @@ esp_err_t errOTAMeshTransmit(mesh_addr_t* pMeshNodeAddr) // loop through all OTA messages or until abort is called or error for (uint32_t u32Index = 0; ((u32Index < QUEUE_MESSAGE_OTA_SIZE) && (bAbort == false) && (err == ESP_OK)); u32Index++) //loop through all OTA messages { - // if(uxQueueSpacesAvailable(queueMessageOTA) < QUEUE_MESSAGE_OTA_SIZE) - // { - //queue not empty - if (xQueueReceive(queueMessageOTA, &sMeshPacket, ((3000) / portTICK_PERIOD_MS)) != pdTRUE) - { - ESP_LOGE(LOG_TAG, "Unable to receive OTA Messages from queue"); - err = ESP_FAIL; - } - - if((err == ESP_OK) && (bCheckMACEquality(sMeshPacket.meshSenderAddr.addr, pMeshNodeAddr->addr))) //if OTA_Version_Request - { - //packet from node received - switch (sMeshPacket.type) - { - case OTA_ACK: //increase index for next round - u32Index++; - bNodeIsResponding = true; - u32Index = QUEUE_MESSAGE_OTA_SIZE;//this will end the loop through all OTA messages - break; - case OTA_Abort: //abort this OTA process - bAbort = true; - bNodeIsResponding = true; - break; - default: - //receives wrong OTA message type from node --> back to queue - //vAddOTAControllMessageToQueue(&sMeshPacket); - break; - } - } - else if (err == ESP_OK) - { - //received from wrong node --> back to queue - vAddOTAControllMessageToQueue(&sMeshPacket); - } - /* - } - else + // if(uxQueueSpacesAvailable(queueMessageOTA) < QUEUE_MESSAGE_OTA_SIZE) + // { + //queue not empty + if (xQueueReceive(queueMessageOTA, &sMeshPacket, ((3000) / portTICK_PERIOD_MS)) != pdTRUE) { - // OTA Message queue is empty --> wait some time - ESP_LOGI(LOG_TAG, "OTA-TX: ota message queue empty --> wait"); - vTaskDelay( (OTA_MESH_TIMEOUT) / portTICK_PERIOD_MS); + ESP_LOGE(LOG_TAG, "Unable to receive OTA Messages from queue"); + err = ESP_FAIL; } - */ + + if((err == ESP_OK) && (bCheckMACEquality(sMeshPacket.meshSenderAddr.addr, pMeshNodeAddr->addr))) //if OTA_Version_Request + { + //packet from node received + switch (sMeshPacket.type) + { + case OTA_ACK: //increase index for next round + u32Index++; + bNodeIsResponding = true; + u32Index = QUEUE_MESSAGE_OTA_SIZE;//this will end the loop through all OTA messages + break; + case OTA_Abort: //abort this OTA process + bAbort = true; + bNodeIsResponding = true; + break; + default: + //receives wrong OTA message type from node --> back to queue + //vAddOTAControllMessageToQueue(&sMeshPacket); + break; + } + } + else if (err == ESP_OK) + { + //received from wrong node --> back to queue + vAddOTAControllMessageToQueue(&sMeshPacket); + } + /* + } + else + { + // OTA Message queue is empty --> wait some time + ESP_LOGI(LOG_TAG, "OTA-TX: ota message queue empty --> wait"); + vTaskDelay( (OTA_MESH_TIMEOUT) / portTICK_PERIOD_MS); + } + */ }//end OTA message loop @@ -779,7 +796,7 @@ esp_err_t errOTAMeshTransmit(mesh_addr_t* pMeshNodeAddr) bAbort = true; err = ESP_FAIL; //this OTA process failed with error } - u32SegmentCounter++; + u32SegmentCounter++; }//end of partition segment loop return err; } @@ -807,56 +824,56 @@ esp_err_t errOTAMeshReceive(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr) for (uint32_t u32Index = 0; ((u32Index < QUEUE_MESSAGE_OTA_SIZE) && (bAbort == false)); u32Index++) //loop through all OTA messages { //if(uxQueueSpacesAvailable(queueMessageOTA) < QUEUE_MESSAGE_OTA_SIZE) - // { - //queue not empty - if (xQueueReceive(queueMessageOTA, &sMeshPacket, ((3000) / portTICK_PERIOD_MS)) != pdTRUE) - { - ESP_LOGE(LOG_TAG, "Unable to receive OTA Messages from queue"); - err = ESP_FAIL; - } - - if((err == ESP_OK) && (bCheckMACEquality(sMeshPacket.meshSenderAddr.addr, pMeshNodeAddr->addr))) //if OTA_Version_Request - { - //packet from node received - switch (sMeshPacket.type) - { - case OTA_Complete: //signal end of this OTA process, fall through because same behavior as OTA_Data - bComplete = true; - ESP_LOGI(LOG_TAG, "OTA-RX: rec Complete --> last segment"); - //fall through - case OTA_Data: //data segement received - bNodeIsResponding = true; - ERROR_CHECK(esp_ota_write(otaHandle, sMeshPacket.au8Payload, OTA_MESH_SEGMENT_SIZE)); - u32OTABytesWritten = ((u32SegmentCounter+1) * OTA_MESH_SEGMENT_SIZE); - vPrintOTAProgress(&(pOTAPartition->size), &u32OTABytesWritten, Receiver); - u32Index = QUEUE_MESSAGE_OTA_SIZE; //this will end the loop through all OTA messages - break; - case OTA_Abort: //abort this OTA process - bAbort = true; - bNodeIsResponding = true; - ESP_LOGI(LOG_TAG, "OTA-RX: rec Abort"); - //this will end the loop through all OTA messages - break; - default: - //receives wrong OTA message type from node --> back to queue - //vAddOTAControllMessageToQueue(&sMeshPacket); - break; - } - } - else if (err == ESP_OK) - { - //received from wrong node --> back to queue - vAddOTAControllMessageToQueue(&sMeshPacket); - } - - /* } - else + // { + //queue not empty + if (xQueueReceive(queueMessageOTA, &sMeshPacket, ((3000) / portTICK_PERIOD_MS)) != pdTRUE) { - ESP_LOGI(LOG_TAG, "OTA-RX: ota message queue empty --> wait"); - // OTA Message queue is empty --> wait some time - vTaskDelay( (OTA_MESH_TIMEOUT) / portTICK_PERIOD_MS); + ESP_LOGE(LOG_TAG, "Unable to receive OTA Messages from queue"); + err = ESP_FAIL; } - */ + + if((err == ESP_OK) && (bCheckMACEquality(sMeshPacket.meshSenderAddr.addr, pMeshNodeAddr->addr))) //if OTA_Version_Request + { + //packet from node received + switch (sMeshPacket.type) + { + case OTA_Complete: //signal end of this OTA process, fall through because same behavior as OTA_Data + bComplete = true; + ESP_LOGI(LOG_TAG, "OTA-RX: rec Complete --> last segment"); + //fall through + case OTA_Data: //data segement received + bNodeIsResponding = true; + ERROR_CHECK(esp_ota_write(otaHandle, sMeshPacket.au8Payload, OTA_MESH_SEGMENT_SIZE)); + u32OTABytesWritten = ((u32SegmentCounter+1) * OTA_MESH_SEGMENT_SIZE); + vPrintOTAProgress(&(pOTAPartition->size), &u32OTABytesWritten, Receiver); + u32Index = QUEUE_MESSAGE_OTA_SIZE; //this will end the loop through all OTA messages + break; + case OTA_Abort: //abort this OTA process + bAbort = true; + bNodeIsResponding = true; + ESP_LOGI(LOG_TAG, "OTA-RX: rec Abort"); + //this will end the loop through all OTA messages + break; + default: + //receives wrong OTA message type from node --> back to queue + //vAddOTAControllMessageToQueue(&sMeshPacket); + break; + } + } + else if (err == ESP_OK) + { + //received from wrong node --> back to queue + vAddOTAControllMessageToQueue(&sMeshPacket); + } + + /* } + else + { + ESP_LOGI(LOG_TAG, "OTA-RX: ota message queue empty --> wait"); + // OTA Message queue is empty --> wait some time + vTaskDelay( (OTA_MESH_TIMEOUT) / portTICK_PERIOD_MS); + } + */ }//end of OTA message loop @@ -876,7 +893,7 @@ esp_err_t errOTAMeshReceive(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr) if(bAbort == false) { //no error while ota write --> send OTA_ACK packet - ESP_LOGI(LOG_TAG, "OTA-RX: no error while ota write --> send OTA_ACK packet"); + //ESP_LOGI(LOG_TAG, "OTA-RX: no error while ota write --> send OTA_ACK packet"); sMeshPacket.type = OTA_ACK; err = errSendMeshPacket(pMeshNodeAddr, &sMeshPacket); } @@ -890,7 +907,7 @@ esp_err_t errOTAMeshReceive(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr) errSendMeshPacket(pMeshNodeAddr, &sMeshPacket); } } - u32SegmentCounter++; + u32SegmentCounter++; }//end of partition segement loop if(bComplete == true) diff --git a/components/mesh_ota/Mesh_network.c b/components/mesh_ota/Mesh_network.c index e28c1c8..d81f1a8 100644 --- a/components/mesh_ota/Mesh_network.c +++ b/components/mesh_ota/Mesh_network.c @@ -127,6 +127,16 @@ bool bCheckMACEquality(uint8_t* pu8aMAC, uint8_t* pu8bMAC) { bRet = false; } + + if(index == 5) + { + //last byte of mac + if(abs((pu8aMAC[index] - pu8bMAC[index])) <= 1) + { + bRet = true; //last byte differs 1 ore less + } + } + index++; } return bRet; diff --git a/components/mesh_ota/include/Mesh_network.h b/components/mesh_ota/include/Mesh_network.h index b4c2d13..f2c0421 100644 --- a/components/mesh_ota/include/Mesh_network.h +++ b/components/mesh_ota/include/Mesh_network.h @@ -8,6 +8,7 @@ #include "esp_log.h" #include "esp_mesh.h" #include "esp_mesh_internal.h" +#include #ifndef CONFIG_MESH_MESSAGE_SIZE #define CONFIG_MESH_MESSAGE_SIZE 1500 From 14028679e1e48fe8fb6f705fee97e4ac3a69bb52 Mon Sep 17 00:00:00 2001 From: localhorst Date: Wed, 20 Jan 2021 15:18:22 +0100 Subject: [PATCH 14/21] fixing timeout and non-relevant OTA messages --- components/mesh_ota/Mesh_OTA.c | 43 ++++++++++++++++++++------ components/mesh_ota/Mesh_network.c | 1 - components/mesh_ota/include/Mesh_OTA.h | 5 +-- 3 files changed, 37 insertions(+), 12 deletions(-) diff --git a/components/mesh_ota/Mesh_OTA.c b/components/mesh_ota/Mesh_OTA.c index 1772af0..bef1e0b 100644 --- a/components/mesh_ota/Mesh_OTA.c +++ b/components/mesh_ota/Mesh_OTA.c @@ -67,7 +67,7 @@ esp_err_t errMeshOTAInitialize() } ERROR_CHECK(errMeshNetworkSetChildConnectedHandle(vAddNodeToPossibleUpdatableQueue)); - ERROR_CHECK(errMeshNetworkSetOTAMessageHandleHandle(vAddOTAControllMessageToQueue)); + ERROR_CHECK(errMeshNetworkSetOTAMessageHandleHandle(vAddOtaMessageToQueue)); ERROR_CHECK(errMeshNetworkSetChangeStateOfServerWorkerHandle(vChangeStateOfServerWorker)); if(err == ESP_OK) @@ -121,7 +121,7 @@ void vAddNodeToPossibleUpdatableQueue(uint8_t* pu8MAC) } } -void vAddOTAControllMessageToQueue(MESH_PACKET_t* puMeshPacket) +void vAddOtaMessageToQueue(MESH_PACKET_t* puMeshPacket) { //send ota packet to packet queue if (xQueueSend(queueMessageOTA, puMeshPacket, portMAX_DELAY) != pdPASS) @@ -455,7 +455,7 @@ esp_err_t errOTAMeshMaster(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr) else if (err == ESP_OK) { //received from wrong node or type --> back to queue - vAddOTAControllMessageToQueue(&sOTAMessage); + vAddOtaMessageToQueue(&sOTAMessage); } } else @@ -674,10 +674,33 @@ esp_err_t errSendOTAVersionResponse(mesh_addr_t* pMeshReceiverAddr) pBootPartition = esp_ota_get_boot_partition(); //get boot partition (that will booted after reset), not the running partition ERROR_CHECK(esp_ota_get_partition_description(pBootPartition, &bootPartitionDesc)); //get metadate of partition memcpy(&packet.au8Payload, &bootPartitionDesc.version, 12); //copy local version to OTA_Version_Response packet + + ESP_LOGI(LOG_TAG, "Send OTA_Version_Response to 0x%x", pMeshReceiverAddr->addr[5]); + err = errSendMeshPacket(pMeshReceiverAddr, &packet); return err; } +void vClearOtaMessageQueue(mesh_addr_t* pMeshNodeAddr) +{ + MESH_PACKET_t sMeshPacket; //packet for sending and receiving + for (uint32_t u32Index = 0; (u32Index < QUEUE_MESSAGE_OTA_SIZE); u32Index++) //loop through all OTA messages + { + if (xQueueReceive(queueMessageOTA, &sMeshPacket, 0) == pdTRUE) + { + if(!(bCheckMACEquality(sMeshPacket.meshSenderAddr.addr, pMeshNodeAddr->addr))) + { + //received OTA message is NOT from pMeshNodeAddr --> keep it in queue + vAddOtaMessageToQueue(&sMeshPacket); + } + else + { + ESP_LOGI(LOG_TAG, "Removed type %i from node 0x%x", sMeshPacket.type, pMeshNodeAddr->addr[5]); + } + } + }//end OTA message loop +} + esp_err_t errSendOTAVersionRequest(mesh_addr_t* pMeshReceiverAddr) { esp_err_t err = ESP_OK; @@ -746,7 +769,7 @@ esp_err_t errOTAMeshTransmit(mesh_addr_t* pMeshNodeAddr) // if(uxQueueSpacesAvailable(queueMessageOTA) < QUEUE_MESSAGE_OTA_SIZE) // { //queue not empty - if (xQueueReceive(queueMessageOTA, &sMeshPacket, ((3000) / portTICK_PERIOD_MS)) != pdTRUE) + if (xQueueReceive(queueMessageOTA, &sMeshPacket, ((OTA_MESH_TIMEOUT) / portTICK_PERIOD_MS)) != pdTRUE) { ESP_LOGE(LOG_TAG, "Unable to receive OTA Messages from queue"); err = ESP_FAIL; @@ -768,14 +791,14 @@ esp_err_t errOTAMeshTransmit(mesh_addr_t* pMeshNodeAddr) break; default: //receives wrong OTA message type from node --> back to queue - //vAddOTAControllMessageToQueue(&sMeshPacket); + //vAddOtaMessageToQueue(&sMeshPacket); break; } } else if (err == ESP_OK) { //received from wrong node --> back to queue - vAddOTAControllMessageToQueue(&sMeshPacket); + vAddOtaMessageToQueue(&sMeshPacket); } /* } @@ -798,6 +821,7 @@ esp_err_t errOTAMeshTransmit(mesh_addr_t* pMeshNodeAddr) } u32SegmentCounter++; }//end of partition segment loop + vClearOtaMessageQueue(pMeshNodeAddr); return err; } @@ -826,7 +850,7 @@ esp_err_t errOTAMeshReceive(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr) //if(uxQueueSpacesAvailable(queueMessageOTA) < QUEUE_MESSAGE_OTA_SIZE) // { //queue not empty - if (xQueueReceive(queueMessageOTA, &sMeshPacket, ((3000) / portTICK_PERIOD_MS)) != pdTRUE) + if (xQueueReceive(queueMessageOTA, &sMeshPacket, ((OTA_MESH_TIMEOUT) / portTICK_PERIOD_MS)) != pdTRUE) { ESP_LOGE(LOG_TAG, "Unable to receive OTA Messages from queue"); err = ESP_FAIL; @@ -856,14 +880,14 @@ esp_err_t errOTAMeshReceive(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr) break; default: //receives wrong OTA message type from node --> back to queue - //vAddOTAControllMessageToQueue(&sMeshPacket); + //vAddOtaMessageToQueue(&sMeshPacket); break; } } else if (err == ESP_OK) { //received from wrong node --> back to queue - vAddOTAControllMessageToQueue(&sMeshPacket); + vAddOtaMessageToQueue(&sMeshPacket); } /* } @@ -927,5 +951,6 @@ esp_err_t errOTAMeshReceive(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr) //not all OTA segments received --> abort this OTA process ERROR_CHECK(esp_ota_abort(otaHandle)); } + vClearOtaMessageQueue(pMeshNodeAddr); return err; } diff --git a/components/mesh_ota/Mesh_network.c b/components/mesh_ota/Mesh_network.c index d81f1a8..4217dd5 100644 --- a/components/mesh_ota/Mesh_network.c +++ b/components/mesh_ota/Mesh_network.c @@ -136,7 +136,6 @@ bool bCheckMACEquality(uint8_t* pu8aMAC, uint8_t* pu8bMAC) bRet = true; //last byte differs 1 ore less } } - index++; } return bRet; diff --git a/components/mesh_ota/include/Mesh_OTA.h b/components/mesh_ota/include/Mesh_OTA.h index cbf5630..075c8f5 100644 --- a/components/mesh_ota/include/Mesh_OTA.h +++ b/components/mesh_ota/include/Mesh_OTA.h @@ -23,7 +23,7 @@ #define OTA_HTTPS_SEGMENT_SIZE 2048U #define OTA_PROGRESS_LOG_INTERVAL 7U #define OTA_MESH_SEGMENT_SIZE MESH_NETWORK_PAYLOAD_SIZE -#define OTA_MESH_TIMEOUT 400U //in ms +#define OTA_MESH_TIMEOUT 20000U //in ms #define ERROR_CHECK(x) if (err == ESP_OK) \ { \ @@ -59,10 +59,11 @@ void vPrintOTAProgress(const uint32_t* const pu32TotalImageSize, const uint32_t* void vAddAllNeighboursToQueue(void); esp_err_t errSendOTAVersionResponse(mesh_addr_t* meshReceiverAddr); esp_err_t errSendOTAVersionRequest(mesh_addr_t* meshReceiverAddr); +void vClearOtaMessageQueue(mesh_addr_t* pMeshNodeAddr); //Handler void vAddNodeToPossibleUpdatableQueue(uint8_t* pu8MAC); -void vAddOTAControllMessageToQueue(MESH_PACKET_t* puMeshPacket); +void vAddOtaMessageToQueue(MESH_PACKET_t* puMeshPacket); void vChangeStateOfServerWorker(bool state); //Tasks From e4c620c9c58c6aede2fccbea207fbc0d87c6b9ca Mon Sep 17 00:00:00 2001 From: localhorst Date: Wed, 20 Jan 2021 20:55:33 +0100 Subject: [PATCH 15/21] splitted into several modules; include cleanup --- components/mesh_ota/CMakeLists.txt | 2 +- .../{HTTPS_client.c => HTTPS_Client.c} | 2 +- .../{Mesh_network.c => Mesh_Network.c} | 2 +- ...twork_handler.c => Mesh_Network_Handler.c} | 2 +- components/mesh_ota/Mesh_OTA.c | 637 +----------------- components/mesh_ota/Mesh_OTA_Globals.c | 10 + .../mesh_ota/Mesh_OTA_Partition_Access.c | 323 +++++++++ components/mesh_ota/Mesh_OTA_Util.c | 314 +++++++++ .../{HTTPS_client.h => HTTPS_Client.h} | 9 - .../{Mesh_network.h => Mesh_Network.h} | 11 +- components/mesh_ota/include/Mesh_OTA.h | 39 +- components/mesh_ota/include/Mesh_OTA_Access.h | 28 + .../mesh_ota/include/Mesh_OTA_Globals.h | 19 + components/mesh_ota/include/Mesh_OTA_Util.h | 35 + main/Blinky_LED.c | 2 +- main/Blinky_LED.h | 1 + main/Main.c | 18 +- 17 files changed, 757 insertions(+), 697 deletions(-) rename components/mesh_ota/{HTTPS_client.c => HTTPS_Client.c} (99%) rename components/mesh_ota/{Mesh_network.c => Mesh_Network.c} (99%) rename components/mesh_ota/{Mesh_network_handler.c => Mesh_Network_Handler.c} (99%) create mode 100644 components/mesh_ota/Mesh_OTA_Globals.c create mode 100644 components/mesh_ota/Mesh_OTA_Partition_Access.c create mode 100644 components/mesh_ota/Mesh_OTA_Util.c rename components/mesh_ota/include/{HTTPS_client.h => HTTPS_Client.h} (91%) rename components/mesh_ota/include/{Mesh_network.h => Mesh_Network.h} (78%) create mode 100644 components/mesh_ota/include/Mesh_OTA_Access.h create mode 100644 components/mesh_ota/include/Mesh_OTA_Globals.h create mode 100644 components/mesh_ota/include/Mesh_OTA_Util.h diff --git a/components/mesh_ota/CMakeLists.txt b/components/mesh_ota/CMakeLists.txt index 8d5c8bc..78a3b4c 100644 --- a/components/mesh_ota/CMakeLists.txt +++ b/components/mesh_ota/CMakeLists.txt @@ -1,4 +1,4 @@ -idf_component_register(SRCS "HTTPS_client.c" "Mesh_network_handler.c" "Mesh_network.c" "Mesh_OTA.c" +idf_component_register(SRCS "Mesh_OTA_Util.c" "Mesh_Network.c" "Mesh_Network_Handler.c" "HTTPS_Client.c" "Mesh_OTA_Partition_Access.c" "Mesh_OTA_Globals.c" "Mesh_OTA.c" INCLUDE_DIRS "include" REQUIRES nvs_flash esp_http_client diff --git a/components/mesh_ota/HTTPS_client.c b/components/mesh_ota/HTTPS_Client.c similarity index 99% rename from components/mesh_ota/HTTPS_client.c rename to components/mesh_ota/HTTPS_Client.c index 6518925..41d847b 100644 --- a/components/mesh_ota/HTTPS_client.c +++ b/components/mesh_ota/HTTPS_Client.c @@ -1,4 +1,4 @@ -#include "HTTPS_client.h" +#include "HTTPS_Client.h" static const char *TAG = "https_client"; diff --git a/components/mesh_ota/Mesh_network.c b/components/mesh_ota/Mesh_Network.c similarity index 99% rename from components/mesh_ota/Mesh_network.c rename to components/mesh_ota/Mesh_Network.c index 4217dd5..f04fc46 100644 --- a/components/mesh_ota/Mesh_network.c +++ b/components/mesh_ota/Mesh_Network.c @@ -1,5 +1,5 @@ -#include "Mesh_OTA.h" +#include "Mesh_Network.h" static const char *LOG_TAG = "mesh_network"; static uint8_t tx_buf[CONFIG_MESH_MESSAGE_SIZE] = { 0, }; diff --git a/components/mesh_ota/Mesh_network_handler.c b/components/mesh_ota/Mesh_Network_Handler.c similarity index 99% rename from components/mesh_ota/Mesh_network_handler.c rename to components/mesh_ota/Mesh_Network_Handler.c index 3f5e2f7..791cd71 100644 --- a/components/mesh_ota/Mesh_network_handler.c +++ b/components/mesh_ota/Mesh_Network_Handler.c @@ -1,5 +1,5 @@ -#include "Mesh_OTA.h" +#include "Mesh_Network.h" static const char *LOG_TAG = "mesh_network_handler"; diff --git a/components/mesh_ota/Mesh_OTA.c b/components/mesh_ota/Mesh_OTA.c index bef1e0b..6292756 100644 --- a/components/mesh_ota/Mesh_OTA.c +++ b/components/mesh_ota/Mesh_OTA.c @@ -1,16 +1,10 @@ #include "Mesh_OTA.h" +#include "Mesh_OTA_Util.h" +#include "Mesh_OTA_Globals.h" +#include "Mesh_OTA_Access.h" static const char *LOG_TAG = "mesh_ota"; -xQueueHandle queueNodes; //nodes that should be checked for ota update (contains children and parent) -xQueueHandle queueMessageOTA; //mesh ota controll messages like "OTA_Version_Response" "OTA_ACK" - -SemaphoreHandle_t bsStartStopServerWorker; //binary semaphore -SemaphoreHandle_t bsOTAProcess; //binary semaphore - -const esp_partition_t* pOTAPartition; //pointer to ota partition -bool bWantReboot; //flag to signal pending reboot - esp_err_t errMeshOTAInitialize() { esp_err_t err = ESP_OK; @@ -105,75 +99,6 @@ esp_err_t errMeshOTAInitialize() return err; } -void vAddNodeToPossibleUpdatableQueue(uint8_t* pu8MAC) -{ - //send payload to node queues - mesh_addr_t addrNode; - memcpy(&addrNode.addr, (uint8_t *)pu8MAC, 6); //copy MAC - - if (xQueueSend(queueNodes, &addrNode, portMAX_DELAY) != pdPASS) - { - ESP_LOGE(LOG_TAG, "Unable to push node into node queue"); - } - else - { - ESP_LOGI(LOG_TAG, "added node \"%x:%x:%x:%x:%x:%x\" to possible updatable queue", addrNode.addr[0], addrNode.addr[1], addrNode.addr[2], addrNode.addr[3], addrNode.addr[4], addrNode.addr[5]); - } -} - -void vAddOtaMessageToQueue(MESH_PACKET_t* puMeshPacket) -{ - //send ota packet to packet queue - if (xQueueSend(queueMessageOTA, puMeshPacket, portMAX_DELAY) != pdPASS) - { - ESP_LOGE(LOG_TAG, "Unable to push ota packet into packet queue"); - } - else - { - switch (puMeshPacket->type) - { - case OTA_Abort: - ESP_LOGI(LOG_TAG, "added ota message to queue: OTA_Abort from 0x%x", puMeshPacket->meshSenderAddr.addr[5]); - break; - case OTA_Version_Request: - ESP_LOGI(LOG_TAG, "added ota message to queue: OTA_Version_Request from 0x%x", puMeshPacket->meshSenderAddr.addr[5]); - break; - - case OTA_Version_Response: - ESP_LOGI(LOG_TAG, "added ota message to queue: OTA_Version Response from 0x%x", puMeshPacket->meshSenderAddr.addr[5]); - break; - default: - break; - } - } -} - -void vChangeStateOfServerWorker(bool bState) //allow access via function ptn to networl_handler -{ - static bool bLastState = false; - - if(bState != bLastState) //change only if necessary - { - ESP_LOGI(LOG_TAG, "server worker change handler"); - - if(bState == true) - { - if (xSemaphoreGive(bsStartStopServerWorker) != pdTRUE) - { - ESP_LOGE(LOG_TAG, "Unable to give mutex to activate the server worker"); - } - } - else - { - if (xSemaphoreTake(bsStartStopServerWorker,( TickType_t ) 10 ) != pdTRUE) - { - ESP_LOGE(LOG_TAG, "Unable to obtain mutex to deactivate the server worker"); - } - } - bLastState = bState; - } -} - void vTaskServerWorker(void *arg) { esp_err_t err; @@ -272,84 +197,6 @@ void vTaskOTAWorker(void *arg) } } -esp_err_t errOTAHTTPS(bool* pbNewOTAImage) -{ - esp_err_t err = ESP_OK; - char u8OTABuffer[OTA_HTTPS_SEGMENT_SIZE]; //store image segment from server before ota write - uint32_t u32BufferLenght = OTA_HTTPS_SEGMENT_SIZE; //size of buffer - uint32_t u32BytesRead = 0; //number of bytes that are read from server, <= u32BufferLenght - char pcRemoteVersionNumber[12]; //string for version number in server image - const esp_partition_t* pBootPartition; //pointer to boot partition (that will booted after reset) - static esp_ota_handle_t otaHandle; //OTA process handle - uint32_t u32StartOffset = 0U; //start offset for image (exclude the http response data) - esp_app_desc_t bootPartitionDesc; //Metadate from boot partition - uint32_t u32OTABytesWritten = 0U; //counter unsed for progress log - - ERROR_CHECK(errHTTPSClientRetrieveData(u8OTABuffer, &u32BufferLenght, &u32BytesRead)); //read first bytes if image, including the version - - ERROR_CHECK(errExtractVersionNumber(u8OTABuffer, &u32BytesRead, pcRemoteVersionNumber)); //extract version numbers - - if(err == ESP_OK) //check if version number is found - { - xSemaphoreTake(bsOTAProcess, portMAX_DELAY); //wait for binary semaphore that allows to start the OTA process - - pBootPartition = esp_ota_get_boot_partition(); //get boot partition (that will booted after reset), not the running partition - ERROR_CHECK(esp_ota_get_partition_description(pBootPartition, &bootPartitionDesc)); //get metadata of partition - - if(bNewerVersion((bootPartitionDesc).version, pcRemoteVersionNumber)) //compare local and remote version - { - // server image is newer --> OTA update required - ESP_LOGI(LOG_TAG, "Server: image is newer --> OTA update required"); - - ERROR_CHECK(errFindImageStart(u8OTABuffer, &u32BufferLenght, &u32StartOffset)); //get image start offset - - ERROR_CHECK(esp_ota_begin(pOTAPartition, OTA_SIZE_UNKNOWN, &otaHandle)); //start ota update process - if(err == ESP_OK) - { - //image download and ota partition write - ESP_LOGI(LOG_TAG, "start OTA download via HTTPS"); - do - { - vPrintOTAProgress(&(pOTAPartition->size), &u32OTABytesWritten, Receiver); - ERROR_CHECK(esp_ota_write(otaHandle, (const void*) u8OTABuffer+u32StartOffset, (u32BytesRead-u32StartOffset))); - - if(err == ESP_OK) - { - //write was succsesfull - u32StartOffset = 0U; //reset the offset for next download - ERROR_CHECK(errHTTPSClientRetrieveData(u8OTABuffer, &u32BufferLenght, &u32BytesRead)); //download next data segment - u32OTABytesWritten = u32OTABytesWritten + u32BytesRead; //update counter - } - } - while ((u32BytesRead > 0) && (err == ESP_OK) && (u32OTABytesWritten <= pOTAPartition->size)); //loop until error or complete image downloaded - } - - if(err == ESP_OK) - { - //no error occurred --> finish ota update process - ERROR_CHECK(esp_ota_end(otaHandle)); //finish process - ERROR_CHECK(esp_ota_set_boot_partition(pOTAPartition)); //set new image as boot - if(err == ESP_OK) - { - *pbNewOTAImage = true; //image validated - } - } - else - { - //error occurred --> abort ota update process - ESP_LOGE(LOG_TAG, "abort ota process due to error 0x%x -> %s", err, esp_err_to_name(err)); - ERROR_CHECK(esp_ota_abort(otaHandle)); - *pbNewOTAImage = false; //ota update failed - } - } - else - { - ESP_LOGI(LOG_TAG, "server image is NOT newer --> OTA update NOT required"); - } - xSemaphoreGive(bsOTAProcess); //free binary semaphore, this allows other tasks to start the OTA process - } //end version number extracted - return err; -} esp_err_t errOTAMeshSlave(bool* pbNewOTAImage) { @@ -476,481 +323,3 @@ esp_err_t errOTAMeshMaster(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr) } return err; } - -bool bNewerVersion(const char* pu8Local, const char* pu8Remote) -{ - /* - * Return true if remote version is newer (higher) than local version - */ - char u8LocalTmp[12]; //local version - char u8RemoteTmp[12]; //remote version - char* pu8saveptrLocal; //context for strok_r - char* pu8saveptrRemote; //context for strok_r - bool bReturn = false; //flag to stop loop - uint8_t u8Index = 0; //numbers counter in version string - - strncpy(u8LocalTmp, pu8Local, 12); //copy in tmp - strncpy(u8RemoteTmp, pu8Remote, 12); //copy in tmp - - char* pu8TokenLocal = strtok_r(u8LocalTmp, ".", &pu8saveptrLocal); //split tokens - char* pu8TokenRemote = strtok_r(u8RemoteTmp, ".", &pu8saveptrRemote); //split tokens - - while( (u8Index <= 2) && (bReturn == false)) //loop through tokens - { - u8Index++; - if(atoi(pu8TokenLocal) < atoi(pu8TokenRemote)) - { - bReturn = true; //version number difference --> stop loop - } - pu8TokenLocal = strtok_r(NULL, ".", &pu8saveptrLocal); //split tokens - pu8TokenRemote = strtok_r(NULL, ".", &pu8saveptrRemote); //split tokens - } - return bReturn; -} - -esp_err_t errFindImageStart(const char* pu8Data, uint32_t* pu32DataLenght, uint32_t* pu32StartOffset) -{ - /* - Offset value - 0 = 0xE9 (first byte in image --> magic byte) - 48 = first digit of version number - */ - - esp_err_t errReturn = ESP_OK; - bool bImageStartOffsetFound = false; - uint32_t u32DataIndex = 0; - uint32_t u32FirstDotOffset = 0; - uint32_t u32SecondDotOffset = 0; - uint8_t u8FirstDotIndex = 0; - uint8_t u8SecondDotIndex = 0; - - *pu32StartOffset = 0U; //reset offset to zero - - while((u32DataIndex < *pu32DataLenght) && (bImageStartOffsetFound == false)) - { - //search for magic byte - if(pu8Data[u32DataIndex] == 0xe9) - { - //magic byte found - while ((u8FirstDotIndex < 3) && (u32FirstDotOffset == 0)) - { - //search first dot in version number - if((u32DataIndex+49+u8FirstDotIndex) < *pu32DataLenght) - { - if((pu8Data[(u32DataIndex+49+u8FirstDotIndex)] == 0x2e)) - { - //first dot found - u32FirstDotOffset = (u32DataIndex+49+u8FirstDotIndex); - } - } - u8FirstDotIndex++; - } - - while ((u8SecondDotIndex < 3) && (u32SecondDotOffset == 0) && (u32FirstDotOffset != 0)) - { - //search first dot in version number - if((u32FirstDotOffset+(u8SecondDotIndex+2)) < *pu32DataLenght) - { - if((pu8Data[(u32FirstDotOffset+(u8SecondDotIndex+2))] == 0x2e)) - { - //second dot found - u32SecondDotOffset = (u32FirstDotOffset+(u8SecondDotIndex+2)); - } - } - u8SecondDotIndex++; - } - - if((u32FirstDotOffset != 0) && (u32SecondDotOffset != 0)) - { - //image start found based on magic byte and version number systax - *pu32StartOffset = u32DataIndex; //store image start offset - bImageStartOffsetFound = true; - } - else - { - // this is propably not the magic byte --> reset - u32FirstDotOffset = 0; - u32SecondDotOffset = 0; - u8FirstDotIndex = 0; - u8SecondDotIndex = 0; - } - } - u32DataIndex++; - } - - if(bImageStartOffsetFound == false) - { - errReturn = ESP_ERR_NOT_FOUND; - } - - return errReturn; -} - -esp_err_t errExtractVersionNumber(const char* pu8Data, uint32_t* pu32DataLenght, char* pc8RemoteVersionNumber) -{ - uint32_t u32StartOffset; - esp_err_t err = ESP_OK; - - strcpy(pc8RemoteVersionNumber, "999.999.999"); //init value - err = errFindImageStart(pu8Data, pu32DataLenght, &u32StartOffset); //get image start offset - - if(err == ESP_OK) - { - //image found - strncpy(pc8RemoteVersionNumber, pu8Data+(u32StartOffset+48), 11); //copy version number - pc8RemoteVersionNumber[12] = '\0'; - } - return err; -} - -void vPrintOTAProgress(const uint32_t* const pu32TotalImageSize, const uint32_t* const pu32BytesWritten, OTA_MESH_ROLE_t eRole) -{ - uint32_t u32Percentage = 0U; - static uint32_t u32LastPercentage = 0U; - - if((*pu32BytesWritten) >= (*pu32TotalImageSize)) - { - u32Percentage = 100; - } - else - { - u32Percentage = (uint32_t) (((float) (*pu32BytesWritten)/(float) (*pu32TotalImageSize)) * 100.0); - } - - if((u32Percentage-u32LastPercentage) >= OTA_PROGRESS_LOG_INTERVAL) - { - if(eRole == Transmitter) - { - ESP_LOGI(LOG_TAG, "Transmitting OTA update: %i %%", u32Percentage); - } - - if(eRole == Receiver) - { - ESP_LOGI(LOG_TAG, "Receiving OTA update: %i %%", u32Percentage); - } - - - - u32LastPercentage = u32Percentage; - } -} - -void vAddAllNeighboursToQueue(void) -{ - esp_err_t err = ESP_OK; - - mesh_addr_t addrParent; //addr of parent node - mesh_addr_t childrenAddr[CONFIG_MESH_ROUTE_TABLE_SIZE]; //array of children attached to this node - uint16_t u16ChildrenSize = 0U; //number of children attached to this node - - err = errGetParentNode(&addrParent); - - if(err == ESP_OK) - { - vAddNodeToPossibleUpdatableQueue(addrParent.addr); - ESP_LOGI(LOG_TAG, "added parent"); - } - - err = ESP_OK; //reset error code - - ERROR_CHECK(errGetChildren(childrenAddr, &u16ChildrenSize)); //get all children - - for (uint16_t u16Index = 0; ((u16Index < u16ChildrenSize) && (err == ESP_OK)); u16Index++) - { - vAddNodeToPossibleUpdatableQueue(childrenAddr[u16Index].addr); - ESP_LOGI(LOG_TAG, "added child"); - } -} - -esp_err_t errSendOTAVersionResponse(mesh_addr_t* pMeshReceiverAddr) -{ - esp_err_t err = ESP_OK; - MESH_PACKET_t packet; - packet.type = OTA_Version_Response; - - const esp_partition_t* pBootPartition; //pointer to boot partition (that will booted after reset) - esp_app_desc_t bootPartitionDesc; //Metadata from boot partition - - pBootPartition = esp_ota_get_boot_partition(); //get boot partition (that will booted after reset), not the running partition - ERROR_CHECK(esp_ota_get_partition_description(pBootPartition, &bootPartitionDesc)); //get metadate of partition - memcpy(&packet.au8Payload, &bootPartitionDesc.version, 12); //copy local version to OTA_Version_Response packet - - ESP_LOGI(LOG_TAG, "Send OTA_Version_Response to 0x%x", pMeshReceiverAddr->addr[5]); - - err = errSendMeshPacket(pMeshReceiverAddr, &packet); - return err; -} - -void vClearOtaMessageQueue(mesh_addr_t* pMeshNodeAddr) -{ - MESH_PACKET_t sMeshPacket; //packet for sending and receiving - for (uint32_t u32Index = 0; (u32Index < QUEUE_MESSAGE_OTA_SIZE); u32Index++) //loop through all OTA messages - { - if (xQueueReceive(queueMessageOTA, &sMeshPacket, 0) == pdTRUE) - { - if(!(bCheckMACEquality(sMeshPacket.meshSenderAddr.addr, pMeshNodeAddr->addr))) - { - //received OTA message is NOT from pMeshNodeAddr --> keep it in queue - vAddOtaMessageToQueue(&sMeshPacket); - } - else - { - ESP_LOGI(LOG_TAG, "Removed type %i from node 0x%x", sMeshPacket.type, pMeshNodeAddr->addr[5]); - } - } - }//end OTA message loop -} - -esp_err_t errSendOTAVersionRequest(mesh_addr_t* pMeshReceiverAddr) -{ - esp_err_t err = ESP_OK; - MESH_PACKET_t packet; - packet.type = OTA_Version_Request; - - const esp_partition_t* pBootPartition; //pointer to boot partition (that will booted after reset) - esp_app_desc_t bootPartitionDesc; //Metadata from boot partition - - pBootPartition = esp_ota_get_boot_partition(); //get boot partition (that will booted after reset), not the running partition - ERROR_CHECK(esp_ota_get_partition_description(pBootPartition, &bootPartitionDesc)); //get metadate of partition - memcpy(&packet.au8Payload, &bootPartitionDesc.version, 12); //copy local version to OTA_Version_Request packet - err = errSendMeshPacket(pMeshReceiverAddr, &packet); - return err; -} - -esp_err_t errOTAMeshTransmit(mesh_addr_t* pMeshNodeAddr) -{ - esp_err_t err = ESP_OK; - const esp_partition_t* pBootPartition; //pointer to boot partition (that will booted after reset) - MESH_PACKET_t sMeshPacket; //packet for sending and receiving - // uint32_t u32Index = 0U; //index for partition read offset - bool bAbort = false; //abort the OTA process - bool bNodeIsResponding = false; //remote node is still active - uint32_t u32OTABytesWritten = 0U; - uint32_t u32SegmentCounter = 0U; - - pBootPartition = esp_ota_get_boot_partition(); //get boot partition (that will booted after reset), not the running partition - - //loop through partition to read in segmensts until end or error or abort called - while( ((OTA_MESH_SEGMENT_SIZE * u32SegmentCounter) < pBootPartition->size) && (err == ESP_OK) && (bAbort == false)) - { - bNodeIsResponding = false; //reset to default - - // read partition with offset based in index - ERROR_CHECK(esp_partition_read(pBootPartition, (OTA_MESH_SEGMENT_SIZE * u32SegmentCounter), sMeshPacket.au8Payload, OTA_MESH_SEGMENT_SIZE)); - u32OTABytesWritten = ((u32SegmentCounter+1) * OTA_MESH_SEGMENT_SIZE); - vPrintOTAProgress(&(pBootPartition->size), &u32OTABytesWritten, Transmitter); - - if(err == ESP_OK) - { - //no error while read --> send OTA_DATA packet - sMeshPacket.type = OTA_Data; - - if((OTA_MESH_SEGMENT_SIZE * (u32SegmentCounter+1)) >= pBootPartition->size) //check if last segment - { - //last partition image segment --> send OTA_Complete - ESP_LOGI(LOG_TAG, "OTA-TX: last segment--> send Complete"); - sMeshPacket.type = OTA_Complete; - } - //ESP_LOGI(LOG_TAG, "OTA-TX: send packet"); - err = errSendMeshPacket(pMeshNodeAddr, &sMeshPacket); - } - else - { - // error while read --> send OTA_ABORT and abort this OTA process - sMeshPacket.type = OTA_Abort; - bAbort = true; - ESP_LOGI(LOG_TAG, "OTA-TX: error while read --> send ABORT"); - errSendMeshPacket(pMeshNodeAddr, &sMeshPacket); - } - - // loop through all OTA messages or until abort is called or error - for (uint32_t u32Index = 0; ((u32Index < QUEUE_MESSAGE_OTA_SIZE) && (bAbort == false) && (err == ESP_OK)); u32Index++) //loop through all OTA messages - { - // if(uxQueueSpacesAvailable(queueMessageOTA) < QUEUE_MESSAGE_OTA_SIZE) - // { - //queue not empty - if (xQueueReceive(queueMessageOTA, &sMeshPacket, ((OTA_MESH_TIMEOUT) / portTICK_PERIOD_MS)) != pdTRUE) - { - ESP_LOGE(LOG_TAG, "Unable to receive OTA Messages from queue"); - err = ESP_FAIL; - } - - if((err == ESP_OK) && (bCheckMACEquality(sMeshPacket.meshSenderAddr.addr, pMeshNodeAddr->addr))) //if OTA_Version_Request - { - //packet from node received - switch (sMeshPacket.type) - { - case OTA_ACK: //increase index for next round - u32Index++; - bNodeIsResponding = true; - u32Index = QUEUE_MESSAGE_OTA_SIZE;//this will end the loop through all OTA messages - break; - case OTA_Abort: //abort this OTA process - bAbort = true; - bNodeIsResponding = true; - break; - default: - //receives wrong OTA message type from node --> back to queue - //vAddOtaMessageToQueue(&sMeshPacket); - break; - } - } - else if (err == ESP_OK) - { - //received from wrong node --> back to queue - vAddOtaMessageToQueue(&sMeshPacket); - } - /* - } - else - { - // OTA Message queue is empty --> wait some time - ESP_LOGI(LOG_TAG, "OTA-TX: ota message queue empty --> wait"); - vTaskDelay( (OTA_MESH_TIMEOUT) / portTICK_PERIOD_MS); - } - */ - - }//end OTA message loop - - if(bNodeIsResponding == false) - { - //no abort was called but node didn’t responded - ESP_LOGE(LOG_TAG, "OTA-TX: no abort was called but node didn’t responded --> error"); - bAbort = true; - err = ESP_FAIL; //this OTA process failed with error - } - u32SegmentCounter++; - }//end of partition segment loop - vClearOtaMessageQueue(pMeshNodeAddr); - return err; -} - -esp_err_t errOTAMeshReceive(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr) -{ - esp_err_t err = ESP_OK; - MESH_PACKET_t sMeshPacket; //packet for sending and receiving - bool bComplete = false; //complete the OTA process - bool bAbort = false; //abort the OTA process - bool bNodeIsResponding = false; //remote node is still active - uint32_t u32OTABytesWritten = 0U; //counter unsed for progress log - static esp_ota_handle_t otaHandle; //OTA process handle - *pbNewOTAImage = false; - uint32_t u32SegmentCounter = 0U; - - ERROR_CHECK(esp_ota_begin(pOTAPartition, OTA_SIZE_UNKNOWN, &otaHandle)); //start ota update process - - //partition segement loop through partition to read in segmensts until end or error or abort called - while((bComplete == false) && (err == ESP_OK) && (bAbort == false) && (u32OTABytesWritten <= pOTAPartition->size)) - { - bNodeIsResponding = false; //reset to default - - // loop through all OTA messages or until abort is called - for (uint32_t u32Index = 0; ((u32Index < QUEUE_MESSAGE_OTA_SIZE) && (bAbort == false)); u32Index++) //loop through all OTA messages - { - //if(uxQueueSpacesAvailable(queueMessageOTA) < QUEUE_MESSAGE_OTA_SIZE) - // { - //queue not empty - if (xQueueReceive(queueMessageOTA, &sMeshPacket, ((OTA_MESH_TIMEOUT) / portTICK_PERIOD_MS)) != pdTRUE) - { - ESP_LOGE(LOG_TAG, "Unable to receive OTA Messages from queue"); - err = ESP_FAIL; - } - - if((err == ESP_OK) && (bCheckMACEquality(sMeshPacket.meshSenderAddr.addr, pMeshNodeAddr->addr))) //if OTA_Version_Request - { - //packet from node received - switch (sMeshPacket.type) - { - case OTA_Complete: //signal end of this OTA process, fall through because same behavior as OTA_Data - bComplete = true; - ESP_LOGI(LOG_TAG, "OTA-RX: rec Complete --> last segment"); - //fall through - case OTA_Data: //data segement received - bNodeIsResponding = true; - ERROR_CHECK(esp_ota_write(otaHandle, sMeshPacket.au8Payload, OTA_MESH_SEGMENT_SIZE)); - u32OTABytesWritten = ((u32SegmentCounter+1) * OTA_MESH_SEGMENT_SIZE); - vPrintOTAProgress(&(pOTAPartition->size), &u32OTABytesWritten, Receiver); - u32Index = QUEUE_MESSAGE_OTA_SIZE; //this will end the loop through all OTA messages - break; - case OTA_Abort: //abort this OTA process - bAbort = true; - bNodeIsResponding = true; - ESP_LOGI(LOG_TAG, "OTA-RX: rec Abort"); - //this will end the loop through all OTA messages - break; - default: - //receives wrong OTA message type from node --> back to queue - //vAddOtaMessageToQueue(&sMeshPacket); - break; - } - } - else if (err == ESP_OK) - { - //received from wrong node --> back to queue - vAddOtaMessageToQueue(&sMeshPacket); - } - - /* } - else - { - ESP_LOGI(LOG_TAG, "OTA-RX: ota message queue empty --> wait"); - // OTA Message queue is empty --> wait some time - vTaskDelay( (OTA_MESH_TIMEOUT) / portTICK_PERIOD_MS); - } - */ - - }//end of OTA message loop - - if(bNodeIsResponding == false) - { - //no abort was called but node didn’t responded --> error - ESP_LOGI(LOG_TAG, "OTA-RX: no abort was called but node didn’t responded --> error"); - bAbort = true; //this will stop the partition segement loop - err = ESP_FAIL; //this OTA process failed with error - } - else - { - //node has responded with OTA_DATA or OTA_Complete or OTA_ABORT - if(err == ESP_OK) - { - - if(bAbort == false) - { - //no error while ota write --> send OTA_ACK packet - //ESP_LOGI(LOG_TAG, "OTA-RX: no error while ota write --> send OTA_ACK packet"); - sMeshPacket.type = OTA_ACK; - err = errSendMeshPacket(pMeshNodeAddr, &sMeshPacket); - } - } - else - { - // error while read --> send OTA_ABORT and abort this OTA process - sMeshPacket.type = OTA_Abort; - bAbort = true; - ESP_LOGI(LOG_TAG, "OTA-RX: abort --> send ABORT"); - errSendMeshPacket(pMeshNodeAddr, &sMeshPacket); - } - } - u32SegmentCounter++; - }//end of partition segement loop - - if(bComplete == true) - { - //all OTA segments received --> validate - ESP_LOGI(LOG_TAG, "OTA-RX: validate image "); - ERROR_CHECK(esp_ota_end(otaHandle)); - ERROR_CHECK(esp_ota_set_boot_partition(pOTAPartition)); - if(err == ESP_OK) - { - //successfully updated OTA partition - *pbNewOTAImage = true; - } - } - else - { - //not all OTA segments received --> abort this OTA process - ERROR_CHECK(esp_ota_abort(otaHandle)); - } - vClearOtaMessageQueue(pMeshNodeAddr); - return err; -} diff --git a/components/mesh_ota/Mesh_OTA_Globals.c b/components/mesh_ota/Mesh_OTA_Globals.c new file mode 100644 index 0000000..890a888 --- /dev/null +++ b/components/mesh_ota/Mesh_OTA_Globals.c @@ -0,0 +1,10 @@ +#include "Mesh_OTA_Globals.h" + +xQueueHandle queueNodes; //nodes that should be checked for ota update (contains children and parent) +xQueueHandle queueMessageOTA; //mesh ota controll messages like "OTA_Version_Response" "OTA_ACK" + +SemaphoreHandle_t bsStartStopServerWorker; //binary semaphore +SemaphoreHandle_t bsOTAProcess; //binary semaphore + +const esp_partition_t* pOTAPartition; //pointer to ota partition +bool bWantReboot; //flag to signal pending reboot diff --git a/components/mesh_ota/Mesh_OTA_Partition_Access.c b/components/mesh_ota/Mesh_OTA_Partition_Access.c new file mode 100644 index 0000000..6776c26 --- /dev/null +++ b/components/mesh_ota/Mesh_OTA_Partition_Access.c @@ -0,0 +1,323 @@ +#include "Mesh_OTA.h" +#include "Mesh_OTA_Util.h" +#include "Mesh_OTA_Globals.h" +#include "Mesh_OTA_Access.h" + +static const char *LOG_TAG = "mesh_ota_access"; + +esp_err_t errOTAMeshTransmit(mesh_addr_t* pMeshNodeAddr) +{ + esp_err_t err = ESP_OK; + const esp_partition_t* pBootPartition; //pointer to boot partition (that will booted after reset) + MESH_PACKET_t sMeshPacket; //packet for sending and receiving + // uint32_t u32Index = 0U; //index for partition read offset + bool bAbort = false; //abort the OTA process + bool bNodeIsResponding = false; //remote node is still active + uint32_t u32OTABytesWritten = 0U; + uint32_t u32SegmentCounter = 0U; + + pBootPartition = esp_ota_get_boot_partition(); //get boot partition (that will booted after reset), not the running partition + + //loop through partition to read in segmensts until end or error or abort called + while( ((OTA_MESH_SEGMENT_SIZE * u32SegmentCounter) < pBootPartition->size) && (err == ESP_OK) && (bAbort == false)) + { + bNodeIsResponding = false; //reset to default + + // read partition with offset based in index + ERROR_CHECK(esp_partition_read(pBootPartition, (OTA_MESH_SEGMENT_SIZE * u32SegmentCounter), sMeshPacket.au8Payload, OTA_MESH_SEGMENT_SIZE)); + u32OTABytesWritten = ((u32SegmentCounter+1) * OTA_MESH_SEGMENT_SIZE); + vPrintOTAProgress(&(pBootPartition->size), &u32OTABytesWritten, Transmitter); + + if(err == ESP_OK) + { + //no error while read --> send OTA_DATA packet + sMeshPacket.type = OTA_Data; + + if((OTA_MESH_SEGMENT_SIZE * (u32SegmentCounter+1)) >= pBootPartition->size) //check if last segment + { + //last partition image segment --> send OTA_Complete + ESP_LOGI(LOG_TAG, "OTA-TX: last segment--> send Complete"); + sMeshPacket.type = OTA_Complete; + } + //ESP_LOGI(LOG_TAG, "OTA-TX: send packet"); + err = errSendMeshPacket(pMeshNodeAddr, &sMeshPacket); + } + else + { + // error while read --> send OTA_ABORT and abort this OTA process + sMeshPacket.type = OTA_Abort; + bAbort = true; + ESP_LOGI(LOG_TAG, "OTA-TX: error while read --> send ABORT"); + errSendMeshPacket(pMeshNodeAddr, &sMeshPacket); + } + + // loop through all OTA messages or until abort is called or error + for (uint32_t u32Index = 0; ((u32Index < QUEUE_MESSAGE_OTA_SIZE) && (bAbort == false) && (err == ESP_OK)); u32Index++) //loop through all OTA messages + { + // if(uxQueueSpacesAvailable(queueMessageOTA) < QUEUE_MESSAGE_OTA_SIZE) + // { + //queue not empty + if (xQueueReceive(queueMessageOTA, &sMeshPacket, ((OTA_MESH_TIMEOUT) / portTICK_PERIOD_MS)) != pdTRUE) + { + ESP_LOGE(LOG_TAG, "Unable to receive OTA Messages from queue"); + err = ESP_FAIL; + } + + if((err == ESP_OK) && (bCheckMACEquality(sMeshPacket.meshSenderAddr.addr, pMeshNodeAddr->addr))) //if OTA_Version_Request + { + //packet from node received + switch (sMeshPacket.type) + { + case OTA_ACK: //increase index for next round + u32Index++; + bNodeIsResponding = true; + u32Index = QUEUE_MESSAGE_OTA_SIZE;//this will end the loop through all OTA messages + break; + case OTA_Abort: //abort this OTA process + bAbort = true; + bNodeIsResponding = true; + break; + default: + //receives wrong OTA message type from node --> back to queue + //vAddOtaMessageToQueue(&sMeshPacket); + break; + } + } + else if (err == ESP_OK) + { + //received from wrong node --> back to queue + vAddOtaMessageToQueue(&sMeshPacket); + } + /* + } + else + { + // OTA Message queue is empty --> wait some time + ESP_LOGI(LOG_TAG, "OTA-TX: ota message queue empty --> wait"); + vTaskDelay( (OTA_MESH_TIMEOUT) / portTICK_PERIOD_MS); + } + */ + + }//end OTA message loop + + if(bNodeIsResponding == false) + { + //no abort was called but node didn’t responded + ESP_LOGE(LOG_TAG, "OTA-TX: no abort was called but node didn’t responded --> error"); + bAbort = true; + err = ESP_FAIL; //this OTA process failed with error + } + u32SegmentCounter++; + }//end of partition segment loop + vClearOtaMessageQueue(pMeshNodeAddr); + return err; +} + +esp_err_t errOTAMeshReceive(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr) +{ + esp_err_t err = ESP_OK; + MESH_PACKET_t sMeshPacket; //packet for sending and receiving + bool bComplete = false; //complete the OTA process + bool bAbort = false; //abort the OTA process + bool bNodeIsResponding = false; //remote node is still active + uint32_t u32OTABytesWritten = 0U; //counter unsed for progress log + static esp_ota_handle_t otaHandle; //OTA process handle + *pbNewOTAImage = false; + uint32_t u32SegmentCounter = 0U; + + ERROR_CHECK(esp_ota_begin(pOTAPartition, OTA_SIZE_UNKNOWN, &otaHandle)); //start ota update process + + //partition segement loop through partition to read in segmensts until end or error or abort called + while((bComplete == false) && (err == ESP_OK) && (bAbort == false) && (u32OTABytesWritten <= pOTAPartition->size)) + { + bNodeIsResponding = false; //reset to default + + // loop through all OTA messages or until abort is called + for (uint32_t u32Index = 0; ((u32Index < QUEUE_MESSAGE_OTA_SIZE) && (bAbort == false)); u32Index++) //loop through all OTA messages + { + //if(uxQueueSpacesAvailable(queueMessageOTA) < QUEUE_MESSAGE_OTA_SIZE) + // { + //queue not empty + if (xQueueReceive(queueMessageOTA, &sMeshPacket, ((OTA_MESH_TIMEOUT) / portTICK_PERIOD_MS)) != pdTRUE) + { + ESP_LOGE(LOG_TAG, "Unable to receive OTA Messages from queue"); + err = ESP_FAIL; + } + + if((err == ESP_OK) && (bCheckMACEquality(sMeshPacket.meshSenderAddr.addr, pMeshNodeAddr->addr))) //if OTA_Version_Request + { + //packet from node received + switch (sMeshPacket.type) + { + case OTA_Complete: //signal end of this OTA process, fall through because same behavior as OTA_Data + bComplete = true; + ESP_LOGI(LOG_TAG, "OTA-RX: rec Complete --> last segment"); + //fall through + case OTA_Data: //data segement received + bNodeIsResponding = true; + ERROR_CHECK(esp_ota_write(otaHandle, sMeshPacket.au8Payload, OTA_MESH_SEGMENT_SIZE)); + u32OTABytesWritten = ((u32SegmentCounter+1) * OTA_MESH_SEGMENT_SIZE); + vPrintOTAProgress(&(pOTAPartition->size), &u32OTABytesWritten, Receiver); + u32Index = QUEUE_MESSAGE_OTA_SIZE; //this will end the loop through all OTA messages + break; + case OTA_Abort: //abort this OTA process + bAbort = true; + bNodeIsResponding = true; + ESP_LOGI(LOG_TAG, "OTA-RX: rec Abort"); + //this will end the loop through all OTA messages + break; + default: + //receives wrong OTA message type from node --> back to queue + //vAddOtaMessageToQueue(&sMeshPacket); + break; + } + } + else if (err == ESP_OK) + { + //received from wrong node --> back to queue + vAddOtaMessageToQueue(&sMeshPacket); + } + + /* } + else + { + ESP_LOGI(LOG_TAG, "OTA-RX: ota message queue empty --> wait"); + // OTA Message queue is empty --> wait some time + vTaskDelay( (OTA_MESH_TIMEOUT) / portTICK_PERIOD_MS); + } + */ + + }//end of OTA message loop + + if(bNodeIsResponding == false) + { + //no abort was called but node didn’t responded --> error + ESP_LOGI(LOG_TAG, "OTA-RX: no abort was called but node didn’t responded --> error"); + bAbort = true; //this will stop the partition segement loop + err = ESP_FAIL; //this OTA process failed with error + } + else + { + //node has responded with OTA_DATA or OTA_Complete or OTA_ABORT + if(err == ESP_OK) + { + + if(bAbort == false) + { + //no error while ota write --> send OTA_ACK packet + //ESP_LOGI(LOG_TAG, "OTA-RX: no error while ota write --> send OTA_ACK packet"); + sMeshPacket.type = OTA_ACK; + err = errSendMeshPacket(pMeshNodeAddr, &sMeshPacket); + } + } + else + { + // error while read --> send OTA_ABORT and abort this OTA process + sMeshPacket.type = OTA_Abort; + bAbort = true; + ESP_LOGI(LOG_TAG, "OTA-RX: abort --> send ABORT"); + errSendMeshPacket(pMeshNodeAddr, &sMeshPacket); + } + } + u32SegmentCounter++; + }//end of partition segement loop + + if(bComplete == true) + { + //all OTA segments received --> validate + ESP_LOGI(LOG_TAG, "OTA-RX: validate image "); + ERROR_CHECK(esp_ota_end(otaHandle)); + ERROR_CHECK(esp_ota_set_boot_partition(pOTAPartition)); + if(err == ESP_OK) + { + //successfully updated OTA partition + *pbNewOTAImage = true; + } + } + else + { + //not all OTA segments received --> abort this OTA process + ERROR_CHECK(esp_ota_abort(otaHandle)); + } + vClearOtaMessageQueue(pMeshNodeAddr); + return err; +} + +esp_err_t errOTAHTTPS(bool* pbNewOTAImage) +{ + esp_err_t err = ESP_OK; + char u8OTABuffer[OTA_HTTPS_SEGMENT_SIZE]; //store image segment from server before ota write + uint32_t u32BufferLenght = OTA_HTTPS_SEGMENT_SIZE; //size of buffer + uint32_t u32BytesRead = 0; //number of bytes that are read from server, <= u32BufferLenght + char pcRemoteVersionNumber[12]; //string for version number in server image + const esp_partition_t* pBootPartition; //pointer to boot partition (that will booted after reset) + static esp_ota_handle_t otaHandle; //OTA process handle + uint32_t u32StartOffset = 0U; //start offset for image (exclude the http response data) + esp_app_desc_t bootPartitionDesc; //Metadate from boot partition + uint32_t u32OTABytesWritten = 0U; //counter unsed for progress log + + ERROR_CHECK(errHTTPSClientRetrieveData(u8OTABuffer, &u32BufferLenght, &u32BytesRead)); //read first bytes if image, including the version + + ERROR_CHECK(errExtractVersionNumber(u8OTABuffer, &u32BytesRead, pcRemoteVersionNumber)); //extract version numbers + + if(err == ESP_OK) //check if version number is found + { + xSemaphoreTake(bsOTAProcess, portMAX_DELAY); //wait for binary semaphore that allows to start the OTA process + + pBootPartition = esp_ota_get_boot_partition(); //get boot partition (that will booted after reset), not the running partition + ERROR_CHECK(esp_ota_get_partition_description(pBootPartition, &bootPartitionDesc)); //get metadata of partition + + if(bNewerVersion((bootPartitionDesc).version, pcRemoteVersionNumber)) //compare local and remote version + { + // server image is newer --> OTA update required + ESP_LOGI(LOG_TAG, "Server: image is newer --> OTA update required"); + + ERROR_CHECK(errFindImageStart(u8OTABuffer, &u32BufferLenght, &u32StartOffset)); //get image start offset + + ERROR_CHECK(esp_ota_begin(pOTAPartition, OTA_SIZE_UNKNOWN, &otaHandle)); //start ota update process + if(err == ESP_OK) + { + //image download and ota partition write + ESP_LOGI(LOG_TAG, "start OTA download via HTTPS"); + do + { + vPrintOTAProgress(&(pOTAPartition->size), &u32OTABytesWritten, Receiver); + ERROR_CHECK(esp_ota_write(otaHandle, (const void*) u8OTABuffer+u32StartOffset, (u32BytesRead-u32StartOffset))); + + if(err == ESP_OK) + { + //write was succsesfull + u32StartOffset = 0U; //reset the offset for next download + ERROR_CHECK(errHTTPSClientRetrieveData(u8OTABuffer, &u32BufferLenght, &u32BytesRead)); //download next data segment + u32OTABytesWritten = u32OTABytesWritten + u32BytesRead; //update counter + } + } + while ((u32BytesRead > 0) && (err == ESP_OK) && (u32OTABytesWritten <= pOTAPartition->size)); //loop until error or complete image downloaded + } + + if(err == ESP_OK) + { + //no error occurred --> finish ota update process + ERROR_CHECK(esp_ota_end(otaHandle)); //finish process + ERROR_CHECK(esp_ota_set_boot_partition(pOTAPartition)); //set new image as boot + if(err == ESP_OK) + { + *pbNewOTAImage = true; //image validated + } + } + else + { + //error occurred --> abort ota update process + ESP_LOGE(LOG_TAG, "abort ota process due to error 0x%x -> %s", err, esp_err_to_name(err)); + ERROR_CHECK(esp_ota_abort(otaHandle)); + *pbNewOTAImage = false; //ota update failed + } + } + else + { + ESP_LOGI(LOG_TAG, "server image is NOT newer --> OTA update NOT required"); + } + xSemaphoreGive(bsOTAProcess); //free binary semaphore, this allows other tasks to start the OTA process + } //end version number extracted + return err; +} \ No newline at end of file diff --git a/components/mesh_ota/Mesh_OTA_Util.c b/components/mesh_ota/Mesh_OTA_Util.c new file mode 100644 index 0000000..7a955a3 --- /dev/null +++ b/components/mesh_ota/Mesh_OTA_Util.c @@ -0,0 +1,314 @@ +#include "Mesh_OTA_Util.h" +#include "Mesh_OTA_Globals.h" + +static const char *LOG_TAG = "mesh_ota"; + +void vAddNodeToPossibleUpdatableQueue(uint8_t* pu8MAC) +{ + //send payload to node queues + mesh_addr_t addrNode; + memcpy(&addrNode.addr, (uint8_t *)pu8MAC, 6); //copy MAC + + if (xQueueSend(queueNodes, &addrNode, portMAX_DELAY) != pdPASS) + { + ESP_LOGE(LOG_TAG, "Unable to push node into node queue"); + } + else + { + ESP_LOGI(LOG_TAG, "added node \"%x:%x:%x:%x:%x:%x\" to possible updatable queue", addrNode.addr[0], addrNode.addr[1], addrNode.addr[2], addrNode.addr[3], addrNode.addr[4], addrNode.addr[5]); + } +} + +void vAddOtaMessageToQueue(MESH_PACKET_t* puMeshPacket) +{ + //send ota packet to packet queue + if (xQueueSend(queueMessageOTA, puMeshPacket, portMAX_DELAY) != pdPASS) + { + ESP_LOGE(LOG_TAG, "Unable to push ota packet into packet queue"); + } + else + { + switch (puMeshPacket->type) + { + case OTA_Abort: + ESP_LOGI(LOG_TAG, "added ota message to queue: OTA_Abort from 0x%x", puMeshPacket->meshSenderAddr.addr[5]); + break; + case OTA_Version_Request: + ESP_LOGI(LOG_TAG, "added ota message to queue: OTA_Version_Request from 0x%x", puMeshPacket->meshSenderAddr.addr[5]); + break; + + case OTA_Version_Response: + ESP_LOGI(LOG_TAG, "added ota message to queue: OTA_Version Response from 0x%x", puMeshPacket->meshSenderAddr.addr[5]); + break; + default: + break; + } + } +} + +void vChangeStateOfServerWorker(bool bState) //allow access via function ptn to networl_handler +{ + static bool bLastState = false; + + if(bState != bLastState) //change only if necessary + { + ESP_LOGI(LOG_TAG, "server worker change handler"); + + if(bState == true) + { + if (xSemaphoreGive(bsStartStopServerWorker) != pdTRUE) + { + ESP_LOGE(LOG_TAG, "Unable to give mutex to activate the server worker"); + } + } + else + { + if (xSemaphoreTake(bsStartStopServerWorker,( TickType_t ) 10 ) != pdTRUE) + { + ESP_LOGE(LOG_TAG, "Unable to obtain mutex to deactivate the server worker"); + } + } + bLastState = bState; + } +} + +bool bNewerVersion(const char* pu8Local, const char* pu8Remote) +{ + /* + * Return true if remote version is newer (higher) than local version + */ + char u8LocalTmp[12]; //local version + char u8RemoteTmp[12]; //remote version + char* pu8saveptrLocal; //context for strok_r + char* pu8saveptrRemote; //context for strok_r + bool bReturn = false; //flag to stop loop + uint8_t u8Index = 0; //numbers counter in version string + + strncpy(u8LocalTmp, pu8Local, 12); //copy in tmp + strncpy(u8RemoteTmp, pu8Remote, 12); //copy in tmp + + char* pu8TokenLocal = strtok_r(u8LocalTmp, ".", &pu8saveptrLocal); //split tokens + char* pu8TokenRemote = strtok_r(u8RemoteTmp, ".", &pu8saveptrRemote); //split tokens + + while( (u8Index <= 2) && (bReturn == false)) //loop through tokens + { + u8Index++; + if(atoi(pu8TokenLocal) < atoi(pu8TokenRemote)) + { + bReturn = true; //version number difference --> stop loop + } + pu8TokenLocal = strtok_r(NULL, ".", &pu8saveptrLocal); //split tokens + pu8TokenRemote = strtok_r(NULL, ".", &pu8saveptrRemote); //split tokens + } + return bReturn; +} + +esp_err_t errFindImageStart(const char* pu8Data, uint32_t* pu32DataLenght, uint32_t* pu32StartOffset) +{ + /* + Offset value + 0 = 0xE9 (first byte in image --> magic byte) + 48 = first digit of version number + */ + + esp_err_t errReturn = ESP_OK; + bool bImageStartOffsetFound = false; + uint32_t u32DataIndex = 0; + uint32_t u32FirstDotOffset = 0; + uint32_t u32SecondDotOffset = 0; + uint8_t u8FirstDotIndex = 0; + uint8_t u8SecondDotIndex = 0; + + *pu32StartOffset = 0U; //reset offset to zero + + while((u32DataIndex < *pu32DataLenght) && (bImageStartOffsetFound == false)) + { + //search for magic byte + if(pu8Data[u32DataIndex] == 0xe9) + { + //magic byte found + while ((u8FirstDotIndex < 3) && (u32FirstDotOffset == 0)) + { + //search first dot in version number + if((u32DataIndex+49+u8FirstDotIndex) < *pu32DataLenght) + { + if((pu8Data[(u32DataIndex+49+u8FirstDotIndex)] == 0x2e)) + { + //first dot found + u32FirstDotOffset = (u32DataIndex+49+u8FirstDotIndex); + } + } + u8FirstDotIndex++; + } + + while ((u8SecondDotIndex < 3) && (u32SecondDotOffset == 0) && (u32FirstDotOffset != 0)) + { + //search first dot in version number + if((u32FirstDotOffset+(u8SecondDotIndex+2)) < *pu32DataLenght) + { + if((pu8Data[(u32FirstDotOffset+(u8SecondDotIndex+2))] == 0x2e)) + { + //second dot found + u32SecondDotOffset = (u32FirstDotOffset+(u8SecondDotIndex+2)); + } + } + u8SecondDotIndex++; + } + + if((u32FirstDotOffset != 0) && (u32SecondDotOffset != 0)) + { + //image start found based on magic byte and version number systax + *pu32StartOffset = u32DataIndex; //store image start offset + bImageStartOffsetFound = true; + } + else + { + // this is propably not the magic byte --> reset + u32FirstDotOffset = 0; + u32SecondDotOffset = 0; + u8FirstDotIndex = 0; + u8SecondDotIndex = 0; + } + } + u32DataIndex++; + } + + if(bImageStartOffsetFound == false) + { + errReturn = ESP_ERR_NOT_FOUND; + } + + return errReturn; +} + +esp_err_t errExtractVersionNumber(const char* pu8Data, uint32_t* pu32DataLenght, char* pc8RemoteVersionNumber) +{ + uint32_t u32StartOffset; + esp_err_t err = ESP_OK; + + strcpy(pc8RemoteVersionNumber, "999.999.999"); //init value + err = errFindImageStart(pu8Data, pu32DataLenght, &u32StartOffset); //get image start offset + + if(err == ESP_OK) + { + //image found + strncpy(pc8RemoteVersionNumber, pu8Data+(u32StartOffset+48), 11); //copy version number + pc8RemoteVersionNumber[12] = '\0'; + } + return err; +} + +void vPrintOTAProgress(const uint32_t* const pu32TotalImageSize, const uint32_t* const pu32BytesWritten, OTA_MESH_ROLE_t eRole) +{ + uint32_t u32Percentage = 0U; + static uint32_t u32LastPercentage = 0U; + + if((*pu32BytesWritten) >= (*pu32TotalImageSize)) + { + u32Percentage = 100; + } + else + { + u32Percentage = (uint32_t) (((float) (*pu32BytesWritten)/(float) (*pu32TotalImageSize)) * 100.0); + } + + if((u32Percentage-u32LastPercentage) >= OTA_PROGRESS_LOG_INTERVAL) + { + if(eRole == Transmitter) + { + ESP_LOGI(LOG_TAG, "Transmitting OTA update: %i %%", u32Percentage); + } + + if(eRole == Receiver) + { + ESP_LOGI(LOG_TAG, "Receiving OTA update: %i %%", u32Percentage); + } + + + + u32LastPercentage = u32Percentage; + } +} + +void vAddAllNeighboursToQueue(void) +{ + esp_err_t err = ESP_OK; + + mesh_addr_t addrParent; //addr of parent node + mesh_addr_t childrenAddr[CONFIG_MESH_ROUTE_TABLE_SIZE]; //array of children attached to this node + uint16_t u16ChildrenSize = 0U; //number of children attached to this node + + err = errGetParentNode(&addrParent); + + if(err == ESP_OK) + { + vAddNodeToPossibleUpdatableQueue(addrParent.addr); + ESP_LOGI(LOG_TAG, "added parent"); + } + + err = ESP_OK; //reset error code + + ERROR_CHECK(errGetChildren(childrenAddr, &u16ChildrenSize)); //get all children + + for (uint16_t u16Index = 0; ((u16Index < u16ChildrenSize) && (err == ESP_OK)); u16Index++) + { + vAddNodeToPossibleUpdatableQueue(childrenAddr[u16Index].addr); + ESP_LOGI(LOG_TAG, "added child"); + } +} + +esp_err_t errSendOTAVersionResponse(mesh_addr_t* pMeshReceiverAddr) +{ + esp_err_t err = ESP_OK; + MESH_PACKET_t packet; + packet.type = OTA_Version_Response; + + const esp_partition_t* pBootPartition; //pointer to boot partition (that will booted after reset) + esp_app_desc_t bootPartitionDesc; //Metadata from boot partition + + pBootPartition = esp_ota_get_boot_partition(); //get boot partition (that will booted after reset), not the running partition + ERROR_CHECK(esp_ota_get_partition_description(pBootPartition, &bootPartitionDesc)); //get metadate of partition + memcpy(&packet.au8Payload, &bootPartitionDesc.version, 12); //copy local version to OTA_Version_Response packet + + ESP_LOGI(LOG_TAG, "Send OTA_Version_Response to 0x%x", pMeshReceiverAddr->addr[5]); + + err = errSendMeshPacket(pMeshReceiverAddr, &packet); + return err; +} + +void vClearOtaMessageQueue(mesh_addr_t* pMeshNodeAddr) +{ + MESH_PACKET_t sMeshPacket; //packet for sending and receiving + for (uint32_t u32Index = 0; (u32Index < QUEUE_MESSAGE_OTA_SIZE); u32Index++) //loop through all OTA messages + { + if (xQueueReceive(queueMessageOTA, &sMeshPacket, 0) == pdTRUE) + { + if(!(bCheckMACEquality(sMeshPacket.meshSenderAddr.addr, pMeshNodeAddr->addr))) + { + //received OTA message is NOT from pMeshNodeAddr --> keep it in queue + vAddOtaMessageToQueue(&sMeshPacket); + } + else + { + ESP_LOGI(LOG_TAG, "Removed type %i from node 0x%x", sMeshPacket.type, pMeshNodeAddr->addr[5]); + } + } + }//end OTA message loop +} + +esp_err_t errSendOTAVersionRequest(mesh_addr_t* pMeshReceiverAddr) +{ + esp_err_t err = ESP_OK; + MESH_PACKET_t packet; + packet.type = OTA_Version_Request; + + const esp_partition_t* pBootPartition; //pointer to boot partition (that will booted after reset) + esp_app_desc_t bootPartitionDesc; //Metadata from boot partition + + pBootPartition = esp_ota_get_boot_partition(); //get boot partition (that will booted after reset), not the running partition + ERROR_CHECK(esp_ota_get_partition_description(pBootPartition, &bootPartitionDesc)); //get metadate of partition + memcpy(&packet.au8Payload, &bootPartitionDesc.version, 12); //copy local version to OTA_Version_Request packet + err = errSendMeshPacket(pMeshReceiverAddr, &packet); + return err; +} + diff --git a/components/mesh_ota/include/HTTPS_client.h b/components/mesh_ota/include/HTTPS_Client.h similarity index 91% rename from components/mesh_ota/include/HTTPS_client.h rename to components/mesh_ota/include/HTTPS_Client.h index 0150363..91baafd 100644 --- a/components/mesh_ota/include/HTTPS_client.h +++ b/components/mesh_ota/include/HTTPS_Client.h @@ -5,19 +5,10 @@ #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" -#include "esp_wifi.h" #include "esp_event.h" #include "esp_log.h" #include "esp_system.h" -#include "nvs_flash.h" #include "esp_netif.h" - -#include "lwip/err.h" -#include "lwip/sockets.h" -#include "lwip/sys.h" -#include "lwip/netdb.h" -#include "lwip/dns.h" - #include "mbedtls/platform.h" #include "mbedtls/net_sockets.h" #include "mbedtls/esp_debug.h" diff --git a/components/mesh_ota/include/Mesh_network.h b/components/mesh_ota/include/Mesh_Network.h similarity index 78% rename from components/mesh_ota/include/Mesh_network.h rename to components/mesh_ota/include/Mesh_Network.h index f2c0421..e448e36 100644 --- a/components/mesh_ota/include/Mesh_network.h +++ b/components/mesh_ota/include/Mesh_Network.h @@ -8,7 +8,7 @@ #include "esp_log.h" #include "esp_mesh.h" #include "esp_mesh_internal.h" -#include +#include "nvs_flash.h" #ifndef CONFIG_MESH_MESSAGE_SIZE #define CONFIG_MESH_MESSAGE_SIZE 1500 @@ -67,6 +67,15 @@ struct meshPacket typedef struct meshPacket MESH_PACKET_t; +#define ERROR_CHECK(x) if (err == ESP_OK) \ + { \ + err = (x); \ + if (err != ESP_OK) \ + { \ + ESP_LOGE(LOG_TAG, "%s failed with error: 0x%x -> %s", #x, err, esp_err_to_name(err)); \ + } \ + } \ + extern bool bIsMeshConnected; extern int32_t i32MeshLayer; extern mesh_addr_t meshParentAddr; diff --git a/components/mesh_ota/include/Mesh_OTA.h b/components/mesh_ota/include/Mesh_OTA.h index 075c8f5..24a2e41 100644 --- a/components/mesh_ota/include/Mesh_OTA.h +++ b/components/mesh_ota/include/Mesh_OTA.h @@ -1,20 +1,14 @@ #ifndef H_MESH_OTA #define H_MESH_OTA -#include -#include "esp_wifi.h" #include "esp_system.h" #include "esp_event.h" #include "esp_log.h" -#include "esp_mesh.h" -#include "esp_mesh_internal.h" -#include "nvs_flash.h" -#include "driver/gpio.h" #include "esp_ota_ops.h" #include "esp_partition.h" -#include "Mesh_network.h" -#include "HTTPS_client.h" +#include "Mesh_Network.h" +#include "HTTPS_Client.h" #define ERASE_NVS //erase non volatile storage if full #define QUEUE_NODES_SIZE 10 @@ -34,42 +28,15 @@ } \ } \ -enum otaMeshRole -{ - Transmitter, - Receiver -}; - -typedef enum otaMeshRole OTA_MESH_ROLE_t; - esp_err_t errMeshOTAInitialize(); -esp_err_t errOTAHTTPS(bool* pbNewOTAImage); + esp_err_t errOTAMeshSlave(bool* pbNewOTAImage); esp_err_t errOTAMeshMaster(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr); -esp_err_t errOTAMeshTransmit(mesh_addr_t* pMeshNodeAddr); -esp_err_t errOTAMeshReceive(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr); -//helper functions -bool bNewerVersion(const char* pu8Local, const char* pu8Remote); -esp_err_t errExtractVersionNumber(const char* pu8Data, uint32_t* pu32DataLenght, char* pc8RemoteVersionNumber); -esp_err_t errFindImageStart(const char* pu8Data, uint32_t* pu32DataLenght, uint32_t* pu32StartOffset); -void vPrintOTAProgress(const uint32_t* const pu32TotalImageSize, const uint32_t* const pu32BytesWritten, OTA_MESH_ROLE_t eRole); -void vAddAllNeighboursToQueue(void); -esp_err_t errSendOTAVersionResponse(mesh_addr_t* meshReceiverAddr); -esp_err_t errSendOTAVersionRequest(mesh_addr_t* meshReceiverAddr); -void vClearOtaMessageQueue(mesh_addr_t* pMeshNodeAddr); - -//Handler -void vAddNodeToPossibleUpdatableQueue(uint8_t* pu8MAC); -void vAddOtaMessageToQueue(MESH_PACKET_t* puMeshPacket); -void vChangeStateOfServerWorker(bool state); - //Tasks void vTaskServerWorker(void *arg); void vTaskOTAWorker(void *arg); - - #endif /* H_MESH_OTA */ diff --git a/components/mesh_ota/include/Mesh_OTA_Access.h b/components/mesh_ota/include/Mesh_OTA_Access.h new file mode 100644 index 0000000..2336d1a --- /dev/null +++ b/components/mesh_ota/include/Mesh_OTA_Access.h @@ -0,0 +1,28 @@ +#ifndef H_MESH_OTA_ACCESS +#define H_MESH_OTA_ACCESS + +#include "esp_system.h" +#include "esp_event.h" +#include "esp_log.h" +#include "nvs_flash.h" +#include "esp_ota_ops.h" +#include "esp_partition.h" + +#include "Mesh_Network.h" +#include "HTTPS_Client.h" + +#define ERROR_CHECK(x) if (err == ESP_OK) \ + { \ + err = (x); \ + if (err != ESP_OK) \ + { \ + ESP_LOGE(LOG_TAG, "%s failed with error: 0x%x -> %s", #x, err, esp_err_to_name(err)); \ + } \ + } \ + +esp_err_t errOTAMeshTransmit(mesh_addr_t* pMeshNodeAddr); +esp_err_t errOTAMeshReceive(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr); + +esp_err_t errOTAHTTPS(bool* pbNewOTAImage); + +#endif /* H_MESH_OTA_ACCESS */ diff --git a/components/mesh_ota/include/Mesh_OTA_Globals.h b/components/mesh_ota/include/Mesh_OTA_Globals.h new file mode 100644 index 0000000..63f67e3 --- /dev/null +++ b/components/mesh_ota/include/Mesh_OTA_Globals.h @@ -0,0 +1,19 @@ +#ifndef H_MESH_OTA_GLOBALS +#define H_MESH_OTA_GLOBALS + +#include "esp_system.h" +#include "esp_partition.h" + +#include "Mesh_Network.h" +#include "HTTPS_Client.h" + +extern xQueueHandle queueNodes; //nodes that should be checked for ota update (contains children and parent) +extern xQueueHandle queueMessageOTA; //mesh ota controll messages like "OTA_Version_Response" "OTA_ACK" + +extern SemaphoreHandle_t bsStartStopServerWorker; //binary semaphore +extern SemaphoreHandle_t bsOTAProcess; //binary semaphore + +extern const esp_partition_t* pOTAPartition; //pointer to ota partition +extern bool bWantReboot; //flag to signal pending reboot + +#endif /* H_MESH_OTA_GLOBALS */ diff --git a/components/mesh_ota/include/Mesh_OTA_Util.h b/components/mesh_ota/include/Mesh_OTA_Util.h new file mode 100644 index 0000000..cbcafc8 --- /dev/null +++ b/components/mesh_ota/include/Mesh_OTA_Util.h @@ -0,0 +1,35 @@ +#ifndef H_MESH_OTA_UTIL +#define H_MESH_OTA_UTIL + +#include "esp_system.h" +#include "esp_event.h" +#include "esp_log.h" + +#include "Mesh_Network.h" +#include "HTTPS_Client.h" +#include "Mesh_OTA.h" + +enum otaMeshRole +{ + Transmitter, + Receiver +}; + +typedef enum otaMeshRole OTA_MESH_ROLE_t; + +//helper functions +bool bNewerVersion(const char* pu8Local, const char* pu8Remote); +esp_err_t errExtractVersionNumber(const char* pu8Data, uint32_t* pu32DataLenght, char* pc8RemoteVersionNumber); +esp_err_t errFindImageStart(const char* pu8Data, uint32_t* pu32DataLenght, uint32_t* pu32StartOffset); +void vPrintOTAProgress(const uint32_t* const pu32TotalImageSize, const uint32_t* const pu32BytesWritten, OTA_MESH_ROLE_t eRole); +void vAddAllNeighboursToQueue(void); +esp_err_t errSendOTAVersionResponse(mesh_addr_t* meshReceiverAddr); +esp_err_t errSendOTAVersionRequest(mesh_addr_t* meshReceiverAddr); +void vClearOtaMessageQueue(mesh_addr_t* pMeshNodeAddr); + +//Handler +void vAddNodeToPossibleUpdatableQueue(uint8_t* pu8MAC); +void vAddOtaMessageToQueue(MESH_PACKET_t* puMeshPacket); +void vChangeStateOfServerWorker(bool state); + +#endif /* H_MESH_OTA_UTIL */ diff --git a/main/Blinky_LED.c b/main/Blinky_LED.c index 384d4bb..6317f82 100644 --- a/main/Blinky_LED.c +++ b/main/Blinky_LED.c @@ -183,4 +183,4 @@ void vTaskReceiveData(void *arg) } vTaskDelay(200 / portTICK_PERIOD_MS); } -} \ No newline at end of file +} diff --git a/main/Blinky_LED.h b/main/Blinky_LED.h index a5ec54e..a807322 100644 --- a/main/Blinky_LED.h +++ b/main/Blinky_LED.h @@ -11,6 +11,7 @@ #include "Mesh_OTA.h" + #define GPIO_BOOT_BTN 0 //GPIO0 (Boot BTN) #define GPIO_LED 2 //GPIO2 (internal blue LED in DevKit V1.0) diff --git a/main/Main.c b/main/Main.c index 50164a3..eabab6c 100644 --- a/main/Main.c +++ b/main/Main.c @@ -1,15 +1,9 @@ - -#include -#include "esp_wifi.h" +#include +#include "sdkconfig.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" #include "esp_system.h" -#include "esp_event.h" -#include "esp_log.h" -#include "esp_mesh.h" -#include "esp_mesh_internal.h" -#include "nvs_flash.h" -#include "driver/gpio.h" -#include "esp_ota_ops.h" -#include "esp_partition.h" +#include "esp_spi_flash.h" #include "Mesh_OTA.h" #include "Blinky_LED.h" @@ -19,7 +13,7 @@ static const char *LOG_TAG = "esp_main"; void app_main(void) { esp_err_t err = ESP_OK; - ESP_LOGI(LOG_TAG, "hardcoded: 0.0.1"); + ESP_LOGI(LOG_TAG, "hardcoded version: 0.0.1"); ESP_LOGI(LOG_TAG, "start mesh network"); err = errMeshNetworkInitialize(); From 7f0e82fd2990900425f07410ff9799c33d64c805 Mon Sep 17 00:00:00 2001 From: localhorst Date: Wed, 20 Jan 2021 21:40:51 +0100 Subject: [PATCH 16/21] renamed functions in modules --- components/mesh_ota/HTTPS_Client.c | 1 + components/mesh_ota/Mesh_Network.c | 265 +++++----- components/mesh_ota/Mesh_Network_Handler.c | 6 +- components/mesh_ota/Mesh_OTA.c | 61 ++- components/mesh_ota/Mesh_OTA_Globals.c | 5 + .../mesh_ota/Mesh_OTA_Partition_Access.c | 493 +++++++++--------- components/mesh_ota/Mesh_OTA_Util.c | 241 +++++---- components/mesh_ota/include/Mesh_Network.h | 32 +- components/mesh_ota/include/Mesh_OTA.h | 15 +- ...A_Access.h => Mesh_OTA_Partition_Access.h} | 13 +- components/mesh_ota/include/Mesh_OTA_Util.h | 22 +- components/mesh_ota/test/test_mesh_ota.c | 40 +- main/Blinky_LED.c | 16 +- 13 files changed, 614 insertions(+), 596 deletions(-) rename components/mesh_ota/include/{Mesh_OTA_Access.h => Mesh_OTA_Partition_Access.h} (74%) diff --git a/components/mesh_ota/HTTPS_Client.c b/components/mesh_ota/HTTPS_Client.c index 41d847b..ca55e6d 100644 --- a/components/mesh_ota/HTTPS_Client.c +++ b/components/mesh_ota/HTTPS_Client.c @@ -2,6 +2,7 @@ static const char *TAG = "https_client"; +//HTTP GET data static const char *REQUEST = "GET " CONFIG_OTA_HTTPS_URL " HTTP/1.1\r\n" "Host: "CONFIG_OTA_HTTPS_SERVER_COMMON_NAME"\r\n" "User-Agent: esp-idf/1.0 esp32\r\n" diff --git a/components/mesh_ota/Mesh_Network.c b/components/mesh_ota/Mesh_Network.c index f04fc46..0e6a3f4 100644 --- a/components/mesh_ota/Mesh_Network.c +++ b/components/mesh_ota/Mesh_Network.c @@ -2,13 +2,29 @@ #include "Mesh_Network.h" static const char *LOG_TAG = "mesh_network"; -static uint8_t tx_buf[CONFIG_MESH_MESSAGE_SIZE] = { 0, }; -static uint8_t rx_buf[CONFIG_MESH_MESSAGE_SIZE] = { 0, }; + + +//w: errMeshNetworkInitialize +//r: errMeshNetworkInitialize;vMeshNetworkGetOwnAddr;errMeshNetworkGetChildren uint8_t u8ownMAC[6]; + +//w: errMeshNetworkInitialize; vMeshNetworkMeshEventHandler +//r: vMeshNetworkMeshEventHandler esp_netif_t* netif_sta; + +//w: errMeshNetworkInitialize; vMeshNetworkMeshEventHandler +//r: errMeshNetworkInitialize; bool bIsMeshConnected; + +//w: errMeshNetworkInitialize; vMeshNetworkMeshEventHandler +//r: vMeshNetworkMeshEventHandler int32_t i32MeshLayer; + +//w: errMeshNetworkInitialize; vMeshNetworkMeshEventHandler +//r: vMeshNetworkMeshEventHandler mesh_addr_t meshParentAddr; + +//function pointer for callbacks void (*pAppRxHandle)(uint8_t*, uint8_t* ); void (*pOTAChildConnectHandle)(uint8_t* ); void (*pOTAMessageHandle)(MESH_PACKET_t* ); @@ -47,7 +63,7 @@ esp_err_t errMeshNetworkInitialize() ERROR_CHECK(esp_mesh_init()); //mesh initialization - ERROR_CHECK(esp_event_handler_register(MESH_EVENT, ESP_EVENT_ANY_ID, &vMeshEventHandler, NULL)); + ERROR_CHECK(esp_event_handler_register(MESH_EVENT, ESP_EVENT_ANY_ID, &vMeshNetworkMeshEventHandler, NULL)); //set mesh topology ERROR_CHECK(esp_mesh_set_topology(CONFIG_MESH_TOPOLOGY)); @@ -97,7 +113,7 @@ esp_err_t errMeshNetworkInitializeWiFi() esp_err_t err = ESP_OK; wifi_init_config_t config = WIFI_INIT_CONFIG_DEFAULT(); ERROR_CHECK(esp_wifi_init(&config)); - ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &vIPEventHandler, NULL)); + ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &vMeshNetworkIpEventHandler, NULL)); ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_FLASH)); ERROR_CHECK(esp_wifi_start()); return err; @@ -115,8 +131,88 @@ esp_err_t errMeshNetworkInitializeRouter(mesh_cfg_t* cfg) return err; } +esp_err_t errMeshNetworkSetChildConnectedHandle(void (*pChildConnectHandleTmp)(uint8_t * pu8Data)) +{ + pOTAChildConnectHandle = pChildConnectHandleTmp; + return ESP_OK; +} + +esp_err_t errMeshNetworkSetAppReceiveHandle(void (*pAppRxHandleTmp)(uint8_t * pu8Data, uint8_t* pu8Sender)) +{ + pAppRxHandle = pAppRxHandleTmp; //set handle from app as receive handle if an app packet is received + return ESP_OK; +} + +esp_err_t errMeshNetworkSetOTAMessageHandleHandle(void (*pOTAMessageHandleTmp)(MESH_PACKET_t* puMeshPacket)) +{ + pOTAMessageHandle = pOTAMessageHandleTmp; + return ESP_OK; +} + +esp_err_t errMeshNetworkSetChangeStateOfServerWorkerHandle(void (*pChangeStateOfServerWorkerHandleTmp)(bool bState)) +{ + pChangeStateOfServerWorkerHandle = pChangeStateOfServerWorkerHandleTmp; + return ESP_OK; +} + +esp_err_t errMeshNetworkSendMeshPacket(mesh_addr_t* pAddrDest, MESH_PACKET_t* pPacket) +{ + esp_err_t err; + mesh_data_t data; + uint8_t tx_buf[CONFIG_MESH_MESSAGE_SIZE] = { 0, }; + data.data = tx_buf; + data.size = sizeof(tx_buf); + data.proto = MESH_PROTO_BIN; + data.tos = MESH_TOS_P2P; + memcpy(tx_buf, (uint8_t *)pPacket, sizeof(MESH_PACKET_t)); + + err = esp_mesh_send(pAddrDest, &data, MESH_DATA_P2P, NULL, 0); + + return err; +} + +bool bMeshNetworkIsRootNode() +{ + return esp_mesh_is_root(); +} + +bool bMeshNetworkIsNodeNeighbour(mesh_addr_t* pNode) +{ + esp_err_t err = ESP_OK; + bool bReturn = false; + mesh_addr_t addrParent; //addr of parent node + mesh_addr_t childrenAddr[CONFIG_MESH_ROUTE_TABLE_SIZE]; //array of children attached to this node + uint16_t u16ChildrenSize = 0U; //number of children attached to this node + + err = errMeshNetworkGetParentNode(&addrParent); + + if(err == ESP_OK) + { + if(bMeshNetworkCheckMACEquality(pNode->addr, addrParent.addr) == true) + { + bReturn = true; //node was found + } + } + + if(bReturn == false) + { + err = ESP_OK; //reset error code + + ERROR_CHECK(errMeshNetworkGetChildren(childrenAddr, &u16ChildrenSize)); //get all children + + for (uint16_t u16Index = 0; ((u16Index < u16ChildrenSize) && (err == ESP_OK) && (bReturn == false)); u16Index++) + { + if(bMeshNetworkCheckMACEquality(pNode->addr, childrenAddr[u16Index].addr) == true) + { + bReturn = true; //node was found + } + } + } + return bReturn; +} + //returns true if MAC address is equal -bool bCheckMACEquality(uint8_t* pu8aMAC, uint8_t* pu8bMAC) +bool bMeshNetworkCheckMACEquality(uint8_t* pu8aMAC, uint8_t* pu8bMAC) { bool bRet = true; uint8_t index = 0; @@ -141,7 +237,27 @@ bool bCheckMACEquality(uint8_t* pu8aMAC, uint8_t* pu8bMAC) return bRet; } -esp_err_t errGetChildren(mesh_addr_t* pChildren, uint16_t* pu16ChildrenSize) +esp_err_t errMeshNetworkStartReceiveTask() +{ + esp_err_t err = ESP_OK; + BaseType_t xReturned; + + xReturned = xTaskCreate(vMeshNetworkTaskReceiveMeshData, "ReceiveMeshData", 7000, NULL, 5, NULL); + + if(xReturned != pdPASS) + { + err = ESP_FAIL; + } + return err; +} + +void vMeshNetworkGetOwnAddr(mesh_addr_t* pMeshOwnAddr) +{ + memcpy(pMeshOwnAddr->addr, u8ownMAC, 6); +} + + +esp_err_t errMeshNetworkGetChildren(mesh_addr_t* pChildren, uint16_t* pu16ChildrenSize) { esp_err_t err = ESP_OK; int route_table_size = 0; @@ -153,7 +269,7 @@ esp_err_t errGetChildren(mesh_addr_t* pChildren, uint16_t* pu16ChildrenSize) { for(uint16_t index = 0; index < esp_mesh_get_routing_table_size(); index++) { - if(! (bCheckMACEquality(u8ownMAC, route_table[index].addr)) ) + if(! (bMeshNetworkCheckMACEquality(u8ownMAC, route_table[index].addr)) ) { //child node //ESP_LOGI(LOG_TAG, "adding Node: \"0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\" ", route_table[index].addr[0], route_table[index].addr[1], route_table[index].addr[2], route_table[index].addr[3], route_table[index].addr[4], route_table[index].addr[5]); @@ -165,126 +281,12 @@ esp_err_t errGetChildren(mesh_addr_t* pChildren, uint16_t* pu16ChildrenSize) return err; } -esp_err_t errGetParentNode(mesh_addr_t* pMeshParentAddr) -{ - esp_err_t err = ESP_OK; - - if((bIsMeshConnected == false) || (esp_mesh_is_root())) - { - //this node is not connected or is the root --> this node has no parent - err = ESP_FAIL; - } - else - { - //node has parent - memcpy(pMeshParentAddr, &meshParentAddr, sizeof(mesh_addr_t)); - } - return err; -} - -void vGetOwnAddr(mesh_addr_t* pMeshOwnAddr) -{ - memcpy(pMeshOwnAddr->addr, u8ownMAC, 6); -} - -bool bIsRootNode() -{ - return esp_mesh_is_root(); -} - -bool bIsNodeNeighbour(mesh_addr_t* pNode) -{ - esp_err_t err = ESP_OK; - bool bReturn = false; - mesh_addr_t addrParent; //addr of parent node - mesh_addr_t childrenAddr[CONFIG_MESH_ROUTE_TABLE_SIZE]; //array of children attached to this node - uint16_t u16ChildrenSize = 0U; //number of children attached to this node - - err = errGetParentNode(&addrParent); - - if(err == ESP_OK) - { - if(bCheckMACEquality(pNode->addr, addrParent.addr) == true) - { - bReturn = true; //node was found - } - } - - if(bReturn == false) - { - err = ESP_OK; //reset error code - - ERROR_CHECK(errGetChildren(childrenAddr, &u16ChildrenSize)); //get all children - - for (uint16_t u16Index = 0; ((u16Index < u16ChildrenSize) && (err == ESP_OK) && (bReturn == false)); u16Index++) - { - if(bCheckMACEquality(pNode->addr, childrenAddr[u16Index].addr) == true) - { - bReturn = true; //node was found - } - } - } - return bReturn; -} - -esp_err_t errMeshNetworkSetAppReceiveHandle(void (*pAppRxHandleTmp)(uint8_t * pu8Data, uint8_t* pu8Sender)) -{ - pAppRxHandle = pAppRxHandleTmp; //set handle from app as receive handle if an app packet is received - return ESP_OK; -} - -esp_err_t errMeshNetworkSetChildConnectedHandle(void (*pChildConnectHandleTmp)(uint8_t * pu8Data)) -{ - pOTAChildConnectHandle = pChildConnectHandleTmp; - return ESP_OK; -} - -esp_err_t errMeshNetworkSetOTAMessageHandleHandle(void (*pOTAMessageHandleTmp)(MESH_PACKET_t* puMeshPacket)) -{ - pOTAMessageHandle = pOTAMessageHandleTmp; - return ESP_OK; -} - -esp_err_t errMeshNetworkSetChangeStateOfServerWorkerHandle(void (*pChangeStateOfServerWorkerHandleTmp)(bool bState)) -{ - pChangeStateOfServerWorkerHandle = pChangeStateOfServerWorkerHandleTmp; - return ESP_OK; -} - -esp_err_t errSendMeshPacket(mesh_addr_t* pAddrDest, MESH_PACKET_t* pPacket) -{ - esp_err_t err; - mesh_data_t data; - data.data = tx_buf; - data.size = sizeof(tx_buf); - data.proto = MESH_PROTO_BIN; - data.tos = MESH_TOS_P2P; - memcpy(tx_buf, (uint8_t *)pPacket, sizeof(MESH_PACKET_t)); - - err = esp_mesh_send(pAddrDest, &data, MESH_DATA_P2P, NULL, 0); - - return err; -} - -esp_err_t errStartReceiveTask() -{ - esp_err_t err = ESP_OK; - BaseType_t xReturned; - - xReturned = xTaskCreate(vTaskReceiveMeshData, "ReceiveMeshData", 7000, NULL, 5, NULL); - - if(xReturned != pdPASS) - { - err = ESP_FAIL; - } - return err; -} - -void vTaskReceiveMeshData(void *arg) +void vMeshNetworkTaskReceiveMeshData(void *arg) { esp_err_t err; mesh_addr_t from; mesh_data_t data; + uint8_t rx_buf[CONFIG_MESH_MESSAGE_SIZE] = { 0, }; int flag = 0; data.data = rx_buf; data.size = CONFIG_MESH_MESSAGE_SIZE; @@ -329,6 +331,23 @@ void vTaskReceiveMeshData(void *arg) } +esp_err_t errMeshNetworkGetParentNode(mesh_addr_t* pMeshParentAddr) +{ + esp_err_t err = ESP_OK; + + if((bIsMeshConnected == false) || (esp_mesh_is_root())) + { + //this node is not connected or is the root --> this node has no parent + err = ESP_FAIL; + } + else + { + //node has parent + memcpy(pMeshParentAddr, &meshParentAddr, sizeof(mesh_addr_t)); + } + return err; +} + diff --git a/components/mesh_ota/Mesh_Network_Handler.c b/components/mesh_ota/Mesh_Network_Handler.c index 791cd71..6fa0816 100644 --- a/components/mesh_ota/Mesh_Network_Handler.c +++ b/components/mesh_ota/Mesh_Network_Handler.c @@ -3,7 +3,7 @@ static const char *LOG_TAG = "mesh_network_handler"; -void vIPEventHandler(void *arg, esp_event_base_t event_base, int32_t i32EventID, void *vpEventData) +void vMeshNetworkIpEventHandler(void *arg, esp_event_base_t event_base, int32_t i32EventID, void *vpEventData) { ip_event_got_ip_t *event = (ip_event_got_ip_t *) vpEventData; ESP_LOGI(LOG_TAG, "IP:" IPSTR, IP2STR(&event->ip_info.ip)); @@ -13,7 +13,7 @@ void vIPEventHandler(void *arg, esp_event_base_t event_base, int32_t i32EventID, } } -void vMeshEventHandler(void *arg, esp_event_base_t event_base, int32_t i32EventID, void* vpEventData) +void vMeshNetworkMeshEventHandler(void *arg, esp_event_base_t event_base, int32_t i32EventID, void* vpEventData) { mesh_addr_t id = {0,}; static uint16_t last_layer = 0; @@ -95,7 +95,7 @@ if(esp_netif_dhcpc_start(netif_sta) == ESP_ERR_ESP_NETIF_DHCP_ALREADY_STARTED) / if(pChangeStateOfServerWorkerHandle){pChangeStateOfServerWorkerHandle(true);}// signal reconnect } } -errStartReceiveTask();//start receiving +errMeshNetworkStartReceiveTask();//start receiving } break; case MESH_EVENT_PARENT_DISCONNECTED: diff --git a/components/mesh_ota/Mesh_OTA.c b/components/mesh_ota/Mesh_OTA.c index 6292756..1e6db72 100644 --- a/components/mesh_ota/Mesh_OTA.c +++ b/components/mesh_ota/Mesh_OTA.c @@ -1,7 +1,7 @@ #include "Mesh_OTA.h" #include "Mesh_OTA_Util.h" #include "Mesh_OTA_Globals.h" -#include "Mesh_OTA_Access.h" +#include "Mesh_OTA_Partition_Access.h" static const char *LOG_TAG = "mesh_ota"; @@ -60,9 +60,9 @@ esp_err_t errMeshOTAInitialize() } } - ERROR_CHECK(errMeshNetworkSetChildConnectedHandle(vAddNodeToPossibleUpdatableQueue)); - ERROR_CHECK(errMeshNetworkSetOTAMessageHandleHandle(vAddOtaMessageToQueue)); - ERROR_CHECK(errMeshNetworkSetChangeStateOfServerWorkerHandle(vChangeStateOfServerWorker)); + ERROR_CHECK(errMeshNetworkSetChildConnectedHandle(vMeshOtaUtilAddNodeToPossibleUpdatableQueue)); + ERROR_CHECK(errMeshNetworkSetOTAMessageHandleHandle(vMeshOtaUtilAddOtaMessageToQueue)); + ERROR_CHECK(errMeshNetworkSetChangeStateOfServerWorkerHandle(vMeshOtaUtilChangeStateOfServerWorker)); if(err == ESP_OK) { @@ -77,7 +77,7 @@ esp_err_t errMeshOTAInitialize() if(err == ESP_OK) { - xReturned = xTaskCreate(vTaskServerWorker, "vTaskServerWorker", 8192, NULL, 5, NULL); + xReturned = xTaskCreate(vMeshOtaTaskServerWorker, "vMeshOtaTaskServerWorker", 8192, NULL, 5, NULL); if(xReturned != pdPASS) { ESP_LOGE(LOG_TAG, "Unable to create the server worker task"); @@ -88,7 +88,7 @@ esp_err_t errMeshOTAInitialize() if(err == ESP_OK) { - xReturned = xTaskCreate(vTaskOTAWorker, "vTaskOTAWorker", 8192, NULL, 5, NULL); + xReturned = xTaskCreate(vMeshOtaTaskOTAWorker, "vMeshOtaTaskOTAWorker", 8192, NULL, 5, NULL); if(xReturned != pdPASS) { ESP_LOGE(LOG_TAG, "Unable to create the OTA worker task"); @@ -99,7 +99,7 @@ esp_err_t errMeshOTAInitialize() return err; } -void vTaskServerWorker(void *arg) +void vMeshOtaTaskServerWorker(void *arg) { esp_err_t err; bool bNewOTAImage; //true if a new ota image was downloaded and validated @@ -126,7 +126,7 @@ void vTaskServerWorker(void *arg) ERROR_CHECK(errHTTPSClientValidateServer()); ERROR_CHECK(errHTTPSClientSendRequest()); - ERROR_CHECK(errOTAHTTPS(&bNewOTAImage)); + ERROR_CHECK(errMeshOtaPartitionAccessHttps(&bNewOTAImage)); errHTTPSClientReset(); if(bNewOTAImage == true) @@ -134,14 +134,14 @@ void vTaskServerWorker(void *arg) //set want reboot ESP_LOGI(LOG_TAG, "Updated successfully via HTTPS, set pending reboot"); bWantReboot = true; - vAddAllNeighboursToQueue(); //add all existing neighbours to queue (aparent will not be added because this node is the root) + vMeshOtaUtilAddAllNeighboursToQueue(); //add all existing neighbours to queue (aparent will not be added because this node is the root) } vTaskDelay( (SERVER_CHECK_INTERVAL*1000) / portTICK_PERIOD_MS); //sleep till next server checks } } } -void vTaskOTAWorker(void *arg) +void vMeshOtaTaskOTAWorker(void *arg) { esp_err_t err = ESP_OK; bool bNewOTAImage; //true if a new ota image was downloaded and validated @@ -164,7 +164,7 @@ void vTaskOTAWorker(void *arg) //esp_restart(); } - ERROR_CHECK(errOTAMeshSlave(&bNewOTAImage)); + ERROR_CHECK(errMeshOtaSlaveEndpoint(&bNewOTAImage)); } else { @@ -177,12 +177,12 @@ void vTaskOTAWorker(void *arg) err = ESP_FAIL; } - ERROR_CHECK(errOTAMeshMaster(&bNewOTAImage, &meshNodeAddr)); + ERROR_CHECK(errMeshOtaMasterEndpoint(&bNewOTAImage, &meshNodeAddr)); if (err != ESP_OK) { //OTA process faild --> add back to queue - vAddNodeToPossibleUpdatableQueue(meshNodeAddr.addr); + vMeshOtaUtilAddNodeToPossibleUpdatableQueue(meshNodeAddr.addr); } } @@ -191,14 +191,13 @@ void vTaskOTAWorker(void *arg) //set want reboot ESP_LOGI(LOG_TAG, "Updated successfully via Mesh, set pending reboot"); bWantReboot = true; - vAddAllNeighboursToQueue(); //add all existing neighbours to queue + vMeshOtaUtilAddAllNeighboursToQueue(); //add all existing neighbours to queue } vTaskDelay( (1000) / portTICK_PERIOD_MS); } } - -esp_err_t errOTAMeshSlave(bool* pbNewOTAImage) +esp_err_t errMeshOtaSlaveEndpoint(bool* pbNewOTAImage) { esp_err_t err = ESP_OK; MESH_PACKET_t sOTAMessage; @@ -224,22 +223,22 @@ esp_err_t errOTAMeshSlave(bool* pbNewOTAImage) ERROR_CHECK(esp_ota_get_partition_description(pBootPartition, &bootPartitionDesc)); //get metadata of partition //send OTA_Version_Response to sender of OTA_Version_Request packet wirh version in payload - ERROR_CHECK(errSendOTAVersionResponse(&sOTAMessage.meshSenderAddr)); + ERROR_CHECK(errMeshOtaUtilSendOTAVersionResponse(&sOTAMessage.meshSenderAddr)); - if((bNewerVersion((bootPartitionDesc).version, (char*) sOTAMessage.au8Payload)) && (err == ESP_OK)) //compare local and remote version + if((bMeshOtaUtilNewerVersion((bootPartitionDesc).version, (char*) sOTAMessage.au8Payload)) && (err == ESP_OK)) //compare local and remote version { //remote newer as local ESP_LOGI(LOG_TAG, "remote image on node is newer --> OTA update required"); // --> this version older --> start OTA_Rx --> set pbNewOTAImage true - ERROR_CHECK(errOTAMeshReceive(pbNewOTAImage, &sOTAMessage.meshSenderAddr)); + ERROR_CHECK(errMeshOtaPartitionAccessMeshReceive(pbNewOTAImage, &sOTAMessage.meshSenderAddr)); } - if((bNewerVersion((char*) sOTAMessage.au8Payload, (bootPartitionDesc).version)) && (err == ESP_OK)) //compare remote and local version + if((bMeshOtaUtilNewerVersion((char*) sOTAMessage.au8Payload, (bootPartitionDesc).version)) && (err == ESP_OK)) //compare remote and local version { //local newer as remote ESP_LOGI(LOG_TAG, "remote image on node is older --> OTA send required"); // --> this version newer --> start OTA_Tx - ERROR_CHECK(errOTAMeshTransmit(&sOTAMessage.meshSenderAddr)); + ERROR_CHECK(errMeshOtaPartitionAccessMeshTransmit(&sOTAMessage.meshSenderAddr)); } xSemaphoreGive(bsOTAProcess); //free binary semaphore, this allows other tasks to start the OTA process } @@ -247,7 +246,7 @@ esp_err_t errOTAMeshSlave(bool* pbNewOTAImage) return err; } -esp_err_t errOTAMeshMaster(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr) +esp_err_t errMeshOtaMasterEndpoint(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr) { esp_err_t err = ESP_OK; MESH_PACKET_t sOTAMessage; @@ -258,13 +257,13 @@ esp_err_t errOTAMeshMaster(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr) *pbNewOTAImage = false; //set default false - if(bIsNodeNeighbour(pMeshNodeAddr) == true) //check if node is still connected + if(bMeshNetworkIsNodeNeighbour(pMeshNodeAddr) == true) //check if node is still connected { bNodeIsConnected = true; //node is one of the neighbours xSemaphoreTake(bsOTAProcess, portMAX_DELAY); //wait for binary semaphore that allows to start the OTA process ESP_LOGI(LOG_TAG, "Mesh-Master: send Version_Request to 0x%x", pMeshNodeAddr->addr[5]); - ERROR_CHECK(errSendOTAVersionRequest(pMeshNodeAddr)); //send OTA_VERSION_REQUEST with local version in payload + ERROR_CHECK(errMeshOtaUtilSendOTAVersionRequest(pMeshNodeAddr)); //send OTA_VERSION_REQUEST with local version in payload for (uint32_t u32Index = 0; u32Index < QUEUE_MESSAGE_OTA_SIZE; u32Index++) //loop through all OTA messages { @@ -277,32 +276,32 @@ esp_err_t errOTAMeshMaster(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr) err = ESP_FAIL; } - if((err == ESP_OK) && (sOTAMessage.type == OTA_Version_Response) && (bCheckMACEquality(sOTAMessage.meshSenderAddr.addr, pMeshNodeAddr->addr))) //if OTA_Version_Request + if((err == ESP_OK) && (sOTAMessage.type == OTA_Version_Response) && (bMeshNetworkCheckMACEquality(sOTAMessage.meshSenderAddr.addr, pMeshNodeAddr->addr))) //if OTA_Version_Request { bNodeIsResponding = true; pBootPartition = esp_ota_get_boot_partition(); //get boot partition (that will booted after reset), not the running partition ERROR_CHECK(esp_ota_get_partition_description(pBootPartition, &bootPartitionDesc)); //get metadata of partition - if((bNewerVersion((bootPartitionDesc).version, (char*) sOTAMessage.au8Payload)) && (err == ESP_OK)) //compare local and remote version + if((bMeshOtaUtilNewerVersion((bootPartitionDesc).version, (char*) sOTAMessage.au8Payload)) && (err == ESP_OK)) //compare local and remote version { //remote newer as local ESP_LOGI(LOG_TAG, "Mesh: remote image on node is newer --> OTA update required"); // --> this version older --> start OTA_Rx --> set pbNewOTAImage true - ERROR_CHECK(errOTAMeshReceive(pbNewOTAImage, &sOTAMessage.meshSenderAddr)); + ERROR_CHECK(errMeshOtaPartitionAccessMeshReceive(pbNewOTAImage, &sOTAMessage.meshSenderAddr)); } - if((bNewerVersion((char*) sOTAMessage.au8Payload, (bootPartitionDesc).version)) && (err == ESP_OK)) //compare remote and local version + if((bMeshOtaUtilNewerVersion((char*) sOTAMessage.au8Payload, (bootPartitionDesc).version)) && (err == ESP_OK)) //compare remote and local version { //local newer as remote ESP_LOGI(LOG_TAG, "Mesh: remote image on node is older --> OTA send required"); // --> this version newer --> start OTA_Tx - ERROR_CHECK(errOTAMeshTransmit(&sOTAMessage.meshSenderAddr)); + ERROR_CHECK(errMeshOtaPartitionAccessMeshTransmit(&sOTAMessage.meshSenderAddr)); } } else if (err == ESP_OK) { //received from wrong node or type --> back to queue - vAddOtaMessageToQueue(&sOTAMessage); + vMeshOtaUtilAddOtaMessageToQueue(&sOTAMessage); } } else @@ -319,7 +318,7 @@ esp_err_t errOTAMeshMaster(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr) { //add node back to queue if connected and NOT responding ESP_LOGI(LOG_TAG, "OTA-Master: connected and NOT responding --> add node back to queue "); - vAddNodeToPossibleUpdatableQueue(pMeshNodeAddr->addr); + vMeshOtaUtilAddNodeToPossibleUpdatableQueue(pMeshNodeAddr->addr); } return err; } diff --git a/components/mesh_ota/Mesh_OTA_Globals.c b/components/mesh_ota/Mesh_OTA_Globals.c index 890a888..88bda4f 100644 --- a/components/mesh_ota/Mesh_OTA_Globals.c +++ b/components/mesh_ota/Mesh_OTA_Globals.c @@ -6,5 +6,10 @@ xQueueHandle queueMessageOTA; //mesh ota controll messages like "OTA_Version_Res SemaphoreHandle_t bsStartStopServerWorker; //binary semaphore SemaphoreHandle_t bsOTAProcess; //binary semaphore +//w: errMeshOTAInitialize; +//r: errMeshOTAInitialize; errMeshOtaPartitionAccessHttps; errMeshOtaPartitionAccessMeshReceive; const esp_partition_t* pOTAPartition; //pointer to ota partition + +//w: errMeshOTAInitialize; vMeshOtaTaskOTAWorker; vMeshOtaTaskServerWorker +//r: errMeshOTAInitialize; vMeshOtaTaskOTAWorker; vMeshOtaTaskServerWorker bool bWantReboot; //flag to signal pending reboot diff --git a/components/mesh_ota/Mesh_OTA_Partition_Access.c b/components/mesh_ota/Mesh_OTA_Partition_Access.c index 6776c26..83fbf87 100644 --- a/components/mesh_ota/Mesh_OTA_Partition_Access.c +++ b/components/mesh_ota/Mesh_OTA_Partition_Access.c @@ -1,249 +1,11 @@ #include "Mesh_OTA.h" #include "Mesh_OTA_Util.h" #include "Mesh_OTA_Globals.h" -#include "Mesh_OTA_Access.h" +#include "Mesh_OTA_Partition_Access.h" -static const char *LOG_TAG = "mesh_ota_access"; +static const char *LOG_TAG = "mesh_ota_partition_access"; -esp_err_t errOTAMeshTransmit(mesh_addr_t* pMeshNodeAddr) -{ - esp_err_t err = ESP_OK; - const esp_partition_t* pBootPartition; //pointer to boot partition (that will booted after reset) - MESH_PACKET_t sMeshPacket; //packet for sending and receiving - // uint32_t u32Index = 0U; //index for partition read offset - bool bAbort = false; //abort the OTA process - bool bNodeIsResponding = false; //remote node is still active - uint32_t u32OTABytesWritten = 0U; - uint32_t u32SegmentCounter = 0U; - - pBootPartition = esp_ota_get_boot_partition(); //get boot partition (that will booted after reset), not the running partition - - //loop through partition to read in segmensts until end or error or abort called - while( ((OTA_MESH_SEGMENT_SIZE * u32SegmentCounter) < pBootPartition->size) && (err == ESP_OK) && (bAbort == false)) - { - bNodeIsResponding = false; //reset to default - - // read partition with offset based in index - ERROR_CHECK(esp_partition_read(pBootPartition, (OTA_MESH_SEGMENT_SIZE * u32SegmentCounter), sMeshPacket.au8Payload, OTA_MESH_SEGMENT_SIZE)); - u32OTABytesWritten = ((u32SegmentCounter+1) * OTA_MESH_SEGMENT_SIZE); - vPrintOTAProgress(&(pBootPartition->size), &u32OTABytesWritten, Transmitter); - - if(err == ESP_OK) - { - //no error while read --> send OTA_DATA packet - sMeshPacket.type = OTA_Data; - - if((OTA_MESH_SEGMENT_SIZE * (u32SegmentCounter+1)) >= pBootPartition->size) //check if last segment - { - //last partition image segment --> send OTA_Complete - ESP_LOGI(LOG_TAG, "OTA-TX: last segment--> send Complete"); - sMeshPacket.type = OTA_Complete; - } - //ESP_LOGI(LOG_TAG, "OTA-TX: send packet"); - err = errSendMeshPacket(pMeshNodeAddr, &sMeshPacket); - } - else - { - // error while read --> send OTA_ABORT and abort this OTA process - sMeshPacket.type = OTA_Abort; - bAbort = true; - ESP_LOGI(LOG_TAG, "OTA-TX: error while read --> send ABORT"); - errSendMeshPacket(pMeshNodeAddr, &sMeshPacket); - } - - // loop through all OTA messages or until abort is called or error - for (uint32_t u32Index = 0; ((u32Index < QUEUE_MESSAGE_OTA_SIZE) && (bAbort == false) && (err == ESP_OK)); u32Index++) //loop through all OTA messages - { - // if(uxQueueSpacesAvailable(queueMessageOTA) < QUEUE_MESSAGE_OTA_SIZE) - // { - //queue not empty - if (xQueueReceive(queueMessageOTA, &sMeshPacket, ((OTA_MESH_TIMEOUT) / portTICK_PERIOD_MS)) != pdTRUE) - { - ESP_LOGE(LOG_TAG, "Unable to receive OTA Messages from queue"); - err = ESP_FAIL; - } - - if((err == ESP_OK) && (bCheckMACEquality(sMeshPacket.meshSenderAddr.addr, pMeshNodeAddr->addr))) //if OTA_Version_Request - { - //packet from node received - switch (sMeshPacket.type) - { - case OTA_ACK: //increase index for next round - u32Index++; - bNodeIsResponding = true; - u32Index = QUEUE_MESSAGE_OTA_SIZE;//this will end the loop through all OTA messages - break; - case OTA_Abort: //abort this OTA process - bAbort = true; - bNodeIsResponding = true; - break; - default: - //receives wrong OTA message type from node --> back to queue - //vAddOtaMessageToQueue(&sMeshPacket); - break; - } - } - else if (err == ESP_OK) - { - //received from wrong node --> back to queue - vAddOtaMessageToQueue(&sMeshPacket); - } - /* - } - else - { - // OTA Message queue is empty --> wait some time - ESP_LOGI(LOG_TAG, "OTA-TX: ota message queue empty --> wait"); - vTaskDelay( (OTA_MESH_TIMEOUT) / portTICK_PERIOD_MS); - } - */ - - }//end OTA message loop - - if(bNodeIsResponding == false) - { - //no abort was called but node didn’t responded - ESP_LOGE(LOG_TAG, "OTA-TX: no abort was called but node didn’t responded --> error"); - bAbort = true; - err = ESP_FAIL; //this OTA process failed with error - } - u32SegmentCounter++; - }//end of partition segment loop - vClearOtaMessageQueue(pMeshNodeAddr); - return err; -} - -esp_err_t errOTAMeshReceive(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr) -{ - esp_err_t err = ESP_OK; - MESH_PACKET_t sMeshPacket; //packet for sending and receiving - bool bComplete = false; //complete the OTA process - bool bAbort = false; //abort the OTA process - bool bNodeIsResponding = false; //remote node is still active - uint32_t u32OTABytesWritten = 0U; //counter unsed for progress log - static esp_ota_handle_t otaHandle; //OTA process handle - *pbNewOTAImage = false; - uint32_t u32SegmentCounter = 0U; - - ERROR_CHECK(esp_ota_begin(pOTAPartition, OTA_SIZE_UNKNOWN, &otaHandle)); //start ota update process - - //partition segement loop through partition to read in segmensts until end or error or abort called - while((bComplete == false) && (err == ESP_OK) && (bAbort == false) && (u32OTABytesWritten <= pOTAPartition->size)) - { - bNodeIsResponding = false; //reset to default - - // loop through all OTA messages or until abort is called - for (uint32_t u32Index = 0; ((u32Index < QUEUE_MESSAGE_OTA_SIZE) && (bAbort == false)); u32Index++) //loop through all OTA messages - { - //if(uxQueueSpacesAvailable(queueMessageOTA) < QUEUE_MESSAGE_OTA_SIZE) - // { - //queue not empty - if (xQueueReceive(queueMessageOTA, &sMeshPacket, ((OTA_MESH_TIMEOUT) / portTICK_PERIOD_MS)) != pdTRUE) - { - ESP_LOGE(LOG_TAG, "Unable to receive OTA Messages from queue"); - err = ESP_FAIL; - } - - if((err == ESP_OK) && (bCheckMACEquality(sMeshPacket.meshSenderAddr.addr, pMeshNodeAddr->addr))) //if OTA_Version_Request - { - //packet from node received - switch (sMeshPacket.type) - { - case OTA_Complete: //signal end of this OTA process, fall through because same behavior as OTA_Data - bComplete = true; - ESP_LOGI(LOG_TAG, "OTA-RX: rec Complete --> last segment"); - //fall through - case OTA_Data: //data segement received - bNodeIsResponding = true; - ERROR_CHECK(esp_ota_write(otaHandle, sMeshPacket.au8Payload, OTA_MESH_SEGMENT_SIZE)); - u32OTABytesWritten = ((u32SegmentCounter+1) * OTA_MESH_SEGMENT_SIZE); - vPrintOTAProgress(&(pOTAPartition->size), &u32OTABytesWritten, Receiver); - u32Index = QUEUE_MESSAGE_OTA_SIZE; //this will end the loop through all OTA messages - break; - case OTA_Abort: //abort this OTA process - bAbort = true; - bNodeIsResponding = true; - ESP_LOGI(LOG_TAG, "OTA-RX: rec Abort"); - //this will end the loop through all OTA messages - break; - default: - //receives wrong OTA message type from node --> back to queue - //vAddOtaMessageToQueue(&sMeshPacket); - break; - } - } - else if (err == ESP_OK) - { - //received from wrong node --> back to queue - vAddOtaMessageToQueue(&sMeshPacket); - } - - /* } - else - { - ESP_LOGI(LOG_TAG, "OTA-RX: ota message queue empty --> wait"); - // OTA Message queue is empty --> wait some time - vTaskDelay( (OTA_MESH_TIMEOUT) / portTICK_PERIOD_MS); - } - */ - - }//end of OTA message loop - - if(bNodeIsResponding == false) - { - //no abort was called but node didn’t responded --> error - ESP_LOGI(LOG_TAG, "OTA-RX: no abort was called but node didn’t responded --> error"); - bAbort = true; //this will stop the partition segement loop - err = ESP_FAIL; //this OTA process failed with error - } - else - { - //node has responded with OTA_DATA or OTA_Complete or OTA_ABORT - if(err == ESP_OK) - { - - if(bAbort == false) - { - //no error while ota write --> send OTA_ACK packet - //ESP_LOGI(LOG_TAG, "OTA-RX: no error while ota write --> send OTA_ACK packet"); - sMeshPacket.type = OTA_ACK; - err = errSendMeshPacket(pMeshNodeAddr, &sMeshPacket); - } - } - else - { - // error while read --> send OTA_ABORT and abort this OTA process - sMeshPacket.type = OTA_Abort; - bAbort = true; - ESP_LOGI(LOG_TAG, "OTA-RX: abort --> send ABORT"); - errSendMeshPacket(pMeshNodeAddr, &sMeshPacket); - } - } - u32SegmentCounter++; - }//end of partition segement loop - - if(bComplete == true) - { - //all OTA segments received --> validate - ESP_LOGI(LOG_TAG, "OTA-RX: validate image "); - ERROR_CHECK(esp_ota_end(otaHandle)); - ERROR_CHECK(esp_ota_set_boot_partition(pOTAPartition)); - if(err == ESP_OK) - { - //successfully updated OTA partition - *pbNewOTAImage = true; - } - } - else - { - //not all OTA segments received --> abort this OTA process - ERROR_CHECK(esp_ota_abort(otaHandle)); - } - vClearOtaMessageQueue(pMeshNodeAddr); - return err; -} - -esp_err_t errOTAHTTPS(bool* pbNewOTAImage) +esp_err_t errMeshOtaPartitionAccessHttps(bool* pbNewOTAImage) { esp_err_t err = ESP_OK; char u8OTABuffer[OTA_HTTPS_SEGMENT_SIZE]; //store image segment from server before ota write @@ -258,7 +20,7 @@ esp_err_t errOTAHTTPS(bool* pbNewOTAImage) ERROR_CHECK(errHTTPSClientRetrieveData(u8OTABuffer, &u32BufferLenght, &u32BytesRead)); //read first bytes if image, including the version - ERROR_CHECK(errExtractVersionNumber(u8OTABuffer, &u32BytesRead, pcRemoteVersionNumber)); //extract version numbers + ERROR_CHECK(errMeshOtaUtilExtractVersionNumber(u8OTABuffer, &u32BytesRead, pcRemoteVersionNumber)); //extract version numbers if(err == ESP_OK) //check if version number is found { @@ -267,12 +29,12 @@ esp_err_t errOTAHTTPS(bool* pbNewOTAImage) pBootPartition = esp_ota_get_boot_partition(); //get boot partition (that will booted after reset), not the running partition ERROR_CHECK(esp_ota_get_partition_description(pBootPartition, &bootPartitionDesc)); //get metadata of partition - if(bNewerVersion((bootPartitionDesc).version, pcRemoteVersionNumber)) //compare local and remote version + if(bMeshOtaUtilNewerVersion((bootPartitionDesc).version, pcRemoteVersionNumber)) //compare local and remote version { // server image is newer --> OTA update required ESP_LOGI(LOG_TAG, "Server: image is newer --> OTA update required"); - ERROR_CHECK(errFindImageStart(u8OTABuffer, &u32BufferLenght, &u32StartOffset)); //get image start offset + ERROR_CHECK(errMeshOtaUtilFindImageStart(u8OTABuffer, &u32BufferLenght, &u32StartOffset)); //get image start offset ERROR_CHECK(esp_ota_begin(pOTAPartition, OTA_SIZE_UNKNOWN, &otaHandle)); //start ota update process if(err == ESP_OK) @@ -281,7 +43,7 @@ esp_err_t errOTAHTTPS(bool* pbNewOTAImage) ESP_LOGI(LOG_TAG, "start OTA download via HTTPS"); do { - vPrintOTAProgress(&(pOTAPartition->size), &u32OTABytesWritten, Receiver); + vMeshOtaUtilPrintOTAProgress(&(pOTAPartition->size), &u32OTABytesWritten, Receiver); ERROR_CHECK(esp_ota_write(otaHandle, (const void*) u8OTABuffer+u32StartOffset, (u32BytesRead-u32StartOffset))); if(err == ESP_OK) @@ -320,4 +82,243 @@ esp_err_t errOTAHTTPS(bool* pbNewOTAImage) xSemaphoreGive(bsOTAProcess); //free binary semaphore, this allows other tasks to start the OTA process } //end version number extracted return err; -} \ No newline at end of file +} + +esp_err_t errMeshOtaPartitionAccessMeshTransmit(mesh_addr_t* pMeshNodeAddr) +{ + esp_err_t err = ESP_OK; + const esp_partition_t* pBootPartition; //pointer to boot partition (that will booted after reset) + MESH_PACKET_t sMeshPacket; //packet for sending and receiving + // uint32_t u32Index = 0U; //index for partition read offset + bool bAbort = false; //abort the OTA process + bool bNodeIsResponding = false; //remote node is still active + uint32_t u32OTABytesWritten = 0U; + uint32_t u32SegmentCounter = 0U; + + pBootPartition = esp_ota_get_boot_partition(); //get boot partition (that will booted after reset), not the running partition + + //loop through partition to read in segmensts until end or error or abort called + while( ((OTA_MESH_SEGMENT_SIZE * u32SegmentCounter) < pBootPartition->size) && (err == ESP_OK) && (bAbort == false)) + { + bNodeIsResponding = false; //reset to default + + // read partition with offset based in index + ERROR_CHECK(esp_partition_read(pBootPartition, (OTA_MESH_SEGMENT_SIZE * u32SegmentCounter), sMeshPacket.au8Payload, OTA_MESH_SEGMENT_SIZE)); + u32OTABytesWritten = ((u32SegmentCounter+1) * OTA_MESH_SEGMENT_SIZE); + vMeshOtaUtilPrintOTAProgress(&(pBootPartition->size), &u32OTABytesWritten, Transmitter); + + if(err == ESP_OK) + { + //no error while read --> send OTA_DATA packet + sMeshPacket.type = OTA_Data; + + if((OTA_MESH_SEGMENT_SIZE * (u32SegmentCounter+1)) >= pBootPartition->size) //check if last segment + { + //last partition image segment --> send OTA_Complete + ESP_LOGI(LOG_TAG, "OTA-TX: last segment--> send Complete"); + sMeshPacket.type = OTA_Complete; + } + //ESP_LOGI(LOG_TAG, "OTA-TX: send packet"); + err = errMeshNetworkSendMeshPacket(pMeshNodeAddr, &sMeshPacket); + } + else + { + // error while read --> send OTA_ABORT and abort this OTA process + sMeshPacket.type = OTA_Abort; + bAbort = true; + ESP_LOGI(LOG_TAG, "OTA-TX: error while read --> send ABORT"); + errMeshNetworkSendMeshPacket(pMeshNodeAddr, &sMeshPacket); + } + + // loop through all OTA messages or until abort is called or error + for (uint32_t u32Index = 0; ((u32Index < QUEUE_MESSAGE_OTA_SIZE) && (bAbort == false) && (err == ESP_OK)); u32Index++) //loop through all OTA messages + { + // if(uxQueueSpacesAvailable(queueMessageOTA) < QUEUE_MESSAGE_OTA_SIZE) + // { + //queue not empty + if (xQueueReceive(queueMessageOTA, &sMeshPacket, ((OTA_MESH_TIMEOUT) / portTICK_PERIOD_MS)) != pdTRUE) + { + ESP_LOGE(LOG_TAG, "Unable to receive OTA Messages from queue"); + err = ESP_FAIL; + } + + if((err == ESP_OK) && (bMeshNetworkCheckMACEquality(sMeshPacket.meshSenderAddr.addr, pMeshNodeAddr->addr))) //if OTA_Version_Request + { + //packet from node received + switch (sMeshPacket.type) + { + case OTA_ACK: //increase index for next round + u32Index++; + bNodeIsResponding = true; + u32Index = QUEUE_MESSAGE_OTA_SIZE;//this will end the loop through all OTA messages + break; + case OTA_Abort: //abort this OTA process + bAbort = true; + bNodeIsResponding = true; + break; + default: + //receives wrong OTA message type from node --> back to queue + //vMeshOtaUtilAddOtaMessageToQueue(&sMeshPacket); + break; + } + } + else if (err == ESP_OK) + { + //received from wrong node --> back to queue + vMeshOtaUtilAddOtaMessageToQueue(&sMeshPacket); + } + /* + } + else + { + // OTA Message queue is empty --> wait some time + ESP_LOGI(LOG_TAG, "OTA-TX: ota message queue empty --> wait"); + vTaskDelay( (OTA_MESH_TIMEOUT) / portTICK_PERIOD_MS); + } + */ + + }//end OTA message loop + + if(bNodeIsResponding == false) + { + //no abort was called but node didn’t responded + ESP_LOGE(LOG_TAG, "OTA-TX: no abort was called but node didn’t responded --> error"); + bAbort = true; + err = ESP_FAIL; //this OTA process failed with error + } + u32SegmentCounter++; + }//end of partition segment loop + vMeshOtaUtilClearOtaMessageQueue(pMeshNodeAddr); + return err; +} + +esp_err_t errMeshOtaPartitionAccessMeshReceive(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr) +{ + esp_err_t err = ESP_OK; + MESH_PACKET_t sMeshPacket; //packet for sending and receiving + bool bComplete = false; //complete the OTA process + bool bAbort = false; //abort the OTA process + bool bNodeIsResponding = false; //remote node is still active + uint32_t u32OTABytesWritten = 0U; //counter unsed for progress log + static esp_ota_handle_t otaHandle; //OTA process handle + *pbNewOTAImage = false; + uint32_t u32SegmentCounter = 0U; + + ERROR_CHECK(esp_ota_begin(pOTAPartition, OTA_SIZE_UNKNOWN, &otaHandle)); //start ota update process + + //partition segement loop through partition to read in segmensts until end or error or abort called + while((bComplete == false) && (err == ESP_OK) && (bAbort == false) && (u32OTABytesWritten <= pOTAPartition->size)) + { + bNodeIsResponding = false; //reset to default + + // loop through all OTA messages or until abort is called + for (uint32_t u32Index = 0; ((u32Index < QUEUE_MESSAGE_OTA_SIZE) && (bAbort == false)); u32Index++) //loop through all OTA messages + { + //if(uxQueueSpacesAvailable(queueMessageOTA) < QUEUE_MESSAGE_OTA_SIZE) + // { + //queue not empty + if (xQueueReceive(queueMessageOTA, &sMeshPacket, ((OTA_MESH_TIMEOUT) / portTICK_PERIOD_MS)) != pdTRUE) + { + ESP_LOGE(LOG_TAG, "Unable to receive OTA Messages from queue"); + err = ESP_FAIL; + } + + if((err == ESP_OK) && (bMeshNetworkCheckMACEquality(sMeshPacket.meshSenderAddr.addr, pMeshNodeAddr->addr))) //if OTA_Version_Request + { + //packet from node received + switch (sMeshPacket.type) + { + case OTA_Complete: //signal end of this OTA process, fall through because same behavior as OTA_Data + bComplete = true; + ESP_LOGI(LOG_TAG, "OTA-RX: rec Complete --> last segment"); + //fall through + case OTA_Data: //data segement received + bNodeIsResponding = true; + ERROR_CHECK(esp_ota_write(otaHandle, sMeshPacket.au8Payload, OTA_MESH_SEGMENT_SIZE)); + u32OTABytesWritten = ((u32SegmentCounter+1) * OTA_MESH_SEGMENT_SIZE); + vMeshOtaUtilPrintOTAProgress(&(pOTAPartition->size), &u32OTABytesWritten, Receiver); + u32Index = QUEUE_MESSAGE_OTA_SIZE; //this will end the loop through all OTA messages + break; + case OTA_Abort: //abort this OTA process + bAbort = true; + bNodeIsResponding = true; + ESP_LOGI(LOG_TAG, "OTA-RX: rec Abort"); + //this will end the loop through all OTA messages + break; + default: + //receives wrong OTA message type from node --> back to queue + //vMeshOtaUtilAddOtaMessageToQueue(&sMeshPacket); + break; + } + } + else if (err == ESP_OK) + { + //received from wrong node --> back to queue + vMeshOtaUtilAddOtaMessageToQueue(&sMeshPacket); + } + + /* } + else + { + ESP_LOGI(LOG_TAG, "OTA-RX: ota message queue empty --> wait"); + // OTA Message queue is empty --> wait some time + vTaskDelay( (OTA_MESH_TIMEOUT) / portTICK_PERIOD_MS); + } + */ + + }//end of OTA message loop + + if(bNodeIsResponding == false) + { + //no abort was called but node didn’t responded --> error + ESP_LOGI(LOG_TAG, "OTA-RX: no abort was called but node didn’t responded --> error"); + bAbort = true; //this will stop the partition segement loop + err = ESP_FAIL; //this OTA process failed with error + } + else + { + //node has responded with OTA_DATA or OTA_Complete or OTA_ABORT + if(err == ESP_OK) + { + + if(bAbort == false) + { + //no error while ota write --> send OTA_ACK packet + //ESP_LOGI(LOG_TAG, "OTA-RX: no error while ota write --> send OTA_ACK packet"); + sMeshPacket.type = OTA_ACK; + err = errMeshNetworkSendMeshPacket(pMeshNodeAddr, &sMeshPacket); + } + } + else + { + // error while read --> send OTA_ABORT and abort this OTA process + sMeshPacket.type = OTA_Abort; + bAbort = true; + ESP_LOGI(LOG_TAG, "OTA-RX: abort --> send ABORT"); + errMeshNetworkSendMeshPacket(pMeshNodeAddr, &sMeshPacket); + } + } + u32SegmentCounter++; + }//end of partition segement loop + + if(bComplete == true) + { + //all OTA segments received --> validate + ESP_LOGI(LOG_TAG, "OTA-RX: validate image "); + ERROR_CHECK(esp_ota_end(otaHandle)); + ERROR_CHECK(esp_ota_set_boot_partition(pOTAPartition)); + if(err == ESP_OK) + { + //successfully updated OTA partition + *pbNewOTAImage = true; + } + } + else + { + //not all OTA segments received --> abort this OTA process + ERROR_CHECK(esp_ota_abort(otaHandle)); + } + vMeshOtaUtilClearOtaMessageQueue(pMeshNodeAddr); + return err; +} + diff --git a/components/mesh_ota/Mesh_OTA_Util.c b/components/mesh_ota/Mesh_OTA_Util.c index 7a955a3..93dcac9 100644 --- a/components/mesh_ota/Mesh_OTA_Util.c +++ b/components/mesh_ota/Mesh_OTA_Util.c @@ -3,76 +3,7 @@ static const char *LOG_TAG = "mesh_ota"; -void vAddNodeToPossibleUpdatableQueue(uint8_t* pu8MAC) -{ - //send payload to node queues - mesh_addr_t addrNode; - memcpy(&addrNode.addr, (uint8_t *)pu8MAC, 6); //copy MAC - - if (xQueueSend(queueNodes, &addrNode, portMAX_DELAY) != pdPASS) - { - ESP_LOGE(LOG_TAG, "Unable to push node into node queue"); - } - else - { - ESP_LOGI(LOG_TAG, "added node \"%x:%x:%x:%x:%x:%x\" to possible updatable queue", addrNode.addr[0], addrNode.addr[1], addrNode.addr[2], addrNode.addr[3], addrNode.addr[4], addrNode.addr[5]); - } -} - -void vAddOtaMessageToQueue(MESH_PACKET_t* puMeshPacket) -{ - //send ota packet to packet queue - if (xQueueSend(queueMessageOTA, puMeshPacket, portMAX_DELAY) != pdPASS) - { - ESP_LOGE(LOG_TAG, "Unable to push ota packet into packet queue"); - } - else - { - switch (puMeshPacket->type) - { - case OTA_Abort: - ESP_LOGI(LOG_TAG, "added ota message to queue: OTA_Abort from 0x%x", puMeshPacket->meshSenderAddr.addr[5]); - break; - case OTA_Version_Request: - ESP_LOGI(LOG_TAG, "added ota message to queue: OTA_Version_Request from 0x%x", puMeshPacket->meshSenderAddr.addr[5]); - break; - - case OTA_Version_Response: - ESP_LOGI(LOG_TAG, "added ota message to queue: OTA_Version Response from 0x%x", puMeshPacket->meshSenderAddr.addr[5]); - break; - default: - break; - } - } -} - -void vChangeStateOfServerWorker(bool bState) //allow access via function ptn to networl_handler -{ - static bool bLastState = false; - - if(bState != bLastState) //change only if necessary - { - ESP_LOGI(LOG_TAG, "server worker change handler"); - - if(bState == true) - { - if (xSemaphoreGive(bsStartStopServerWorker) != pdTRUE) - { - ESP_LOGE(LOG_TAG, "Unable to give mutex to activate the server worker"); - } - } - else - { - if (xSemaphoreTake(bsStartStopServerWorker,( TickType_t ) 10 ) != pdTRUE) - { - ESP_LOGE(LOG_TAG, "Unable to obtain mutex to deactivate the server worker"); - } - } - bLastState = bState; - } -} - -bool bNewerVersion(const char* pu8Local, const char* pu8Remote) +bool bMeshOtaUtilNewerVersion(const char* pu8Local, const char* pu8Remote) { /* * Return true if remote version is newer (higher) than local version @@ -103,7 +34,24 @@ bool bNewerVersion(const char* pu8Local, const char* pu8Remote) return bReturn; } -esp_err_t errFindImageStart(const char* pu8Data, uint32_t* pu32DataLenght, uint32_t* pu32StartOffset) +esp_err_t errMeshOtaUtilExtractVersionNumber(const char* pu8Data, uint32_t* pu32DataLenght, char* pc8RemoteVersionNumber) +{ + uint32_t u32StartOffset; + esp_err_t err = ESP_OK; + + strcpy(pc8RemoteVersionNumber, "999.999.999"); //init value + err = errMeshOtaUtilFindImageStart(pu8Data, pu32DataLenght, &u32StartOffset); //get image start offset + + if(err == ESP_OK) + { + //image found + strncpy(pc8RemoteVersionNumber, pu8Data+(u32StartOffset+48), 11); //copy version number + pc8RemoteVersionNumber[12] = '\0'; + } + return err; +} + +esp_err_t errMeshOtaUtilFindImageStart(const char* pu8Data, uint32_t* pu32DataLenght, uint32_t* pu32StartOffset) { /* Offset value @@ -181,24 +129,42 @@ esp_err_t errFindImageStart(const char* pu8Data, uint32_t* pu32DataLenght, uint3 return errReturn; } -esp_err_t errExtractVersionNumber(const char* pu8Data, uint32_t* pu32DataLenght, char* pc8RemoteVersionNumber) +esp_err_t errMeshOtaUtilSendOTAVersionRequest(mesh_addr_t* pMeshReceiverAddr) { - uint32_t u32StartOffset; esp_err_t err = ESP_OK; + MESH_PACKET_t packet; + packet.type = OTA_Version_Request; - strcpy(pc8RemoteVersionNumber, "999.999.999"); //init value - err = errFindImageStart(pu8Data, pu32DataLenght, &u32StartOffset); //get image start offset + const esp_partition_t* pBootPartition; //pointer to boot partition (that will booted after reset) + esp_app_desc_t bootPartitionDesc; //Metadata from boot partition - if(err == ESP_OK) - { - //image found - strncpy(pc8RemoteVersionNumber, pu8Data+(u32StartOffset+48), 11); //copy version number - pc8RemoteVersionNumber[12] = '\0'; - } + pBootPartition = esp_ota_get_boot_partition(); //get boot partition (that will booted after reset), not the running partition + ERROR_CHECK(esp_ota_get_partition_description(pBootPartition, &bootPartitionDesc)); //get metadate of partition + memcpy(&packet.au8Payload, &bootPartitionDesc.version, 12); //copy local version to OTA_Version_Request packet + err = errMeshNetworkSendMeshPacket(pMeshReceiverAddr, &packet); return err; } -void vPrintOTAProgress(const uint32_t* const pu32TotalImageSize, const uint32_t* const pu32BytesWritten, OTA_MESH_ROLE_t eRole) +esp_err_t errMeshOtaUtilSendOTAVersionResponse(mesh_addr_t* pMeshReceiverAddr) +{ + esp_err_t err = ESP_OK; + MESH_PACKET_t packet; + packet.type = OTA_Version_Response; + + const esp_partition_t* pBootPartition; //pointer to boot partition (that will booted after reset) + esp_app_desc_t bootPartitionDesc; //Metadata from boot partition + + pBootPartition = esp_ota_get_boot_partition(); //get boot partition (that will booted after reset), not the running partition + ERROR_CHECK(esp_ota_get_partition_description(pBootPartition, &bootPartitionDesc)); //get metadate of partition + memcpy(&packet.au8Payload, &bootPartitionDesc.version, 12); //copy local version to OTA_Version_Response packet + + ESP_LOGI(LOG_TAG, "Send OTA_Version_Response to 0x%x", pMeshReceiverAddr->addr[5]); + + err = errMeshNetworkSendMeshPacket(pMeshReceiverAddr, &packet); + return err; +} + +void vMeshOtaUtilPrintOTAProgress(const uint32_t* const pu32TotalImageSize, const uint32_t* const pu32BytesWritten, OTA_MESH_ROLE_t eRole) { uint32_t u32Percentage = 0U; static uint32_t u32LastPercentage = 0U; @@ -230,7 +196,7 @@ void vPrintOTAProgress(const uint32_t* const pu32TotalImageSize, const uint32_t* } } -void vAddAllNeighboursToQueue(void) +void vMeshOtaUtilAddAllNeighboursToQueue(void) { esp_err_t err = ESP_OK; @@ -238,55 +204,36 @@ void vAddAllNeighboursToQueue(void) mesh_addr_t childrenAddr[CONFIG_MESH_ROUTE_TABLE_SIZE]; //array of children attached to this node uint16_t u16ChildrenSize = 0U; //number of children attached to this node - err = errGetParentNode(&addrParent); + err = errMeshNetworkGetParentNode(&addrParent); if(err == ESP_OK) { - vAddNodeToPossibleUpdatableQueue(addrParent.addr); + vMeshOtaUtilAddNodeToPossibleUpdatableQueue(addrParent.addr); ESP_LOGI(LOG_TAG, "added parent"); } err = ESP_OK; //reset error code - ERROR_CHECK(errGetChildren(childrenAddr, &u16ChildrenSize)); //get all children + ERROR_CHECK(errMeshNetworkGetChildren(childrenAddr, &u16ChildrenSize)); //get all children for (uint16_t u16Index = 0; ((u16Index < u16ChildrenSize) && (err == ESP_OK)); u16Index++) { - vAddNodeToPossibleUpdatableQueue(childrenAddr[u16Index].addr); + vMeshOtaUtilAddNodeToPossibleUpdatableQueue(childrenAddr[u16Index].addr); ESP_LOGI(LOG_TAG, "added child"); } } -esp_err_t errSendOTAVersionResponse(mesh_addr_t* pMeshReceiverAddr) -{ - esp_err_t err = ESP_OK; - MESH_PACKET_t packet; - packet.type = OTA_Version_Response; - - const esp_partition_t* pBootPartition; //pointer to boot partition (that will booted after reset) - esp_app_desc_t bootPartitionDesc; //Metadata from boot partition - - pBootPartition = esp_ota_get_boot_partition(); //get boot partition (that will booted after reset), not the running partition - ERROR_CHECK(esp_ota_get_partition_description(pBootPartition, &bootPartitionDesc)); //get metadate of partition - memcpy(&packet.au8Payload, &bootPartitionDesc.version, 12); //copy local version to OTA_Version_Response packet - - ESP_LOGI(LOG_TAG, "Send OTA_Version_Response to 0x%x", pMeshReceiverAddr->addr[5]); - - err = errSendMeshPacket(pMeshReceiverAddr, &packet); - return err; -} - -void vClearOtaMessageQueue(mesh_addr_t* pMeshNodeAddr) +void vMeshOtaUtilClearOtaMessageQueue(mesh_addr_t* pMeshNodeAddr) { MESH_PACKET_t sMeshPacket; //packet for sending and receiving for (uint32_t u32Index = 0; (u32Index < QUEUE_MESSAGE_OTA_SIZE); u32Index++) //loop through all OTA messages { if (xQueueReceive(queueMessageOTA, &sMeshPacket, 0) == pdTRUE) { - if(!(bCheckMACEquality(sMeshPacket.meshSenderAddr.addr, pMeshNodeAddr->addr))) + if(!(bMeshNetworkCheckMACEquality(sMeshPacket.meshSenderAddr.addr, pMeshNodeAddr->addr))) { //received OTA message is NOT from pMeshNodeAddr --> keep it in queue - vAddOtaMessageToQueue(&sMeshPacket); + vMeshOtaUtilAddOtaMessageToQueue(&sMeshPacket); } else { @@ -296,19 +243,71 @@ void vClearOtaMessageQueue(mesh_addr_t* pMeshNodeAddr) }//end OTA message loop } -esp_err_t errSendOTAVersionRequest(mesh_addr_t* pMeshReceiverAddr) +void vMeshOtaUtilAddNodeToPossibleUpdatableQueue(uint8_t* pu8MAC) { - esp_err_t err = ESP_OK; - MESH_PACKET_t packet; - packet.type = OTA_Version_Request; + //send payload to node queues + mesh_addr_t addrNode; + memcpy(&addrNode.addr, (uint8_t *)pu8MAC, 6); //copy MAC - const esp_partition_t* pBootPartition; //pointer to boot partition (that will booted after reset) - esp_app_desc_t bootPartitionDesc; //Metadata from boot partition - - pBootPartition = esp_ota_get_boot_partition(); //get boot partition (that will booted after reset), not the running partition - ERROR_CHECK(esp_ota_get_partition_description(pBootPartition, &bootPartitionDesc)); //get metadate of partition - memcpy(&packet.au8Payload, &bootPartitionDesc.version, 12); //copy local version to OTA_Version_Request packet - err = errSendMeshPacket(pMeshReceiverAddr, &packet); - return err; + if (xQueueSend(queueNodes, &addrNode, portMAX_DELAY) != pdPASS) + { + ESP_LOGE(LOG_TAG, "Unable to push node into node queue"); + } + else + { + ESP_LOGI(LOG_TAG, "added node \"%x:%x:%x:%x:%x:%x\" to possible updatable queue", addrNode.addr[0], addrNode.addr[1], addrNode.addr[2], addrNode.addr[3], addrNode.addr[4], addrNode.addr[5]); + } } +void vMeshOtaUtilAddOtaMessageToQueue(MESH_PACKET_t* puMeshPacket) +{ + //send ota packet to packet queue + if (xQueueSend(queueMessageOTA, puMeshPacket, portMAX_DELAY) != pdPASS) + { + ESP_LOGE(LOG_TAG, "Unable to push ota packet into packet queue"); + } + else + { + switch (puMeshPacket->type) + { + case OTA_Abort: + ESP_LOGI(LOG_TAG, "added ota message to queue: OTA_Abort from 0x%x", puMeshPacket->meshSenderAddr.addr[5]); + break; + case OTA_Version_Request: + ESP_LOGI(LOG_TAG, "added ota message to queue: OTA_Version_Request from 0x%x", puMeshPacket->meshSenderAddr.addr[5]); + break; + + case OTA_Version_Response: + ESP_LOGI(LOG_TAG, "added ota message to queue: OTA_Version Response from 0x%x", puMeshPacket->meshSenderAddr.addr[5]); + break; + default: + break; + } + } +} + +void vMeshOtaUtilChangeStateOfServerWorker(bool bState) //allow access via function ptn to networl_handler +{ + static bool bLastState = false; + + if(bState != bLastState) //change only if necessary + { + ESP_LOGI(LOG_TAG, "server worker change handler"); + + if(bState == true) + { + if (xSemaphoreGive(bsStartStopServerWorker) != pdTRUE) + { + ESP_LOGE(LOG_TAG, "Unable to give mutex to activate the server worker"); + } + } + else + { + if (xSemaphoreTake(bsStartStopServerWorker,( TickType_t ) 10 ) != pdTRUE) + { + ESP_LOGE(LOG_TAG, "Unable to obtain mutex to deactivate the server worker"); + } + } + bLastState = bState; + } +} diff --git a/components/mesh_ota/include/Mesh_Network.h b/components/mesh_ota/include/Mesh_Network.h index e448e36..5a550bb 100644 --- a/components/mesh_ota/include/Mesh_Network.h +++ b/components/mesh_ota/include/Mesh_Network.h @@ -84,32 +84,28 @@ extern uint8_t u8ownMAC[6]; extern void (*pOTAChildConnectHandle)(uint8_t* ); extern void (*pChangeStateOfServerWorkerHandle)(bool ); -esp_err_t errMeshNetworkInitialize(); -esp_err_t errMeshNetworkInitializeWiFi(); +esp_err_t errMeshNetworkInitialize(void); +esp_err_t errMeshNetworkInitializeWiFi(void); esp_err_t errMeshNetworkInitializeRouter(mesh_cfg_t* cfg); -esp_err_t errMeshNetworkSetAppReceiveHandle(void (*pAppRxHandleTmp)(uint8_t * pu8Data, uint8_t* pu8Sender)); esp_err_t errMeshNetworkSetChildConnectedHandle(void (*pChildConnectHandleTmp)(uint8_t * pu8Data)); +esp_err_t errMeshNetworkSetAppReceiveHandle(void (*pAppRxHandleTmp)(uint8_t * pu8Data, uint8_t* pu8Sender)); esp_err_t errMeshNetworkSetOTAMessageHandleHandle(void (*pOTAMessageHandleTmp)(MESH_PACKET_t* puMeshPacket)); - esp_err_t errMeshNetworkSetChangeStateOfServerWorkerHandle(void (*pChangeStateOfServerWorkerHandleTmp)(bool bState)); -bool bCheckMACEquality(uint8_t* pu8aMAC, uint8_t* pu8bMAC); -void vGetOwnAddr(mesh_addr_t* pMeshOwnAddr); -esp_err_t errGetParentNode(mesh_addr_t* pMeshParentAddr); -esp_err_t errGetChildren(mesh_addr_t* pChildren, uint16_t* pu16ChildrenSize); -bool bIsRootNode(); -bool bIsNodeNeighbour(mesh_addr_t* pNode); - -esp_err_t errStartReceiveTask(); -void vTaskReceiveMeshData(void *arg); -void vMeshEventHandler(void *arg, esp_event_base_t event_base, int32_t i32EventID, void* vpEventData); -void vIPEventHandler(void *arg, esp_event_base_t event_base, int32_t i32EventID, void *event_data); - -esp_err_t errSendMeshPacket(mesh_addr_t* pAddrDest, MESH_PACKET_t* pPacket); - +bool bMeshNetworkIsRootNode(void); +bool bMeshNetworkIsNodeNeighbour(mesh_addr_t* pNode); +bool bMeshNetworkCheckMACEquality(uint8_t* pu8aMAC, uint8_t* pu8bMAC); +esp_err_t errMeshNetworkStartReceiveTask(void); +esp_err_t errMeshNetworkGetParentNode(mesh_addr_t* pMeshParentAddr); +esp_err_t errMeshNetworkGetChildren(mesh_addr_t* pChildren, uint16_t* pu16ChildrenSize); +esp_err_t errMeshNetworkSendMeshPacket(mesh_addr_t* pAddrDest, MESH_PACKET_t* pPacket); +void vMeshNetworkTaskReceiveMeshData(void *arg); +void vMeshNetworkGetOwnAddr(mesh_addr_t* pMeshOwnAddr); +void vMeshNetworkIpEventHandler(void *arg, esp_event_base_t event_base, int32_t i32EventID, void *vpEventData); +void vMeshNetworkMeshEventHandler(void *arg, esp_event_base_t event_base, int32_t i32EventID, void* vpEventData); #endif /* H_MESH_NETWORK */ diff --git a/components/mesh_ota/include/Mesh_OTA.h b/components/mesh_ota/include/Mesh_OTA.h index 24a2e41..d087b2c 100644 --- a/components/mesh_ota/include/Mesh_OTA.h +++ b/components/mesh_ota/include/Mesh_OTA.h @@ -28,15 +28,14 @@ } \ } \ -esp_err_t errMeshOTAInitialize(); - - -esp_err_t errOTAMeshSlave(bool* pbNewOTAImage); -esp_err_t errOTAMeshMaster(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr); - +esp_err_t errMeshOTAInitialize(void); //Tasks -void vTaskServerWorker(void *arg); -void vTaskOTAWorker(void *arg); +void vMeshOtaTaskServerWorker(void *arg); +void vMeshOtaTaskOTAWorker(void *arg); + +//OTA process endpoints +esp_err_t errMeshOtaSlaveEndpoint(bool* pbNewOTAImage); +esp_err_t errMeshOtaMasterEndpoint(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr); #endif /* H_MESH_OTA */ diff --git a/components/mesh_ota/include/Mesh_OTA_Access.h b/components/mesh_ota/include/Mesh_OTA_Partition_Access.h similarity index 74% rename from components/mesh_ota/include/Mesh_OTA_Access.h rename to components/mesh_ota/include/Mesh_OTA_Partition_Access.h index 2336d1a..f161338 100644 --- a/components/mesh_ota/include/Mesh_OTA_Access.h +++ b/components/mesh_ota/include/Mesh_OTA_Partition_Access.h @@ -1,5 +1,5 @@ -#ifndef H_MESH_OTA_ACCESS -#define H_MESH_OTA_ACCESS +#ifndef H_MESH_OTA_PARTITION_ACCESS +#define H_MESH_OTA_PARTITION_ACCESS #include "esp_system.h" #include "esp_event.h" @@ -20,9 +20,8 @@ } \ } \ -esp_err_t errOTAMeshTransmit(mesh_addr_t* pMeshNodeAddr); -esp_err_t errOTAMeshReceive(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr); +esp_err_t errMeshOtaPartitionAccessHttps(bool* pbNewOTAImage); +esp_err_t errMeshOtaPartitionAccessMeshTransmit(mesh_addr_t* pMeshNodeAddr); +esp_err_t errMeshOtaPartitionAccessMeshReceive(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr); -esp_err_t errOTAHTTPS(bool* pbNewOTAImage); - -#endif /* H_MESH_OTA_ACCESS */ +#endif /* H_MESH_OTA_PARTITION_ACCESS */ diff --git a/components/mesh_ota/include/Mesh_OTA_Util.h b/components/mesh_ota/include/Mesh_OTA_Util.h index cbcafc8..11e28ae 100644 --- a/components/mesh_ota/include/Mesh_OTA_Util.h +++ b/components/mesh_ota/include/Mesh_OTA_Util.h @@ -18,18 +18,18 @@ enum otaMeshRole typedef enum otaMeshRole OTA_MESH_ROLE_t; //helper functions -bool bNewerVersion(const char* pu8Local, const char* pu8Remote); -esp_err_t errExtractVersionNumber(const char* pu8Data, uint32_t* pu32DataLenght, char* pc8RemoteVersionNumber); -esp_err_t errFindImageStart(const char* pu8Data, uint32_t* pu32DataLenght, uint32_t* pu32StartOffset); -void vPrintOTAProgress(const uint32_t* const pu32TotalImageSize, const uint32_t* const pu32BytesWritten, OTA_MESH_ROLE_t eRole); -void vAddAllNeighboursToQueue(void); -esp_err_t errSendOTAVersionResponse(mesh_addr_t* meshReceiverAddr); -esp_err_t errSendOTAVersionRequest(mesh_addr_t* meshReceiverAddr); -void vClearOtaMessageQueue(mesh_addr_t* pMeshNodeAddr); +bool bMeshOtaUtilNewerVersion(const char* pu8Local, const char* pu8Remote); +esp_err_t errMeshOtaUtilExtractVersionNumber(const char* pu8Data, uint32_t* pu32DataLenght, char* pc8RemoteVersionNumber); +esp_err_t errMeshOtaUtilFindImageStart(const char* pu8Data, uint32_t* pu32DataLenght, uint32_t* pu32StartOffset); +esp_err_t errMeshOtaUtilSendOTAVersionRequest(mesh_addr_t* pMeshReceiverAddr); +esp_err_t errMeshOtaUtilSendOTAVersionResponse(mesh_addr_t* pMeshReceiverAddr); +void vMeshOtaUtilPrintOTAProgress(const uint32_t* const cpcu32TotalImageSize, const uint32_t* const cpcu32BytesWritten, OTA_MESH_ROLE_t eRole); +void vMeshOtaUtilAddAllNeighboursToQueue(void); +void vMeshOtaUtilClearOtaMessageQueue(mesh_addr_t* pMeshNodeAddr); //Handler -void vAddNodeToPossibleUpdatableQueue(uint8_t* pu8MAC); -void vAddOtaMessageToQueue(MESH_PACKET_t* puMeshPacket); -void vChangeStateOfServerWorker(bool state); +void vMeshOtaUtilAddNodeToPossibleUpdatableQueue(uint8_t* pu8MAC); +void vMeshOtaUtilAddOtaMessageToQueue(MESH_PACKET_t* puMeshPacket); +void vMeshOtaUtilChangeStateOfServerWorker(bool bState); #endif /* H_MESH_OTA_UTIL */ diff --git a/components/mesh_ota/test/test_mesh_ota.c b/components/mesh_ota/test/test_mesh_ota.c index f801293..ff8a866 100644 --- a/components/mesh_ota/test/test_mesh_ota.c +++ b/components/mesh_ota/test/test_mesh_ota.c @@ -10,56 +10,56 @@ TEST_CASE("Remote got patch", "[distinguish newer image version]") { char versionLocal[] = "1.2.3"; //current running image char versionRemote[] = "1.2.4"; //image from server - TEST_ASSERT_TRUE( bNewerVersion(versionLocal, versionRemote) ); + TEST_ASSERT_TRUE( bMeshOtaUtilNewerVersion(versionLocal, versionRemote) ); } TEST_CASE("Remote got minor", "[distinguish newer image version]") { char versionLocal[] = "1.2.3"; //current running image char versionRemote[] = "1.3.3"; //image from server - TEST_ASSERT_TRUE( bNewerVersion(versionLocal, versionRemote) ); + TEST_ASSERT_TRUE( bMeshOtaUtilNewerVersion(versionLocal, versionRemote) ); } TEST_CASE("Remote got major", "[distinguish newer image version]") { char versionLocal[] = "1.2.3"; //current running image char versionRemote[] = "2.2.3"; //image from server - TEST_ASSERT_TRUE( bNewerVersion(versionLocal, versionRemote) ); + TEST_ASSERT_TRUE( bMeshOtaUtilNewerVersion(versionLocal, versionRemote) ); } TEST_CASE("Local got patch", "[distinguish newer image version]") { char versionLocal[] = "1.2.4"; //current running image char versionRemote[] = "1.2.3"; //image from server - TEST_ASSERT_FALSE( bNewerVersion(versionLocal, versionRemote) ); + TEST_ASSERT_FALSE( bMeshOtaUtilNewerVersion(versionLocal, versionRemote) ); } TEST_CASE("Local got minor", "[distinguish newer image version]") { char versionLocal[] = "1.3.3"; //current running image char versionRemote[] = "1.2.3"; //image from server - TEST_ASSERT_FALSE( bNewerVersion(versionLocal, versionRemote) ); + TEST_ASSERT_FALSE( bMeshOtaUtilNewerVersion(versionLocal, versionRemote) ); } TEST_CASE("Local got major", "[distinguish newer image version]") { char versionLocal[] = "2.2.3"; //current running image char versionRemote[] = "1.2.3"; //image from server - TEST_ASSERT_FALSE( bNewerVersion(versionLocal, versionRemote) ); + TEST_ASSERT_FALSE( bMeshOtaUtilNewerVersion(versionLocal, versionRemote) ); } TEST_CASE("Remote got alpha and patch", "[distinguish newer image version]") { char versionLocal[] = "2.2.3"; //current running image char versionRemote[] = "a2.2.4"; //image from server - TEST_ASSERT_TRUE( bNewerVersion(versionLocal, versionRemote) ); + TEST_ASSERT_TRUE( bMeshOtaUtilNewerVersion(versionLocal, versionRemote) ); } TEST_CASE("Remote got max", "[distinguish newer image version]") { char versionLocal[] = "2.2.3"; //current running image char versionRemote[] = "999.999.999"; //image from server - TEST_ASSERT_TRUE( bNewerVersion(versionLocal, versionRemote) ); + TEST_ASSERT_TRUE( bMeshOtaUtilNewerVersion(versionLocal, versionRemote) ); } // ### ### ### find start offset in firmware image ### ### ### @@ -68,7 +68,7 @@ TEST_CASE("with http response + 0.0.1", "[find start offset in firmware image]" { uint32_t u32StartOffset; uint32_t u32DataLenght = sizeof(dataWithHttpRespone0_0_1)/sizeof(dataWithHttpRespone0_0_1[0]); - esp_err_t err = errFindImageStart(dataWithHttpRespone0_0_1, &u32DataLenght, &u32StartOffset); + esp_err_t err = errMeshOtaUtilFindImageStart(dataWithHttpRespone0_0_1, &u32DataLenght, &u32StartOffset); if(err == ESP_OK) { TEST_ASSERT_EQUAL_INT(305, u32StartOffset); @@ -83,7 +83,7 @@ TEST_CASE("without http response + 0.0.1", "[find start offset in firmware imag { uint32_t u32StartOffset; uint32_t u32DataLenght = sizeof(dataWithoutHttpRespone0_0_1)/sizeof(dataWithoutHttpRespone0_0_1[0]); - esp_err_t err = errFindImageStart(dataWithoutHttpRespone0_0_1, &u32DataLenght, &u32StartOffset); + esp_err_t err = errMeshOtaUtilFindImageStart(dataWithoutHttpRespone0_0_1, &u32DataLenght, &u32StartOffset); if(err == ESP_OK) { TEST_ASSERT_EQUAL_INT(0, u32StartOffset); @@ -99,7 +99,7 @@ TEST_CASE("with http response + 999.999.999", "[find start offset in firmware i { uint32_t u32StartOffset; uint32_t u32DataLenght = sizeof(dataWithHttpRespone999_999_999)/sizeof(dataWithHttpRespone999_999_999[0]); - esp_err_t err = errFindImageStart(dataWithHttpRespone999_999_999, &u32DataLenght, &u32StartOffset); + esp_err_t err = errMeshOtaUtilFindImageStart(dataWithHttpRespone999_999_999, &u32DataLenght, &u32StartOffset); if(err == ESP_OK) { TEST_ASSERT_EQUAL_INT(305, u32StartOffset); @@ -114,7 +114,7 @@ TEST_CASE("without http response + 999.999.999", "[find start offset in firmwar { uint32_t u32StartOffset; uint32_t u32DataLenght = sizeof(dataWithoutHttpRespone999_999_999)/sizeof(dataWithoutHttpRespone999_999_999[0]); - esp_err_t err = errFindImageStart(dataWithoutHttpRespone999_999_999, &u32DataLenght, &u32StartOffset); + esp_err_t err = errMeshOtaUtilFindImageStart(dataWithoutHttpRespone999_999_999, &u32DataLenght, &u32StartOffset); if(err == ESP_OK) { TEST_ASSERT_EQUAL_INT(0, u32StartOffset); @@ -129,7 +129,7 @@ TEST_CASE("with http response + 999.9.999", "[find start offset in firmware ima { uint32_t u32StartOffset; uint32_t u32DataLenght = sizeof(dataWithHttpRespone999_9_999)/sizeof(dataWithHttpRespone999_9_999[0]); - esp_err_t err = errFindImageStart(dataWithHttpRespone999_9_999, &u32DataLenght, &u32StartOffset); + esp_err_t err = errMeshOtaUtilFindImageStart(dataWithHttpRespone999_9_999, &u32DataLenght, &u32StartOffset); if(err == ESP_OK) { TEST_ASSERT_EQUAL_INT(302, u32StartOffset); @@ -144,7 +144,7 @@ TEST_CASE("with http response + 999.99.999", "[find start offset in firmware im { uint32_t u32StartOffset; uint32_t u32DataLenght = sizeof(dataWithHttpRespone999_99_999)/sizeof(dataWithHttpRespone999_99_999[0]); - esp_err_t err = errFindImageStart(dataWithHttpRespone999_99_999, &u32DataLenght, &u32StartOffset); + esp_err_t err = errMeshOtaUtilFindImageStart(dataWithHttpRespone999_99_999, &u32DataLenght, &u32StartOffset); if(err == ESP_OK) { TEST_ASSERT_EQUAL_INT(299, u32StartOffset); @@ -162,10 +162,10 @@ TEST_CASE("extract version 0.0.1", "[extract image version number]") char versionLocal[] = "0.0.0"; //current running image char versionRemote[12];//image from server uint32_t u32DataLenght = sizeof(dataWithHttpRespone0_0_1)/sizeof(dataWithHttpRespone0_0_1[0]); - esp_err_t err = errExtractVersionNumber(dataWithHttpRespone0_0_1, &u32DataLenght, versionRemote); + esp_err_t err = errMeshOtaUtilExtractVersionNumber(dataWithHttpRespone0_0_1, &u32DataLenght, versionRemote); if(err == ESP_OK) { - TEST_ASSERT_TRUE( bNewerVersion(versionLocal, versionRemote) ); + TEST_ASSERT_TRUE( bMeshOtaUtilNewerVersion(versionLocal, versionRemote) ); } else { @@ -178,10 +178,10 @@ TEST_CASE("extract version 999.999.999", "[extract image version number]") char versionLocal[] = "0.0.0"; //current running image char versionRemote[12];//image from server uint32_t u32DataLenght = sizeof(dataWithHttpRespone999_999_999)/sizeof(dataWithHttpRespone999_999_999[0]); - esp_err_t err = errExtractVersionNumber(dataWithHttpRespone999_999_999, &u32DataLenght, versionRemote); + esp_err_t err = errMeshOtaUtilExtractVersionNumber(dataWithHttpRespone999_999_999, &u32DataLenght, versionRemote); if(err == ESP_OK) { - TEST_ASSERT_TRUE( bNewerVersion(versionLocal, versionRemote) ); + TEST_ASSERT_TRUE( bMeshOtaUtilNewerVersion(versionLocal, versionRemote) ); } else { @@ -194,10 +194,10 @@ TEST_CASE("extract version 999.99.999", "[extract image version number]") char versionLocal[] = "999.100.999"; //current running image char versionRemote[12];//image from server uint32_t u32DataLenght = sizeof(dataWithHttpRespone999_99_999)/sizeof(dataWithHttpRespone999_99_999[0]); - esp_err_t err = errExtractVersionNumber(dataWithHttpRespone999_99_999, &u32DataLenght, versionRemote); + esp_err_t err = errMeshOtaUtilExtractVersionNumber(dataWithHttpRespone999_99_999, &u32DataLenght, versionRemote); if(err == ESP_OK) { - TEST_ASSERT_FALSE( bNewerVersion(versionLocal, versionRemote) ); + TEST_ASSERT_FALSE( bMeshOtaUtilNewerVersion(versionLocal, versionRemote) ); } else { diff --git a/main/Blinky_LED.c b/main/Blinky_LED.c index 6317f82..475b8f2 100644 --- a/main/Blinky_LED.c +++ b/main/Blinky_LED.c @@ -107,20 +107,20 @@ void vTaskReadUserInput(void *arg) memcpy(meshPacket.au8Payload, &bTmpPacket, sizeof(BLINKY_PACKET_t)); - if(bIsRootNode() == false) + if(bMeshNetworkIsRootNode() == false) { //this node is not root --> send led action to parent - ERROR_CHECK(errGetParentNode(&addrParent)); - ERROR_CHECK(errSendMeshPacket(&addrParent, &meshPacket)); + ERROR_CHECK(errMeshNetworkGetParentNode(&addrParent)); + ERROR_CHECK(errMeshNetworkSendMeshPacket(&addrParent, &meshPacket)); } else { //this node is root --> send led action to children - ERROR_CHECK(errGetChildren(childrenAddr, &u16ChildrenSize)); + ERROR_CHECK(errMeshNetworkGetChildren(childrenAddr, &u16ChildrenSize)); for (uint16_t u16Index = 0; u16Index < u16ChildrenSize; u16Index++) { - ERROR_CHECK (errSendMeshPacket(&childrenAddr[u16Index], &meshPacket)); + ERROR_CHECK (errMeshNetworkSendMeshPacket(&childrenAddr[u16Index], &meshPacket)); } } vTaskDelay(200 / portTICK_PERIOD_MS); @@ -170,15 +170,15 @@ void vTaskReceiveData(void *arg) } } - ERROR_CHECK(errGetChildren(childrenAddr, &u16ChildrenSize)); //get all children attached to this node + ERROR_CHECK(errMeshNetworkGetChildren(childrenAddr, &u16ChildrenSize)); //get all children attached to this node memcpy(meshPacket.au8Payload, &bTmpPacket, sizeof(BLINKY_PACKET_t)); //copy led action in mesh packet payload for (uint16_t u16Index = 0; u16Index < u16ChildrenSize; u16Index++) { //loop through children - if(bCheckMACEquality(bTmpPacket.meshSenderAddr.addr, childrenAddr[u16Index].addr) == false) //exclude the sender node + if(bMeshNetworkCheckMACEquality(bTmpPacket.meshSenderAddr.addr, childrenAddr[u16Index].addr) == false) //exclude the sender node { - ERROR_CHECK (errSendMeshPacket(&childrenAddr[u16Index], &meshPacket)); //send to child + ERROR_CHECK (errMeshNetworkSendMeshPacket(&childrenAddr[u16Index], &meshPacket)); //send to child } } vTaskDelay(200 / portTICK_PERIOD_MS); From 77e87ec840ba83cca7fa745d37125a3eb9340655 Mon Sep 17 00:00:00 2001 From: localhorst Date: Wed, 20 Jan 2021 22:39:18 +0100 Subject: [PATCH 17/21] changed the most params to const --- components/mesh_ota/HTTPS_Client.c | 30 +++---- components/mesh_ota/Mesh_Network.c | 58 +++++++------ components/mesh_ota/Mesh_Network_Handler.c | 2 +- components/mesh_ota/Mesh_OTA.c | 26 +++--- .../mesh_ota/Mesh_OTA_Partition_Access.c | 30 +++---- components/mesh_ota/Mesh_OTA_Util.c | 82 +++++++++---------- components/mesh_ota/include/HTTPS_Client.h | 12 +-- components/mesh_ota/include/Mesh_Network.h | 26 +++--- components/mesh_ota/include/Mesh_OTA.h | 4 +- .../include/Mesh_OTA_Partition_Access.h | 6 +- components/mesh_ota/include/Mesh_OTA_Util.h | 21 ++--- main/Blinky_LED.c | 2 +- main/Blinky_LED.h | 2 +- 13 files changed, 150 insertions(+), 151 deletions(-) diff --git a/components/mesh_ota/HTTPS_Client.c b/components/mesh_ota/HTTPS_Client.c index ca55e6d..cc83b4d 100644 --- a/components/mesh_ota/HTTPS_Client.c +++ b/components/mesh_ota/HTTPS_Client.c @@ -12,12 +12,12 @@ static const char *REQUEST = "GET " CONFIG_OTA_HTTPS_URL " HTTP/1.1\r\n" static HTTPS_Client_t sHTTPS_ClientConfig; -https_client_ret_t https_clientInitEmbedTLS(); -https_client_ret_t errHTTPSClientConnectToServer(); -https_client_ret_t errHTTPSClientValidateServer(); -https_client_ret_t errHTTPSClientSendRequest(); +https_client_ret_t https_clientInitEmbedTLS(void); +https_client_ret_t errHTTPSClientConnectToServer(void); +https_client_ret_t errHTTPSClientValidateServer(void); +https_client_ret_t errHTTPSClientSendRequest(void); -https_client_ret_t errHTTPSClientInitialize() +https_client_ret_t errHTTPSClientInitialize(void) { https_client_ret_t i32RetHTTPClient = HTTPS_CLIENT_OK; @@ -31,27 +31,27 @@ https_client_ret_t errHTTPSClientInitialize() return i32RetHTTPClient; } -https_client_ret_t errHTTPSClientRetrieveData(char* pu8Data, uint32_t* pu32DataLenght, uint32_t* pu32BytesRead) +https_client_ret_t errHTTPSClientRetrieveData(char* const cpu8Data, const uint32_t* const cpcu32DataLenght, uint32_t* pu32BytesRead) { https_client_ret_t i32RetHTTPClient = HTTPS_CLIENT_OK; int32_t i32RetRetrieveData = ESP_OK; bool bRetriveData = true; - bzero(pu8Data, *pu32DataLenght); - *pu32BytesRead = 0U; + bzero(cpu8Data, *cpcu32DataLenght); + (*pu32BytesRead) = 0U; while (bRetriveData) { mbedtls_ssl_conf_read_timeout(&sHTTPS_ClientConfig.conf, HTTPS_READ_TIMEOUT); //set timeout //Reading HTTP response - i32RetRetrieveData = mbedtls_ssl_read(&sHTTPS_ClientConfig.ssl, (unsigned char *)(pu8Data+(*pu32BytesRead)), ((*pu32DataLenght)-(*pu32BytesRead))); + i32RetRetrieveData = mbedtls_ssl_read(&sHTTPS_ClientConfig.ssl, (unsigned char *)(cpu8Data+(*pu32BytesRead)), ((*cpcu32DataLenght)-(*pu32BytesRead))); if(i32RetRetrieveData > 0) { //Data received *pu32BytesRead = *pu32BytesRead + i32RetRetrieveData; - if(*pu32DataLenght > 0) + if(*cpcu32DataLenght > 0) { //buffer not full yet --> read some more bRetriveData = true; @@ -86,7 +86,7 @@ https_client_ret_t errHTTPSClientRetrieveData(char* pu8Data, uint32_t* pu32DataL return i32RetHTTPClient; } -https_client_ret_t errHTTPSClientReset() +https_client_ret_t errHTTPSClientReset(void) { https_client_ret_t i32RetHTTPClient = HTTPS_CLIENT_OK; @@ -103,7 +103,7 @@ https_client_ret_t errHTTPSClientReset() return i32RetHTTPClient; } -https_client_ret_t https_clientInitEmbedTLS() +https_client_ret_t https_clientInitEmbedTLS(void) { https_client_ret_t i32RetHTTPClient = HTTPS_CLIENT_OK; @@ -197,7 +197,7 @@ https_client_ret_t https_clientInitEmbedTLS() return i32RetHTTPClient; } -https_client_ret_t errHTTPSClientConnectToServer() +https_client_ret_t errHTTPSClientConnectToServer(void) { https_client_ret_t i32RetHTTPClient = HTTPS_CLIENT_OK; int32_t i32RetServerConnect = ESP_OK; @@ -230,7 +230,7 @@ https_client_ret_t errHTTPSClientConnectToServer() return i32RetHTTPClient; } -https_client_ret_t errHTTPSClientValidateServer() +https_client_ret_t errHTTPSClientValidateServer(void) { https_client_ret_t i32RetHTTPClient = HTTPS_CLIENT_OK; int32_t i32RetValidateServer = ESP_OK; @@ -248,7 +248,7 @@ https_client_ret_t errHTTPSClientValidateServer() return i32RetHTTPClient; } -https_client_ret_t errHTTPSClientSendRequest() +https_client_ret_t errHTTPSClientSendRequest(void) { https_client_ret_t i32RetHTTPClient = HTTPS_CLIENT_OK; int32_t i32RetSendRequest = ESP_OK; diff --git a/components/mesh_ota/Mesh_Network.c b/components/mesh_ota/Mesh_Network.c index 0e6a3f4..74e69e3 100644 --- a/components/mesh_ota/Mesh_Network.c +++ b/components/mesh_ota/Mesh_Network.c @@ -10,7 +10,7 @@ uint8_t u8ownMAC[6]; //w: errMeshNetworkInitialize; vMeshNetworkMeshEventHandler //r: vMeshNetworkMeshEventHandler -esp_netif_t* netif_sta; +esp_netif_t* pNetifSta; //w: errMeshNetworkInitialize; vMeshNetworkMeshEventHandler //r: errMeshNetworkInitialize; @@ -25,10 +25,10 @@ int32_t i32MeshLayer; mesh_addr_t meshParentAddr; //function pointer for callbacks -void (*pAppRxHandle)(uint8_t*, uint8_t* ); -void (*pOTAChildConnectHandle)(uint8_t* ); -void (*pOTAMessageHandle)(MESH_PACKET_t* ); -void (*pChangeStateOfServerWorkerHandle)(bool ); +void (*pAppRxHandle)(const uint8_t* const, const uint8_t* const); +void (*pOTAChildConnectHandle)(const uint8_t* const); +void (*pOTAMessageHandle)(const MESH_PACKET_t* const); +void (*pChangeStateOfServerWorkerHandle)(const bool ); esp_err_t errMeshNetworkInitialize() { @@ -36,7 +36,7 @@ esp_err_t errMeshNetworkInitialize() esp_err_t err; bIsMeshConnected = false; i32MeshLayer = -1; - netif_sta = NULL; + pNetifSta = NULL; err = nvs_flash_init(); //init non-volatile storage @@ -54,7 +54,7 @@ esp_err_t errMeshNetworkInitialize() ERROR_CHECK(esp_event_loop_create_default()); //create network interfaces for mesh (only station instance saved for further manipulation, soft AP instance ignored - ERROR_CHECK(esp_netif_create_default_wifi_mesh_netifs(&netif_sta, NULL)); + ERROR_CHECK(esp_netif_create_default_wifi_mesh_netifs(&pNetifSta, NULL)); //wifi initialization ERROR_CHECK(errMeshNetworkInitializeWiFi()); @@ -131,31 +131,31 @@ esp_err_t errMeshNetworkInitializeRouter(mesh_cfg_t* cfg) return err; } -esp_err_t errMeshNetworkSetChildConnectedHandle(void (*pChildConnectHandleTmp)(uint8_t * pu8Data)) +esp_err_t errMeshNetworkSetChildConnectedHandle(void (*pChildConnectHandleTmp)(const uint8_t* const cpcu8Data)) { pOTAChildConnectHandle = pChildConnectHandleTmp; return ESP_OK; } -esp_err_t errMeshNetworkSetAppReceiveHandle(void (*pAppRxHandleTmp)(uint8_t * pu8Data, uint8_t* pu8Sender)) +esp_err_t errMeshNetworkSetAppReceiveHandle(void (*pAppRxHandleTmp)(const uint8_t* const cpcu8Data, const uint8_t* const pu8Sender)) { pAppRxHandle = pAppRxHandleTmp; //set handle from app as receive handle if an app packet is received return ESP_OK; } -esp_err_t errMeshNetworkSetOTAMessageHandleHandle(void (*pOTAMessageHandleTmp)(MESH_PACKET_t* puMeshPacket)) +esp_err_t errMeshNetworkSetOTAMessageHandleHandle(void (*pOTAMessageHandleTmp)(const MESH_PACKET_t* const cpcuMeshPacket)) { pOTAMessageHandle = pOTAMessageHandleTmp; return ESP_OK; } -esp_err_t errMeshNetworkSetChangeStateOfServerWorkerHandle(void (*pChangeStateOfServerWorkerHandleTmp)(bool bState)) +esp_err_t errMeshNetworkSetChangeStateOfServerWorkerHandle(void (*pChangeStateOfServerWorkerHandleTmp)(const bool cbState)) { pChangeStateOfServerWorkerHandle = pChangeStateOfServerWorkerHandleTmp; return ESP_OK; } -esp_err_t errMeshNetworkSendMeshPacket(mesh_addr_t* pAddrDest, MESH_PACKET_t* pPacket) +esp_err_t errMeshNetworkSendMeshPacket(const mesh_addr_t* const cpcAddrDest, const MESH_PACKET_t* const cpcPacket) { esp_err_t err; mesh_data_t data; @@ -164,9 +164,9 @@ esp_err_t errMeshNetworkSendMeshPacket(mesh_addr_t* pAddrDest, MESH_PACKET_t* pP data.size = sizeof(tx_buf); data.proto = MESH_PROTO_BIN; data.tos = MESH_TOS_P2P; - memcpy(tx_buf, (uint8_t *)pPacket, sizeof(MESH_PACKET_t)); + memcpy(tx_buf, (uint8_t *)cpcPacket, sizeof(MESH_PACKET_t)); - err = esp_mesh_send(pAddrDest, &data, MESH_DATA_P2P, NULL, 0); + err = esp_mesh_send(cpcAddrDest, &data, MESH_DATA_P2P, NULL, 0); return err; } @@ -176,7 +176,7 @@ bool bMeshNetworkIsRootNode() return esp_mesh_is_root(); } -bool bMeshNetworkIsNodeNeighbour(mesh_addr_t* pNode) +bool bMeshNetworkIsNodeNeighbour(const mesh_addr_t* const cpcNode) { esp_err_t err = ESP_OK; bool bReturn = false; @@ -188,7 +188,7 @@ bool bMeshNetworkIsNodeNeighbour(mesh_addr_t* pNode) if(err == ESP_OK) { - if(bMeshNetworkCheckMACEquality(pNode->addr, addrParent.addr) == true) + if(bMeshNetworkCheckMACEquality(cpcNode->addr, addrParent.addr) == true) { bReturn = true; //node was found } @@ -202,7 +202,7 @@ bool bMeshNetworkIsNodeNeighbour(mesh_addr_t* pNode) for (uint16_t u16Index = 0; ((u16Index < u16ChildrenSize) && (err == ESP_OK) && (bReturn == false)); u16Index++) { - if(bMeshNetworkCheckMACEquality(pNode->addr, childrenAddr[u16Index].addr) == true) + if(bMeshNetworkCheckMACEquality(cpcNode->addr, childrenAddr[u16Index].addr) == true) { bReturn = true; //node was found } @@ -212,14 +212,14 @@ bool bMeshNetworkIsNodeNeighbour(mesh_addr_t* pNode) } //returns true if MAC address is equal -bool bMeshNetworkCheckMACEquality(uint8_t* pu8aMAC, uint8_t* pu8bMAC) +bool bMeshNetworkCheckMACEquality(const uint8_t* const cpcu8aMAC, const uint8_t* const cpcu8bMAC) { bool bRet = true; uint8_t index = 0; while ((index < 6) && (bRet == true)) { - if(pu8aMAC[index] != pu8bMAC[index]) + if(cpcu8aMAC[index] != cpcu8bMAC[index]) { bRet = false; } @@ -227,7 +227,7 @@ bool bMeshNetworkCheckMACEquality(uint8_t* pu8aMAC, uint8_t* pu8bMAC) if(index == 5) { //last byte of mac - if(abs((pu8aMAC[index] - pu8bMAC[index])) <= 1) + if(abs((cpcu8aMAC[index] - cpcu8bMAC[index])) <= 1) { bRet = true; //last byte differs 1 ore less } @@ -251,17 +251,16 @@ esp_err_t errMeshNetworkStartReceiveTask() return err; } -void vMeshNetworkGetOwnAddr(mesh_addr_t* pMeshOwnAddr) +void vMeshNetworkGetOwnAddr(mesh_addr_t* const cpMeshOwnAddr) { - memcpy(pMeshOwnAddr->addr, u8ownMAC, 6); + memcpy(cpMeshOwnAddr->addr, u8ownMAC, 6); } - -esp_err_t errMeshNetworkGetChildren(mesh_addr_t* pChildren, uint16_t* pu16ChildrenSize) +esp_err_t errMeshNetworkGetChildren(mesh_addr_t* const cpChildren, uint16_t* const cpu16ChildrenSize) { esp_err_t err = ESP_OK; int route_table_size = 0; - *pu16ChildrenSize = 0; + *cpu16ChildrenSize = 0; mesh_addr_t route_table[CONFIG_MESH_ROUTE_TABLE_SIZE]; ERROR_CHECK(esp_mesh_get_routing_table((mesh_addr_t *) &route_table, (CONFIG_MESH_ROUTE_TABLE_SIZE * 6), &route_table_size)); @@ -273,8 +272,8 @@ esp_err_t errMeshNetworkGetChildren(mesh_addr_t* pChildren, uint16_t* pu16Childr { //child node //ESP_LOGI(LOG_TAG, "adding Node: \"0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\" ", route_table[index].addr[0], route_table[index].addr[1], route_table[index].addr[2], route_table[index].addr[3], route_table[index].addr[4], route_table[index].addr[5]); - pChildren[*pu16ChildrenSize] = route_table[index]; - *pu16ChildrenSize = (*pu16ChildrenSize)+1; + cpChildren[*cpu16ChildrenSize] = route_table[index]; + (*cpu16ChildrenSize) = (*cpu16ChildrenSize)+1; } } } @@ -330,8 +329,7 @@ void vMeshNetworkTaskReceiveMeshData(void *arg) } //end while } - -esp_err_t errMeshNetworkGetParentNode(mesh_addr_t* pMeshParentAddr) +esp_err_t errMeshNetworkGetParentNode(mesh_addr_t* const cpMeshParentAddr) { esp_err_t err = ESP_OK; @@ -343,7 +341,7 @@ esp_err_t errMeshNetworkGetParentNode(mesh_addr_t* pMeshParentAddr) else { //node has parent - memcpy(pMeshParentAddr, &meshParentAddr, sizeof(mesh_addr_t)); + memcpy(cpMeshParentAddr, &meshParentAddr, sizeof(mesh_addr_t)); } return err; } diff --git a/components/mesh_ota/Mesh_Network_Handler.c b/components/mesh_ota/Mesh_Network_Handler.c index 6fa0816..73dacd9 100644 --- a/components/mesh_ota/Mesh_Network_Handler.c +++ b/components/mesh_ota/Mesh_Network_Handler.c @@ -90,7 +90,7 @@ last_layer = i32MeshLayer; bIsMeshConnected = true; if (esp_mesh_is_root()) { -if(esp_netif_dhcpc_start(netif_sta) == ESP_ERR_ESP_NETIF_DHCP_ALREADY_STARTED) //get a IP from router +if(esp_netif_dhcpc_start(pNetifSta) == ESP_ERR_ESP_NETIF_DHCP_ALREADY_STARTED) //get a IP from router { if(pChangeStateOfServerWorkerHandle){pChangeStateOfServerWorkerHandle(true);}// signal reconnect } diff --git a/components/mesh_ota/Mesh_OTA.c b/components/mesh_ota/Mesh_OTA.c index 1e6db72..63aac6a 100644 --- a/components/mesh_ota/Mesh_OTA.c +++ b/components/mesh_ota/Mesh_OTA.c @@ -197,13 +197,13 @@ void vMeshOtaTaskOTAWorker(void *arg) } } -esp_err_t errMeshOtaSlaveEndpoint(bool* pbNewOTAImage) +esp_err_t errMeshOtaSlaveEndpoint(bool* const cpbNewOTAImage) { esp_err_t err = ESP_OK; MESH_PACKET_t sOTAMessage; const esp_partition_t* pBootPartition; //pointer to boot partition (that will booted after reset) esp_app_desc_t bootPartitionDesc; //Metadate from boot partition - *pbNewOTAImage = false; //set default false + *cpbNewOTAImage = false; //set default false //read OTAMessages queue if(uxQueueSpacesAvailable(queueMessageOTA) < QUEUE_MESSAGE_OTA_SIZE) @@ -229,8 +229,8 @@ esp_err_t errMeshOtaSlaveEndpoint(bool* pbNewOTAImage) { //remote newer as local ESP_LOGI(LOG_TAG, "remote image on node is newer --> OTA update required"); - // --> this version older --> start OTA_Rx --> set pbNewOTAImage true - ERROR_CHECK(errMeshOtaPartitionAccessMeshReceive(pbNewOTAImage, &sOTAMessage.meshSenderAddr)); + // --> this version older --> start OTA_Rx --> set cpbNewOTAImage true + ERROR_CHECK(errMeshOtaPartitionAccessMeshReceive(cpbNewOTAImage, &sOTAMessage.meshSenderAddr)); } if((bMeshOtaUtilNewerVersion((char*) sOTAMessage.au8Payload, (bootPartitionDesc).version)) && (err == ESP_OK)) //compare remote and local version @@ -246,7 +246,7 @@ esp_err_t errMeshOtaSlaveEndpoint(bool* pbNewOTAImage) return err; } -esp_err_t errMeshOtaMasterEndpoint(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr) +esp_err_t errMeshOtaMasterEndpoint(bool* const cpbNewOTAImage, const mesh_addr_t* const cpcMeshNodeAddr) { esp_err_t err = ESP_OK; MESH_PACKET_t sOTAMessage; @@ -255,15 +255,15 @@ esp_err_t errMeshOtaMasterEndpoint(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAd bool bNodeIsConnected = false; bool bNodeIsResponding = false; - *pbNewOTAImage = false; //set default false + *cpbNewOTAImage = false; //set default false - if(bMeshNetworkIsNodeNeighbour(pMeshNodeAddr) == true) //check if node is still connected + if(bMeshNetworkIsNodeNeighbour(cpcMeshNodeAddr) == true) //check if node is still connected { bNodeIsConnected = true; //node is one of the neighbours xSemaphoreTake(bsOTAProcess, portMAX_DELAY); //wait for binary semaphore that allows to start the OTA process - ESP_LOGI(LOG_TAG, "Mesh-Master: send Version_Request to 0x%x", pMeshNodeAddr->addr[5]); - ERROR_CHECK(errMeshOtaUtilSendOTAVersionRequest(pMeshNodeAddr)); //send OTA_VERSION_REQUEST with local version in payload + ESP_LOGI(LOG_TAG, "Mesh-Master: send Version_Request to 0x%x", cpcMeshNodeAddr->addr[5]); + ERROR_CHECK(errMeshOtaUtilSendOTAVersionRequest(cpcMeshNodeAddr)); //send OTA_VERSION_REQUEST with local version in payload for (uint32_t u32Index = 0; u32Index < QUEUE_MESSAGE_OTA_SIZE; u32Index++) //loop through all OTA messages { @@ -276,7 +276,7 @@ esp_err_t errMeshOtaMasterEndpoint(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAd err = ESP_FAIL; } - if((err == ESP_OK) && (sOTAMessage.type == OTA_Version_Response) && (bMeshNetworkCheckMACEquality(sOTAMessage.meshSenderAddr.addr, pMeshNodeAddr->addr))) //if OTA_Version_Request + if((err == ESP_OK) && (sOTAMessage.type == OTA_Version_Response) && (bMeshNetworkCheckMACEquality(sOTAMessage.meshSenderAddr.addr, cpcMeshNodeAddr->addr))) //if OTA_Version_Request { bNodeIsResponding = true; pBootPartition = esp_ota_get_boot_partition(); //get boot partition (that will booted after reset), not the running partition @@ -286,8 +286,8 @@ esp_err_t errMeshOtaMasterEndpoint(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAd { //remote newer as local ESP_LOGI(LOG_TAG, "Mesh: remote image on node is newer --> OTA update required"); - // --> this version older --> start OTA_Rx --> set pbNewOTAImage true - ERROR_CHECK(errMeshOtaPartitionAccessMeshReceive(pbNewOTAImage, &sOTAMessage.meshSenderAddr)); + // --> this version older --> start OTA_Rx --> set cpbNewOTAImage true + ERROR_CHECK(errMeshOtaPartitionAccessMeshReceive(cpbNewOTAImage, &sOTAMessage.meshSenderAddr)); } if((bMeshOtaUtilNewerVersion((char*) sOTAMessage.au8Payload, (bootPartitionDesc).version)) && (err == ESP_OK)) //compare remote and local version @@ -318,7 +318,7 @@ esp_err_t errMeshOtaMasterEndpoint(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAd { //add node back to queue if connected and NOT responding ESP_LOGI(LOG_TAG, "OTA-Master: connected and NOT responding --> add node back to queue "); - vMeshOtaUtilAddNodeToPossibleUpdatableQueue(pMeshNodeAddr->addr); + vMeshOtaUtilAddNodeToPossibleUpdatableQueue(cpcMeshNodeAddr->addr); } return err; } diff --git a/components/mesh_ota/Mesh_OTA_Partition_Access.c b/components/mesh_ota/Mesh_OTA_Partition_Access.c index 83fbf87..f859e6b 100644 --- a/components/mesh_ota/Mesh_OTA_Partition_Access.c +++ b/components/mesh_ota/Mesh_OTA_Partition_Access.c @@ -5,7 +5,7 @@ static const char *LOG_TAG = "mesh_ota_partition_access"; -esp_err_t errMeshOtaPartitionAccessHttps(bool* pbNewOTAImage) +esp_err_t errMeshOtaPartitionAccessHttps(bool* const cpbNewOTAImage) { esp_err_t err = ESP_OK; char u8OTABuffer[OTA_HTTPS_SEGMENT_SIZE]; //store image segment from server before ota write @@ -64,7 +64,7 @@ esp_err_t errMeshOtaPartitionAccessHttps(bool* pbNewOTAImage) ERROR_CHECK(esp_ota_set_boot_partition(pOTAPartition)); //set new image as boot if(err == ESP_OK) { - *pbNewOTAImage = true; //image validated + *cpbNewOTAImage = true; //image validated } } else @@ -72,7 +72,7 @@ esp_err_t errMeshOtaPartitionAccessHttps(bool* pbNewOTAImage) //error occurred --> abort ota update process ESP_LOGE(LOG_TAG, "abort ota process due to error 0x%x -> %s", err, esp_err_to_name(err)); ERROR_CHECK(esp_ota_abort(otaHandle)); - *pbNewOTAImage = false; //ota update failed + *cpbNewOTAImage = false; //ota update failed } } else @@ -84,7 +84,7 @@ esp_err_t errMeshOtaPartitionAccessHttps(bool* pbNewOTAImage) return err; } -esp_err_t errMeshOtaPartitionAccessMeshTransmit(mesh_addr_t* pMeshNodeAddr) +esp_err_t errMeshOtaPartitionAccessMeshTransmit(const mesh_addr_t* const cpcMeshNodeAddr) { esp_err_t err = ESP_OK; const esp_partition_t* pBootPartition; //pointer to boot partition (that will booted after reset) @@ -119,7 +119,7 @@ esp_err_t errMeshOtaPartitionAccessMeshTransmit(mesh_addr_t* pMeshNodeAddr) sMeshPacket.type = OTA_Complete; } //ESP_LOGI(LOG_TAG, "OTA-TX: send packet"); - err = errMeshNetworkSendMeshPacket(pMeshNodeAddr, &sMeshPacket); + err = errMeshNetworkSendMeshPacket(cpcMeshNodeAddr, &sMeshPacket); } else { @@ -127,7 +127,7 @@ esp_err_t errMeshOtaPartitionAccessMeshTransmit(mesh_addr_t* pMeshNodeAddr) sMeshPacket.type = OTA_Abort; bAbort = true; ESP_LOGI(LOG_TAG, "OTA-TX: error while read --> send ABORT"); - errMeshNetworkSendMeshPacket(pMeshNodeAddr, &sMeshPacket); + errMeshNetworkSendMeshPacket(cpcMeshNodeAddr, &sMeshPacket); } // loop through all OTA messages or until abort is called or error @@ -142,7 +142,7 @@ esp_err_t errMeshOtaPartitionAccessMeshTransmit(mesh_addr_t* pMeshNodeAddr) err = ESP_FAIL; } - if((err == ESP_OK) && (bMeshNetworkCheckMACEquality(sMeshPacket.meshSenderAddr.addr, pMeshNodeAddr->addr))) //if OTA_Version_Request + if((err == ESP_OK) && (bMeshNetworkCheckMACEquality(sMeshPacket.meshSenderAddr.addr, cpcMeshNodeAddr->addr))) //if OTA_Version_Request { //packet from node received switch (sMeshPacket.type) @@ -188,11 +188,11 @@ esp_err_t errMeshOtaPartitionAccessMeshTransmit(mesh_addr_t* pMeshNodeAddr) } u32SegmentCounter++; }//end of partition segment loop - vMeshOtaUtilClearOtaMessageQueue(pMeshNodeAddr); + vMeshOtaUtilClearOtaMessageQueue(cpcMeshNodeAddr); return err; } -esp_err_t errMeshOtaPartitionAccessMeshReceive(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr) +esp_err_t errMeshOtaPartitionAccessMeshReceive(bool* const cpbNewOTAImage, const mesh_addr_t* const cpcMeshNodeAddr) { esp_err_t err = ESP_OK; MESH_PACKET_t sMeshPacket; //packet for sending and receiving @@ -201,7 +201,7 @@ esp_err_t errMeshOtaPartitionAccessMeshReceive(bool* pbNewOTAImage, mesh_addr_t* bool bNodeIsResponding = false; //remote node is still active uint32_t u32OTABytesWritten = 0U; //counter unsed for progress log static esp_ota_handle_t otaHandle; //OTA process handle - *pbNewOTAImage = false; + *cpbNewOTAImage = false; uint32_t u32SegmentCounter = 0U; ERROR_CHECK(esp_ota_begin(pOTAPartition, OTA_SIZE_UNKNOWN, &otaHandle)); //start ota update process @@ -223,7 +223,7 @@ esp_err_t errMeshOtaPartitionAccessMeshReceive(bool* pbNewOTAImage, mesh_addr_t* err = ESP_FAIL; } - if((err == ESP_OK) && (bMeshNetworkCheckMACEquality(sMeshPacket.meshSenderAddr.addr, pMeshNodeAddr->addr))) //if OTA_Version_Request + if((err == ESP_OK) && (bMeshNetworkCheckMACEquality(sMeshPacket.meshSenderAddr.addr, cpcMeshNodeAddr->addr))) //if OTA_Version_Request { //packet from node received switch (sMeshPacket.type) @@ -286,7 +286,7 @@ esp_err_t errMeshOtaPartitionAccessMeshReceive(bool* pbNewOTAImage, mesh_addr_t* //no error while ota write --> send OTA_ACK packet //ESP_LOGI(LOG_TAG, "OTA-RX: no error while ota write --> send OTA_ACK packet"); sMeshPacket.type = OTA_ACK; - err = errMeshNetworkSendMeshPacket(pMeshNodeAddr, &sMeshPacket); + err = errMeshNetworkSendMeshPacket(cpcMeshNodeAddr, &sMeshPacket); } } else @@ -295,7 +295,7 @@ esp_err_t errMeshOtaPartitionAccessMeshReceive(bool* pbNewOTAImage, mesh_addr_t* sMeshPacket.type = OTA_Abort; bAbort = true; ESP_LOGI(LOG_TAG, "OTA-RX: abort --> send ABORT"); - errMeshNetworkSendMeshPacket(pMeshNodeAddr, &sMeshPacket); + errMeshNetworkSendMeshPacket(cpcMeshNodeAddr, &sMeshPacket); } } u32SegmentCounter++; @@ -310,7 +310,7 @@ esp_err_t errMeshOtaPartitionAccessMeshReceive(bool* pbNewOTAImage, mesh_addr_t* if(err == ESP_OK) { //successfully updated OTA partition - *pbNewOTAImage = true; + *cpbNewOTAImage = true; } } else @@ -318,7 +318,7 @@ esp_err_t errMeshOtaPartitionAccessMeshReceive(bool* pbNewOTAImage, mesh_addr_t* //not all OTA segments received --> abort this OTA process ERROR_CHECK(esp_ota_abort(otaHandle)); } - vMeshOtaUtilClearOtaMessageQueue(pMeshNodeAddr); + vMeshOtaUtilClearOtaMessageQueue(cpcMeshNodeAddr); return err; } diff --git a/components/mesh_ota/Mesh_OTA_Util.c b/components/mesh_ota/Mesh_OTA_Util.c index 93dcac9..c43b016 100644 --- a/components/mesh_ota/Mesh_OTA_Util.c +++ b/components/mesh_ota/Mesh_OTA_Util.c @@ -3,7 +3,7 @@ static const char *LOG_TAG = "mesh_ota"; -bool bMeshOtaUtilNewerVersion(const char* pu8Local, const char* pu8Remote) +bool bMeshOtaUtilNewerVersion(const char* cpu8Local, const char* cpu8Remote) { /* * Return true if remote version is newer (higher) than local version @@ -15,8 +15,8 @@ bool bMeshOtaUtilNewerVersion(const char* pu8Local, const char* pu8Remote) bool bReturn = false; //flag to stop loop uint8_t u8Index = 0; //numbers counter in version string - strncpy(u8LocalTmp, pu8Local, 12); //copy in tmp - strncpy(u8RemoteTmp, pu8Remote, 12); //copy in tmp + strncpy(u8LocalTmp, cpu8Local, 12); //copy in tmp + strncpy(u8RemoteTmp, cpu8Remote, 12); //copy in tmp char* pu8TokenLocal = strtok_r(u8LocalTmp, ".", &pu8saveptrLocal); //split tokens char* pu8TokenRemote = strtok_r(u8RemoteTmp, ".", &pu8saveptrRemote); //split tokens @@ -34,24 +34,24 @@ bool bMeshOtaUtilNewerVersion(const char* pu8Local, const char* pu8Remote) return bReturn; } -esp_err_t errMeshOtaUtilExtractVersionNumber(const char* pu8Data, uint32_t* pu32DataLenght, char* pc8RemoteVersionNumber) +esp_err_t errMeshOtaUtilExtractVersionNumber(const char* cpu8Data, uint32_t* const cpcu32DataLenght, char* const pc8RemoteVersionNumber) { uint32_t u32StartOffset; esp_err_t err = ESP_OK; strcpy(pc8RemoteVersionNumber, "999.999.999"); //init value - err = errMeshOtaUtilFindImageStart(pu8Data, pu32DataLenght, &u32StartOffset); //get image start offset + err = errMeshOtaUtilFindImageStart(cpu8Data, cpcu32DataLenght, &u32StartOffset); //get image start offset if(err == ESP_OK) { //image found - strncpy(pc8RemoteVersionNumber, pu8Data+(u32StartOffset+48), 11); //copy version number + strncpy(pc8RemoteVersionNumber, cpu8Data+(u32StartOffset+48), 11); //copy version number pc8RemoteVersionNumber[12] = '\0'; } return err; } -esp_err_t errMeshOtaUtilFindImageStart(const char* pu8Data, uint32_t* pu32DataLenght, uint32_t* pu32StartOffset) +esp_err_t errMeshOtaUtilFindImageStart(const char* const cpu8Data, const uint32_t* const cpcu32DataLenght, uint32_t* const cpu32StartOffset) { /* Offset value @@ -67,20 +67,20 @@ esp_err_t errMeshOtaUtilFindImageStart(const char* pu8Data, uint32_t* pu32DataLe uint8_t u8FirstDotIndex = 0; uint8_t u8SecondDotIndex = 0; - *pu32StartOffset = 0U; //reset offset to zero + *cpu32StartOffset = 0U; //reset offset to zero - while((u32DataIndex < *pu32DataLenght) && (bImageStartOffsetFound == false)) + while((u32DataIndex < *cpcu32DataLenght) && (bImageStartOffsetFound == false)) { //search for magic byte - if(pu8Data[u32DataIndex] == 0xe9) + if(cpu8Data[u32DataIndex] == 0xe9) { //magic byte found while ((u8FirstDotIndex < 3) && (u32FirstDotOffset == 0)) { //search first dot in version number - if((u32DataIndex+49+u8FirstDotIndex) < *pu32DataLenght) + if((u32DataIndex+49+u8FirstDotIndex) < *cpcu32DataLenght) { - if((pu8Data[(u32DataIndex+49+u8FirstDotIndex)] == 0x2e)) + if((cpu8Data[(u32DataIndex+49+u8FirstDotIndex)] == 0x2e)) { //first dot found u32FirstDotOffset = (u32DataIndex+49+u8FirstDotIndex); @@ -92,9 +92,9 @@ esp_err_t errMeshOtaUtilFindImageStart(const char* pu8Data, uint32_t* pu32DataLe while ((u8SecondDotIndex < 3) && (u32SecondDotOffset == 0) && (u32FirstDotOffset != 0)) { //search first dot in version number - if((u32FirstDotOffset+(u8SecondDotIndex+2)) < *pu32DataLenght) + if((u32FirstDotOffset+(u8SecondDotIndex+2)) < *cpcu32DataLenght) { - if((pu8Data[(u32FirstDotOffset+(u8SecondDotIndex+2))] == 0x2e)) + if((cpu8Data[(u32FirstDotOffset+(u8SecondDotIndex+2))] == 0x2e)) { //second dot found u32SecondDotOffset = (u32FirstDotOffset+(u8SecondDotIndex+2)); @@ -106,7 +106,7 @@ esp_err_t errMeshOtaUtilFindImageStart(const char* pu8Data, uint32_t* pu32DataLe if((u32FirstDotOffset != 0) && (u32SecondDotOffset != 0)) { //image start found based on magic byte and version number systax - *pu32StartOffset = u32DataIndex; //store image start offset + *cpu32StartOffset = u32DataIndex; //store image start offset bImageStartOffsetFound = true; } else @@ -129,7 +129,7 @@ esp_err_t errMeshOtaUtilFindImageStart(const char* pu8Data, uint32_t* pu32DataLe return errReturn; } -esp_err_t errMeshOtaUtilSendOTAVersionRequest(mesh_addr_t* pMeshReceiverAddr) +esp_err_t errMeshOtaUtilSendOTAVersionRequest(const mesh_addr_t* const cpcMeshReceiverAddr) { esp_err_t err = ESP_OK; MESH_PACKET_t packet; @@ -141,11 +141,11 @@ esp_err_t errMeshOtaUtilSendOTAVersionRequest(mesh_addr_t* pMeshReceiverAddr) pBootPartition = esp_ota_get_boot_partition(); //get boot partition (that will booted after reset), not the running partition ERROR_CHECK(esp_ota_get_partition_description(pBootPartition, &bootPartitionDesc)); //get metadate of partition memcpy(&packet.au8Payload, &bootPartitionDesc.version, 12); //copy local version to OTA_Version_Request packet - err = errMeshNetworkSendMeshPacket(pMeshReceiverAddr, &packet); + err = errMeshNetworkSendMeshPacket(cpcMeshReceiverAddr, &packet); return err; } -esp_err_t errMeshOtaUtilSendOTAVersionResponse(mesh_addr_t* pMeshReceiverAddr) +esp_err_t errMeshOtaUtilSendOTAVersionResponse(const mesh_addr_t* const cpcMeshReceiverAddr) { esp_err_t err = ESP_OK; MESH_PACKET_t packet; @@ -158,34 +158,34 @@ esp_err_t errMeshOtaUtilSendOTAVersionResponse(mesh_addr_t* pMeshReceiverAddr) ERROR_CHECK(esp_ota_get_partition_description(pBootPartition, &bootPartitionDesc)); //get metadate of partition memcpy(&packet.au8Payload, &bootPartitionDesc.version, 12); //copy local version to OTA_Version_Response packet - ESP_LOGI(LOG_TAG, "Send OTA_Version_Response to 0x%x", pMeshReceiverAddr->addr[5]); + ESP_LOGI(LOG_TAG, "Send OTA_Version_Response to 0x%x", cpcMeshReceiverAddr->addr[5]); - err = errMeshNetworkSendMeshPacket(pMeshReceiverAddr, &packet); + err = errMeshNetworkSendMeshPacket(cpcMeshReceiverAddr, &packet); return err; } -void vMeshOtaUtilPrintOTAProgress(const uint32_t* const pu32TotalImageSize, const uint32_t* const pu32BytesWritten, OTA_MESH_ROLE_t eRole) +void vMeshOtaUtilPrintOTAProgress(const uint32_t* const cpcu32TotalImageSize, const uint32_t* const cpcu32BytesWritten, const OTA_MESH_ROLE_t ceRole) { uint32_t u32Percentage = 0U; static uint32_t u32LastPercentage = 0U; - if((*pu32BytesWritten) >= (*pu32TotalImageSize)) + if((*cpcu32BytesWritten) >= (*cpcu32TotalImageSize)) { u32Percentage = 100; } else { - u32Percentage = (uint32_t) (((float) (*pu32BytesWritten)/(float) (*pu32TotalImageSize)) * 100.0); + u32Percentage = (uint32_t) (((float) (*cpcu32BytesWritten)/(float) (*cpcu32TotalImageSize)) * 100.0); } if((u32Percentage-u32LastPercentage) >= OTA_PROGRESS_LOG_INTERVAL) { - if(eRole == Transmitter) + if(ceRole == Transmitter) { ESP_LOGI(LOG_TAG, "Transmitting OTA update: %i %%", u32Percentage); } - if(eRole == Receiver) + if(ceRole == Receiver) { ESP_LOGI(LOG_TAG, "Receiving OTA update: %i %%", u32Percentage); } @@ -223,31 +223,31 @@ void vMeshOtaUtilAddAllNeighboursToQueue(void) } } -void vMeshOtaUtilClearOtaMessageQueue(mesh_addr_t* pMeshNodeAddr) +void vMeshOtaUtilClearOtaMessageQueue(const mesh_addr_t* const cpcMeshNodeAddr) { MESH_PACKET_t sMeshPacket; //packet for sending and receiving for (uint32_t u32Index = 0; (u32Index < QUEUE_MESSAGE_OTA_SIZE); u32Index++) //loop through all OTA messages { if (xQueueReceive(queueMessageOTA, &sMeshPacket, 0) == pdTRUE) { - if(!(bMeshNetworkCheckMACEquality(sMeshPacket.meshSenderAddr.addr, pMeshNodeAddr->addr))) + if(!(bMeshNetworkCheckMACEquality(sMeshPacket.meshSenderAddr.addr, cpcMeshNodeAddr->addr))) { - //received OTA message is NOT from pMeshNodeAddr --> keep it in queue + //received OTA message is NOT from cpcMeshNodeAddr --> keep it in queue vMeshOtaUtilAddOtaMessageToQueue(&sMeshPacket); } else { - ESP_LOGI(LOG_TAG, "Removed type %i from node 0x%x", sMeshPacket.type, pMeshNodeAddr->addr[5]); + ESP_LOGI(LOG_TAG, "Removed type %i from node 0x%x", sMeshPacket.type, cpcMeshNodeAddr->addr[5]); } } }//end OTA message loop } -void vMeshOtaUtilAddNodeToPossibleUpdatableQueue(uint8_t* pu8MAC) +void vMeshOtaUtilAddNodeToPossibleUpdatableQueue(const uint8_t* const cpcu8MAC) { //send payload to node queues mesh_addr_t addrNode; - memcpy(&addrNode.addr, (uint8_t *)pu8MAC, 6); //copy MAC + memcpy(&addrNode.addr, (uint8_t *)cpcu8MAC, 6); //copy MAC if (xQueueSend(queueNodes, &addrNode, portMAX_DELAY) != pdPASS) { @@ -259,26 +259,26 @@ void vMeshOtaUtilAddNodeToPossibleUpdatableQueue(uint8_t* pu8MAC) } } -void vMeshOtaUtilAddOtaMessageToQueue(MESH_PACKET_t* puMeshPacket) +void vMeshOtaUtilAddOtaMessageToQueue(const MESH_PACKET_t* const cpcuMeshPacket) { //send ota packet to packet queue - if (xQueueSend(queueMessageOTA, puMeshPacket, portMAX_DELAY) != pdPASS) + if (xQueueSend(queueMessageOTA, cpcuMeshPacket, portMAX_DELAY) != pdPASS) { ESP_LOGE(LOG_TAG, "Unable to push ota packet into packet queue"); } else { - switch (puMeshPacket->type) + switch (cpcuMeshPacket->type) { case OTA_Abort: - ESP_LOGI(LOG_TAG, "added ota message to queue: OTA_Abort from 0x%x", puMeshPacket->meshSenderAddr.addr[5]); + ESP_LOGI(LOG_TAG, "added ota message to queue: OTA_Abort from 0x%x", cpcuMeshPacket->meshSenderAddr.addr[5]); break; case OTA_Version_Request: - ESP_LOGI(LOG_TAG, "added ota message to queue: OTA_Version_Request from 0x%x", puMeshPacket->meshSenderAddr.addr[5]); + ESP_LOGI(LOG_TAG, "added ota message to queue: OTA_Version_Request from 0x%x", cpcuMeshPacket->meshSenderAddr.addr[5]); break; case OTA_Version_Response: - ESP_LOGI(LOG_TAG, "added ota message to queue: OTA_Version Response from 0x%x", puMeshPacket->meshSenderAddr.addr[5]); + ESP_LOGI(LOG_TAG, "added ota message to queue: OTA_Version Response from 0x%x", cpcuMeshPacket->meshSenderAddr.addr[5]); break; default: break; @@ -286,15 +286,15 @@ void vMeshOtaUtilAddOtaMessageToQueue(MESH_PACKET_t* puMeshPacket) } } -void vMeshOtaUtilChangeStateOfServerWorker(bool bState) //allow access via function ptn to networl_handler +void vMeshOtaUtilChangeStateOfServerWorker(const bool cbState) //allow access via function ptn to network_handler { static bool bLastState = false; - if(bState != bLastState) //change only if necessary + if(cbState != bLastState) //change only if necessary { ESP_LOGI(LOG_TAG, "server worker change handler"); - if(bState == true) + if(cbState == true) { if (xSemaphoreGive(bsStartStopServerWorker) != pdTRUE) { @@ -308,6 +308,6 @@ void vMeshOtaUtilChangeStateOfServerWorker(bool bState) //allow access via funct ESP_LOGE(LOG_TAG, "Unable to obtain mutex to deactivate the server worker"); } } - bLastState = bState; + bLastState = cbState; } } diff --git a/components/mesh_ota/include/HTTPS_Client.h b/components/mesh_ota/include/HTTPS_Client.h index 91baafd..f4411f9 100644 --- a/components/mesh_ota/include/HTTPS_Client.h +++ b/components/mesh_ota/include/HTTPS_Client.h @@ -57,12 +57,12 @@ struct HTTPS_Client typedef int32_t https_client_ret_t; typedef struct HTTPS_Client HTTPS_Client_t; -https_client_ret_t errHTTPSClientInitialize(); -https_client_ret_t errHTTPSClientConnectToServer(); -https_client_ret_t errHTTPSClientValidateServer(); -https_client_ret_t errHTTPSClientSendRequest(); -https_client_ret_t errHTTPSClientRetrieveData(char* pu8Data, uint32_t* pu32DataLenght, uint32_t* pu32BytesRead); -https_client_ret_t errHTTPSClientReset(); +https_client_ret_t errHTTPSClientInitialize(void); +https_client_ret_t errHTTPSClientConnectToServer(void); +https_client_ret_t errHTTPSClientValidateServer(void); +https_client_ret_t errHTTPSClientSendRequest(void); +https_client_ret_t errHTTPSClientRetrieveData(char* const cpu8Data, const uint32_t* const cpcu32DataLenght, uint32_t* pu32BytesRead); +https_client_ret_t errHTTPSClientReset(void); #endif /* H_HTTPS_CLIENT */ diff --git a/components/mesh_ota/include/Mesh_Network.h b/components/mesh_ota/include/Mesh_Network.h index 5a550bb..e8d2789 100644 --- a/components/mesh_ota/include/Mesh_Network.h +++ b/components/mesh_ota/include/Mesh_Network.h @@ -79,31 +79,31 @@ typedef struct meshPacket MESH_PACKET_t; extern bool bIsMeshConnected; extern int32_t i32MeshLayer; extern mesh_addr_t meshParentAddr; -extern esp_netif_t* netif_sta; +extern esp_netif_t* pNetifSta; extern uint8_t u8ownMAC[6]; -extern void (*pOTAChildConnectHandle)(uint8_t* ); -extern void (*pChangeStateOfServerWorkerHandle)(bool ); +extern void (*pOTAChildConnectHandle)(const uint8_t* const); +extern void (*pChangeStateOfServerWorkerHandle)(const bool ); esp_err_t errMeshNetworkInitialize(void); esp_err_t errMeshNetworkInitializeWiFi(void); esp_err_t errMeshNetworkInitializeRouter(mesh_cfg_t* cfg); -esp_err_t errMeshNetworkSetChildConnectedHandle(void (*pChildConnectHandleTmp)(uint8_t * pu8Data)); -esp_err_t errMeshNetworkSetAppReceiveHandle(void (*pAppRxHandleTmp)(uint8_t * pu8Data, uint8_t* pu8Sender)); -esp_err_t errMeshNetworkSetOTAMessageHandleHandle(void (*pOTAMessageHandleTmp)(MESH_PACKET_t* puMeshPacket)); -esp_err_t errMeshNetworkSetChangeStateOfServerWorkerHandle(void (*pChangeStateOfServerWorkerHandleTmp)(bool bState)); +esp_err_t errMeshNetworkSetChildConnectedHandle(void (*pChildConnectHandleTmp)(const uint8_t* const cpcu8Data)); +esp_err_t errMeshNetworkSetAppReceiveHandle(void (*pAppRxHandleTmp)(const uint8_t* const cpcu8Data, const uint8_t* const cpcu8Sender)); +esp_err_t errMeshNetworkSetOTAMessageHandleHandle(void (*pOTAMessageHandleTmp)(const MESH_PACKET_t* const cpcuMeshPacket)); +esp_err_t errMeshNetworkSetChangeStateOfServerWorkerHandle(void (*pChangeStateOfServerWorkerHandleTmp)(const bool cbState)); bool bMeshNetworkIsRootNode(void); -bool bMeshNetworkIsNodeNeighbour(mesh_addr_t* pNode); -bool bMeshNetworkCheckMACEquality(uint8_t* pu8aMAC, uint8_t* pu8bMAC); +bool bMeshNetworkIsNodeNeighbour(const mesh_addr_t* const cpcNode); +bool bMeshNetworkCheckMACEquality(const uint8_t* const cpcu8aMAC, const uint8_t* const cpcu8bMAC); esp_err_t errMeshNetworkStartReceiveTask(void); -esp_err_t errMeshNetworkGetParentNode(mesh_addr_t* pMeshParentAddr); -esp_err_t errMeshNetworkGetChildren(mesh_addr_t* pChildren, uint16_t* pu16ChildrenSize); -esp_err_t errMeshNetworkSendMeshPacket(mesh_addr_t* pAddrDest, MESH_PACKET_t* pPacket); +esp_err_t errMeshNetworkGetParentNode(mesh_addr_t* const cpMeshParentAddr); +esp_err_t errMeshNetworkGetChildren(mesh_addr_t* const cpChildren, uint16_t* const cpu16ChildrenSize); +esp_err_t errMeshNetworkSendMeshPacket(const mesh_addr_t* const cpcAddrDest, const MESH_PACKET_t* const cpcPacket); void vMeshNetworkTaskReceiveMeshData(void *arg); -void vMeshNetworkGetOwnAddr(mesh_addr_t* pMeshOwnAddr); +void vMeshNetworkGetOwnAddr(mesh_addr_t* const cpMeshOwnAddr); void vMeshNetworkIpEventHandler(void *arg, esp_event_base_t event_base, int32_t i32EventID, void *vpEventData); void vMeshNetworkMeshEventHandler(void *arg, esp_event_base_t event_base, int32_t i32EventID, void* vpEventData); diff --git a/components/mesh_ota/include/Mesh_OTA.h b/components/mesh_ota/include/Mesh_OTA.h index d087b2c..eab5377 100644 --- a/components/mesh_ota/include/Mesh_OTA.h +++ b/components/mesh_ota/include/Mesh_OTA.h @@ -35,7 +35,7 @@ void vMeshOtaTaskServerWorker(void *arg); void vMeshOtaTaskOTAWorker(void *arg); //OTA process endpoints -esp_err_t errMeshOtaSlaveEndpoint(bool* pbNewOTAImage); -esp_err_t errMeshOtaMasterEndpoint(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr); +esp_err_t errMeshOtaSlaveEndpoint(bool* const cpbNewOTAImage); +esp_err_t errMeshOtaMasterEndpoint(bool* const cpbNewOTAImage, const mesh_addr_t* const cpcMeshNodeAddr); #endif /* H_MESH_OTA */ diff --git a/components/mesh_ota/include/Mesh_OTA_Partition_Access.h b/components/mesh_ota/include/Mesh_OTA_Partition_Access.h index f161338..c64a154 100644 --- a/components/mesh_ota/include/Mesh_OTA_Partition_Access.h +++ b/components/mesh_ota/include/Mesh_OTA_Partition_Access.h @@ -20,8 +20,8 @@ } \ } \ -esp_err_t errMeshOtaPartitionAccessHttps(bool* pbNewOTAImage); -esp_err_t errMeshOtaPartitionAccessMeshTransmit(mesh_addr_t* pMeshNodeAddr); -esp_err_t errMeshOtaPartitionAccessMeshReceive(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr); +esp_err_t errMeshOtaPartitionAccessHttps(bool* const cpbNewOTAImage); +esp_err_t errMeshOtaPartitionAccessMeshTransmit(const mesh_addr_t* const cpcMeshNodeAddr); +esp_err_t errMeshOtaPartitionAccessMeshReceive(bool* const cpbNewOTAImage, const mesh_addr_t* const cpcMeshNodeAddr); #endif /* H_MESH_OTA_PARTITION_ACCESS */ diff --git a/components/mesh_ota/include/Mesh_OTA_Util.h b/components/mesh_ota/include/Mesh_OTA_Util.h index 11e28ae..dfdeb1d 100644 --- a/components/mesh_ota/include/Mesh_OTA_Util.h +++ b/components/mesh_ota/include/Mesh_OTA_Util.h @@ -18,18 +18,19 @@ enum otaMeshRole typedef enum otaMeshRole OTA_MESH_ROLE_t; //helper functions -bool bMeshOtaUtilNewerVersion(const char* pu8Local, const char* pu8Remote); -esp_err_t errMeshOtaUtilExtractVersionNumber(const char* pu8Data, uint32_t* pu32DataLenght, char* pc8RemoteVersionNumber); -esp_err_t errMeshOtaUtilFindImageStart(const char* pu8Data, uint32_t* pu32DataLenght, uint32_t* pu32StartOffset); -esp_err_t errMeshOtaUtilSendOTAVersionRequest(mesh_addr_t* pMeshReceiverAddr); -esp_err_t errMeshOtaUtilSendOTAVersionResponse(mesh_addr_t* pMeshReceiverAddr); -void vMeshOtaUtilPrintOTAProgress(const uint32_t* const cpcu32TotalImageSize, const uint32_t* const cpcu32BytesWritten, OTA_MESH_ROLE_t eRole); +bool bMeshOtaUtilNewerVersion(const char* cpu8Local, const char* cpu8Remote); +esp_err_t errMeshOtaUtilExtractVersionNumber(const char* cpu8Data, uint32_t* const cpu32DataLenght, char* const pc8RemoteVersionNumber); +esp_err_t errMeshOtaUtilFindImageStart(const char* const cpu8Data, const uint32_t* const cpu32DataLenght, uint32_t* const cpu32StartOffset); +esp_err_t errMeshOtaUtilSendOTAVersionRequest(const mesh_addr_t* const cpcMeshReceiverAddr); +esp_err_t errMeshOtaUtilSendOTAVersionResponse(const mesh_addr_t* const cpcMeshReceiverAddr); +void vMeshOtaUtilPrintOTAProgress(const uint32_t* const cpcu32TotalImageSize, const uint32_t* const cpcu32BytesWritten, const OTA_MESH_ROLE_t ceRole); void vMeshOtaUtilAddAllNeighboursToQueue(void); -void vMeshOtaUtilClearOtaMessageQueue(mesh_addr_t* pMeshNodeAddr); +void vMeshOtaUtilClearOtaMessageQueue(const mesh_addr_t* const cpcMeshNodeAddr); //Handler -void vMeshOtaUtilAddNodeToPossibleUpdatableQueue(uint8_t* pu8MAC); -void vMeshOtaUtilAddOtaMessageToQueue(MESH_PACKET_t* puMeshPacket); -void vMeshOtaUtilChangeStateOfServerWorker(bool bState); +void vMeshOtaUtilAddNodeToPossibleUpdatableQueue(const uint8_t* const cpcu8MAC); +void vMeshOtaUtilAddOtaMessageToQueue(const MESH_PACKET_t* const cpcuMeshPacket); +void vMeshOtaUtilChangeStateOfServerWorker(const bool cbState); #endif /* H_MESH_OTA_UTIL */ + diff --git a/main/Blinky_LED.c b/main/Blinky_LED.c index 475b8f2..3366ca9 100644 --- a/main/Blinky_LED.c +++ b/main/Blinky_LED.c @@ -62,7 +62,7 @@ void vGPIOInitialize() gpio_config(&gpioConf); } -void rxHandle(uint8_t* pu8Data, uint8_t* pu8Sender) +void rxHandle(const uint8_t* const pu8Data, const uint8_t* const pu8Sender) { //send payload to app queue BLINKY_PACKET_t bTmpPacket; diff --git a/main/Blinky_LED.h b/main/Blinky_LED.h index a807322..aec6683 100644 --- a/main/Blinky_LED.h +++ b/main/Blinky_LED.h @@ -31,7 +31,7 @@ typedef struct blinky_packet BLINKY_PACKET_t; esp_err_t errBlinkyLEDInitialize(); void vGPIOInitialize(); -void rxHandle(uint8_t* pu8Data, uint8_t* pu8Sender); +void rxHandle(const uint8_t* const pu8Data, const uint8_t* const pu8Sender); void vTaskReadUserInput(void *arg); void vTaskReceiveData(void *arg); From b29887e0ac2442a2b75c2c92f19e3ea7de3e02a6 Mon Sep 17 00:00:00 2001 From: localhorst Date: Wed, 20 Jan 2021 23:04:18 +0100 Subject: [PATCH 18/21] added allow reboot define and clear node from node queue after successfully ota process --- components/mesh_ota/Mesh_OTA.c | 14 ++++++++++---- components/mesh_ota/Mesh_OTA_Globals.c | 2 +- components/mesh_ota/Mesh_OTA_Util.c | 21 +++++++++++++++++++++ components/mesh_ota/include/Mesh_OTA.h | 1 + components/mesh_ota/include/Mesh_OTA_Util.h | 1 + 5 files changed, 34 insertions(+), 5 deletions(-) diff --git a/components/mesh_ota/Mesh_OTA.c b/components/mesh_ota/Mesh_OTA.c index 63aac6a..37ff690 100644 --- a/components/mesh_ota/Mesh_OTA.c +++ b/components/mesh_ota/Mesh_OTA.c @@ -157,11 +157,11 @@ void vMeshOtaTaskOTAWorker(void *arg) //nodes queue is empty ESP_LOGI(LOG_TAG, "nodes queue is empty"); - if(bWantReboot == true) + if((bWantReboot == true) && (OTA_ALLOW_REBOOT == 1)) { - //ESP_LOGI(LOG_TAG, "ESP32 Reboot ..."); - //vTaskDelay( (1000) / portTICK_PERIOD_MS); - //esp_restart(); + ESP_LOGE(LOG_TAG, "ESP32 Reboot ..."); + vTaskDelay( (1000) / portTICK_PERIOD_MS); + esp_restart(); } ERROR_CHECK(errMeshOtaSlaveEndpoint(&bNewOTAImage)); @@ -184,6 +184,11 @@ void vMeshOtaTaskOTAWorker(void *arg) //OTA process faild --> add back to queue vMeshOtaUtilAddNodeToPossibleUpdatableQueue(meshNodeAddr.addr); } + else + { + vMeshOtaUtilClearNeighboursQueue(&meshNodeAddr); //remove this node from queue + } + } if(bNewOTAImage == true) @@ -191,6 +196,7 @@ void vMeshOtaTaskOTAWorker(void *arg) //set want reboot ESP_LOGI(LOG_TAG, "Updated successfully via Mesh, set pending reboot"); bWantReboot = true; + vMeshOtaUtilAddAllNeighboursToQueue(); //add all existing neighbours to queue } vTaskDelay( (1000) / portTICK_PERIOD_MS); diff --git a/components/mesh_ota/Mesh_OTA_Globals.c b/components/mesh_ota/Mesh_OTA_Globals.c index 88bda4f..ab74a46 100644 --- a/components/mesh_ota/Mesh_OTA_Globals.c +++ b/components/mesh_ota/Mesh_OTA_Globals.c @@ -7,7 +7,7 @@ SemaphoreHandle_t bsStartStopServerWorker; //binary semaphore SemaphoreHandle_t bsOTAProcess; //binary semaphore //w: errMeshOTAInitialize; -//r: errMeshOTAInitialize; errMeshOtaPartitionAccessHttps; errMeshOtaPartitionAccessMeshReceive; +//r: errMeshOTAInitialize; errMeshOtaPartitionAccessHttps; errMeshOtaPartitionAccessMeshReceive; const esp_partition_t* pOTAPartition; //pointer to ota partition //w: errMeshOTAInitialize; vMeshOtaTaskOTAWorker; vMeshOtaTaskServerWorker diff --git a/components/mesh_ota/Mesh_OTA_Util.c b/components/mesh_ota/Mesh_OTA_Util.c index c43b016..eba303b 100644 --- a/components/mesh_ota/Mesh_OTA_Util.c +++ b/components/mesh_ota/Mesh_OTA_Util.c @@ -243,6 +243,27 @@ void vMeshOtaUtilClearOtaMessageQueue(const mesh_addr_t* const cpcMeshNodeAddr) }//end OTA message loop } +void vMeshOtaUtilClearNeighboursQueue(const mesh_addr_t* const cpcMeshNodeAddr) +{ + mesh_addr_t sNode; //packet for sending and receiving + for (uint32_t u32Index = 0; (u32Index < QUEUE_MESSAGE_OTA_SIZE); u32Index++) //loop through all OTA messages + { + if (xQueueReceive(queueNodes, &sNode, 0) == pdTRUE) + { + if(!(bMeshNetworkCheckMACEquality(sNode.addr, cpcMeshNodeAddr->addr))) + { + //node is NOT cpcMeshNodeAddr --> keep it in queue + vMeshOtaUtilAddNodeToPossibleUpdatableQueue(cpcMeshNodeAddr->addr); + } + else + { + ESP_LOGI(LOG_TAG, "Removed node 0x%x", cpcMeshNodeAddr->addr[5]); + } + } + }//end OTA message loop +} + + void vMeshOtaUtilAddNodeToPossibleUpdatableQueue(const uint8_t* const cpcu8MAC) { //send payload to node queues diff --git a/components/mesh_ota/include/Mesh_OTA.h b/components/mesh_ota/include/Mesh_OTA.h index eab5377..c15b537 100644 --- a/components/mesh_ota/include/Mesh_OTA.h +++ b/components/mesh_ota/include/Mesh_OTA.h @@ -18,6 +18,7 @@ #define OTA_PROGRESS_LOG_INTERVAL 7U #define OTA_MESH_SEGMENT_SIZE MESH_NETWORK_PAYLOAD_SIZE #define OTA_MESH_TIMEOUT 20000U //in ms +#define OTA_ALLOW_REBOOT 0 #define ERROR_CHECK(x) if (err == ESP_OK) \ { \ diff --git a/components/mesh_ota/include/Mesh_OTA_Util.h b/components/mesh_ota/include/Mesh_OTA_Util.h index dfdeb1d..2518282 100644 --- a/components/mesh_ota/include/Mesh_OTA_Util.h +++ b/components/mesh_ota/include/Mesh_OTA_Util.h @@ -26,6 +26,7 @@ esp_err_t errMeshOtaUtilSendOTAVersionResponse(const mesh_addr_t* const cpcMeshR void vMeshOtaUtilPrintOTAProgress(const uint32_t* const cpcu32TotalImageSize, const uint32_t* const cpcu32BytesWritten, const OTA_MESH_ROLE_t ceRole); void vMeshOtaUtilAddAllNeighboursToQueue(void); void vMeshOtaUtilClearOtaMessageQueue(const mesh_addr_t* const cpcMeshNodeAddr); +void vMeshOtaUtilClearNeighboursQueue(const mesh_addr_t* const cpcMeshNodeAddr); //Handler void vMeshOtaUtilAddNodeToPossibleUpdatableQueue(const uint8_t* const cpcu8MAC); From f3749b99853257754fa698205e4714c68ec54d46 Mon Sep 17 00:00:00 2001 From: localhorst Date: Thu, 21 Jan 2021 00:01:27 +0100 Subject: [PATCH 19/21] added doxygen --- components/mesh_ota/HTTPS_Client.c | 92 +++++++++++++++++++--- components/mesh_ota/Mesh_Network.c | 73 ++++++++++++++++- components/mesh_ota/Mesh_Network_Handler.c | 31 ++++++++ components/mesh_ota/include/HTTPS_Client.h | 10 +++ main/Blinky_LED.c | 66 +++++++++++++++- main/Blinky_LED.h | 13 ++- 6 files changed, 269 insertions(+), 16 deletions(-) diff --git a/components/mesh_ota/HTTPS_Client.c b/components/mesh_ota/HTTPS_Client.c index cc83b4d..02f0155 100644 --- a/components/mesh_ota/HTTPS_Client.c +++ b/components/mesh_ota/HTTPS_Client.c @@ -1,3 +1,13 @@ +/** +* @file HTTPS_Client.c +* @brief Used to download the OTA image from the server +* @author Hendrik Schutter +* @date 20.01.2021 +* +* Additional Infos: Connects via HTTPS and HTTPS Basic Auth to the Server. +* Downloads the image in segments +*/ + #include "HTTPS_Client.h" static const char *TAG = "https_client"; @@ -17,6 +27,16 @@ https_client_ret_t errHTTPSClientConnectToServer(void); https_client_ret_t errHTTPSClientValidateServer(void); https_client_ret_t errHTTPSClientSendRequest(void); +/** +* @fn https_client_ret_t errHTTPSClientInitialize(void) +* @brief Initialize the client +* @param void +* @return HTTPS_Client error code +* @author Hendrik Schutter +* @date 20.01.2021 +* +* Initialize embedTLS +*/ https_client_ret_t errHTTPSClientInitialize(void) { https_client_ret_t i32RetHTTPClient = HTTPS_CLIENT_OK; @@ -31,6 +51,18 @@ https_client_ret_t errHTTPSClientInitialize(void) return i32RetHTTPClient; } +/** +* @fn https_client_ret_t errHTTPSClientRetrieveData(char* const cpu8Data, const uint32_t* const cpcu32DataLenght, uint32_t* pu32BytesRead) +* @brief receive a image segment from server +* @param cpu8Data data buffer +* @param cpcu32DataLenght desired byte amount +* @param pu32BytesRead actual received byte amount +* @return HTTPS_Client error code +* @author Hendrik Schutter +* @date 20.01.2021 +* +* Read segement and handle all events like EOF or timeout +*/ https_client_ret_t errHTTPSClientRetrieveData(char* const cpu8Data, const uint32_t* const cpcu32DataLenght, uint32_t* pu32BytesRead) { https_client_ret_t i32RetHTTPClient = HTTPS_CLIENT_OK; @@ -86,6 +118,16 @@ https_client_ret_t errHTTPSClientRetrieveData(char* const cpu8Data, const uint32 return i32RetHTTPClient; } +/** +* @fn https_client_ret_t errHTTPSClientReset(void) +* @brief reset client for next receive of image +* @param void +* @return HTTPS_Client error code +* @author Hendrik Schutter +* @date 20.01.2021 +* +* reset session +*/ https_client_ret_t errHTTPSClientReset(void) { https_client_ret_t i32RetHTTPClient = HTTPS_CLIENT_OK; @@ -103,9 +145,18 @@ https_client_ret_t errHTTPSClientReset(void) return i32RetHTTPClient; } +/** +* @fn https_client_ret_t https_clientInitEmbedTLS(void) +* @brief init embedTLS +* @param void +* @return HTTPS_Client error code +* @author Hendrik Schutter +* @date 20.01.2021 +* +* attach certs for tls +*/ https_client_ret_t https_clientInitEmbedTLS(void) { - https_client_ret_t i32RetHTTPClient = HTTPS_CLIENT_OK; int32_t i32RetEmbedTLS = ESP_OK; static bool bAlreadySetup = false; @@ -168,20 +219,13 @@ https_client_ret_t https_clientInitEmbedTLS(void) i32RetEmbedTLS = mbedtls_ssl_setup(&sHTTPS_ClientConfig.ssl, &sHTTPS_ClientConfig.conf); //call this only once if(i32RetEmbedTLS != ESP_OK) { - ESP_LOGE(TAG, "mbedtls_ssl_setup returned 0x%x\n\n", i32RetEmbedTLS); - - // uint8_t buffer[20]; - //mbedtls_strerror(i32RetEmbedTLS, buffer, 20); - //ESP_LOGE(TAG, "%s", buffer); + ESP_LOGE(TAG, "mbedtls_ssl_setup returned 0x%x\n", i32RetEmbedTLS); } else { bAlreadySetup = true; } - } - - } if(i32RetEmbedTLS == ESP_OK) @@ -197,6 +241,16 @@ https_client_ret_t https_clientInitEmbedTLS(void) return i32RetHTTPClient; } +/** +* @fn https_client_ret_t errHTTPSClientConnectToServer(void) +* @brief connect to server +* @param void +* @return HTTPS_Client error code +* @author Hendrik Schutter +* @date 20.01.2021 +* +* open TLS session +*/ https_client_ret_t errHTTPSClientConnectToServer(void) { https_client_ret_t i32RetHTTPClient = HTTPS_CLIENT_OK; @@ -230,6 +284,16 @@ https_client_ret_t errHTTPSClientConnectToServer(void) return i32RetHTTPClient; } +/** +* @fn https_client_ret_t errHTTPSClientValidateServer(void) +* @brief validate server +* @param void +* @return HTTPS_Client error code +* @author Hendrik Schutter +* @date 20.01.2021 +* +* check CDN and cert +*/ https_client_ret_t errHTTPSClientValidateServer(void) { https_client_ret_t i32RetHTTPClient = HTTPS_CLIENT_OK; @@ -248,6 +312,16 @@ https_client_ret_t errHTTPSClientValidateServer(void) return i32RetHTTPClient; } +/** +* @fn https_client_ret_t errHTTPSClientSendRequest(void) +* @brief send request to server +* @param void +* @return HTTPS_Client error code +* @author Hendrik Schutter +* @date 20.01.2021 +* +* send HTTP GET request +*/ https_client_ret_t errHTTPSClientSendRequest(void) { https_client_ret_t i32RetHTTPClient = HTTPS_CLIENT_OK; diff --git a/components/mesh_ota/Mesh_Network.c b/components/mesh_ota/Mesh_Network.c index 74e69e3..74ebcfc 100644 --- a/components/mesh_ota/Mesh_Network.c +++ b/components/mesh_ota/Mesh_Network.c @@ -1,9 +1,16 @@ +/** +* @file Mesh_Network.c +* @brief Mesh network layer used by OTA and APP +* @author Hendrik Schutter, init based in ESP32-IDE code +* @date 20.01.2021 +* +* Additional Infos: Start network and send and receive data. +*/ #include "Mesh_Network.h" static const char *LOG_TAG = "mesh_network"; - //w: errMeshNetworkInitialize //r: errMeshNetworkInitialize;vMeshNetworkGetOwnAddr;errMeshNetworkGetChildren uint8_t u8ownMAC[6]; @@ -30,7 +37,17 @@ void (*pOTAChildConnectHandle)(const uint8_t* const); void (*pOTAMessageHandle)(const MESH_PACKET_t* const); void (*pChangeStateOfServerWorkerHandle)(const bool ); -esp_err_t errMeshNetworkInitialize() +/** +* @fn esp_err_t errMeshNetworkInitialize() +* @brief Starts the mesh network +* @param void +* @return ESP32 error code +* @author Hendrik Schutter, init based in ESP32-IDE code +* @date 20.01.2021 +* +* Initialize the network +*/ +esp_err_t errMeshNetworkInitialize(void) { //init module variables esp_err_t err; @@ -107,6 +124,16 @@ esp_err_t errMeshNetworkInitialize() return ESP_OK; } +/** +* @fn esp_err_t errMeshNetworkInitializeWiFi() +* @brief Starts the WiFI +* @param void +* @return ESP32 error code +* @author Hendrik Schutter, init based in ESP32-IDE code +* @date 20.01.2021 +* +* start the wifi +*/ esp_err_t errMeshNetworkInitializeWiFi() { //wifi initialization @@ -119,6 +146,16 @@ esp_err_t errMeshNetworkInitializeWiFi() return err; } +/** +* @fn esp_err_t errMeshNetworkInitializeRouter(mesh_cfg_t* cfg) +* @brief Starts the router +* @param cfg router config +* @return ESP32 error code +* @author Hendrik Schutter, init based in ESP32-IDE code +* @date 20.01.2021 +* +* Initialize the network +*/ esp_err_t errMeshNetworkInitializeRouter(mesh_cfg_t* cfg) { //router initialization @@ -131,24 +168,56 @@ esp_err_t errMeshNetworkInitializeRouter(mesh_cfg_t* cfg) return err; } +/** +* @fn esp_err_t errMeshNetworkSetChildConnectedHandle(void (*pChildConnectHandleTmp)(const uint8_t* const cpcu8Data)) +* @brief set callback for event when child connects +* @param (*pChildConnectHandleTmp)(const uint8_t* const cpcu8Data) function pointer +* @return ESP32 error code +* @author Hendrik Schutter +* @date 20.01.2021 +*/ esp_err_t errMeshNetworkSetChildConnectedHandle(void (*pChildConnectHandleTmp)(const uint8_t* const cpcu8Data)) { pOTAChildConnectHandle = pChildConnectHandleTmp; return ESP_OK; } +/** +* @fn esp_err_t errMeshNetworkSetAppReceiveHandle(void (*pAppRxHandleTmp)(const uint8_t* const cpcu8Data, const uint8_t* const pu8Sender)) +* @brief set callback for event when application data is received +* @param (*pAppRxHandleTmp)(const uint8_t* const cpcu8Data, const uint8_t* const pu8Sender) function pointer +* @return ESP32 error code +* @author Hendrik Schutter +* @date 20.01.2021 +*/ esp_err_t errMeshNetworkSetAppReceiveHandle(void (*pAppRxHandleTmp)(const uint8_t* const cpcu8Data, const uint8_t* const pu8Sender)) { pAppRxHandle = pAppRxHandleTmp; //set handle from app as receive handle if an app packet is received return ESP_OK; } +/** +* @fn esp_err_t errMeshNetworkSetOTAMessageHandleHandle(void (*pOTAMessageHandleTmp)(const MESH_PACKET_t* const cpcuMeshPacket)) +* @brief set callback for event when OTA message is received +* @param (*pOTAMessageHandleTmp)(const MESH_PACKET_t* const cpcuMeshPacket) function pointer +* @return ESP32 error code +* @author Hendrik Schutter +* @date 20.01.2021 +*/ esp_err_t errMeshNetworkSetOTAMessageHandleHandle(void (*pOTAMessageHandleTmp)(const MESH_PACKET_t* const cpcuMeshPacket)) { pOTAMessageHandle = pOTAMessageHandleTmp; return ESP_OK; } +/** +* @fn esp_err_t errMeshNetworkSetChangeStateOfServerWorkerHandle(void (*pChangeStateOfServerWorkerHandleTmp)(const bool cbState)) +* @brief set callback for event when connectify to server is changed +* @param (*pChangeStateOfServerWorkerHandleTmp)(const bool cbState) function pointer +* @return ESP32 error code +* @author Hendrik Schutter +* @date 20.01.2021 +*/ esp_err_t errMeshNetworkSetChangeStateOfServerWorkerHandle(void (*pChangeStateOfServerWorkerHandleTmp)(const bool cbState)) { pChangeStateOfServerWorkerHandle = pChangeStateOfServerWorkerHandleTmp; diff --git a/components/mesh_ota/Mesh_Network_Handler.c b/components/mesh_ota/Mesh_Network_Handler.c index 73dacd9..5f71897 100644 --- a/components/mesh_ota/Mesh_Network_Handler.c +++ b/components/mesh_ota/Mesh_Network_Handler.c @@ -1,8 +1,28 @@ +/** +* @file Mesh_Network_Handler.c +* @brief Handler for events from mesh network (no messages) +* @author Hendrik Schutter +* @date 20.01.2021 +* +* Additional Infos: IP event received or parrent or child connected or disconnected +*/ + #include "Mesh_Network.h" static const char *LOG_TAG = "mesh_network_handler"; +/** +* @fn void vMeshNetworkIpEventHandler(void *arg, esp_event_base_t event_base, int32_t i32EventID, void *vpEventData) +* @brief received an IP event +* @param arg +* @param event_base +* @param i32EventID +* @param vpEventData +* @return void +* @author ESP-IDF +* @date 20.01.2021 +*/ void vMeshNetworkIpEventHandler(void *arg, esp_event_base_t event_base, int32_t i32EventID, void *vpEventData) { ip_event_got_ip_t *event = (ip_event_got_ip_t *) vpEventData; @@ -13,6 +33,17 @@ void vMeshNetworkIpEventHandler(void *arg, esp_event_base_t event_base, int32_t } } +/** +* @fn void vMeshNetworkMeshEventHandler(void *arg, esp_event_base_t event_base, int32_t i32EventID, void* vpEventData) +* @brief received an mesh event +* @param arg +* @param event_base +* @param i32EventID +* @param vpEventData +* @return void +* @author ESP-IDF +* @date 20.01.2021 +*/ void vMeshNetworkMeshEventHandler(void *arg, esp_event_base_t event_base, int32_t i32EventID, void* vpEventData) { mesh_addr_t id = {0,}; diff --git a/components/mesh_ota/include/HTTPS_Client.h b/components/mesh_ota/include/HTTPS_Client.h index f4411f9..091b91e 100644 --- a/components/mesh_ota/include/HTTPS_Client.h +++ b/components/mesh_ota/include/HTTPS_Client.h @@ -1,3 +1,13 @@ +/** +* @file HTTPS_Client.h +* @brief Used to download the OTA image from the server +* @author Hendrik Schutter +* @date 20.01.2021 +* +* Additional Infos: Connects via HTTPS and HTTPS Basic Auth to the Server. +* Downloads the image in segments +*/ + #ifndef H_HTTPS_CLIENT #define H_HTTPS_CLIENT diff --git a/main/Blinky_LED.c b/main/Blinky_LED.c index 3366ca9..a7ce7a9 100644 --- a/main/Blinky_LED.c +++ b/main/Blinky_LED.c @@ -1,13 +1,32 @@ +/** +* @file Blinky_LED.c +* @brief Demo application using the mesh network +* @author Hendrik Schutter +* @date 20.01.2021 +* +* Additional Infos: If button "BOOT" on ESP32-Module is pressed, all LED2 (blue) in the network will toggle the state. +*/ + #include "Blinky_LED.h" static const char *LOG_TAG = "blinky_led"; static bool bLEDisOn = false; //set led default off -static mesh_addr_t addrParent; //addr of parent node +static mesh_addr_t addrParent; //addr of parent node static mesh_addr_t childrenAddr[CONFIG_MESH_ROUTE_TABLE_SIZE]; //array of children attached to this node static uint16_t u16ChildrenSize; //number of children attached to this node xQueueHandle queueBlinkyLEDPackets; //handle for led action queue -esp_err_t errBlinkyLEDInitialize() +/** +* @fn esp_err_t errBlinkyLEDInitialize() +* @brief Starts the demp app +* @param void +* @return ESP32 error code +* @author Hendrik Schutter +* @date 20.01.2021 +* +* Initialize the queue and starts the tasks +*/ +esp_err_t errBlinkyLEDInitialize(void) { esp_err_t err = ESP_OK; BaseType_t xReturned; @@ -45,7 +64,17 @@ esp_err_t errBlinkyLEDInitialize() return err; } -void vGPIOInitialize() +/** +* @fn void vGPIOInitialize(void) +* @brief sets the GPIO pins to correct modes +* @param void +* @return void +* @author Hendrik Schutter +* @date 20.01.2021 +* +* Initialize GPIO +*/ +void vGPIOInitialize(void) { gpio_config_t gpioConf; @@ -62,6 +91,17 @@ void vGPIOInitialize() gpio_config(&gpioConf); } +/** +* @fn void rxHandle(const uint8_t* const pu8Data, const uint8_t* const pu8Sender) +* @brief callback handler from mesh network layer +* @param pu8Data data received +* @param pu8Sender sender node from data +* @return void +* @author Hendrik Schutter +* @date 20.01.2021 +* +* Adds the data into queue +*/ void rxHandle(const uint8_t* const pu8Data, const uint8_t* const pu8Sender) { //send payload to app queue @@ -74,6 +114,16 @@ void rxHandle(const uint8_t* const pu8Data, const uint8_t* const pu8Sender) } } +/** +* @fn void vTaskReadUserInput(void *arg) +* @brief FreeRTOS task reading the user input (button) +* @param args parameter for task +* @return void +* @author Hendrik Schutter +* @date 20.01.2021 +* +* Adds a button press to the queue +*/ void vTaskReadUserInput(void *arg) { esp_err_t err = ESP_OK; @@ -129,6 +179,16 @@ void vTaskReadUserInput(void *arg) } } +/** +* @fn void vTaskReceiveData(void *arg) +* @brief FreeRTOS task reading queue and setting the LED +* @param args parameter for task +* @return void +* @author Hendrik Schutter +* @date 20.01.2021 +* +* Sets the LED off or on based on data in queue +*/ void vTaskReceiveData(void *arg) { esp_err_t err = ESP_OK; diff --git a/main/Blinky_LED.h b/main/Blinky_LED.h index aec6683..c25cf04 100644 --- a/main/Blinky_LED.h +++ b/main/Blinky_LED.h @@ -1,3 +1,12 @@ +/** +* @file Blinky_LED.h +* @brief Demo application using the mesh network +* @author Hendrik Schutter +* @date 20.01.2021 +* +* Additional Infos: If button "BOOT" on ESP32-Module is pressed, all LED2 (blue) in the network will toggle the state. +*/ + #ifndef H_BLINKY_LED #define H_BLINKY_LED @@ -29,8 +38,8 @@ struct blinky_packet typedef struct blinky_packet BLINKY_PACKET_t; -esp_err_t errBlinkyLEDInitialize(); -void vGPIOInitialize(); +esp_err_t errBlinkyLEDInitialize(void); +void vGPIOInitialize(void); void rxHandle(const uint8_t* const pu8Data, const uint8_t* const pu8Sender); void vTaskReadUserInput(void *arg); void vTaskReceiveData(void *arg); From 7fe1f189856084a6e7eff3d466641c24fd275e85 Mon Sep 17 00:00:00 2001 From: localhorst Date: Thu, 21 Jan 2021 11:11:37 +0100 Subject: [PATCH 20/21] added all doxygen comments --- components/mesh_ota/HTTPS_Client.c | 2 +- components/mesh_ota/Mesh_Network.c | 81 ++++++++- components/mesh_ota/Mesh_OTA.c | 96 ++++++++--- components/mesh_ota/Mesh_OTA_Globals.c | 7 + .../mesh_ota/Mesh_OTA_Partition_Access.c | 128 ++++++++------ components/mesh_ota/Mesh_OTA_Util.c | 163 ++++++++++++++---- components/mesh_ota/include/Mesh_Network.h | 9 + components/mesh_ota/include/Mesh_OTA.h | 7 + .../mesh_ota/include/Mesh_OTA_Globals.h | 8 + .../include/Mesh_OTA_Partition_Access.h | 10 ++ components/mesh_ota/include/Mesh_OTA_Util.h | 7 + 11 files changed, 406 insertions(+), 112 deletions(-) diff --git a/components/mesh_ota/HTTPS_Client.c b/components/mesh_ota/HTTPS_Client.c index 02f0155..e42bb56 100644 --- a/components/mesh_ota/HTTPS_Client.c +++ b/components/mesh_ota/HTTPS_Client.c @@ -56,7 +56,7 @@ https_client_ret_t errHTTPSClientInitialize(void) * @brief receive a image segment from server * @param cpu8Data data buffer * @param cpcu32DataLenght desired byte amount -* @param pu32BytesRead actual received byte amount +* @param pu32BytesRead actual received byte amount * @return HTTPS_Client error code * @author Hendrik Schutter * @date 20.01.2021 diff --git a/components/mesh_ota/Mesh_Network.c b/components/mesh_ota/Mesh_Network.c index 74ebcfc..2b39185 100644 --- a/components/mesh_ota/Mesh_Network.c +++ b/components/mesh_ota/Mesh_Network.c @@ -224,6 +224,15 @@ esp_err_t errMeshNetworkSetChangeStateOfServerWorkerHandle(void (*pChangeStateOf return ESP_OK; } +/** +* @fn esp_err_t errMeshNetworkSendMeshPacket(const mesh_addr_t* const cpcAddrDest, const MESH_PACKET_t* const cpcPacket) +* @brief send packet to mesh node +* @param cpcAddrDest address from mesh node +* @param cpcPacket packet to send +* @return ESP32 error code +* @author Hendrik Schutter +* @date 20.01.2021 +*/ esp_err_t errMeshNetworkSendMeshPacket(const mesh_addr_t* const cpcAddrDest, const MESH_PACKET_t* const cpcPacket) { esp_err_t err; @@ -240,11 +249,27 @@ esp_err_t errMeshNetworkSendMeshPacket(const mesh_addr_t* const cpcAddrDest, con return err; } -bool bMeshNetworkIsRootNode() +/** +* @fn bool bMeshNetworkIsRootNode() +* @brief return true if this node is the root +* @param void +* @return boolean +* @author Hendrik Schutter +* @date 21.01.2021 +*/ +bool bMeshNetworkIsRootNode(void) { return esp_mesh_is_root(); } +/** +* @fn bool bMeshNetworkIsNodeNeighbour(const mesh_addr_t* const cpcNode) +* @brief return true if node is neighbour if this +* @param cpcNode to check +* @return boolean +* @author Hendrik Schutter +* @date 21.01.2021 +*/ bool bMeshNetworkIsNodeNeighbour(const mesh_addr_t* const cpcNode) { esp_err_t err = ESP_OK; @@ -280,7 +305,16 @@ bool bMeshNetworkIsNodeNeighbour(const mesh_addr_t* const cpcNode) return bReturn; } -//returns true if MAC address is equal + +/** +* @fn bool bMeshNetworkCheckMACEquality(const uint8_t* const cpcu8aMAC, const uint8_t* const cpcu8bMAC) +* @brief returns true if MAC address is equal +* @param cpcu8aMAC first MAC +* @param cpcu8bMAC second MAC +* @return boolean +* @author Hendrik Schutter +* @date 21.01.2021 +*/ bool bMeshNetworkCheckMACEquality(const uint8_t* const cpcu8aMAC, const uint8_t* const cpcu8bMAC) { bool bRet = true; @@ -306,7 +340,15 @@ bool bMeshNetworkCheckMACEquality(const uint8_t* const cpcu8aMAC, const uint8_t* return bRet; } -esp_err_t errMeshNetworkStartReceiveTask() +/** +* @fn esp_err_t errMeshNetworkStartReceiveTask() +* @brief start the task to receive the mesh packets +* @param void +* @return ESP32 error code +* @author Hendrik Schutter +* @date 21.01.2021 +*/ +esp_err_t errMeshNetworkStartReceiveTask(void) { esp_err_t err = ESP_OK; BaseType_t xReturned; @@ -320,11 +362,28 @@ esp_err_t errMeshNetworkStartReceiveTask() return err; } +/** +* @fn vMeshNetworkGetOwnAddr(mesh_addr_t* const cpMeshOwnAddr) +* @brief return own MAC addr +* @param cpMeshOwnAddr pointer to own mac +* @return void +* @author Hendrik Schutter +* @date 21.01.2021 +*/ void vMeshNetworkGetOwnAddr(mesh_addr_t* const cpMeshOwnAddr) { memcpy(cpMeshOwnAddr->addr, u8ownMAC, 6); } +/** +* @fn esp_err_t errMeshNetworkGetChildren(mesh_addr_t* const cpChildren, uint16_t* const cpu16ChildrenSize) +* @brief get all connected children to node in array +* @param cpChildren pointer to array +* @param cpu16ChildrenSize pointer to size of array +* @return ESP32 error code +* @author Hendrik Schutter +* @date 21.01.2021 +*/ esp_err_t errMeshNetworkGetChildren(mesh_addr_t* const cpChildren, uint16_t* const cpu16ChildrenSize) { esp_err_t err = ESP_OK; @@ -349,6 +408,14 @@ esp_err_t errMeshNetworkGetChildren(mesh_addr_t* const cpChildren, uint16_t* con return err; } +/** +* @fn void vMeshNetworkTaskReceiveMeshData(void *arg) +* @brief Task to receive all mesh packets +* @param arg +* @return void +* @author Hendrik Schutter +* @date 21.01.2021 +*/ void vMeshNetworkTaskReceiveMeshData(void *arg) { esp_err_t err; @@ -398,6 +465,14 @@ void vMeshNetworkTaskReceiveMeshData(void *arg) } //end while } +/** +* @fn esp_err_t errMeshNetworkGetParentNode(mesh_addr_t* const cpMeshParentAddr) +* @brief get parrent node if connected to it +* @param cpMeshParentAddr pointer to parent node addrs +* @return ESP32 error code +* @author Hendrik Schutter +* @date 21.01.2021 +*/ esp_err_t errMeshNetworkGetParentNode(mesh_addr_t* const cpMeshParentAddr) { esp_err_t err = ESP_OK; diff --git a/components/mesh_ota/Mesh_OTA.c b/components/mesh_ota/Mesh_OTA.c index 37ff690..4a8a35f 100644 --- a/components/mesh_ota/Mesh_OTA.c +++ b/components/mesh_ota/Mesh_OTA.c @@ -1,3 +1,10 @@ +/** +* @file Mesh_OTA.c +* @brief Start and implement OTA updates via HTTPS from server and other mesh nodes (bidirectional) +* @author Hendrik Schutter +* @date 21.01.2021 +*/ + #include "Mesh_OTA.h" #include "Mesh_OTA_Util.h" #include "Mesh_OTA_Globals.h" @@ -5,7 +12,18 @@ static const char *LOG_TAG = "mesh_ota"; -esp_err_t errMeshOTAInitialize() +/** +* @fn esp_err_t errMeshOTAInitialize(void) +* @brief Starts Mesh OTA functionality +* @param void +* @return ESP32 error code +* @author Hendrik Schutter +* @date 21.01.2021 +* +* Initialize queues and tasks +* Set callbacks +*/ +esp_err_t errMeshOTAInitialize(void) { esp_err_t err = ESP_OK; BaseType_t xReturned; @@ -15,7 +33,7 @@ esp_err_t errMeshOTAInitialize() queueNodes = xQueueCreate(QUEUE_NODES_SIZE, sizeof(mesh_addr_t)); if (queueNodes == 0) // Queue not created { - ESP_LOGE(LOG_TAG, "Unable to create Queue for Nodes"); + ESP_LOGE(LOG_TAG, "Unable to create queue for nodes"); err = ESP_FAIL; } @@ -25,7 +43,7 @@ esp_err_t errMeshOTAInitialize() queueMessageOTA = xQueueCreate(QUEUE_MESSAGE_OTA_SIZE, sizeof(MESH_PACKET_t)); if (queueMessageOTA == 0) // Queue not created { - ESP_LOGE(LOG_TAG, "Unable to create Queue for OTA Messages"); + ESP_LOGE(LOG_TAG, "Unable to create queue for OTA messages"); err = ESP_FAIL; } } @@ -35,7 +53,7 @@ esp_err_t errMeshOTAInitialize() bsStartStopServerWorker = xSemaphoreCreateBinary(); if( bsStartStopServerWorker == NULL ) { - ESP_LOGE(LOG_TAG, "Unable to create Mutex to represent state of Server worker"); + ESP_LOGE(LOG_TAG, "Unable to create mutex to represent state of server worker"); err = ESP_FAIL; } } @@ -45,7 +63,7 @@ esp_err_t errMeshOTAInitialize() bsOTAProcess = xSemaphoreCreateBinary(); if( bsOTAProcess == NULL ) { - ESP_LOGE(LOG_TAG, "Unable to create Mutex to grant access to OTA Process"); + ESP_LOGE(LOG_TAG, "Unable to create mutex to grant access to OTA process"); err = ESP_FAIL; } } @@ -55,11 +73,12 @@ esp_err_t errMeshOTAInitialize() xSemaphoreGive(bsOTAProcess); //unlock binary semaphore if( bsOTAProcess == NULL ) { - ESP_LOGE(LOG_TAG, "Unable to unlock Mutex to grant access to OTA Process"); + ESP_LOGE(LOG_TAG, "Unable to unlock mutex to grant access to OTA process"); err = ESP_FAIL; } } + //register callbacks in network ERROR_CHECK(errMeshNetworkSetChildConnectedHandle(vMeshOtaUtilAddNodeToPossibleUpdatableQueue)); ERROR_CHECK(errMeshNetworkSetOTAMessageHandleHandle(vMeshOtaUtilAddOtaMessageToQueue)); ERROR_CHECK(errMeshNetworkSetChangeStateOfServerWorkerHandle(vMeshOtaUtilChangeStateOfServerWorker)); @@ -99,9 +118,17 @@ esp_err_t errMeshOTAInitialize() return err; } +/** +* @fn void vMeshOtaTaskServerWorker(void *arg) +* @brief Task for updating from server via HTTPS +* @param arg +* @return void +* @author Hendrik Schutter +* @date 21.01.2021 +*/ void vMeshOtaTaskServerWorker(void *arg) { - esp_err_t err; + esp_err_t err = ESP_OK; bool bNewOTAImage; //true if a new ota image was downloaded and validated bool bFirstRun = true; @@ -118,6 +145,7 @@ void vMeshOtaTaskServerWorker(void *arg) if(bFirstRun == true) { + //init on first run ERROR_CHECK(errHTTPSClientInitialize()); bFirstRun = false; } @@ -141,6 +169,14 @@ void vMeshOtaTaskServerWorker(void *arg) } } +/** +* @fn void vMeshOtaTaskServerWorker(void *arg) +* @brief Task for updating from nodes in mesh network +* @param arg +* @return void +* @author Hendrik Schutter +* @date 21.01.2021 +*/ void vMeshOtaTaskOTAWorker(void *arg) { esp_err_t err = ESP_OK; @@ -155,8 +191,6 @@ void vMeshOtaTaskOTAWorker(void *arg) if((uxQueueSpacesAvailable(queueNodes) - QUEUE_NODES_SIZE) == 0) { //nodes queue is empty - ESP_LOGI(LOG_TAG, "nodes queue is empty"); - if((bWantReboot == true) && (OTA_ALLOW_REBOOT == 1)) { ESP_LOGE(LOG_TAG, "ESP32 Reboot ..."); @@ -169,8 +203,6 @@ void vMeshOtaTaskOTAWorker(void *arg) else { //queue not empty - ESP_LOGI(LOG_TAG, "nodes queue not empty: %i", (QUEUE_NODES_SIZE - uxQueueSpacesAvailable(queueNodes))); - if (xQueueReceive(queueNodes, &meshNodeAddr, ((100) / portTICK_PERIOD_MS)) != pdTRUE) { ESP_LOGE(LOG_TAG, "Unable to receive OTA Messages from Queue"); @@ -188,7 +220,6 @@ void vMeshOtaTaskOTAWorker(void *arg) { vMeshOtaUtilClearNeighboursQueue(&meshNodeAddr); //remove this node from queue } - } if(bNewOTAImage == true) @@ -196,18 +227,28 @@ void vMeshOtaTaskOTAWorker(void *arg) //set want reboot ESP_LOGI(LOG_TAG, "Updated successfully via Mesh, set pending reboot"); bWantReboot = true; - vMeshOtaUtilAddAllNeighboursToQueue(); //add all existing neighbours to queue } vTaskDelay( (1000) / portTICK_PERIOD_MS); } } +/** +* @fn esp_err_t errMeshOtaSlaveEndpoint(bool* const cpbNewOTAImage) +* @brief Endpoint for OTA process that is called from remote node +* @param cpbNewOTAImage pointer to boolean to signal if a new image was successfully received +* @return ESP32 error code +* @author Hendrik Schutter +* @date 21.01.2021 +* +* Answers the OTA_Version_Request with OTA_Version_Response +* calls errMeshOtaPartitionAccessMeshReceive OR errMeshOtaPartitionAccessMeshTransmit based on version number +*/ esp_err_t errMeshOtaSlaveEndpoint(bool* const cpbNewOTAImage) { esp_err_t err = ESP_OK; MESH_PACKET_t sOTAMessage; - const esp_partition_t* pBootPartition; //pointer to boot partition (that will booted after reset) + const esp_partition_t* cpBootPartition = NULL; //pointer to boot partition (that will booted after reset) esp_app_desc_t bootPartitionDesc; //Metadate from boot partition *cpbNewOTAImage = false; //set default false @@ -225,8 +266,8 @@ esp_err_t errMeshOtaSlaveEndpoint(bool* const cpbNewOTAImage) { xSemaphoreTake(bsOTAProcess, portMAX_DELAY); //wait for binary semaphore that allows to start the OTA process - pBootPartition = esp_ota_get_boot_partition(); //get boot partition (that will booted after reset), not the running partition - ERROR_CHECK(esp_ota_get_partition_description(pBootPartition, &bootPartitionDesc)); //get metadata of partition + cpBootPartition = esp_ota_get_boot_partition(); //get boot partition (that will booted after reset), not the running partition + ERROR_CHECK(esp_ota_get_partition_description(cpBootPartition, &bootPartitionDesc)); //get metadata of partition //send OTA_Version_Response to sender of OTA_Version_Request packet wirh version in payload ERROR_CHECK(errMeshOtaUtilSendOTAVersionResponse(&sOTAMessage.meshSenderAddr)); @@ -252,11 +293,23 @@ esp_err_t errMeshOtaSlaveEndpoint(bool* const cpbNewOTAImage) return err; } +/** +* @fn esp_err_t errMeshOtaMasterEndpoint(bool* const cpbNewOTAImage, const mesh_addr_t* const cpcMeshNodeAddr) +* @brief Endpoint for OTA process that calls remote node +* @param cpbNewOTAImage pointer to boolean to signal if a new image was successfully received +* @param cpcMeshNodeAddr pointer to remote node addr +* @return ESP32 error code +* @author Hendrik Schutter +* @date 21.01.2021 +* +* Sends the OTA_Version_Request to remote node +* calls errMeshOtaPartitionAccessMeshReceive OR errMeshOtaPartitionAccessMeshTransmit based on version number received +*/ esp_err_t errMeshOtaMasterEndpoint(bool* const cpbNewOTAImage, const mesh_addr_t* const cpcMeshNodeAddr) { esp_err_t err = ESP_OK; MESH_PACKET_t sOTAMessage; - const esp_partition_t* pBootPartition; //pointer to boot partition (that will booted after reset) + const esp_partition_t* cpBootPartition = NULL; //pointer to boot partition (that will booted after reset) esp_app_desc_t bootPartitionDesc; //Metadata from boot partition bool bNodeIsConnected = false; bool bNodeIsResponding = false; @@ -268,7 +321,6 @@ esp_err_t errMeshOtaMasterEndpoint(bool* const cpbNewOTAImage, const mesh_addr_t bNodeIsConnected = true; //node is one of the neighbours xSemaphoreTake(bsOTAProcess, portMAX_DELAY); //wait for binary semaphore that allows to start the OTA process - ESP_LOGI(LOG_TAG, "Mesh-Master: send Version_Request to 0x%x", cpcMeshNodeAddr->addr[5]); ERROR_CHECK(errMeshOtaUtilSendOTAVersionRequest(cpcMeshNodeAddr)); //send OTA_VERSION_REQUEST with local version in payload for (uint32_t u32Index = 0; u32Index < QUEUE_MESSAGE_OTA_SIZE; u32Index++) //loop through all OTA messages @@ -285,8 +337,8 @@ esp_err_t errMeshOtaMasterEndpoint(bool* const cpbNewOTAImage, const mesh_addr_t if((err == ESP_OK) && (sOTAMessage.type == OTA_Version_Response) && (bMeshNetworkCheckMACEquality(sOTAMessage.meshSenderAddr.addr, cpcMeshNodeAddr->addr))) //if OTA_Version_Request { bNodeIsResponding = true; - pBootPartition = esp_ota_get_boot_partition(); //get boot partition (that will booted after reset), not the running partition - ERROR_CHECK(esp_ota_get_partition_description(pBootPartition, &bootPartitionDesc)); //get metadata of partition + cpBootPartition = esp_ota_get_boot_partition(); //get boot partition (that will booted after reset), not the running partition + ERROR_CHECK(esp_ota_get_partition_description(cpBootPartition, &bootPartitionDesc)); //get metadata of partition if((bMeshOtaUtilNewerVersion((bootPartitionDesc).version, (char*) sOTAMessage.au8Payload)) && (err == ESP_OK)) //compare local and remote version { @@ -313,7 +365,7 @@ esp_err_t errMeshOtaMasterEndpoint(bool* const cpbNewOTAImage, const mesh_addr_t else { // OTA Message queue is empty --> wait some time - ESP_LOGI(LOG_TAG, "OTA-Master: OTA Message queue is empty --> wait some time"); + ESP_LOGD(LOG_TAG, "OTA-Master: OTA Message queue is empty --> wait some time"); vTaskDelay( (1000/QUEUE_MESSAGE_OTA_SIZE) / portTICK_PERIOD_MS); } }//end loop @@ -323,7 +375,7 @@ esp_err_t errMeshOtaMasterEndpoint(bool* const cpbNewOTAImage, const mesh_addr_t if((bNodeIsResponding == false) && (bNodeIsConnected == true)) { //add node back to queue if connected and NOT responding - ESP_LOGI(LOG_TAG, "OTA-Master: connected and NOT responding --> add node back to queue "); + ESP_LOGD(LOG_TAG, "OTA-Master: connected and NOT responding --> add node back to queue "); vMeshOtaUtilAddNodeToPossibleUpdatableQueue(cpcMeshNodeAddr->addr); } return err; diff --git a/components/mesh_ota/Mesh_OTA_Globals.c b/components/mesh_ota/Mesh_OTA_Globals.c index ab74a46..4bf2198 100644 --- a/components/mesh_ota/Mesh_OTA_Globals.c +++ b/components/mesh_ota/Mesh_OTA_Globals.c @@ -1,3 +1,10 @@ +/** +* @file Mesh_OTA_Globals.c +* @brief global variables unsed in Mesh_OTA +* @author Hendrik Schutter +* @date 21.01.2021 +*/ + #include "Mesh_OTA_Globals.h" xQueueHandle queueNodes; //nodes that should be checked for ota update (contains children and parent) diff --git a/components/mesh_ota/Mesh_OTA_Partition_Access.c b/components/mesh_ota/Mesh_OTA_Partition_Access.c index f859e6b..506b2be 100644 --- a/components/mesh_ota/Mesh_OTA_Partition_Access.c +++ b/components/mesh_ota/Mesh_OTA_Partition_Access.c @@ -1,3 +1,13 @@ +/** +* @file Mesh_OTA_Partition_Access.c +* @brief Write and read partition if requested from Mesh_OTA +* @author Hendrik Schutter +* @date 21.01.2021 +* +* Additional Infos: Write image via HTTPS +* Receive or transmit via Mesh +*/ + #include "Mesh_OTA.h" #include "Mesh_OTA_Util.h" #include "Mesh_OTA_Globals.h" @@ -5,6 +15,18 @@ static const char *LOG_TAG = "mesh_ota_partition_access"; +/** +* @fn esp_err_t errMeshOtaPartitionAccessHttps(bool* const cpbNewOTAImage) +* @brief Downloads and writes the image from the server to partition +* @param cpbNewOTAImage pointer to boolean to signal if a new image was successfully received +* @return ESP32 error code +* @author Hendrik Schutter +* @date 21.01.2021 +* +* Checks if the image on server is newer +* Downloads the image in segements +* Handles OTA process +*/ esp_err_t errMeshOtaPartitionAccessHttps(bool* const cpbNewOTAImage) { esp_err_t err = ESP_OK; @@ -22,7 +44,8 @@ esp_err_t errMeshOtaPartitionAccessHttps(bool* const cpbNewOTAImage) ERROR_CHECK(errMeshOtaUtilExtractVersionNumber(u8OTABuffer, &u32BytesRead, pcRemoteVersionNumber)); //extract version numbers - if(err == ESP_OK) //check if version number is found + //check if version number is found + if(err == ESP_OK) { xSemaphoreTake(bsOTAProcess, portMAX_DELAY); //wait for binary semaphore that allows to start the OTA process @@ -35,8 +58,8 @@ esp_err_t errMeshOtaPartitionAccessHttps(bool* const cpbNewOTAImage) ESP_LOGI(LOG_TAG, "Server: image is newer --> OTA update required"); ERROR_CHECK(errMeshOtaUtilFindImageStart(u8OTABuffer, &u32BufferLenght, &u32StartOffset)); //get image start offset - ERROR_CHECK(esp_ota_begin(pOTAPartition, OTA_SIZE_UNKNOWN, &otaHandle)); //start ota update process + if(err == ESP_OK) { //image download and ota partition write @@ -54,7 +77,8 @@ esp_err_t errMeshOtaPartitionAccessHttps(bool* const cpbNewOTAImage) u32OTABytesWritten = u32OTABytesWritten + u32BytesRead; //update counter } } - while ((u32BytesRead > 0) && (err == ESP_OK) && (u32OTABytesWritten <= pOTAPartition->size)); //loop until error or complete image downloaded + //loop until error or complete image downloaded + while ((u32BytesRead > 0) && (err == ESP_OK) && (u32OTABytesWritten <= pOTAPartition->size)); } if(err == ESP_OK) @@ -70,7 +94,7 @@ esp_err_t errMeshOtaPartitionAccessHttps(bool* const cpbNewOTAImage) else { //error occurred --> abort ota update process - ESP_LOGE(LOG_TAG, "abort ota process due to error 0x%x -> %s", err, esp_err_to_name(err)); + ESP_LOGE(LOG_TAG, "abort OTA process due to error 0x%x -> %s", err, esp_err_to_name(err)); ERROR_CHECK(esp_ota_abort(otaHandle)); *cpbNewOTAImage = false; //ota update failed } @@ -84,27 +108,39 @@ esp_err_t errMeshOtaPartitionAccessHttps(bool* const cpbNewOTAImage) return err; } +/** +* @fn esp_err_t errMeshOtaPartitionAccessMeshTransmit(const mesh_addr_t* const cpcMeshNodeAddr) +* @brief Reads the local image and sends it to node +* @param cpcMeshNodeAddr pointer to mesh node addr to send the image segments to +* @return ESP32 error code +* @author Hendrik Schutter +* @date 21.01.2021 +* +* Reads the newest OTA image in segments +* Sends the image to mesh node in segments +* Handles OTA process +*/ esp_err_t errMeshOtaPartitionAccessMeshTransmit(const mesh_addr_t* const cpcMeshNodeAddr) { esp_err_t err = ESP_OK; - const esp_partition_t* pBootPartition; //pointer to boot partition (that will booted after reset) + const esp_partition_t* pBootPartition = NULL; //pointer to boot partition (that will booted after reset) MESH_PACKET_t sMeshPacket; //packet for sending and receiving // uint32_t u32Index = 0U; //index for partition read offset bool bAbort = false; //abort the OTA process bool bNodeIsResponding = false; //remote node is still active - uint32_t u32OTABytesWritten = 0U; - uint32_t u32SegmentCounter = 0U; + uint32_t u32OTABytesWritten = 0U; //counter of bytes unsed for progress log + uint32_t u32SegmentCounter = 0U; //counter of segments unsed for progress log pBootPartition = esp_ota_get_boot_partition(); //get boot partition (that will booted after reset), not the running partition //loop through partition to read in segmensts until end or error or abort called while( ((OTA_MESH_SEGMENT_SIZE * u32SegmentCounter) < pBootPartition->size) && (err == ESP_OK) && (bAbort == false)) { - bNodeIsResponding = false; //reset to default + bNodeIsResponding = false; //reset to default for this loop // read partition with offset based in index ERROR_CHECK(esp_partition_read(pBootPartition, (OTA_MESH_SEGMENT_SIZE * u32SegmentCounter), sMeshPacket.au8Payload, OTA_MESH_SEGMENT_SIZE)); - u32OTABytesWritten = ((u32SegmentCounter+1) * OTA_MESH_SEGMENT_SIZE); + u32OTABytesWritten = ((u32SegmentCounter+1) * OTA_MESH_SEGMENT_SIZE); //calc bytes that are written in this ota process vMeshOtaUtilPrintOTAProgress(&(pBootPartition->size), &u32OTABytesWritten, Transmitter); if(err == ESP_OK) @@ -115,10 +151,9 @@ esp_err_t errMeshOtaPartitionAccessMeshTransmit(const mesh_addr_t* const cpcMesh if((OTA_MESH_SEGMENT_SIZE * (u32SegmentCounter+1)) >= pBootPartition->size) //check if last segment { //last partition image segment --> send OTA_Complete - ESP_LOGI(LOG_TAG, "OTA-TX: last segment--> send Complete"); + ESP_LOGD(LOG_TAG, "OTA-TX: last segment--> send Complete"); sMeshPacket.type = OTA_Complete; } - //ESP_LOGI(LOG_TAG, "OTA-TX: send packet"); err = errMeshNetworkSendMeshPacket(cpcMeshNodeAddr, &sMeshPacket); } else @@ -126,39 +161,35 @@ esp_err_t errMeshOtaPartitionAccessMeshTransmit(const mesh_addr_t* const cpcMesh // error while read --> send OTA_ABORT and abort this OTA process sMeshPacket.type = OTA_Abort; bAbort = true; - ESP_LOGI(LOG_TAG, "OTA-TX: error while read --> send ABORT"); + ESP_LOGE(LOG_TAG, "OTA-TX: error while read --> send ABORT"); errMeshNetworkSendMeshPacket(cpcMeshNodeAddr, &sMeshPacket); } // loop through all OTA messages or until abort is called or error for (uint32_t u32Index = 0; ((u32Index < QUEUE_MESSAGE_OTA_SIZE) && (bAbort == false) && (err == ESP_OK)); u32Index++) //loop through all OTA messages { - // if(uxQueueSpacesAvailable(queueMessageOTA) < QUEUE_MESSAGE_OTA_SIZE) - // { - //queue not empty + //get OTA message from queue if (xQueueReceive(queueMessageOTA, &sMeshPacket, ((OTA_MESH_TIMEOUT) / portTICK_PERIOD_MS)) != pdTRUE) { ESP_LOGE(LOG_TAG, "Unable to receive OTA Messages from queue"); err = ESP_FAIL; } - if((err == ESP_OK) && (bMeshNetworkCheckMACEquality(sMeshPacket.meshSenderAddr.addr, cpcMeshNodeAddr->addr))) //if OTA_Version_Request + //check if from correct node + if((err == ESP_OK) && (bMeshNetworkCheckMACEquality(sMeshPacket.meshSenderAddr.addr, cpcMeshNodeAddr->addr))) { - //packet from node received + //packet from node received --> handle it switch (sMeshPacket.type) { - case OTA_ACK: //increase index for next round - u32Index++; + case OTA_ACK: //start next loop for segment bNodeIsResponding = true; - u32Index = QUEUE_MESSAGE_OTA_SIZE;//this will end the loop through all OTA messages + u32Index = QUEUE_MESSAGE_OTA_SIZE; //this will end the loop through all OTA messages break; case OTA_Abort: //abort this OTA process bAbort = true; bNodeIsResponding = true; break; default: - //receives wrong OTA message type from node --> back to queue - //vMeshOtaUtilAddOtaMessageToQueue(&sMeshPacket); break; } } @@ -167,16 +198,6 @@ esp_err_t errMeshOtaPartitionAccessMeshTransmit(const mesh_addr_t* const cpcMesh //received from wrong node --> back to queue vMeshOtaUtilAddOtaMessageToQueue(&sMeshPacket); } - /* - } - else - { - // OTA Message queue is empty --> wait some time - ESP_LOGI(LOG_TAG, "OTA-TX: ota message queue empty --> wait"); - vTaskDelay( (OTA_MESH_TIMEOUT) / portTICK_PERIOD_MS); - } - */ - }//end OTA message loop if(bNodeIsResponding == false) @@ -188,10 +209,23 @@ esp_err_t errMeshOtaPartitionAccessMeshTransmit(const mesh_addr_t* const cpcMesh } u32SegmentCounter++; }//end of partition segment loop - vMeshOtaUtilClearOtaMessageQueue(cpcMeshNodeAddr); + vMeshOtaUtilClearOtaMessageQueue(cpcMeshNodeAddr); //remove all OTA messages from remote node return err; } +/** +* @fn esp_err_t errMeshOtaPartitionAccessMeshReceive(bool* const cpbNewOTAImage, const mesh_addr_t* const cpcMeshNodeAddr) +* @brief Downloads and writes the image from the remote node +* @param cpbNewOTAImage pointer to boolean to signal if a new image was successfully received +* @param cpcMeshNodeAddr pointer to mesh node addr to receive the image segments from +* @return ESP32 error code +* @author Hendrik Schutter +* @date 21.01.2021 +* +* Receives the images segments from remote node +* Writtes segments to OTA partition +* Handles OTA process +*/ esp_err_t errMeshOtaPartitionAccessMeshReceive(bool* const cpbNewOTAImage, const mesh_addr_t* const cpcMeshNodeAddr) { esp_err_t err = ESP_OK; @@ -201,8 +235,8 @@ esp_err_t errMeshOtaPartitionAccessMeshReceive(bool* const cpbNewOTAImage, const bool bNodeIsResponding = false; //remote node is still active uint32_t u32OTABytesWritten = 0U; //counter unsed for progress log static esp_ota_handle_t otaHandle; //OTA process handle - *cpbNewOTAImage = false; - uint32_t u32SegmentCounter = 0U; + *cpbNewOTAImage = false; //set default to false + uint32_t u32SegmentCounter = 0U; //counter of segments unsed for progress log ERROR_CHECK(esp_ota_begin(pOTAPartition, OTA_SIZE_UNKNOWN, &otaHandle)); //start ota update process @@ -230,24 +264,21 @@ esp_err_t errMeshOtaPartitionAccessMeshReceive(bool* const cpbNewOTAImage, const { case OTA_Complete: //signal end of this OTA process, fall through because same behavior as OTA_Data bComplete = true; - ESP_LOGI(LOG_TAG, "OTA-RX: rec Complete --> last segment"); - //fall through + //fall through case OTA_Data: //data segement received bNodeIsResponding = true; ERROR_CHECK(esp_ota_write(otaHandle, sMeshPacket.au8Payload, OTA_MESH_SEGMENT_SIZE)); - u32OTABytesWritten = ((u32SegmentCounter+1) * OTA_MESH_SEGMENT_SIZE); - vMeshOtaUtilPrintOTAProgress(&(pOTAPartition->size), &u32OTABytesWritten, Receiver); + u32OTABytesWritten = ((u32SegmentCounter+1) * OTA_MESH_SEGMENT_SIZE); //calc bytes that are written in this ota process + vMeshOtaUtilPrintOTAProgress(&(pOTAPartition->size), &u32OTABytesWritten, Receiver); u32Index = QUEUE_MESSAGE_OTA_SIZE; //this will end the loop through all OTA messages break; case OTA_Abort: //abort this OTA process bAbort = true; bNodeIsResponding = true; - ESP_LOGI(LOG_TAG, "OTA-RX: rec Abort"); + ESP_LOGE(LOG_TAG, "OTA-RX: receives abort --> abort this OTA process on this node"); //this will end the loop through all OTA messages break; default: - //receives wrong OTA message type from node --> back to queue - //vMeshOtaUtilAddOtaMessageToQueue(&sMeshPacket); break; } } @@ -256,16 +287,6 @@ esp_err_t errMeshOtaPartitionAccessMeshReceive(bool* const cpbNewOTAImage, const //received from wrong node --> back to queue vMeshOtaUtilAddOtaMessageToQueue(&sMeshPacket); } - - /* } - else - { - ESP_LOGI(LOG_TAG, "OTA-RX: ota message queue empty --> wait"); - // OTA Message queue is empty --> wait some time - vTaskDelay( (OTA_MESH_TIMEOUT) / portTICK_PERIOD_MS); - } - */ - }//end of OTA message loop if(bNodeIsResponding == false) @@ -284,7 +305,6 @@ esp_err_t errMeshOtaPartitionAccessMeshReceive(bool* const cpbNewOTAImage, const if(bAbort == false) { //no error while ota write --> send OTA_ACK packet - //ESP_LOGI(LOG_TAG, "OTA-RX: no error while ota write --> send OTA_ACK packet"); sMeshPacket.type = OTA_ACK; err = errMeshNetworkSendMeshPacket(cpcMeshNodeAddr, &sMeshPacket); } @@ -305,7 +325,7 @@ esp_err_t errMeshOtaPartitionAccessMeshReceive(bool* const cpbNewOTAImage, const { //all OTA segments received --> validate ESP_LOGI(LOG_TAG, "OTA-RX: validate image "); - ERROR_CHECK(esp_ota_end(otaHandle)); + ERROR_CHECK(esp_ota_end(otaHandle)); //validate image ERROR_CHECK(esp_ota_set_boot_partition(pOTAPartition)); if(err == ESP_OK) { diff --git a/components/mesh_ota/Mesh_OTA_Util.c b/components/mesh_ota/Mesh_OTA_Util.c index eba303b..d39a6d0 100644 --- a/components/mesh_ota/Mesh_OTA_Util.c +++ b/components/mesh_ota/Mesh_OTA_Util.c @@ -1,17 +1,32 @@ +/** +* @file Mesh_OTA_Util.c +* @brief Utility and helper functions to perfrom mesh OTA updates +* @author Hendrik Schutter +* @date 21.01.2021 +*/ + #include "Mesh_OTA_Util.h" #include "Mesh_OTA_Globals.h" static const char *LOG_TAG = "mesh_ota"; +/** +* @fn bool bMeshOtaUtilNewerVersion(const char* cpu8Local, const char* cpu8Remote) +* @brief compares to version strings +* @param cpu8Local local image version string +* @param cpu8Remote remote image version string +* @return bool +* @author Hendrik Schutter +* @date 21.01.2021 +* +* Returns true if remote is newer +*/ bool bMeshOtaUtilNewerVersion(const char* cpu8Local, const char* cpu8Remote) { - /* - * Return true if remote version is newer (higher) than local version - */ char u8LocalTmp[12]; //local version char u8RemoteTmp[12]; //remote version - char* pu8saveptrLocal; //context for strok_r - char* pu8saveptrRemote; //context for strok_r + char* pu8saveptrLocal = NULL; //context for strok_r + char* pu8saveptrRemote = NULL; //context for strok_r bool bReturn = false; //flag to stop loop uint8_t u8Index = 0; //numbers counter in version string @@ -34,6 +49,18 @@ bool bMeshOtaUtilNewerVersion(const char* cpu8Local, const char* cpu8Remote) return bReturn; } +/** +* @fn esp_err_t errMeshOtaUtilExtractVersionNumber(const char* cpu8Data, uint32_t* const cpcu32DataLenght, char* const pc8RemoteVersionNumber) +* @brief extract version number from image data +* @param cpu8Data image data buffer +* @param cpcu32DataLenght pointer to lenght of image data +* @param pc8RemoteVersionNumber pointer version number +* @return ESP32 error code +* @author Hendrik Schutters +* @date 21.01.2021 +* +* Search version number in raw image data +*/ esp_err_t errMeshOtaUtilExtractVersionNumber(const char* cpu8Data, uint32_t* const cpcu32DataLenght, char* const pc8RemoteVersionNumber) { uint32_t u32StartOffset; @@ -51,14 +78,25 @@ esp_err_t errMeshOtaUtilExtractVersionNumber(const char* cpu8Data, uint32_t* con return err; } +/** +* @fn esp_err_t errMeshOtaUtilFindImageStart(const char* const cpu8Data, const uint32_t* const cpcu32DataLenght, uint32_t* const cpu32StartOffset) +* @brief find start offset from image raw data +* @param cpu8Data image data buffer +* @param cpcu32DataLenght pointer to lenght of image data +* @param cpu32StartOffset pointer to determined offset +* @return ESP32 error code +* @author Hendrik Schutter +* @date 21.01.2021 +* +* Search offset in raw image data from server (exclude HTTP response) +*/ esp_err_t errMeshOtaUtilFindImageStart(const char* const cpu8Data, const uint32_t* const cpcu32DataLenght, uint32_t* const cpu32StartOffset) { - /* - Offset value - 0 = 0xE9 (first byte in image --> magic byte) - 48 = first digit of version number - */ - + + // Offset value + // 0 = 0xE9 (first byte in image --> magic byte) + // 48 = first digit of version number + esp_err_t errReturn = ESP_OK; bool bImageStartOffsetFound = false; uint32_t u32DataIndex = 0; @@ -129,13 +167,21 @@ esp_err_t errMeshOtaUtilFindImageStart(const char* const cpu8Data, const uint32_ return errReturn; } +/** +* @fn esp_err_t errMeshOtaUtilSendOTAVersionRequest(const mesh_addr_t* const cpcMeshReceiverAddr) +* @brief send OTA_Version_Request to node +* @param cpcMeshReceiverAddr node addr +* @return ESP32 error code +* @author Hendrik Schutter +* @date 21.01.2021 +*/ esp_err_t errMeshOtaUtilSendOTAVersionRequest(const mesh_addr_t* const cpcMeshReceiverAddr) { esp_err_t err = ESP_OK; MESH_PACKET_t packet; packet.type = OTA_Version_Request; - const esp_partition_t* pBootPartition; //pointer to boot partition (that will booted after reset) + const esp_partition_t* pBootPartition = NULL; //pointer to boot partition (that will booted after reset) esp_app_desc_t bootPartitionDesc; //Metadata from boot partition pBootPartition = esp_ota_get_boot_partition(); //get boot partition (that will booted after reset), not the running partition @@ -145,25 +191,43 @@ esp_err_t errMeshOtaUtilSendOTAVersionRequest(const mesh_addr_t* const cpcMeshRe return err; } +/** +* @fn esp_err_t errMeshOtaUtilSendOTAVersionResponse(const mesh_addr_t* const cpcMeshReceiverAddr) +* @brief send OTA_Version_Response to node +* @param cpcMeshReceiverAddr node addr +* @return ESP32 error code +* @author Hendrik Schutter +* @date 21.01.2021 +*/ esp_err_t errMeshOtaUtilSendOTAVersionResponse(const mesh_addr_t* const cpcMeshReceiverAddr) { esp_err_t err = ESP_OK; MESH_PACKET_t packet; packet.type = OTA_Version_Response; - const esp_partition_t* pBootPartition; //pointer to boot partition (that will booted after reset) + const esp_partition_t* pBootPartition = NULL; //pointer to boot partition (that will booted after reset) esp_app_desc_t bootPartitionDesc; //Metadata from boot partition pBootPartition = esp_ota_get_boot_partition(); //get boot partition (that will booted after reset), not the running partition ERROR_CHECK(esp_ota_get_partition_description(pBootPartition, &bootPartitionDesc)); //get metadate of partition memcpy(&packet.au8Payload, &bootPartitionDesc.version, 12); //copy local version to OTA_Version_Response packet - ESP_LOGI(LOG_TAG, "Send OTA_Version_Response to 0x%x", cpcMeshReceiverAddr->addr[5]); + ESP_LOGD(LOG_TAG, "Send OTA_Version_Response to 0x%x", cpcMeshReceiverAddr->addr[5]); err = errMeshNetworkSendMeshPacket(cpcMeshReceiverAddr, &packet); return err; } +/** +* @fn void vMeshOtaUtilPrintOTAProgress(const uint32_t* const cpcu32TotalImageSize, const uint32_t* const cpcu32BytesWritten, const OTA_MESH_ROLE_t ceRole) +* @brief print LOG for OTA process progress +* @param cpcu32TotalImageSize size of OTA partition +* @param cpcu32BytesWritten actual bytes written +* @param ceRole role if this OTA process +* @return void +* @author Hendrik Schutter +* @date 21.01.2021 +*/ void vMeshOtaUtilPrintOTAProgress(const uint32_t* const cpcu32TotalImageSize, const uint32_t* const cpcu32BytesWritten, const OTA_MESH_ROLE_t ceRole) { uint32_t u32Percentage = 0U; @@ -196,6 +260,14 @@ void vMeshOtaUtilPrintOTAProgress(const uint32_t* const cpcu32TotalImageSize, co } } +/** +* @fn void vMeshOtaUtilAddAllNeighboursToQueue(void) +* @brief add all neigbhours (children and parent) to queue +* @param void +* @return void +* @author Hendrik Schutter +* @date 21.01.2021 +*/ void vMeshOtaUtilAddAllNeighboursToQueue(void) { esp_err_t err = ESP_OK; @@ -209,7 +281,6 @@ void vMeshOtaUtilAddAllNeighboursToQueue(void) if(err == ESP_OK) { vMeshOtaUtilAddNodeToPossibleUpdatableQueue(addrParent.addr); - ESP_LOGI(LOG_TAG, "added parent"); } err = ESP_OK; //reset error code @@ -219,10 +290,17 @@ void vMeshOtaUtilAddAllNeighboursToQueue(void) for (uint16_t u16Index = 0; ((u16Index < u16ChildrenSize) && (err == ESP_OK)); u16Index++) { vMeshOtaUtilAddNodeToPossibleUpdatableQueue(childrenAddr[u16Index].addr); - ESP_LOGI(LOG_TAG, "added child"); } } +/** +* @fn void vMeshOtaUtilClearOtaMessageQueue(const mesh_addr_t* const cpcMeshNodeAddr) +* @brief remode all OTA messages from this node in queue +* @param cpcMeshNodeAddr node addr +* @return void +* @author Hendrik Schutter +* @date 21.01.2021 +*/ void vMeshOtaUtilClearOtaMessageQueue(const mesh_addr_t* const cpcMeshNodeAddr) { MESH_PACKET_t sMeshPacket; //packet for sending and receiving @@ -235,14 +313,18 @@ void vMeshOtaUtilClearOtaMessageQueue(const mesh_addr_t* const cpcMeshNodeAddr) //received OTA message is NOT from cpcMeshNodeAddr --> keep it in queue vMeshOtaUtilAddOtaMessageToQueue(&sMeshPacket); } - else - { - ESP_LOGI(LOG_TAG, "Removed type %i from node 0x%x", sMeshPacket.type, cpcMeshNodeAddr->addr[5]); - } } }//end OTA message loop } +/** +* @fn void vMeshOtaUtilClearNeighboursQueue(const mesh_addr_t* const cpcMeshNodeAddr) +* @brief remode all instances of this node in queue +* @param cpcMeshNodeAddr node addr +* @return void +* @author Hendrik Schutter +* @date 21.01.2021 +*/ void vMeshOtaUtilClearNeighboursQueue(const mesh_addr_t* const cpcMeshNodeAddr) { mesh_addr_t sNode; //packet for sending and receiving @@ -255,15 +337,18 @@ void vMeshOtaUtilClearNeighboursQueue(const mesh_addr_t* const cpcMeshNodeAddr) //node is NOT cpcMeshNodeAddr --> keep it in queue vMeshOtaUtilAddNodeToPossibleUpdatableQueue(cpcMeshNodeAddr->addr); } - else - { - ESP_LOGI(LOG_TAG, "Removed node 0x%x", cpcMeshNodeAddr->addr[5]); - } } }//end OTA message loop } - +/** +* @fn void vMeshOtaUtilAddNodeToPossibleUpdatableQueue(const uint8_t* const cpcu8MAC) +* @brief add node instance to queue +* @param cpcu8MAC MAC addr of node +* @return void +* @author Hendrik Schutter +* @date 21.01.2021 +*/ void vMeshOtaUtilAddNodeToPossibleUpdatableQueue(const uint8_t* const cpcu8MAC) { //send payload to node queues @@ -276,10 +361,18 @@ void vMeshOtaUtilAddNodeToPossibleUpdatableQueue(const uint8_t* const cpcu8MAC) } else { - ESP_LOGI(LOG_TAG, "added node \"%x:%x:%x:%x:%x:%x\" to possible updatable queue", addrNode.addr[0], addrNode.addr[1], addrNode.addr[2], addrNode.addr[3], addrNode.addr[4], addrNode.addr[5]); + ESP_LOGD(LOG_TAG, "added node \"%x:%x:%x:%x:%x:%x\" to possible updatable queue", addrNode.addr[0], addrNode.addr[1], addrNode.addr[2], addrNode.addr[3], addrNode.addr[4], addrNode.addr[5]); } } +/** +* @fn void vMeshOtaUtilAddOtaMessageToQueue(const MESH_PACKET_t* const cpcuMeshPacket) +* @brief add OTA message to queue +* @param cpcuMeshPacket OTA message +* @return void +* @author Hendrik Schutter +* @date 21.01.2021 +*/ void vMeshOtaUtilAddOtaMessageToQueue(const MESH_PACKET_t* const cpcuMeshPacket) { //send ota packet to packet queue @@ -292,14 +385,14 @@ void vMeshOtaUtilAddOtaMessageToQueue(const MESH_PACKET_t* const cpcuMeshPacket) switch (cpcuMeshPacket->type) { case OTA_Abort: - ESP_LOGI(LOG_TAG, "added ota message to queue: OTA_Abort from 0x%x", cpcuMeshPacket->meshSenderAddr.addr[5]); + ESP_LOGD(LOG_TAG, "added ota message to queue: OTA_Abort from 0x%x", cpcuMeshPacket->meshSenderAddr.addr[5]); break; case OTA_Version_Request: - ESP_LOGI(LOG_TAG, "added ota message to queue: OTA_Version_Request from 0x%x", cpcuMeshPacket->meshSenderAddr.addr[5]); + ESP_LOGD(LOG_TAG, "added ota message to queue: OTA_Version_Request from 0x%x", cpcuMeshPacket->meshSenderAddr.addr[5]); break; case OTA_Version_Response: - ESP_LOGI(LOG_TAG, "added ota message to queue: OTA_Version Response from 0x%x", cpcuMeshPacket->meshSenderAddr.addr[5]); + ESP_LOGD(LOG_TAG, "added ota message to queue: OTA_Version Response from 0x%x", cpcuMeshPacket->meshSenderAddr.addr[5]); break; default: break; @@ -307,14 +400,20 @@ void vMeshOtaUtilAddOtaMessageToQueue(const MESH_PACKET_t* const cpcuMeshPacket) } } -void vMeshOtaUtilChangeStateOfServerWorker(const bool cbState) //allow access via function ptn to network_handler +/** +* @fn void vMeshOtaUtilChangeStateOfServerWorker(const bool cbState) +* @brief callback for mesh network if connectivity to server changed +* @param cbState boolean state +* @return void +* @author Hendrik Schutter +* @date 21.01.2021 +*/ +void vMeshOtaUtilChangeStateOfServerWorker(const bool cbState) { static bool bLastState = false; if(cbState != bLastState) //change only if necessary { - ESP_LOGI(LOG_TAG, "server worker change handler"); - if(cbState == true) { if (xSemaphoreGive(bsStartStopServerWorker) != pdTRUE) diff --git a/components/mesh_ota/include/Mesh_Network.h b/components/mesh_ota/include/Mesh_Network.h index e8d2789..35b97bb 100644 --- a/components/mesh_ota/include/Mesh_Network.h +++ b/components/mesh_ota/include/Mesh_Network.h @@ -1,3 +1,12 @@ +/** +* @file Mesh_Network.h +* @brief Mesh network layer used by OTA and APP +* @author Hendrik Schutter, init based in ESP32-IDE code +* @date 20.01.2021 +* +* Additional Infos: Start network and send and receive data. +*/ + #ifndef H_MESH_NETWORK #define H_MESH_NETWORK diff --git a/components/mesh_ota/include/Mesh_OTA.h b/components/mesh_ota/include/Mesh_OTA.h index c15b537..c6d7c4d 100644 --- a/components/mesh_ota/include/Mesh_OTA.h +++ b/components/mesh_ota/include/Mesh_OTA.h @@ -1,3 +1,10 @@ +/** +* @file Mesh_OTA.h +* @brief Start and implement OTA updates via HTTPS from server and other mesh nodes (bidirectional) +* @author Hendrik Schutter +* @date 21.01.2021 +*/ + #ifndef H_MESH_OTA #define H_MESH_OTA diff --git a/components/mesh_ota/include/Mesh_OTA_Globals.h b/components/mesh_ota/include/Mesh_OTA_Globals.h index 63f67e3..8ef7ba6 100644 --- a/components/mesh_ota/include/Mesh_OTA_Globals.h +++ b/components/mesh_ota/include/Mesh_OTA_Globals.h @@ -1,3 +1,11 @@ +/** +* @file Mesh_OTA_Globals.h +* @brief global variables unsed in Mesh_OTA +* @author Hendrik Schutter +* @date 21.01.2021 +* +*/ + #ifndef H_MESH_OTA_GLOBALS #define H_MESH_OTA_GLOBALS diff --git a/components/mesh_ota/include/Mesh_OTA_Partition_Access.h b/components/mesh_ota/include/Mesh_OTA_Partition_Access.h index c64a154..103bdf4 100644 --- a/components/mesh_ota/include/Mesh_OTA_Partition_Access.h +++ b/components/mesh_ota/include/Mesh_OTA_Partition_Access.h @@ -1,3 +1,13 @@ +/** +* @file Mesh_OTA_Partition_Access.h +* @brief Write and read partition if requested from Mesh_OTA +* @author Hendrik Schutter +* @date 21.01.2021 +* +* Additional Infos: Write image via HTTPS +* Receive or transmit via Mesh +*/ + #ifndef H_MESH_OTA_PARTITION_ACCESS #define H_MESH_OTA_PARTITION_ACCESS diff --git a/components/mesh_ota/include/Mesh_OTA_Util.h b/components/mesh_ota/include/Mesh_OTA_Util.h index 2518282..77304a6 100644 --- a/components/mesh_ota/include/Mesh_OTA_Util.h +++ b/components/mesh_ota/include/Mesh_OTA_Util.h @@ -1,3 +1,10 @@ +/** +* @file Mesh_OTA_Util.h +* @brief Utility and helper functions to perfrom mesh OTA updates +* @author Hendrik Schutter +* @date 21.01.2021 +*/ + #ifndef H_MESH_OTA_UTIL #define H_MESH_OTA_UTIL From 9600b76a8081e187fb8d52645d89443855a702f6 Mon Sep 17 00:00:00 2001 From: localhorst Date: Thu, 21 Jan 2021 11:43:09 +0100 Subject: [PATCH 21/21] added doxygen file --- Doxyfile | 2580 +++++++++++++++++ components/mesh_ota/Mesh_Network.c | 10 +- components/mesh_ota/Mesh_OTA.c | 10 +- .../mesh_ota/Mesh_OTA_Partition_Access.c | 16 +- components/mesh_ota/Mesh_OTA_Util.c | 20 +- components/mesh_ota/include/Mesh_Network.h | 2 +- components/mesh_ota/include/Mesh_OTA_Util.h | 6 +- main/Blinky_LED.c | 2 +- 8 files changed, 2613 insertions(+), 33 deletions(-) create mode 100644 Doxyfile diff --git a/Doxyfile b/Doxyfile new file mode 100644 index 0000000..7240065 --- /dev/null +++ b/Doxyfile @@ -0,0 +1,2580 @@ +# Doxyfile 1.8.20 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the configuration +# file that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# https://www.gnu.org/software/libiconv/ for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = Mesh_OTA + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = Bachelorarbeit Hendrik Schutter + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = ./Doxygen + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all generated output in the proper direction. +# Possible values are: None, LTR, RTL and Context. +# The default value is: None. + +OUTPUT_TEXT_DIRECTION = None + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line +# such as +# /*************** +# as being the beginning of a Javadoc-style comment "banner". If set to NO, the +# Javadoc-style will behave just like regular comments and it will not be +# interpreted by doxygen. +# The default value is: NO. + +JAVADOC_BANNER = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# By default Python docstrings are displayed as preformatted text and doxygen's +# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the +# doxygen's special commands can be used and the contents of the docstring +# documentation blocks is shown as doxygen documentation. +# The default value is: YES. + +PYTHON_DOCSTRING = YES + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 3 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines (in the resulting output). You can put ^^ in the value part of an +# alias to insert a newline as if a physical newline was in the original file. +# When you need a literal { or } or , in the value part of an alias you have to +# escape them by means of a backslash (\), this can lead to conflicts with the +# commands \{ and \} for these it is advised to use the version @{ and @} or use +# a double escape (\\{ and \\}) + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice +# sources only. Doxygen will then generate output that is more tailored for that +# language. For instance, namespaces will be presented as modules, types will be +# separated into more groups, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_SLICE = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, JavaScript, +# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, VHDL, +# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser +# tries to guess whether the code is fixed or free formatted code, this is the +# default for Fortran type files). For instance to make doxygen treat .inc files +# as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See https://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 5. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 5 + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use +# during processing. When set to 0 doxygen will based this on the number of +# cores available in the system. You can set it explicitly to a value larger +# than 0 to get more control over the balance between CPU load and processing +# speed. At this moment only the input processing can be done using multiple +# threads. Since this is still an experimental feature the default is set to 1, +# which efficively disables parallel processing. Please report any issues you +# encounter. Generating dot graphs in parallel is controlled by the +# DOT_NUM_THREADS setting. +# Minimum value: 0, maximum value: 32, default value: 1. + +NUM_PROC_THREADS = 1 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual +# methods of a class will be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIV_VIRTUAL = NO + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# declarations. If set to NO, these declarations will be included in the +# documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES, upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# (including Cygwin) and Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = YES + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. If +# EXTRACT_ALL is set to YES then this flag will automatically be disabled. +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. +# The default value is: NO. + +WARN_AS_ERROR = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = ./components/mesh_ota/ ./components/mesh_ota/include/ ./main/ + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: https://www.gnu.org/software/libiconv/) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C comment), +# *.doc (to be provided as doxygen C comment), *.txt (to be provided as doxygen +# C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, +# *.vhdl, *.ucf, *.qsf and *.ice. + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.idl \ + *.ddl \ + *.odl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.cs \ + *.d \ + *.php \ + *.php4 \ + *.php5 \ + *.phtml \ + *.inc \ + *.m \ + *.markdown \ + *.md \ + *.mm \ + *.dox \ + *.doc \ + *.txt \ + *.py \ + *.pyw \ + *.f90 \ + *.f95 \ + *.f03 \ + *.f08 \ + *.f18 \ + *.f \ + *.for \ + *.vhd \ + *.vhdl \ + *.ucf \ + *.qsf \ + *.ice + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# entity all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see https://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# https://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = NO + +# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML +# documentation will contain a main index with vertical navigation menus that +# are dynamically created via JavaScript. If disabled, the navigation index will +# consists of multiple levels of tabs that are statically embedded in every HTML +# page. Disable this option to support browsers that do not have JavaScript, +# like the Qt help browser. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_MENUS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: https://developer.apple.com/xcode/), introduced with OSX +# 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy +# genXcode/_index.html for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the main .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = YES + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg +# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see +# https://inkscape.org) to generate formulas as SVG images instead of PNGs for +# the HTML output. These images will generally look nicer at scaled resolutions. +# Possible values are: png (the default) and svg (looks nicer but requires the +# pdf2svg or inkscape tool). +# The default value is: png. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FORMULA_FORMAT = png + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANSPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands +# to create new LaTeX commands to be used in formulas as building blocks. See +# the section "Including formulas" for details. + +FORMULA_MACROFILE = + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# https://www.mathjax.org) which uses client side JavaScript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from https://www.mathjax.org before deployment. +# The default value is: https://cdn.jsdelivr.net/npm/mathjax@2. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = https://cdn.jsdelivr.net/npm/mathjax@2 + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /