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 */