Browse Source

OTA Tx and Rx over Mesh

feature/blockingOTA
Hendrik Schutter 1 year ago
parent
commit
57c71c401c
  1. 311
      components/mesh_ota/Mesh_OTA.c
  2. 1
      components/mesh_ota/Mesh_network.c
  3. 14
      components/mesh_ota/include/Mesh_OTA.h
  4. 6
      components/mesh_ota/include/Mesh_network.h

311
components/mesh_ota/Mesh_OTA.c

@ -130,7 +130,7 @@ void vAddOTAControllMessageToQueue(MESH_PACKET_t* puMeshPacket)
}
else
{
ESP_LOGI(LOG_TAG, "added ota controll message to queue");
ESP_LOGI(LOG_TAG, "added ota message to queue: %i (type)", puMeshPacket->type);
}
}
@ -239,6 +239,12 @@ void vTaskOTAWorker(void *arg)
}
ERROR_CHECK(errOTAMeshMaster(&bNewOTAImage, &meshNodeAddr));
if (err != ESP_OK)
{
//OTA process faild --> add back to queue
vAddNodeToPossibleUpdatableQueue(meshNodeAddr.addr);
}
}
if(bNewOTAImage == true)
@ -290,7 +296,7 @@ esp_err_t errOTAHTTPS(bool* pbNewOTAImage)
ESP_LOGI(LOG_TAG, "start OTA download via HTTPS");
do
{
vPrintOTAProgress(&(pOTAPartition->size), &u32OTABytesWritten);
vPrintOTAProgress(&(pOTAPartition->size), &u32OTABytesWritten, Receiver);
ERROR_CHECK(esp_ota_write(otaHandle, (const void*) u8OTABuffer+u32StartOffset, (u32BytesRead-u32StartOffset)));
if(err == ESP_OK)
@ -364,6 +370,7 @@ esp_err_t errOTAMeshSlave(bool* pbNewOTAImage)
//remote newer as local
ESP_LOGI(LOG_TAG, "remote image on node is newer --> OTA update required");
// --> this version older --> start OTA_Rx --> set pbNewOTAImage true
ERROR_CHECK(errOTAMeshReceive(pbNewOTAImage, &sOTAMessage.meshSenderAddr));
}
if((bNewerVersion((char*) sOTAMessage.au8Payload, (bootPartitionDesc).version)) && (err == ESP_OK)) //compare remote and local version
@ -371,6 +378,7 @@ esp_err_t errOTAMeshSlave(bool* pbNewOTAImage)
//local newer as remote
ESP_LOGI(LOG_TAG, "remote image on node is older --> OTA send required");
// --> this version newer --> start OTA_Tx
ERROR_CHECK(errOTAMeshTransmit(&sOTAMessage.meshSenderAddr));
}
xSemaphoreGive(bsOTAProcess); //free binary semaphore, this allows other tasks to start the OTA process
}
@ -396,10 +404,6 @@ esp_err_t errOTAMeshMaster(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr)
ERROR_CHECK(errSendOTAVersionRequest(pMeshNodeAddr)); //send OTA_VERSION_REQUEST with local version in payload
//read OTA_Version_Response (if from this node) (all other OTA message add again)
// if(uxQueueSpacesAvailable(queueMessageOTA) < QUEUE_MESSAGE_OTA_SIZE)
//{
for (uint32_t u32Index = 0; u32Index < QUEUE_MESSAGE_OTA_SIZE; u32Index++) //loop through all OTA messages
{
if(uxQueueSpacesAvailable(queueMessageOTA) < QUEUE_MESSAGE_OTA_SIZE)
@ -422,6 +426,7 @@ esp_err_t errOTAMeshMaster(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr)
//remote newer as local
ESP_LOGI(LOG_TAG, "Mesh: remote image on node is newer --> OTA update required");
// --> this version older --> start OTA_Rx --> set pbNewOTAImage true
ERROR_CHECK(errOTAMeshReceive(pbNewOTAImage, &sOTAMessage.meshSenderAddr));
}
if((bNewerVersion((char*) sOTAMessage.au8Payload, (bootPartitionDesc).version)) && (err == ESP_OK)) //compare remote and local version
@ -429,14 +434,20 @@ esp_err_t errOTAMeshMaster(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr)
//local newer as remote
ESP_LOGI(LOG_TAG, "Mesh: remote image on node is older --> OTA send required");
// --> this version newer --> start OTA_Tx
ERROR_CHECK(errOTAMeshTransmit(&sOTAMessage.meshSenderAddr));
}
}
else
else if (err == ESP_OK)
{
//send wrong OTA message back to queue
//received from wrong node or type --> back to queue
vAddOTAControllMessageToQueue(&sOTAMessage);
}
}
else
{
// OTA Message queue is empty --> wait some time
vTaskDelay( (1000/QUEUE_MESSAGE_OTA_SIZE) / portTICK_PERIOD_MS);
}
}//end loop
xSemaphoreGive(bsOTAProcess); //free binary semaphore, this allows other tasks to start the OTA process
}
@ -575,7 +586,7 @@ esp_err_t errExtractVersionNumber(const char* pu8Data, uint32_t* pu32DataLenght,
return err;
}
void vPrintOTAProgress(const uint32_t* const pu32TotalImageSize, const uint32_t* const pu32BytesWritten)
void vPrintOTAProgress(const uint32_t* const pu32TotalImageSize, const uint32_t* const pu32BytesWritten, OTA_MESH_ROLE_t eRole)
{
uint32_t u32Percentage = 0U;
static uint32_t u32LastPercentage = 0U;
@ -591,7 +602,18 @@ void vPrintOTAProgress(const uint32_t* const pu32TotalImageSize, const uint32_t*
if((u32Percentage-u32LastPercentage) >= OTA_PROGRESS_LOG_INTERVAL)
{
ESP_LOGI(LOG_TAG, "OTA update progress: %i %%", u32Percentage);
if(eRole == Transmitter)
{
ESP_LOGI(LOG_TAG, "Transmitting OTA update: %i %%", u32Percentage);
}
if(eRole == Receiver)
{
ESP_LOGI(LOG_TAG, "Receiving OTA update: %i %%", u32Percentage);
}
u32LastPercentage = u32Percentage;
}
}
@ -655,109 +677,216 @@ esp_err_t errSendOTAVersionRequest(mesh_addr_t* pMeshReceiverAddr)
return err;
}
/*
esp_err_t esp_mesh_ota_send(mesh_addr_t* dest)
esp_err_t errOTAMeshTransmit(mesh_addr_t* pMeshNodeAddr)
{
esp_err_t err = ESP_OK;
const esp_partition_t* pBootPartition; //pointer to boot partition (that will booted after reset)
MESH_PACKET_t sMeshPacket; //packet for sending and receiving
uint32_t u32Index = 0U; //index for partition read offset
bool bAbort = false; //abort the OTA process
bool bNodeIsResponding = false; //remote node is still active
uint32_t u32OTABytesWritten = 0U;
static uint32_t u32index;
pBootPartition = esp_ota_get_boot_partition(); //get boot partition (that will booted after reset), not the running partition
const esp_partition_t * pBootPartition = esp_ota_get_boot_partition();
//loop through partition to read in segmensts until end or error or abort called
while( ((OTA_MESH_SEGMENT_SIZE * u32Index) < pBootPartition->size) && (err == ESP_OK) && (bAbort == false))
{
bNodeIsResponding = false; //reset to default
if((*pBootPartition).subtype == 0)
{
// read partition with offset based in index
ERROR_CHECK(esp_partition_read(pBootPartition, (OTA_MESH_SEGMENT_SIZE * u32Index), sMeshPacket.au8Payload, OTA_MESH_SEGMENT_SIZE));
u32OTABytesWritten = ((u32Index+1) * OTA_MESH_SEGMENT_SIZE);
vPrintOTAProgress(&(pBootPartition->size), &u32OTABytesWritten, Transmitter);
int data_read = 0;
if(err == ESP_OK)
{
//no error while read --> send OTA_DATA packet
sMeshPacket.type = OTA_Data;
struct ota_mesh_packet packet;
packet.type=OTA_Data;
if((OTA_MESH_SEGMENT_SIZE * (u32Index+1)) >= pBootPartition->size) //check if last segment
{
//last partition image segment --> send OTA_Complete
sMeshPacket.type = OTA_Complete;
}
if(u32index == 1024)
{
//all data read
data_read = 0;
u32index = 0;
}
else
{
ESP_LOGI(MESH_TAG, "OTA-Data read: %i", u32index);
err = esp_partition_read(pBootPartition, (1024*u32index), packet.au8Payload, 1024 );
ESP_ERROR_CHECK(err);
data_read = 1024;
u32index++;
}
err = errSendMeshPacket(pMeshNodeAddr, &sMeshPacket);
}
else
{
// error while read --> send OTA_ABORT and abort this OTA process
sMeshPacket.type = OTA_Abort;
bAbort = true;
errSendMeshPacket(pMeshNodeAddr, &sMeshPacket);
}
if (data_read > 0)
{
//send ota fragemnt to node
esp_mesh_send_packet(dest, &packet);
}
// loop through all OTA messages or until abort is called or error
for (uint32_t u32Index = 0; ((u32Index < QUEUE_MESSAGE_OTA_SIZE) && (bAbort == false) && (err == ESP_OK)); u32Index++) //loop through all OTA messages
{
if(uxQueueSpacesAvailable(queueMessageOTA) < QUEUE_MESSAGE_OTA_SIZE)
{
//queue not empty
if (xQueueReceive(queueMessageOTA, &sMeshPacket, ((3000) / portTICK_PERIOD_MS)) != pdTRUE)
{
ESP_LOGE(LOG_TAG, "Unable to receive OTA Messages from queue");
err = ESP_FAIL;
}
ESP_ERROR_CHECK(err);
}
else
{
ESP_LOGI(MESH_TAG, "Subtype: %d", (*pBootPartition).subtype);
}
if((err == ESP_OK) && (bCheckMACEquality(sMeshPacket.meshSenderAddr.addr, pMeshNodeAddr->addr))) //if OTA_Version_Request
{
//packet from node received
switch (sMeshPacket.type)
{
case OTA_ACK: //increase index for next round
u32Index++;
bNodeIsResponding = true;
break;
case OTA_Abort: //abort this OTA process
bAbort = true;
bNodeIsResponding = true;
break;
default:
//receives wrong OTA message type from node --> back to queue
vAddOTAControllMessageToQueue(&sMeshPacket);
break;
}
}
else if (err == ESP_OK)
{
//received from wrong node --> back to queue
vAddOTAControllMessageToQueue(&sMeshPacket);
}
}
else
{
// OTA Message queue is empty --> wait some time
vTaskDelay( (1000/QUEUE_MESSAGE_OTA_SIZE) / portTICK_PERIOD_MS);
}
}//end OTA message loop
if(bNodeIsResponding == false)
{
//no abort was called but node didn’t responded
bAbort = true;
err = ESP_FAIL; //this OTA process failed with error
}
}//end of partition segment loop
return err;
}
esp_err_t esp_mesh_ota_receive(mesh_addr_t* dest, struct ota_mesh_packet* packet)
esp_err_t errOTAMeshReceive(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr)
{
esp_err_t err = ESP_OK;
static esp_ota_handle_t otaHandle;
static uint32_t u32index;
const esp_partition_t * pBootPartition = esp_ota_get_boot_partition();
const esp_partition_t * pOTAPartition = esp_ota_get_next_update_partition(pBootPartition);
if(u32index == 0)
{
//first run
err = esp_ota_begin(pOTAPartition, OTA_SIZE_UNKNOWN, &otaHandle);
ESP_ERROR_CHECK(err);
}
ESP_LOGI(MESH_TAG, "OTA-Data write: %i", u32index);
err = esp_ota_write(otaHandle, packet->au8Payload, 1024);
if(err != ESP_OK)
{
ESP_LOGE(MESH_TAG, "OTA-Data write error: %i at %i", err, u32index);
}
ESP_ERROR_CHECK(err);
if(u32index >= 1023)
{
//ota update complete
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;
ESP_LOGI(MESH_TAG, "OTA-Data complete arrived: %i", u32index);
err = esp_ota_end(otaHandle);
ESP_ERROR_CHECK(err);
esp_app_desc_t otaPartitionDesc;
err = esp_ota_get_partition_description(pOTAPartition, &otaPartitionDesc);
ESP_ERROR_CHECK(err);
ESP_LOGI(MESH_TAG, "pOTAPartition project_name: %s", (otaPartitionDesc).project_name);
ERROR_CHECK(esp_ota_begin(pOTAPartition, OTA_SIZE_UNKNOWN, &otaHandle)); //start ota update process
err = esp_ota_set_boot_partition(pOTAPartition);
ESP_ERROR_CHECK(err);
//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
struct ota_mesh_packet retPacket;
retPacket.type=OTA_Complete;
ESP_ERROR_CHECK (esp_mesh_send_packet(dest, &retPacket)); //send back to parent
// loop through all OTA messages or until abort is called
for (uint32_t u32Index = 0; ((u32Index < QUEUE_MESSAGE_OTA_SIZE) && (bAbort == false)); u32Index++) //loop through all OTA messages
{
if(uxQueueSpacesAvailable(queueMessageOTA) < QUEUE_MESSAGE_OTA_SIZE)
{
//queue not empty
if (xQueueReceive(queueMessageOTA, &sMeshPacket, ((3000) / portTICK_PERIOD_MS)) != pdTRUE)
{
ESP_LOGE(LOG_TAG, "Unable to receive OTA Messages from queue");
err = ESP_FAIL;
}
//check if this node has children --> Update them
if((err == ESP_OK) && (bCheckMACEquality(sMeshPacket.meshSenderAddr.addr, pMeshNodeAddr->addr))) //if OTA_Version_Request
{
//packet from node received
switch (sMeshPacket.type)
{
case OTA_Complete: //signal end of this OTA process, fall through because same behavior as OTA_Data
bComplete = true;
//fall through
case OTA_Data: //data segement received
bNodeIsResponding = true;
ERROR_CHECK(esp_ota_write(otaHandle, sMeshPacket.au8Payload, OTA_MESH_SEGMENT_SIZE));
u32OTABytesWritten = ((u32Index+1) * OTA_MESH_SEGMENT_SIZE);
vPrintOTAProgress(&(pOTAPartition->size), &u32OTABytesWritten, Receiver);
break;
case OTA_Abort: //abort this OTA process
bAbort = true;
bNodeIsResponding = true;
break;
default:
//receives wrong OTA message type from node --> back to queue
vAddOTAControllMessageToQueue(&sMeshPacket);
break;
}
}
else if (err == ESP_OK)
{
//received from wrong node --> back to queue
vAddOTAControllMessageToQueue(&sMeshPacket);
}
}
else
{
// OTA Message queue is empty --> wait some time
vTaskDelay( (1000/QUEUE_MESSAGE_OTA_SIZE) / portTICK_PERIOD_MS);
}
esp_restart();
}
}//end of OTA message loop
u32index++;
if(bNodeIsResponding == false)
{
//no abort was called but node didn’t responded --> error
bAbort = true; //this will stop the partition segement loop
err = ESP_FAIL; //this OTA process failed with error
}
else
{
//node has responded with OTA_DATA or OTA_Complete or OTA_ABORT
if(err == ESP_OK)
{
if(bAbort == false)
{
//no error while ota write --> send OTA_ACK packet
sMeshPacket.type = OTA_ACK;
err = errSendMeshPacket(pMeshNodeAddr, &sMeshPacket);
}
}
else
{
// error while read --> send OTA_ABORT and abort this OTA process
sMeshPacket.type = OTA_Abort;
bAbort = true;
errSendMeshPacket(pMeshNodeAddr, &sMeshPacket);
}
}
}//end of partition segement loop
if(bComplete == true)
{
//all OTA segments received --> validate
ERROR_CHECK(esp_ota_end(otaHandle));
ERROR_CHECK(esp_ota_set_boot_partition(pOTAPartition));
if(err == ESP_OK)
{
//successfully updated OTA partition
*pbNewOTAImage = true;
}
}
else
{
//not all OTA segments received --> abort this OTA process
ERROR_CHECK(esp_ota_abort(otaHandle));
}
return err;
}
*/

