added OTA process mutex; progress log; reboot flag
This commit is contained in:
		| @ -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; | ||||
|  | ||||
| @ -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) | ||||
| { | ||||
|  | ||||
| @ -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 */ | ||||
|  | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| @ -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 */ | ||||
|  | ||||
|  | ||||
		Reference in New Issue
	
	Block a user