refactor #2
| @ -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 | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| #include "HTTPS_client.h" | ||||
| #include "HTTPS_Client.h" | ||||
| 
 | ||||
| static const char *TAG = "https_client"; | ||||
| 
 | ||||
| @ -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, }; | ||||
| @ -1,5 +1,5 @@ | ||||
| 
 | ||||
| #include "Mesh_OTA.h" | ||||
| #include "Mesh_Network.h" | ||||
| 
 | ||||
| static const char *LOG_TAG = "mesh_network_handler"; | ||||
| 
 | ||||
| @ -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; | ||||
| } | ||||
|  | ||||
							
								
								
									
										10
									
								
								components/mesh_ota/Mesh_OTA_Globals.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								components/mesh_ota/Mesh_OTA_Globals.c
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||
							
								
								
									
										323
									
								
								components/mesh_ota/Mesh_OTA_Partition_Access.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										323
									
								
								components/mesh_ota/Mesh_OTA_Partition_Access.c
									
									
									
									
									
										Normal file
									
								
							| @ -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; | ||||
| } | ||||
							
								
								
									
										314
									
								
								components/mesh_ota/Mesh_OTA_Util.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										314
									
								
								components/mesh_ota/Mesh_OTA_Util.c
									
									
									
									
									
										Normal file
									
								
							| @ -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; | ||||
| } | ||||
|  | ||||
| @ -5,19 +5,10 @@ | ||||
| #include <stdlib.h> | ||||
| #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" | ||||
| @ -8,7 +8,7 @@ | ||||
| #include "esp_log.h" | ||||
| #include "esp_mesh.h" | ||||
| #include "esp_mesh_internal.h" | ||||
| #include <stdlib.h> | ||||
| #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; | ||||
| @ -1,20 +1,14 @@ | ||||
| #ifndef H_MESH_OTA | ||||
| #define H_MESH_OTA | ||||
|  | ||||
| #include <string.h> | ||||
| #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 */ | ||||
|  | ||||
							
								
								
									
										28
									
								
								components/mesh_ota/include/Mesh_OTA_Access.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								components/mesh_ota/include/Mesh_OTA_Access.h
									
									
									
									
									
										Normal file
									
								
							| @ -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 */ | ||||
							
								
								
									
										19
									
								
								components/mesh_ota/include/Mesh_OTA_Globals.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								components/mesh_ota/include/Mesh_OTA_Globals.h
									
									
									
									
									
										Normal file
									
								
							| @ -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 */ | ||||
							
								
								
									
										35
									
								
								components/mesh_ota/include/Mesh_OTA_Util.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								components/mesh_ota/include/Mesh_OTA_Util.h
									
									
									
									
									
										Normal file
									
								
							| @ -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 */ | ||||
| @ -183,4 +183,4 @@ void vTaskReceiveData(void *arg) | ||||
|                 } | ||||
|             vTaskDelay(200 / portTICK_PERIOD_MS); | ||||
|         } | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -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) | ||||
|  | ||||
|  | ||||
							
								
								
									
										18
									
								
								main/Main.c
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								main/Main.c
									
									
									
									
									
								
							| @ -1,15 +1,9 @@ | ||||
|  | ||||
| #include <string.h> | ||||
| #include "esp_wifi.h" | ||||
| #include <stdio.h> | ||||
| #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(); | ||||
|  | ||||
		Reference in New Issue
	
	Block a user