1
components/mesh_ota/Mesh_network.c

@ -305,6 +305,7 @@ void vTaskReceiveMeshData(void *arg)
case OTA_Data:
case OTA_ACK:
case OTA_Complete:
case OTA_Abort:
//call the rx handle from OTA
if(pOTAMessageHandle)
{

14
components/mesh_ota/include/Mesh_OTA.h

@ -22,6 +22,7 @@
#define SERVER_CHECK_INTERVAL 30 //in seconds
#define OTA_HTTPS_SEGMENT_SIZE 2048U
#define OTA_PROGRESS_LOG_INTERVAL 7U
#define OTA_MESH_SEGMENT_SIZE MESH_NETWORK_PAYLOAD_SIZE
#define ERROR_CHECK(x) if (err == ESP_OK) \
{ \
@ -32,17 +33,28 @@
} \
} \
enum otaMeshRole
{
Transmitter,
Receiver
};
typedef enum otaMeshRole OTA_MESH_ROLE_t;
esp_err_t errMeshOTAInitialize();
esp_err_t errOTAHTTPS(bool* pbNewOTAImage);
esp_err_t errOTAMeshSlave(bool* pbNewOTAImage);
esp_err_t errOTAMeshMaster(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr);
esp_err_t errOTAMeshTransmit(mesh_addr_t* pMeshNodeAddr);
esp_err_t errOTAMeshReceive(bool* pbNewOTAImage, mesh_addr_t* pMeshNodeAddr);
//helper functions
bool bNewerVersion(const char* pu8Local, const char* pu8Remote);
esp_err_t errExtractVersionNumber(const char* pu8Data, uint32_t* pu32DataLenght, char* pc8RemoteVersionNumber);
esp_err_t errFindImageStart(const char* pu8Data, uint32_t* pu32DataLenght, uint32_t* pu32StartOffset);
void vPrintOTAProgress(const uint32_t* const pu32TotalImageSize, const uint32_t* const pu32BytesWritten);
void vPrintOTAProgress(const uint32_t* const pu32TotalImageSize, const uint32_t* const pu32BytesWritten, OTA_MESH_ROLE_t eRole);
void vAddAllNeighboursToQueue(void);
esp_err_t errSendOTAVersionResponse(mesh_addr_t* meshReceiverAddr);
esp_err_t errSendOTAVersionRequest(mesh_addr_t* meshReceiverAddr);

6
components/mesh_ota/include/Mesh_network.h

@ -46,6 +46,7 @@
#define CONFIG_MESH_ROUTE_TABLE_SIZE 50
#endif
#define MESH_NETWORK_PAYLOAD_SIZE 1024U
struct meshPacket
{
@ -56,9 +57,10 @@ struct meshPacket
OTA_Version_Response, //send own version in payload
OTA_Data, //send image segment
OTA_ACK, //ack image segment
OTA_Complete //signal end of image
OTA_Complete, //signal end of image
OTA_Abort //abort OTA process
} type;
uint8_t au8Payload[1024];
uint8_t au8Payload[MESH_NETWORK_PAYLOAD_SIZE];
mesh_addr_t meshSenderAddr;
};

Loading…
Cancel
Save

Du besuchst diese Seite mit einem veralteten IPv4-Internetzugang. Möglicherweise treten in Zukunft Probleme mit der Erreichbarkeit und Performance auf. Bitte frage deinen Internetanbieter oder Netzwerkadministrator nach IPv6-Unterstützung.
You are visiting this site with an outdated IPv4 internet access. You may experience problems with accessibility and performance in the future. Please ask your ISP or network administrator for IPv6 support.
Weitere Infos | More Information
Klicke zum schließen | Click to close