2021-01-11 22:56:39 +01:00
# include "Mesh_OTA.h"
2021-01-02 00:30:13 +01:00
2021-01-17 23:27:01 +01:00
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
2021-01-18 19:03:32 +01:00
SemaphoreHandle_t bsOTAProcess ; //binary semaphore
2021-01-17 23:27:01 +01:00
2021-01-18 17:38:08 +01:00
const esp_partition_t * pOTAPartition ; //pointer to ota partition
2021-01-18 19:03:32 +01:00
bool bWantReboot ; //flag to signal pending reboot
2021-01-18 17:38:08 +01:00
2021-01-17 23:27:01 +01:00
esp_err_t errMeshOTAInitialize ( )
{
esp_err_t err = ESP_OK ;
BaseType_t xReturned ;
2021-01-18 19:03:32 +01:00
bWantReboot = false ;
2021-01-17 23:27:01 +01:00
//create queue to store nodes for ota worker task
queueNodes = xQueueCreate ( QUEUE_NODES_SIZE , sizeof ( mesh_addr_t ) ) ;
if ( queueNodes = = 0 ) // Queue not created
{
ESP_LOGE ( LOG_TAG , " Unable to create Queue for Nodes " ) ;
err = ESP_FAIL ;
}
if ( err = = ESP_OK )
{
//create queue to store ota messages
queueMessageOTA = xQueueCreate ( QUEUE_MESSAGE_OTA_SIZE , sizeof ( MESH_PACKET_t ) ) ;
if ( queueMessageOTA = = 0 ) // Queue not created
{
ESP_LOGE ( LOG_TAG , " Unable to create Queue for OTA Messages " ) ;
err = ESP_FAIL ;
}
}
if ( err = = ESP_OK )
{
bsStartStopServerWorker = xSemaphoreCreateBinary ( ) ;
if ( bsStartStopServerWorker = = NULL )
{
ESP_LOGE ( LOG_TAG , " Unable to create Mutex to represent state of Server worker " ) ;
err = ESP_FAIL ;
}
}
2021-01-18 19:03:32 +01:00
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 ;
}
}
2021-01-17 23:27:01 +01:00
ERROR_CHECK ( errMeshNetworkSetChildConnectedHandle ( vAddNodeToPossibleUpdatableQueue ) ) ;
2021-01-20 15:18:22 +01:00
ERROR_CHECK ( errMeshNetworkSetOTAMessageHandleHandle ( vAddOtaMessageToQueue ) ) ;
2021-01-17 23:27:01 +01:00
ERROR_CHECK ( errMeshNetworkSetChangeStateOfServerWorkerHandle ( vChangeStateOfServerWorker ) ) ;
2021-01-18 17:38:08 +01:00
if ( err = = ESP_OK )
{
pOTAPartition = esp_ota_get_next_update_partition ( NULL ) ; //get ota partition
if ( pOTAPartition = = NULL )
{
err = ESP_FAIL ;
ESP_LOGE ( LOG_TAG , " unable to get next ota partition " ) ;
}
}
2021-01-17 23:27:01 +01:00
if ( err = = ESP_OK )
{
2021-01-17 23:47:59 +01:00
xReturned = xTaskCreate ( vTaskServerWorker , " vTaskServerWorker " , 8192 , NULL , 5 , NULL ) ;
2021-01-17 23:27:01 +01:00
if ( xReturned ! = pdPASS )
{
ESP_LOGE ( LOG_TAG , " Unable to create the server worker task " ) ;
err = ESP_FAIL ;
}
}
2021-01-18 22:56:42 +01:00
if ( err = = ESP_OK )
{
xReturned = xTaskCreate ( vTaskOTAWorker , " vTaskOTAWorker " , 8192 , NULL , 5 , NULL ) ;
if ( xReturned ! = pdPASS )
{
ESP_LOGE ( LOG_TAG , " Unable to create the OTA worker task " ) ;
err = ESP_FAIL ;
}
}
2021-01-17 23:27:01 +01:00
return err ;
}
2021-01-18 22:56:42 +01:00
void vAddNodeToPossibleUpdatableQueue ( uint8_t * pu8MAC )
2021-01-17 23:27:01 +01:00
{
2021-01-18 22:56:42 +01:00
//send payload to node queues
2021-01-17 23:27:01 +01:00
mesh_addr_t addrNode ;
2021-01-18 22:56:42 +01:00
memcpy ( & addrNode . addr , ( uint8_t * ) pu8MAC , 6 ) ; //copy MAC
2021-01-17 23:27:01 +01:00
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 ] ) ;
}
}
2021-01-20 15:18:22 +01:00
void vAddOtaMessageToQueue ( MESH_PACKET_t * puMeshPacket )
2021-01-17 23:27:01 +01:00
{
//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
{
2021-01-20 13:43:41 +01:00
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 ;
}
2021-01-17 23:27:01 +01:00
}
}
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 )
{
2021-01-18 12:49:52 +01:00
esp_err_t err ;
2021-01-18 19:03:32 +01:00
bool bNewOTAImage ; //true if a new ota image was downloaded and validated
2021-01-18 17:38:08 +01:00
bool bFirstRun = true ;
2021-01-17 23:47:59 +01:00
2021-01-18 12:49:52 +01:00
while ( true )
{
err = ESP_OK ;
2021-01-18 19:03:32 +01:00
bNewOTAImage = false ;
2021-01-18 12:49:52 +01:00
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
{
2021-01-18 19:03:32 +01:00
ESP_LOGI ( LOG_TAG , " Checking firmware image on server " ) ;
2021-01-18 17:38:08 +01:00
if ( bFirstRun = = true )
{
2021-01-18 19:03:32 +01:00
ERROR_CHECK ( errHTTPSClientInitialize ( ) ) ;
2021-01-18 17:38:08 +01:00
bFirstRun = false ;
}
2021-01-18 12:49:52 +01:00
2021-01-18 19:03:32 +01:00
ERROR_CHECK ( errHTTPSClientConnectToServer ( ) ) ;
ERROR_CHECK ( errHTTPSClientValidateServer ( ) ) ;
ERROR_CHECK ( errHTTPSClientSendRequest ( ) ) ;
2021-01-18 12:49:52 +01:00
2021-01-18 17:38:08 +01:00
ERROR_CHECK ( errOTAHTTPS ( & bNewOTAImage ) ) ;
2021-01-18 19:03:32 +01:00
errHTTPSClientReset ( ) ;
2021-01-18 12:49:52 +01:00
if ( bNewOTAImage = = true )
{
//set want reboot
2021-01-18 19:03:32 +01:00
ESP_LOGI ( LOG_TAG , " Updated successfully via HTTPS, set pending reboot " ) ;
bWantReboot = true ;
2021-01-18 22:56:42 +01:00
vAddAllNeighboursToQueue ( ) ; //add all existing neighbours to queue (aparent will not be added because this node is the root)
2021-01-18 12:49:52 +01:00
}
2021-01-18 22:56:42 +01:00
vTaskDelay ( ( SERVER_CHECK_INTERVAL * 1000 ) / portTICK_PERIOD_MS ) ; //sleep till next server checks
2021-01-18 12:49:52 +01:00
}
}
}
2021-01-19 12:36:21 +01:00
void vTaskOTAWorker ( void * arg )
{
esp_err_t err = ESP_OK ;
bool bNewOTAImage ; //true if a new ota image was downloaded and validated
mesh_addr_t meshNodeAddr ; //node that should be checked for ota update
while ( true )
{
err = ESP_OK ;
bNewOTAImage = false ;
if ( ( uxQueueSpacesAvailable ( queueNodes ) - QUEUE_NODES_SIZE ) = = 0 )
{
//nodes queue is empty
2021-01-20 13:43:41 +01:00
ESP_LOGI ( LOG_TAG , " nodes queue is empty " ) ;
2021-01-19 12:36:21 +01:00
if ( bWantReboot = = true )
{
2021-01-20 11:20:35 +01:00
//ESP_LOGI(LOG_TAG, "ESP32 Reboot ...");
2021-01-19 12:36:21 +01:00
//vTaskDelay( (1000) / portTICK_PERIOD_MS);
//esp_restart();
}
ERROR_CHECK ( errOTAMeshSlave ( & bNewOTAImage ) ) ;
}
else
{
//queue not empty
ESP_LOGI ( LOG_TAG , " nodes queue not empty: %i " , ( QUEUE_NODES_SIZE - uxQueueSpacesAvailable ( queueNodes ) ) ) ;
if ( xQueueReceive ( queueNodes , & meshNodeAddr , ( ( 100 ) / portTICK_PERIOD_MS ) ) ! = pdTRUE )
{
ESP_LOGE ( LOG_TAG , " Unable to receive OTA Messages from Queue " ) ;
err = ESP_FAIL ;
}
ERROR_CHECK ( errOTAMeshMaster ( & bNewOTAImage , & meshNodeAddr ) ) ;
2021-01-19 22:19:30 +01:00
if ( err ! = ESP_OK )
{
//OTA process faild --> add back to queue
vAddNodeToPossibleUpdatableQueue ( meshNodeAddr . addr ) ;
}
2021-01-19 12:36:21 +01:00
}
if ( bNewOTAImage = = true )
{
//set want reboot
ESP_LOGI ( LOG_TAG , " Updated successfully via Mesh, set pending reboot " ) ;
bWantReboot = true ;
vAddAllNeighboursToQueue ( ) ; //add all existing neighbours to queue
}
vTaskDelay ( ( 1000 ) / portTICK_PERIOD_MS ) ;
}
}
2021-01-18 12:49:52 +01:00
esp_err_t errOTAHTTPS ( bool * pbNewOTAImage )
{
2021-01-17 23:47:59 +01:00
esp_err_t err = ESP_OK ;
2021-01-18 17:38:08 +01:00
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
2021-01-18 19:03:32 +01:00
uint32_t u32OTABytesWritten = 0U ; //counter unsed for progress log
2021-01-17 23:27:01 +01:00
2021-01-18 19:03:32 +01:00
ERROR_CHECK ( errHTTPSClientRetrieveData ( u8OTABuffer , & u32BufferLenght , & u32BytesRead ) ) ; //read first bytes if image, including the version
2021-01-17 23:47:59 +01:00
2021-01-18 17:38:08 +01:00
ERROR_CHECK ( errExtractVersionNumber ( u8OTABuffer , & u32BytesRead , pcRemoteVersionNumber ) ) ; //extract version numbers
2021-01-17 23:47:59 +01:00
2021-01-18 17:38:08 +01:00
if ( err = = ESP_OK ) //check if version number is found
2021-01-18 12:49:52 +01:00
{
2021-01-19 12:36:21 +01:00
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
2021-01-18 17:38:08 +01:00
if ( bNewerVersion ( ( bootPartitionDesc ) . version , pcRemoteVersionNumber ) ) //compare local and remote version
2021-01-18 12:49:52 +01:00
{
// server image is newer --> OTA update required
2021-01-19 17:20:16 +01:00
ESP_LOGI ( LOG_TAG , " Server: image is newer --> OTA update required " ) ;
2021-01-18 12:49:52 +01:00
2021-01-18 17:38:08 +01:00
ERROR_CHECK ( errFindImageStart ( u8OTABuffer , & u32BufferLenght , & u32StartOffset ) ) ; //get image start offset
2021-01-17 23:47:59 +01:00
2021-01-18 17:38:08 +01:00
ERROR_CHECK ( esp_ota_begin ( pOTAPartition , OTA_SIZE_UNKNOWN , & otaHandle ) ) ; //start ota update process
2021-01-18 12:49:52 +01:00
if ( err = = ESP_OK )
{
//image download and ota partition write
2021-01-18 19:03:32 +01:00
ESP_LOGI ( LOG_TAG , " start OTA download via HTTPS " ) ;
2021-01-18 12:49:52 +01:00
do
{
2021-01-19 22:19:30 +01:00
vPrintOTAProgress ( & ( pOTAPartition - > size ) , & u32OTABytesWritten , Receiver ) ;
2021-01-18 17:38:08 +01:00
ERROR_CHECK ( esp_ota_write ( otaHandle , ( const void * ) u8OTABuffer + u32StartOffset , ( u32BytesRead - u32StartOffset ) ) ) ;
2021-01-17 23:47:59 +01:00
2021-01-18 12:49:52 +01:00
if ( err = = ESP_OK )
{
//write was succsesfull
u32StartOffset = 0U ; //reset the offset for next download
2021-01-18 19:03:32 +01:00
ERROR_CHECK ( errHTTPSClientRetrieveData ( u8OTABuffer , & u32BufferLenght , & u32BytesRead ) ) ; //download next data segment
u32OTABytesWritten = u32OTABytesWritten + u32BytesRead ; //update counter
2021-01-18 12:49:52 +01:00
}
2021-01-17 23:47:59 +01:00
}
2021-01-19 17:20:16 +01:00
while ( ( u32BytesRead > 0 ) & & ( err = = ESP_OK ) & & ( u32OTABytesWritten < = pOTAPartition - > size ) ) ; //loop until error or complete image downloaded
2021-01-18 12:49:52 +01:00
}
if ( err = = ESP_OK )
{
//no error occurred --> finish ota update process
ERROR_CHECK ( esp_ota_end ( otaHandle ) ) ; //finish process
2021-01-18 17:38:08 +01:00
ERROR_CHECK ( esp_ota_set_boot_partition ( pOTAPartition ) ) ; //set new image as boot
2021-01-18 12:49:52 +01:00
if ( err = = ESP_OK )
2021-01-17 23:47:59 +01:00
{
2021-01-18 12:49:52 +01:00
* pbNewOTAImage = true ; //image validated
2021-01-17 23:47:59 +01:00
}
}
else
{
2021-01-18 17:38:08 +01:00
//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 ) ) ;
2021-01-18 12:49:52 +01:00
ERROR_CHECK ( esp_ota_abort ( otaHandle ) ) ;
* pbNewOTAImage = false ; //ota update failed
2021-01-17 23:47:59 +01:00
}
2021-01-18 19:03:32 +01:00
}
else
{
ESP_LOGI ( LOG_TAG , " server image is NOT newer --> OTA update NOT required " ) ;
}
2021-01-19 12:36:21 +01:00
xSemaphoreGive ( bsOTAProcess ) ; //free binary semaphore, this allows other tasks to start the OTA process
2021-01-18 12:49:52 +01:00
} //end version number extracted
return err ;
2021-01-17 23:27:01 +01:00
}
2021-01-19 12:36:21 +01:00
esp_err_t errOTAMeshSlave ( bool * pbNewOTAImage )
{
esp_err_t err = ESP_OK ;
MESH_PACKET_t sOTAMessage ;
const esp_partition_t * pBootPartition ; //pointer to boot partition (that will booted after reset)
esp_app_desc_t bootPartitionDesc ; //Metadate from boot partition
* pbNewOTAImage = false ; //set default false
//read OTAMessages queue
if ( uxQueueSpacesAvailable ( queueMessageOTA ) < QUEUE_MESSAGE_OTA_SIZE )
{
//queue not empty
if ( xQueueReceive ( queueMessageOTA , & sOTAMessage , ( ( 100 ) / portTICK_PERIOD_MS ) ) ! = pdTRUE )
{
ESP_LOGE ( LOG_TAG , " Unable to receive OTA Messages from Queue " ) ;
err = ESP_FAIL ;
}
if ( ( err = = ESP_OK ) & & ( sOTAMessage . type = = OTA_Version_Request ) ) //if OTA_Version_Request
{
xSemaphoreTake ( bsOTAProcess , portMAX_DELAY ) ; //wait for binary semaphore that allows to start the OTA process
pBootPartition = esp_ota_get_boot_partition ( ) ; //get boot partition (that will booted after reset), not the running partition
ERROR_CHECK ( esp_ota_get_partition_description ( pBootPartition , & bootPartitionDesc ) ) ; //get metadata of partition
2021-01-19 17:20:16 +01:00
//send OTA_Version_Response to sender of OTA_Version_Request packet wirh version in payload
2021-01-19 12:36:21 +01:00
ERROR_CHECK ( errSendOTAVersionResponse ( & sOTAMessage . meshSenderAddr ) ) ;
if ( ( bNewerVersion ( ( bootPartitionDesc ) . version , ( char * ) sOTAMessage . au8Payload ) ) & & ( err = = ESP_OK ) ) //compare local and remote version
{
//remote newer as local
ESP_LOGI ( LOG_TAG , " remote image on node is newer --> OTA update required " ) ;
// --> this version older --> start OTA_Rx --> set pbNewOTAImage true
2021-01-19 22:19:30 +01:00
ERROR_CHECK ( errOTAMeshReceive ( pbNewOTAImage , & sOTAMessage . meshSenderAddr ) ) ;
2021-01-19 12:36:21 +01:00
}
if ( ( bNewerVersion ( ( char * ) sOTAMessage . au8Payload , ( bootPartitionDesc ) . version ) ) & & ( err = = ESP_OK ) ) //compare remote and local version
{
//local newer as remote
ESP_LOGI ( LOG_TAG , " remote image on node is older --> OTA send required " ) ;
// --> this version newer --> start OTA_Tx
2021-01-19 22:19:30 +01:00
ERROR_CHECK ( errOTAMeshTransmit ( & sOTAMessage . meshSenderAddr ) ) ;
2021-01-19 12:36:21 +01:00
}
xSemaphoreGive ( bsOTAProcess ) ; //free binary semaphore, this allows other tasks to start the OTA process
}
}
return err ;
}
esp_err_t errOTAMeshMaster ( bool * pbNewOTAImage , mesh_addr_t * pMeshNodeAddr )
{
esp_err_t err = ESP_OK ;
MESH_PACKET_t sOTAMessage ;
const esp_partition_t * pBootPartition ; //pointer to boot partition (that will booted after reset)
2021-01-19 17:20:16 +01:00
esp_app_desc_t bootPartitionDesc ; //Metadata from boot partition
bool bNodeIsConnected = false ;
bool bNodeIsResponding = false ;
2021-01-19 12:36:21 +01:00
* pbNewOTAImage = false ; //set default false
2021-01-19 17:20:16 +01:00
if ( bIsNodeNeighbour ( pMeshNodeAddr ) = = true ) //check if node is still connected
{
bNodeIsConnected = true ; //node is one of the neighbours
xSemaphoreTake ( bsOTAProcess , portMAX_DELAY ) ; //wait for binary semaphore that allows to start the OTA process
2021-01-20 13:43:41 +01:00
ESP_LOGI ( LOG_TAG , " Mesh-Master: send Version_Request to 0x%x " , pMeshNodeAddr - > addr [ 5 ] ) ;
2021-01-19 17:20:16 +01:00
ERROR_CHECK ( errSendOTAVersionRequest ( pMeshNodeAddr ) ) ; //send OTA_VERSION_REQUEST with local version in payload
2021-01-19 12:36:21 +01:00
2021-01-19 17:20:16 +01:00
for ( uint32_t u32Index = 0 ; u32Index < QUEUE_MESSAGE_OTA_SIZE ; u32Index + + ) //loop through all OTA messages
{
if ( uxQueueSpacesAvailable ( queueMessageOTA ) < QUEUE_MESSAGE_OTA_SIZE )
{
//queue not empty
if ( xQueueReceive ( queueMessageOTA , & sOTAMessage , ( ( 3000 ) / portTICK_PERIOD_MS ) ) ! = pdTRUE )
{
ESP_LOGE ( LOG_TAG , " Unable to receive OTA Messages from queue " ) ;
err = ESP_FAIL ;
}
if ( ( err = = ESP_OK ) & & ( sOTAMessage . type = = OTA_Version_Response ) & & ( bCheckMACEquality ( sOTAMessage . meshSenderAddr . addr , pMeshNodeAddr - > addr ) ) ) //if OTA_Version_Request
{
bNodeIsResponding = true ;
pBootPartition = esp_ota_get_boot_partition ( ) ; //get boot partition (that will booted after reset), not the running partition
ERROR_CHECK ( esp_ota_get_partition_description ( pBootPartition , & bootPartitionDesc ) ) ; //get metadata of partition
if ( ( bNewerVersion ( ( bootPartitionDesc ) . version , ( char * ) sOTAMessage . au8Payload ) ) & & ( err = = ESP_OK ) ) //compare local and remote version
{
//remote newer as local
ESP_LOGI ( LOG_TAG , " Mesh: remote image on node is newer --> OTA update required " ) ;
// --> this version older --> start OTA_Rx --> set pbNewOTAImage true
2021-01-19 22:19:30 +01:00
ERROR_CHECK ( errOTAMeshReceive ( pbNewOTAImage , & sOTAMessage . meshSenderAddr ) ) ;
2021-01-19 17:20:16 +01:00
}
if ( ( bNewerVersion ( ( char * ) sOTAMessage . au8Payload , ( bootPartitionDesc ) . version ) ) & & ( err = = ESP_OK ) ) //compare remote and local version
{
//local newer as remote
ESP_LOGI ( LOG_TAG , " Mesh: remote image on node is older --> OTA send required " ) ;
// --> this version newer --> start OTA_Tx
2021-01-19 22:19:30 +01:00
ERROR_CHECK ( errOTAMeshTransmit ( & sOTAMessage . meshSenderAddr ) ) ;
2021-01-19 17:20:16 +01:00
}
}
2021-01-19 22:19:30 +01:00
else if ( err = = ESP_OK )
2021-01-19 17:20:16 +01:00
{
2021-01-19 22:19:30 +01:00
//received from wrong node or type --> back to queue
2021-01-20 15:18:22 +01:00
vAddOtaMessageToQueue ( & sOTAMessage ) ;
2021-01-19 17:20:16 +01:00
}
}
2021-01-19 22:19:30 +01:00
else
{
// OTA Message queue is empty --> wait some time
2021-01-20 13:43:41 +01:00
ESP_LOGI ( LOG_TAG , " OTA-Master: OTA Message queue is empty --> wait some time " ) ;
2021-01-19 22:19:30 +01:00
vTaskDelay ( ( 1000 / QUEUE_MESSAGE_OTA_SIZE ) / portTICK_PERIOD_MS ) ;
}
2021-01-19 17:20:16 +01:00
} //end loop
xSemaphoreGive ( bsOTAProcess ) ; //free binary semaphore, this allows other tasks to start the OTA process
}
if ( ( bNodeIsResponding = = false ) & & ( bNodeIsConnected = = true ) )
{
//add node back to queue if connected and NOT responding
2021-01-20 13:43:41 +01:00
ESP_LOGI ( LOG_TAG , " OTA-Master: connected and NOT responding --> add node back to queue " ) ;
2021-01-19 17:20:16 +01:00
vAddNodeToPossibleUpdatableQueue ( pMeshNodeAddr - > addr ) ;
}
2021-01-19 12:36:21 +01:00
return err ;
}
2021-01-16 18:23:10 +01:00
bool bNewerVersion ( const char * pu8Local , const char * pu8Remote )
2021-01-09 17:41:40 +01:00
{
2021-01-19 17:20:16 +01:00
/*
* Return true if remote version is newer ( higher ) than local version
*/
2021-01-09 17:41:40 +01:00
char u8LocalTmp [ 12 ] ; //local version
char u8RemoteTmp [ 12 ] ; //remote version
2021-01-16 18:23:10 +01:00
char * pu8saveptrLocal ; //context for strok_r
char * pu8saveptrRemote ; //context for strok_r
2021-01-09 17:41:40 +01:00
bool bReturn = false ; //flag to stop loop
uint8_t u8Index = 0 ; //numbers counter in version string
2021-01-06 18:10:12 +01:00
2021-01-19 12:36:21 +01:00
strncpy ( u8LocalTmp , pu8Local , 12 ) ; //copy in tmp
strncpy ( u8RemoteTmp , pu8Remote , 12 ) ; //copy in tmp
2021-01-06 18:10:12 +01:00
2021-01-09 17:41:40 +01:00
char * pu8TokenLocal = strtok_r ( u8LocalTmp , " . " , & pu8saveptrLocal ) ; //split tokens
char * pu8TokenRemote = strtok_r ( u8RemoteTmp , " . " , & pu8saveptrRemote ) ; //split tokens
2021-01-06 18:10:12 +01:00
2021-01-09 17:41:40 +01:00
while ( ( u8Index < = 2 ) & & ( bReturn = = false ) ) //loop through tokens
2021-01-02 00:30:13 +01:00
{
2021-01-17 23:27:01 +01:00
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
2021-01-02 00:30:13 +01:00
}
return bReturn ;
}
2021-01-06 18:10:12 +01:00
2021-01-07 23:10:36 +01:00
esp_err_t errFindImageStart ( const char * pu8Data , uint32_t * pu32DataLenght , uint32_t * pu32StartOffset )
2021-01-06 18:10:12 +01:00
{
/*
Offset value
2021-01-09 17:41:40 +01:00
0 = 0xE9 ( first byte in image - - > magic byte )
2021-01-06 18:10:12 +01:00
48 = first digit of version number
*/
esp_err_t errReturn = ESP_OK ;
2021-01-07 17:10:25 +01:00
bool bImageStartOffsetFound = false ;
2021-01-06 18:10:12 +01:00
uint32_t u32DataIndex = 0 ;
uint32_t u32FirstDotOffset = 0 ;
uint32_t u32SecondDotOffset = 0 ;
uint8_t u8FirstDotIndex = 0 ;
uint8_t u8SecondDotIndex = 0 ;
2021-01-09 17:41:40 +01:00
* pu32StartOffset = 0U ; //reset offset to zero
2021-01-16 18:23:10 +01:00
2021-01-07 17:10:25 +01:00
while ( ( u32DataIndex < * pu32DataLenght ) & & ( bImageStartOffsetFound = = false ) )
2021-01-17 23:27:01 +01:00
{
//search for magic byte
if ( pu8Data [ u32DataIndex ] = = 0xe9 )
2021-01-06 18:10:12 +01:00
{
2021-01-17 23:27:01 +01:00
//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 + + ;
}
2021-01-06 18:10:12 +01:00
2021-01-17 23:27:01 +01:00
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 ;
}
2021-01-06 18:10:12 +01:00
}
2021-01-17 23:27:01 +01:00
u32DataIndex + + ;
2021-01-06 18:10:12 +01:00
}
2021-01-07 17:10:25 +01:00
if ( bImageStartOffsetFound = = false )
2021-01-17 23:27:01 +01:00
{
errReturn = ESP_ERR_NOT_FOUND ;
}
2021-01-06 18:10:12 +01:00
return errReturn ;
}
2021-01-07 23:10:36 +01:00
esp_err_t errExtractVersionNumber ( const char * pu8Data , uint32_t * pu32DataLenght , char * pc8RemoteVersionNumber )
2021-01-06 18:10:12 +01:00
{
uint32_t u32StartOffset ;
2021-01-09 17:41:40 +01:00
esp_err_t err = ESP_OK ;
2021-01-06 18:10:12 +01:00
2021-01-09 17:41:40 +01:00
strcpy ( pc8RemoteVersionNumber , " 999.999.999 " ) ; //init value
err = errFindImageStart ( pu8Data , pu32DataLenght , & u32StartOffset ) ; //get image start offset
2021-01-06 18:10:12 +01:00
if ( err = = ESP_OK )
2021-01-17 23:27:01 +01:00
{
//image found
strncpy ( pc8RemoteVersionNumber , pu8Data + ( u32StartOffset + 48 ) , 11 ) ; //copy version number
pc8RemoteVersionNumber [ 12 ] = ' \0 ' ;
}
2021-01-06 18:10:12 +01:00
return err ;
2021-01-07 17:10:25 +01:00
}
2021-01-11 15:22:45 +01:00
2021-01-19 22:19:30 +01:00
void vPrintOTAProgress ( const uint32_t * const pu32TotalImageSize , const uint32_t * const pu32BytesWritten , OTA_MESH_ROLE_t eRole )
2021-01-18 19:03:32 +01:00
{
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 )
{
2021-01-19 22:19:30 +01:00
if ( eRole = = Transmitter )
{
ESP_LOGI ( LOG_TAG , " Transmitting OTA update: %i %% " , u32Percentage ) ;
}
if ( eRole = = Receiver )
{
ESP_LOGI ( LOG_TAG , " Receiving OTA update: %i %% " , u32Percentage ) ;
}
2021-01-18 19:03:32 +01:00
u32LastPercentage = u32Percentage ;
}
}
2021-01-18 22:56:42 +01:00
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
2021-01-19 12:36:21 +01:00
uint16_t u16ChildrenSize = 0U ; //number of children attached to this node
2021-01-18 22:56:42 +01:00
err = errGetParentNode ( & addrParent ) ;
if ( err = = ESP_OK )
{
vAddNodeToPossibleUpdatableQueue ( addrParent . addr ) ;
2021-01-19 12:36:21 +01:00
ESP_LOGI ( LOG_TAG , " added parent " ) ;
2021-01-18 22:56:42 +01:00
}
2021-01-19 12:36:21 +01:00
err = ESP_OK ; //reset error code
2021-01-18 22:56:42 +01:00
ERROR_CHECK ( errGetChildren ( childrenAddr , & u16ChildrenSize ) ) ; //get all children
2021-01-19 12:36:21 +01:00
for ( uint16_t u16Index = 0 ; ( ( u16Index < u16ChildrenSize ) & & ( err = = ESP_OK ) ) ; u16Index + + )
2021-01-18 22:56:42 +01:00
{
vAddNodeToPossibleUpdatableQueue ( childrenAddr [ u16Index ] . addr ) ;
2021-01-19 12:36:21 +01:00
ESP_LOGI ( LOG_TAG , " added child " ) ;
2021-01-18 22:56:42 +01:00
}
}
2021-01-19 12:36:21 +01:00
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
2021-01-20 15:18:22 +01:00
ESP_LOGI ( LOG_TAG , " Send OTA_Version_Response to 0x%x " , pMeshReceiverAddr - > addr [ 5 ] ) ;
2021-01-19 12:36:21 +01:00
err = errSendMeshPacket ( pMeshReceiverAddr , & packet ) ;
return err ;
}
2021-01-20 15:18:22 +01:00
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
}
2021-01-19 17:20:16 +01:00
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 ;
}
2021-01-19 22:19:30 +01:00
esp_err_t errOTAMeshTransmit ( mesh_addr_t * pMeshNodeAddr )
2021-01-11 15:22:45 +01:00
{
esp_err_t err = ESP_OK ;
2021-01-19 22:19:30 +01:00
const esp_partition_t * pBootPartition ; //pointer to boot partition (that will booted after reset)
MESH_PACKET_t sMeshPacket ; //packet for sending and receiving
2021-01-20 13:43:41 +01:00
// uint32_t u32Index = 0U; //index for partition read offset
2021-01-19 22:19:30 +01:00
bool bAbort = false ; //abort the OTA process
bool bNodeIsResponding = false ; //remote node is still active
uint32_t u32OTABytesWritten = 0U ;
2021-01-20 11:20:35 +01:00
uint32_t u32SegmentCounter = 0U ;
2021-01-11 15:22:45 +01:00
2021-01-19 22:19:30 +01:00
pBootPartition = esp_ota_get_boot_partition ( ) ; //get boot partition (that will booted after reset), not the running partition
2021-01-11 15:22:45 +01:00
2021-01-19 22:19:30 +01:00
//loop through partition to read in segmensts until end or error or abort called
2021-01-20 11:20:35 +01:00
while ( ( ( OTA_MESH_SEGMENT_SIZE * u32SegmentCounter ) < pBootPartition - > size ) & & ( err = = ESP_OK ) & & ( bAbort = = false ) )
2021-01-19 22:19:30 +01:00
{
bNodeIsResponding = false ; //reset to default
2021-01-11 15:22:45 +01:00
2021-01-19 22:19:30 +01:00
// read partition with offset based in index
2021-01-20 11:20:35 +01:00
ERROR_CHECK ( esp_partition_read ( pBootPartition , ( OTA_MESH_SEGMENT_SIZE * u32SegmentCounter ) , sMeshPacket . au8Payload , OTA_MESH_SEGMENT_SIZE ) ) ;
u32OTABytesWritten = ( ( u32SegmentCounter + 1 ) * OTA_MESH_SEGMENT_SIZE ) ;
2021-01-19 22:19:30 +01:00
vPrintOTAProgress ( & ( pBootPartition - > size ) , & u32OTABytesWritten , Transmitter ) ;
2021-01-11 15:22:45 +01:00
2021-01-19 22:19:30 +01:00
if ( err = = ESP_OK )
{
//no error while read --> send OTA_DATA packet
sMeshPacket . type = OTA_Data ;
2021-01-11 15:22:45 +01:00
2021-01-20 11:20:35 +01:00
if ( ( OTA_MESH_SEGMENT_SIZE * ( u32SegmentCounter + 1 ) ) > = pBootPartition - > size ) //check if last segment
2021-01-19 22:19:30 +01:00
{
//last partition image segment --> send OTA_Complete
2021-01-20 11:20:35 +01:00
ESP_LOGI ( LOG_TAG , " OTA-TX: last segment--> send Complete " ) ;
2021-01-19 22:19:30 +01:00
sMeshPacket . type = OTA_Complete ;
}
2021-01-20 13:43:41 +01:00
//ESP_LOGI(LOG_TAG, "OTA-TX: send packet");
2021-01-19 22:19:30 +01:00
err = errSendMeshPacket ( pMeshNodeAddr , & sMeshPacket ) ;
}
else
{
// error while read --> send OTA_ABORT and abort this OTA process
sMeshPacket . type = OTA_Abort ;
bAbort = true ;
2021-01-20 11:20:35 +01:00
ESP_LOGI ( LOG_TAG , " OTA-TX: error while read --> send ABORT " ) ;
2021-01-19 22:19:30 +01:00
errSendMeshPacket ( pMeshNodeAddr , & sMeshPacket ) ;
}
2021-01-11 15:22:45 +01:00
2021-01-19 22:19:30 +01:00
// 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
{
2021-01-20 13:43:41 +01:00
// if(uxQueueSpacesAvailable(queueMessageOTA) < QUEUE_MESSAGE_OTA_SIZE)
// {
//queue not empty
2021-01-20 15:18:22 +01:00
if ( xQueueReceive ( queueMessageOTA , & sMeshPacket , ( ( OTA_MESH_TIMEOUT ) / portTICK_PERIOD_MS ) ) ! = pdTRUE )
2021-01-20 13:43:41 +01:00
{
ESP_LOGE ( LOG_TAG , " Unable to receive OTA Messages from queue " ) ;
err = ESP_FAIL ;
}
2021-01-11 15:22:45 +01:00
2021-01-20 13:43:41 +01:00
if ( ( err = = ESP_OK ) & & ( bCheckMACEquality ( sMeshPacket . meshSenderAddr . addr , pMeshNodeAddr - > addr ) ) ) //if OTA_Version_Request
{
//packet from node received
switch ( sMeshPacket . type )
2021-01-19 22:19:30 +01:00
{
2021-01-20 13:43:41 +01:00
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
2021-01-20 15:18:22 +01:00
//vAddOtaMessageToQueue(&sMeshPacket);
2021-01-20 13:43:41 +01:00
break ;
2021-01-19 22:19:30 +01:00
}
}
2021-01-20 13:43:41 +01:00
else if ( err = = ESP_OK )
2021-01-19 22:19:30 +01:00
{
2021-01-20 13:43:41 +01:00
//received from wrong node --> back to queue
2021-01-20 15:18:22 +01:00
vAddOtaMessageToQueue ( & sMeshPacket ) ;
2021-01-19 22:19:30 +01:00
}
2021-01-20 13:43:41 +01:00
/*
}
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 ) ;
}
*/
2021-01-19 22:19:30 +01:00
} //end OTA message loop
if ( bNodeIsResponding = = false )
{
//no abort was called but node didn’ t responded
2021-01-20 11:20:35 +01:00
ESP_LOGE ( LOG_TAG , " OTA-TX: no abort was called but node didn’ t responded --> error " ) ;
2021-01-19 22:19:30 +01:00
bAbort = true ;
err = ESP_FAIL ; //this OTA process failed with error
}
2021-01-20 13:43:41 +01:00
u32SegmentCounter + + ;
2021-01-19 22:19:30 +01:00
} //end of partition segment loop
2021-01-20 15:18:22 +01:00
vClearOtaMessageQueue ( pMeshNodeAddr ) ;
2021-01-11 15:22:45 +01:00
return err ;
}
2021-01-19 22:19:30 +01:00
esp_err_t errOTAMeshReceive ( bool * pbNewOTAImage , mesh_addr_t * pMeshNodeAddr )
2021-01-11 15:22:45 +01:00
{
esp_err_t err = ESP_OK ;
2021-01-19 22:19:30 +01:00
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 ;
2021-01-20 11:20:35 +01:00
uint32_t u32SegmentCounter = 0U ;
2021-01-11 15:22:45 +01:00
2021-01-19 22:19:30 +01:00
ERROR_CHECK ( esp_ota_begin ( pOTAPartition , OTA_SIZE_UNKNOWN , & otaHandle ) ) ; //start ota update process
2021-01-11 15:22:45 +01:00
2021-01-19 22:19:30 +01:00
//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
2021-01-11 15:22:45 +01:00
2021-01-19 22:19:30 +01:00
// 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
{
2021-01-20 11:20:35 +01:00
//if(uxQueueSpacesAvailable(queueMessageOTA) < QUEUE_MESSAGE_OTA_SIZE)
2021-01-20 13:43:41 +01:00
// {
//queue not empty
2021-01-20 15:18:22 +01:00
if ( xQueueReceive ( queueMessageOTA , & sMeshPacket , ( ( OTA_MESH_TIMEOUT ) / portTICK_PERIOD_MS ) ) ! = pdTRUE )
2021-01-20 13:43:41 +01:00
{
ESP_LOGE ( LOG_TAG , " Unable to receive OTA Messages from queue " ) ;
err = ESP_FAIL ;
}
2021-01-11 15:22:45 +01:00
2021-01-20 13:43:41 +01:00
if ( ( err = = ESP_OK ) & & ( bCheckMACEquality ( sMeshPacket . meshSenderAddr . addr , pMeshNodeAddr - > addr ) ) ) //if OTA_Version_Request
{
//packet from node received
switch ( sMeshPacket . type )
2021-01-19 22:19:30 +01:00
{
2021-01-20 13:43:41 +01:00
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
2021-01-20 15:18:22 +01:00
//vAddOtaMessageToQueue(&sMeshPacket);
2021-01-20 13:43:41 +01:00
break ;
2021-01-19 22:19:30 +01:00
}
2021-01-20 13:43:41 +01:00
}
else if ( err = = ESP_OK )
2021-01-19 22:19:30 +01:00
{
2021-01-20 13:43:41 +01:00
//received from wrong node --> back to queue
2021-01-20 15:18:22 +01:00
vAddOtaMessageToQueue ( & sMeshPacket ) ;
2021-01-19 22:19:30 +01:00
}
2021-01-20 13:43:41 +01:00
/* }
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 ) ;
}
*/
2021-01-11 15:22:45 +01:00
2021-01-19 22:19:30 +01:00
} //end of OTA message loop
2021-01-11 15:22:45 +01:00
2021-01-19 22:19:30 +01:00
if ( bNodeIsResponding = = false )
{
//no abort was called but node didn’ t responded --> error
2021-01-20 11:20:35 +01:00
ESP_LOGI ( LOG_TAG , " OTA-RX: no abort was called but node didn’ t responded --> error " ) ;
2021-01-19 22:19:30 +01:00
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 )
{
2021-01-11 15:22:45 +01:00
2021-01-19 22:19:30 +01:00
if ( bAbort = = false )
{
//no error while ota write --> send OTA_ACK packet
2021-01-20 13:43:41 +01:00
//ESP_LOGI(LOG_TAG, "OTA-RX: no error while ota write --> send OTA_ACK packet");
2021-01-19 22:19:30 +01:00
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 ;
2021-01-20 11:20:35 +01:00
ESP_LOGI ( LOG_TAG , " OTA-RX: abort --> send ABORT " ) ;
2021-01-19 22:19:30 +01:00
errSendMeshPacket ( pMeshNodeAddr , & sMeshPacket ) ;
}
}
2021-01-20 13:43:41 +01:00
u32SegmentCounter + + ;
2021-01-19 22:19:30 +01:00
} //end of partition segement loop
2021-01-11 15:22:45 +01:00
2021-01-19 22:19:30 +01:00
if ( bComplete = = true )
{
//all OTA segments received --> validate
2021-01-20 11:20:35 +01:00
ESP_LOGI ( LOG_TAG , " OTA-RX: validate image " ) ;
2021-01-19 22:19:30 +01:00
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 ) ) ;
}
2021-01-20 15:18:22 +01:00
vClearOtaMessageQueue ( pMeshNodeAddr ) ;
2021-01-11 15:22:45 +01:00
return err ;
}