added all doxygen comments

This commit is contained in:
Hendrik Schutter 2021-01-21 11:11:37 +01:00
parent f3749b9985
commit 7fe1f18985
11 changed files with 406 additions and 112 deletions

View File

@ -56,7 +56,7 @@ https_client_ret_t errHTTPSClientInitialize(void)
* @brief receive a image segment from server * @brief receive a image segment from server
* @param cpu8Data data buffer * @param cpu8Data data buffer
* @param cpcu32DataLenght desired byte amount * @param cpcu32DataLenght desired byte amount
* @param pu32BytesRead actual received byte amount * @param pu32BytesRead actual received byte amount
* @return HTTPS_Client error code * @return HTTPS_Client error code
* @author Hendrik Schutter * @author Hendrik Schutter
* @date 20.01.2021 * @date 20.01.2021

View File

@ -224,6 +224,15 @@ esp_err_t errMeshNetworkSetChangeStateOfServerWorkerHandle(void (*pChangeStateOf
return ESP_OK; return ESP_OK;
} }
/**
* @fn esp_err_t errMeshNetworkSendMeshPacket(const mesh_addr_t* const cpcAddrDest, const MESH_PACKET_t* const cpcPacket)
* @brief send packet to mesh node
* @param cpcAddrDest address from mesh node
* @param cpcPacket packet to send
* @return ESP32 error code
* @author Hendrik Schutter
* @date 20.01.2021
*/
esp_err_t errMeshNetworkSendMeshPacket(const mesh_addr_t* const cpcAddrDest, const MESH_PACKET_t* const cpcPacket) esp_err_t errMeshNetworkSendMeshPacket(const mesh_addr_t* const cpcAddrDest, const MESH_PACKET_t* const cpcPacket)
{ {
esp_err_t err; esp_err_t err;
@ -240,11 +249,27 @@ esp_err_t errMeshNetworkSendMeshPacket(const mesh_addr_t* const cpcAddrDest, con
return err; return err;
} }
bool bMeshNetworkIsRootNode() /**
* @fn bool bMeshNetworkIsRootNode()
* @brief return true if this node is the root
* @param void
* @return boolean
* @author Hendrik Schutter
* @date 21.01.2021
*/
bool bMeshNetworkIsRootNode(void)
{ {
return esp_mesh_is_root(); return esp_mesh_is_root();
} }
/**
* @fn bool bMeshNetworkIsNodeNeighbour(const mesh_addr_t* const cpcNode)
* @brief return true if node is neighbour if this
* @param cpcNode to check
* @return boolean
* @author Hendrik Schutter
* @date 21.01.2021
*/
bool bMeshNetworkIsNodeNeighbour(const mesh_addr_t* const cpcNode) bool bMeshNetworkIsNodeNeighbour(const mesh_addr_t* const cpcNode)
{ {
esp_err_t err = ESP_OK; esp_err_t err = ESP_OK;
@ -280,7 +305,16 @@ bool bMeshNetworkIsNodeNeighbour(const mesh_addr_t* const cpcNode)
return bReturn; return bReturn;
} }
//returns true if MAC address is equal
/**
* @fn bool bMeshNetworkCheckMACEquality(const uint8_t* const cpcu8aMAC, const uint8_t* const cpcu8bMAC)
* @brief returns true if MAC address is equal
* @param cpcu8aMAC first MAC
* @param cpcu8bMAC second MAC
* @return boolean
* @author Hendrik Schutter
* @date 21.01.2021
*/
bool bMeshNetworkCheckMACEquality(const uint8_t* const cpcu8aMAC, const uint8_t* const cpcu8bMAC) bool bMeshNetworkCheckMACEquality(const uint8_t* const cpcu8aMAC, const uint8_t* const cpcu8bMAC)
{ {
bool bRet = true; bool bRet = true;
@ -306,7 +340,15 @@ bool bMeshNetworkCheckMACEquality(const uint8_t* const cpcu8aMAC, const uint8_t*
return bRet; return bRet;
} }
esp_err_t errMeshNetworkStartReceiveTask() /**
* @fn esp_err_t errMeshNetworkStartReceiveTask()
* @brief start the task to receive the mesh packets
* @param void
* @return ESP32 error code
* @author Hendrik Schutter
* @date 21.01.2021
*/
esp_err_t errMeshNetworkStartReceiveTask(void)
{ {
esp_err_t err = ESP_OK; esp_err_t err = ESP_OK;
BaseType_t xReturned; BaseType_t xReturned;
@ -320,11 +362,28 @@ esp_err_t errMeshNetworkStartReceiveTask()
return err; return err;
} }
/**
* @fn vMeshNetworkGetOwnAddr(mesh_addr_t* const cpMeshOwnAddr)
* @brief return own MAC addr
* @param cpMeshOwnAddr pointer to own mac
* @return void
* @author Hendrik Schutter
* @date 21.01.2021
*/
void vMeshNetworkGetOwnAddr(mesh_addr_t* const cpMeshOwnAddr) void vMeshNetworkGetOwnAddr(mesh_addr_t* const cpMeshOwnAddr)
{ {
memcpy(cpMeshOwnAddr->addr, u8ownMAC, 6); memcpy(cpMeshOwnAddr->addr, u8ownMAC, 6);
} }
/**
* @fn esp_err_t errMeshNetworkGetChildren(mesh_addr_t* const cpChildren, uint16_t* const cpu16ChildrenSize)
* @brief get all connected children to node in array
* @param cpChildren pointer to array
* @param cpu16ChildrenSize pointer to size of array
* @return ESP32 error code
* @author Hendrik Schutter
* @date 21.01.2021
*/
esp_err_t errMeshNetworkGetChildren(mesh_addr_t* const cpChildren, uint16_t* const cpu16ChildrenSize) esp_err_t errMeshNetworkGetChildren(mesh_addr_t* const cpChildren, uint16_t* const cpu16ChildrenSize)
{ {
esp_err_t err = ESP_OK; esp_err_t err = ESP_OK;
@ -349,6 +408,14 @@ esp_err_t errMeshNetworkGetChildren(mesh_addr_t* const cpChildren, uint16_t* con
return err; return err;
} }
/**
* @fn void vMeshNetworkTaskReceiveMeshData(void *arg)
* @brief Task to receive all mesh packets
* @param arg
* @return void
* @author Hendrik Schutter
* @date 21.01.2021
*/
void vMeshNetworkTaskReceiveMeshData(void *arg) void vMeshNetworkTaskReceiveMeshData(void *arg)
{ {
esp_err_t err; esp_err_t err;
@ -398,6 +465,14 @@ void vMeshNetworkTaskReceiveMeshData(void *arg)
} //end while } //end while
} }
/**
* @fn esp_err_t errMeshNetworkGetParentNode(mesh_addr_t* const cpMeshParentAddr)
* @brief get parrent node if connected to it
* @param cpMeshParentAddr pointer to parent node addrs
* @return ESP32 error code
* @author Hendrik Schutter
* @date 21.01.2021
*/
esp_err_t errMeshNetworkGetParentNode(mesh_addr_t* const cpMeshParentAddr) esp_err_t errMeshNetworkGetParentNode(mesh_addr_t* const cpMeshParentAddr)
{ {
esp_err_t err = ESP_OK; esp_err_t err = ESP_OK;

View File

@ -1,3 +1,10 @@
/**
* @file Mesh_OTA.c
* @brief Start and implement OTA updates via HTTPS from server and other mesh nodes (bidirectional)
* @author Hendrik Schutter
* @date 21.01.2021
*/
#include "Mesh_OTA.h" #include "Mesh_OTA.h"
#include "Mesh_OTA_Util.h" #include "Mesh_OTA_Util.h"
#include "Mesh_OTA_Globals.h" #include "Mesh_OTA_Globals.h"
@ -5,7 +12,18 @@
static const char *LOG_TAG = "mesh_ota"; static const char *LOG_TAG = "mesh_ota";
esp_err_t errMeshOTAInitialize() /**
* @fn esp_err_t errMeshOTAInitialize(void)
* @brief Starts Mesh OTA functionality
* @param void
* @return ESP32 error code
* @author Hendrik Schutter
* @date 21.01.2021
*
* Initialize queues and tasks
* Set callbacks
*/
esp_err_t errMeshOTAInitialize(void)
{ {
esp_err_t err = ESP_OK; esp_err_t err = ESP_OK;
BaseType_t xReturned; BaseType_t xReturned;
@ -15,7 +33,7 @@ esp_err_t errMeshOTAInitialize()
queueNodes = xQueueCreate(QUEUE_NODES_SIZE, sizeof(mesh_addr_t)); queueNodes = xQueueCreate(QUEUE_NODES_SIZE, sizeof(mesh_addr_t));
if (queueNodes == 0) // Queue not created if (queueNodes == 0) // Queue not created
{ {
ESP_LOGE(LOG_TAG, "Unable to create Queue for Nodes"); ESP_LOGE(LOG_TAG, "Unable to create queue for nodes");
err = ESP_FAIL; err = ESP_FAIL;
} }
@ -25,7 +43,7 @@ esp_err_t errMeshOTAInitialize()
queueMessageOTA = xQueueCreate(QUEUE_MESSAGE_OTA_SIZE, sizeof(MESH_PACKET_t)); queueMessageOTA = xQueueCreate(QUEUE_MESSAGE_OTA_SIZE, sizeof(MESH_PACKET_t));
if (queueMessageOTA == 0) // Queue not created if (queueMessageOTA == 0) // Queue not created
{ {
ESP_LOGE(LOG_TAG, "Unable to create Queue for OTA Messages"); ESP_LOGE(LOG_TAG, "Unable to create queue for OTA messages");
err = ESP_FAIL; err = ESP_FAIL;
} }
} }
@ -35,7 +53,7 @@ esp_err_t errMeshOTAInitialize()
bsStartStopServerWorker = xSemaphoreCreateBinary(); bsStartStopServerWorker = xSemaphoreCreateBinary();
if( bsStartStopServerWorker == NULL ) if( bsStartStopServerWorker == NULL )
{ {
ESP_LOGE(LOG_TAG, "Unable to create Mutex to represent state of Server worker"); ESP_LOGE(LOG_TAG, "Unable to create mutex to represent state of server worker");
err = ESP_FAIL; err = ESP_FAIL;
} }
} }
@ -45,7 +63,7 @@ esp_err_t errMeshOTAInitialize()
bsOTAProcess = xSemaphoreCreateBinary(); bsOTAProcess = xSemaphoreCreateBinary();
if( bsOTAProcess == NULL ) if( bsOTAProcess == NULL )
{ {
ESP_LOGE(LOG_TAG, "Unable to create Mutex to grant access to OTA Process"); ESP_LOGE(LOG_TAG, "Unable to create mutex to grant access to OTA process");
err = ESP_FAIL; err = ESP_FAIL;
} }
} }
@ -55,11 +73,12 @@ esp_err_t errMeshOTAInitialize()
xSemaphoreGive(bsOTAProcess); //unlock binary semaphore xSemaphoreGive(bsOTAProcess); //unlock binary semaphore
if( bsOTAProcess == NULL ) if( bsOTAProcess == NULL )
{ {
ESP_LOGE(LOG_TAG, "Unable to unlock Mutex to grant access to OTA Process"); ESP_LOGE(LOG_TAG, "Unable to unlock mutex to grant access to OTA process");
err = ESP_FAIL; err = ESP_FAIL;
} }
} }
//register callbacks in network
ERROR_CHECK(errMeshNetworkSetChildConnectedHandle(vMeshOtaUtilAddNodeToPossibleUpdatableQueue)); ERROR_CHECK(errMeshNetworkSetChildConnectedHandle(vMeshOtaUtilAddNodeToPossibleUpdatableQueue));
ERROR_CHECK(errMeshNetworkSetOTAMessageHandleHandle(vMeshOtaUtilAddOtaMessageToQueue)); ERROR_CHECK(errMeshNetworkSetOTAMessageHandleHandle(vMeshOtaUtilAddOtaMessageToQueue));
ERROR_CHECK(errMeshNetworkSetChangeStateOfServerWorkerHandle(vMeshOtaUtilChangeStateOfServerWorker)); ERROR_CHECK(errMeshNetworkSetChangeStateOfServerWorkerHandle(vMeshOtaUtilChangeStateOfServerWorker));
@ -99,9 +118,17 @@ esp_err_t errMeshOTAInitialize()
return err; return err;
} }
/**
* @fn void vMeshOtaTaskServerWorker(void *arg)
* @brief Task for updating from server via HTTPS
* @param arg
* @return void
* @author Hendrik Schutter
* @date 21.01.2021
*/
void vMeshOtaTaskServerWorker(void *arg) void vMeshOtaTaskServerWorker(void *arg)
{ {
esp_err_t err; esp_err_t err = ESP_OK;
bool bNewOTAImage; //true if a new ota image was downloaded and validated bool bNewOTAImage; //true if a new ota image was downloaded and validated
bool bFirstRun = true; bool bFirstRun = true;
@ -118,6 +145,7 @@ void vMeshOtaTaskServerWorker(void *arg)
if(bFirstRun == true) if(bFirstRun == true)
{ {
//init on first run
ERROR_CHECK(errHTTPSClientInitialize()); ERROR_CHECK(errHTTPSClientInitialize());
bFirstRun = false; bFirstRun = false;
} }
@ -141,6 +169,14 @@ void vMeshOtaTaskServerWorker(void *arg)
} }
} }
/**
* @fn void vMeshOtaTaskServerWorker(void *arg)
* @brief Task for updating from nodes in mesh network
* @param arg
* @return void
* @author Hendrik Schutter
* @date 21.01.2021
*/
void vMeshOtaTaskOTAWorker(void *arg) void vMeshOtaTaskOTAWorker(void *arg)
{ {
esp_err_t err = ESP_OK; esp_err_t err = ESP_OK;
@ -155,8 +191,6 @@ void vMeshOtaTaskOTAWorker(void *arg)
if((uxQueueSpacesAvailable(queueNodes) - QUEUE_NODES_SIZE) == 0) if((uxQueueSpacesAvailable(queueNodes) - QUEUE_NODES_SIZE) == 0)
{ {
//nodes queue is empty //nodes queue is empty
ESP_LOGI(LOG_TAG, "nodes queue is empty");
if((bWantReboot == true) && (OTA_ALLOW_REBOOT == 1)) if((bWantReboot == true) && (OTA_ALLOW_REBOOT == 1))
{ {
ESP_LOGE(LOG_TAG, "ESP32 Reboot ..."); ESP_LOGE(LOG_TAG, "ESP32 Reboot ...");
@ -169,8 +203,6 @@ void vMeshOtaTaskOTAWorker(void *arg)
else else
{ {
//queue not empty //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) if (xQueueReceive(queueNodes, &meshNodeAddr, ((100) / portTICK_PERIOD_MS)) != pdTRUE)
{ {
ESP_LOGE(LOG_TAG, "Unable to receive OTA Messages from Queue"); ESP_LOGE(LOG_TAG, "Unable to receive OTA Messages from Queue");
@ -188,7 +220,6 @@ void vMeshOtaTaskOTAWorker(void *arg)
{ {
vMeshOtaUtilClearNeighboursQueue(&meshNodeAddr); //remove this node from queue vMeshOtaUtilClearNeighboursQueue(&meshNodeAddr); //remove this node from queue
} }
} }
if(bNewOTAImage == true) if(bNewOTAImage == true)
@ -196,18 +227,28 @@ void vMeshOtaTaskOTAWorker(void *arg)
//set want reboot //set want reboot
ESP_LOGI(LOG_TAG, "Updated successfully via Mesh, set pending reboot"); ESP_LOGI(LOG_TAG, "Updated successfully via Mesh, set pending reboot");
bWantReboot = true; bWantReboot = true;
vMeshOtaUtilAddAllNeighboursToQueue(); //add all existing neighbours to queue vMeshOtaUtilAddAllNeighboursToQueue(); //add all existing neighbours to queue
} }
vTaskDelay( (1000) / portTICK_PERIOD_MS); vTaskDelay( (1000) / portTICK_PERIOD_MS);
} }
} }
/**
* @fn esp_err_t errMeshOtaSlaveEndpoint(bool* const cpbNewOTAImage)
* @brief Endpoint for OTA process that is called from remote node
* @param cpbNewOTAImage pointer to boolean to signal if a new image was successfully received
* @return ESP32 error code
* @author Hendrik Schutter
* @date 21.01.2021
*
* Answers the OTA_Version_Request with OTA_Version_Response
* calls errMeshOtaPartitionAccessMeshReceive OR errMeshOtaPartitionAccessMeshTransmit based on version number
*/
esp_err_t errMeshOtaSlaveEndpoint(bool* const cpbNewOTAImage) esp_err_t errMeshOtaSlaveEndpoint(bool* const cpbNewOTAImage)
{ {
esp_err_t err = ESP_OK; esp_err_t err = ESP_OK;
MESH_PACKET_t sOTAMessage; MESH_PACKET_t sOTAMessage;
const esp_partition_t* pBootPartition; //pointer to boot partition (that will booted after reset) const esp_partition_t* cpBootPartition = NULL; //pointer to boot partition (that will booted after reset)
esp_app_desc_t bootPartitionDesc; //Metadate from boot partition esp_app_desc_t bootPartitionDesc; //Metadate from boot partition
*cpbNewOTAImage = false; //set default false *cpbNewOTAImage = false; //set default false
@ -225,8 +266,8 @@ esp_err_t errMeshOtaSlaveEndpoint(bool* const cpbNewOTAImage)
{ {
xSemaphoreTake(bsOTAProcess, portMAX_DELAY); //wait for binary semaphore that allows to start the OTA process 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 cpBootPartition = 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 ERROR_CHECK(esp_ota_get_partition_description(cpBootPartition, &bootPartitionDesc)); //get metadata of partition
//send OTA_Version_Response to sender of OTA_Version_Request packet wirh version in payload //send OTA_Version_Response to sender of OTA_Version_Request packet wirh version in payload
ERROR_CHECK(errMeshOtaUtilSendOTAVersionResponse(&sOTAMessage.meshSenderAddr)); ERROR_CHECK(errMeshOtaUtilSendOTAVersionResponse(&sOTAMessage.meshSenderAddr));
@ -252,11 +293,23 @@ esp_err_t errMeshOtaSlaveEndpoint(bool* const cpbNewOTAImage)
return err; return err;
} }
/**
* @fn esp_err_t errMeshOtaMasterEndpoint(bool* const cpbNewOTAImage, const mesh_addr_t* const cpcMeshNodeAddr)
* @brief Endpoint for OTA process that calls remote node
* @param cpbNewOTAImage pointer to boolean to signal if a new image was successfully received
* @param cpcMeshNodeAddr pointer to remote node addr
* @return ESP32 error code
* @author Hendrik Schutter
* @date 21.01.2021
*
* Sends the OTA_Version_Request to remote node
* calls errMeshOtaPartitionAccessMeshReceive OR errMeshOtaPartitionAccessMeshTransmit based on version number received
*/
esp_err_t errMeshOtaMasterEndpoint(bool* const cpbNewOTAImage, const mesh_addr_t* const cpcMeshNodeAddr) esp_err_t errMeshOtaMasterEndpoint(bool* const cpbNewOTAImage, const mesh_addr_t* const cpcMeshNodeAddr)
{ {
esp_err_t err = ESP_OK; esp_err_t err = ESP_OK;
MESH_PACKET_t sOTAMessage; MESH_PACKET_t sOTAMessage;
const esp_partition_t* pBootPartition; //pointer to boot partition (that will booted after reset) const esp_partition_t* cpBootPartition = NULL; //pointer to boot partition (that will booted after reset)
esp_app_desc_t bootPartitionDesc; //Metadata from boot partition esp_app_desc_t bootPartitionDesc; //Metadata from boot partition
bool bNodeIsConnected = false; bool bNodeIsConnected = false;
bool bNodeIsResponding = false; bool bNodeIsResponding = false;
@ -268,7 +321,6 @@ esp_err_t errMeshOtaMasterEndpoint(bool* const cpbNewOTAImage, const mesh_addr_t
bNodeIsConnected = true; //node is one of the neighbours bNodeIsConnected = true; //node is one of the neighbours
xSemaphoreTake(bsOTAProcess, portMAX_DELAY); //wait for binary semaphore that allows to start the OTA process xSemaphoreTake(bsOTAProcess, portMAX_DELAY); //wait for binary semaphore that allows to start the OTA process
ESP_LOGI(LOG_TAG, "Mesh-Master: send Version_Request to 0x%x", cpcMeshNodeAddr->addr[5]);
ERROR_CHECK(errMeshOtaUtilSendOTAVersionRequest(cpcMeshNodeAddr)); //send OTA_VERSION_REQUEST with local version in payload ERROR_CHECK(errMeshOtaUtilSendOTAVersionRequest(cpcMeshNodeAddr)); //send OTA_VERSION_REQUEST with local version in payload
for (uint32_t u32Index = 0; u32Index < QUEUE_MESSAGE_OTA_SIZE; u32Index++) //loop through all OTA messages for (uint32_t u32Index = 0; u32Index < QUEUE_MESSAGE_OTA_SIZE; u32Index++) //loop through all OTA messages
@ -285,8 +337,8 @@ esp_err_t errMeshOtaMasterEndpoint(bool* const cpbNewOTAImage, const mesh_addr_t
if((err == ESP_OK) && (sOTAMessage.type == OTA_Version_Response) && (bMeshNetworkCheckMACEquality(sOTAMessage.meshSenderAddr.addr, cpcMeshNodeAddr->addr))) //if OTA_Version_Request if((err == ESP_OK) && (sOTAMessage.type == OTA_Version_Response) && (bMeshNetworkCheckMACEquality(sOTAMessage.meshSenderAddr.addr, cpcMeshNodeAddr->addr))) //if OTA_Version_Request
{ {
bNodeIsResponding = true; bNodeIsResponding = true;
pBootPartition = esp_ota_get_boot_partition(); //get boot partition (that will booted after reset), not the running partition cpBootPartition = 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 ERROR_CHECK(esp_ota_get_partition_description(cpBootPartition, &bootPartitionDesc)); //get metadata of partition
if((bMeshOtaUtilNewerVersion((bootPartitionDesc).version, (char*) sOTAMessage.au8Payload)) && (err == ESP_OK)) //compare local and remote version if((bMeshOtaUtilNewerVersion((bootPartitionDesc).version, (char*) sOTAMessage.au8Payload)) && (err == ESP_OK)) //compare local and remote version
{ {
@ -313,7 +365,7 @@ esp_err_t errMeshOtaMasterEndpoint(bool* const cpbNewOTAImage, const mesh_addr_t
else else
{ {
// OTA Message queue is empty --> wait some time // OTA Message queue is empty --> wait some time
ESP_LOGI(LOG_TAG, "OTA-Master: OTA Message queue is empty --> wait some time"); ESP_LOGD(LOG_TAG, "OTA-Master: OTA Message queue is empty --> wait some time");
vTaskDelay( (1000/QUEUE_MESSAGE_OTA_SIZE) / portTICK_PERIOD_MS); vTaskDelay( (1000/QUEUE_MESSAGE_OTA_SIZE) / portTICK_PERIOD_MS);
} }
}//end loop }//end loop
@ -323,7 +375,7 @@ esp_err_t errMeshOtaMasterEndpoint(bool* const cpbNewOTAImage, const mesh_addr_t
if((bNodeIsResponding == false) && (bNodeIsConnected == true)) if((bNodeIsResponding == false) && (bNodeIsConnected == true))
{ {
//add node back to queue if connected and NOT responding //add node back to queue if connected and NOT responding
ESP_LOGI(LOG_TAG, "OTA-Master: connected and NOT responding --> add node back to queue "); ESP_LOGD(LOG_TAG, "OTA-Master: connected and NOT responding --> add node back to queue ");
vMeshOtaUtilAddNodeToPossibleUpdatableQueue(cpcMeshNodeAddr->addr); vMeshOtaUtilAddNodeToPossibleUpdatableQueue(cpcMeshNodeAddr->addr);
} }
return err; return err;

View File

@ -1,3 +1,10 @@
/**
* @file Mesh_OTA_Globals.c
* @brief global variables unsed in Mesh_OTA
* @author Hendrik Schutter
* @date 21.01.2021
*/
#include "Mesh_OTA_Globals.h" #include "Mesh_OTA_Globals.h"
xQueueHandle queueNodes; //nodes that should be checked for ota update (contains children and parent) xQueueHandle queueNodes; //nodes that should be checked for ota update (contains children and parent)

View File

@ -1,3 +1,13 @@
/**
* @file Mesh_OTA_Partition_Access.c
* @brief Write and read partition if requested from Mesh_OTA
* @author Hendrik Schutter
* @date 21.01.2021
*
* Additional Infos: Write image via HTTPS
* Receive or transmit via Mesh
*/
#include "Mesh_OTA.h" #include "Mesh_OTA.h"
#include "Mesh_OTA_Util.h" #include "Mesh_OTA_Util.h"
#include "Mesh_OTA_Globals.h" #include "Mesh_OTA_Globals.h"
@ -5,6 +15,18 @@
static const char *LOG_TAG = "mesh_ota_partition_access"; static const char *LOG_TAG = "mesh_ota_partition_access";
/**
* @fn esp_err_t errMeshOtaPartitionAccessHttps(bool* const cpbNewOTAImage)
* @brief Downloads and writes the image from the server to partition
* @param cpbNewOTAImage pointer to boolean to signal if a new image was successfully received
* @return ESP32 error code
* @author Hendrik Schutter
* @date 21.01.2021
*
* Checks if the image on server is newer
* Downloads the image in segements
* Handles OTA process
*/
esp_err_t errMeshOtaPartitionAccessHttps(bool* const cpbNewOTAImage) esp_err_t errMeshOtaPartitionAccessHttps(bool* const cpbNewOTAImage)
{ {
esp_err_t err = ESP_OK; esp_err_t err = ESP_OK;
@ -22,7 +44,8 @@ esp_err_t errMeshOtaPartitionAccessHttps(bool* const cpbNewOTAImage)
ERROR_CHECK(errMeshOtaUtilExtractVersionNumber(u8OTABuffer, &u32BytesRead, pcRemoteVersionNumber)); //extract version numbers ERROR_CHECK(errMeshOtaUtilExtractVersionNumber(u8OTABuffer, &u32BytesRead, pcRemoteVersionNumber)); //extract version numbers
if(err == ESP_OK) //check if version number is found //check if version number is found
if(err == ESP_OK)
{ {
xSemaphoreTake(bsOTAProcess, portMAX_DELAY); //wait for binary semaphore that allows to start the OTA process xSemaphoreTake(bsOTAProcess, portMAX_DELAY); //wait for binary semaphore that allows to start the OTA process
@ -35,8 +58,8 @@ esp_err_t errMeshOtaPartitionAccessHttps(bool* const cpbNewOTAImage)
ESP_LOGI(LOG_TAG, "Server: image is newer --> OTA update required"); ESP_LOGI(LOG_TAG, "Server: image is newer --> OTA update required");
ERROR_CHECK(errMeshOtaUtilFindImageStart(u8OTABuffer, &u32BufferLenght, &u32StartOffset)); //get image start offset ERROR_CHECK(errMeshOtaUtilFindImageStart(u8OTABuffer, &u32BufferLenght, &u32StartOffset)); //get image start offset
ERROR_CHECK(esp_ota_begin(pOTAPartition, OTA_SIZE_UNKNOWN, &otaHandle)); //start ota update process ERROR_CHECK(esp_ota_begin(pOTAPartition, OTA_SIZE_UNKNOWN, &otaHandle)); //start ota update process
if(err == ESP_OK) if(err == ESP_OK)
{ {
//image download and ota partition write //image download and ota partition write
@ -54,7 +77,8 @@ esp_err_t errMeshOtaPartitionAccessHttps(bool* const cpbNewOTAImage)
u32OTABytesWritten = u32OTABytesWritten + u32BytesRead; //update counter u32OTABytesWritten = u32OTABytesWritten + u32BytesRead; //update counter
} }
} }
while ((u32BytesRead > 0) && (err == ESP_OK) && (u32OTABytesWritten <= pOTAPartition->size)); //loop until error or complete image downloaded //loop until error or complete image downloaded
while ((u32BytesRead > 0) && (err == ESP_OK) && (u32OTABytesWritten <= pOTAPartition->size));
} }
if(err == ESP_OK) if(err == ESP_OK)
@ -70,7 +94,7 @@ esp_err_t errMeshOtaPartitionAccessHttps(bool* const cpbNewOTAImage)
else else
{ {
//error occurred --> abort ota update process //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)); 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)); ERROR_CHECK(esp_ota_abort(otaHandle));
*cpbNewOTAImage = false; //ota update failed *cpbNewOTAImage = false; //ota update failed
} }
@ -84,27 +108,39 @@ esp_err_t errMeshOtaPartitionAccessHttps(bool* const cpbNewOTAImage)
return err; return err;
} }
/**
* @fn esp_err_t errMeshOtaPartitionAccessMeshTransmit(const mesh_addr_t* const cpcMeshNodeAddr)
* @brief Reads the local image and sends it to node
* @param cpcMeshNodeAddr pointer to mesh node addr to send the image segments to
* @return ESP32 error code
* @author Hendrik Schutter
* @date 21.01.2021
*
* Reads the newest OTA image in segments
* Sends the image to mesh node in segments
* Handles OTA process
*/
esp_err_t errMeshOtaPartitionAccessMeshTransmit(const mesh_addr_t* const cpcMeshNodeAddr) esp_err_t errMeshOtaPartitionAccessMeshTransmit(const mesh_addr_t* const cpcMeshNodeAddr)
{ {
esp_err_t err = ESP_OK; esp_err_t err = ESP_OK;
const esp_partition_t* pBootPartition; //pointer to boot partition (that will booted after reset) const esp_partition_t* pBootPartition = NULL; //pointer to boot partition (that will booted after reset)
MESH_PACKET_t sMeshPacket; //packet for sending and receiving MESH_PACKET_t sMeshPacket; //packet for sending and receiving
// uint32_t u32Index = 0U; //index for partition read offset // uint32_t u32Index = 0U; //index for partition read offset
bool bAbort = false; //abort the OTA process bool bAbort = false; //abort the OTA process
bool bNodeIsResponding = false; //remote node is still active bool bNodeIsResponding = false; //remote node is still active
uint32_t u32OTABytesWritten = 0U; uint32_t u32OTABytesWritten = 0U; //counter of bytes unsed for progress log
uint32_t u32SegmentCounter = 0U; uint32_t u32SegmentCounter = 0U; //counter of segments unsed for progress log
pBootPartition = esp_ota_get_boot_partition(); //get boot partition (that will booted after reset), not the running partition 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 //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)) while( ((OTA_MESH_SEGMENT_SIZE * u32SegmentCounter) < pBootPartition->size) && (err == ESP_OK) && (bAbort == false))
{ {
bNodeIsResponding = false; //reset to default bNodeIsResponding = false; //reset to default for this loop
// read partition with offset based in index // read partition with offset based in index
ERROR_CHECK(esp_partition_read(pBootPartition, (OTA_MESH_SEGMENT_SIZE * u32SegmentCounter), sMeshPacket.au8Payload, OTA_MESH_SEGMENT_SIZE)); ERROR_CHECK(esp_partition_read(pBootPartition, (OTA_MESH_SEGMENT_SIZE * u32SegmentCounter), sMeshPacket.au8Payload, OTA_MESH_SEGMENT_SIZE));
u32OTABytesWritten = ((u32SegmentCounter+1) * OTA_MESH_SEGMENT_SIZE); u32OTABytesWritten = ((u32SegmentCounter+1) * OTA_MESH_SEGMENT_SIZE); //calc bytes that are written in this ota process
vMeshOtaUtilPrintOTAProgress(&(pBootPartition->size), &u32OTABytesWritten, Transmitter); vMeshOtaUtilPrintOTAProgress(&(pBootPartition->size), &u32OTABytesWritten, Transmitter);
if(err == ESP_OK) if(err == ESP_OK)
@ -115,10 +151,9 @@ esp_err_t errMeshOtaPartitionAccessMeshTransmit(const mesh_addr_t* const cpcMesh
if((OTA_MESH_SEGMENT_SIZE * (u32SegmentCounter+1)) >= pBootPartition->size) //check if last segment if((OTA_MESH_SEGMENT_SIZE * (u32SegmentCounter+1)) >= pBootPartition->size) //check if last segment
{ {
//last partition image segment --> send OTA_Complete //last partition image segment --> send OTA_Complete
ESP_LOGI(LOG_TAG, "OTA-TX: last segment--> send Complete"); ESP_LOGD(LOG_TAG, "OTA-TX: last segment--> send Complete");
sMeshPacket.type = OTA_Complete; sMeshPacket.type = OTA_Complete;
} }
//ESP_LOGI(LOG_TAG, "OTA-TX: send packet");
err = errMeshNetworkSendMeshPacket(cpcMeshNodeAddr, &sMeshPacket); err = errMeshNetworkSendMeshPacket(cpcMeshNodeAddr, &sMeshPacket);
} }
else else
@ -126,39 +161,35 @@ esp_err_t errMeshOtaPartitionAccessMeshTransmit(const mesh_addr_t* const cpcMesh
// error while read --> send OTA_ABORT and abort this OTA process // error while read --> send OTA_ABORT and abort this OTA process
sMeshPacket.type = OTA_Abort; sMeshPacket.type = OTA_Abort;
bAbort = true; bAbort = true;
ESP_LOGI(LOG_TAG, "OTA-TX: error while read --> send ABORT"); ESP_LOGE(LOG_TAG, "OTA-TX: error while read --> send ABORT");
errMeshNetworkSendMeshPacket(cpcMeshNodeAddr, &sMeshPacket); errMeshNetworkSendMeshPacket(cpcMeshNodeAddr, &sMeshPacket);
} }
// loop through all OTA messages or until abort is called or error // 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 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) //get OTA message from queue
// {
//queue not empty
if (xQueueReceive(queueMessageOTA, &sMeshPacket, ((OTA_MESH_TIMEOUT) / portTICK_PERIOD_MS)) != pdTRUE) if (xQueueReceive(queueMessageOTA, &sMeshPacket, ((OTA_MESH_TIMEOUT) / portTICK_PERIOD_MS)) != pdTRUE)
{ {
ESP_LOGE(LOG_TAG, "Unable to receive OTA Messages from queue"); ESP_LOGE(LOG_TAG, "Unable to receive OTA Messages from queue");
err = ESP_FAIL; err = ESP_FAIL;
} }
if((err == ESP_OK) && (bMeshNetworkCheckMACEquality(sMeshPacket.meshSenderAddr.addr, cpcMeshNodeAddr->addr))) //if OTA_Version_Request //check if from correct node
if((err == ESP_OK) && (bMeshNetworkCheckMACEquality(sMeshPacket.meshSenderAddr.addr, cpcMeshNodeAddr->addr)))
{ {
//packet from node received //packet from node received --> handle it
switch (sMeshPacket.type) switch (sMeshPacket.type)
{ {
case OTA_ACK: //increase index for next round case OTA_ACK: //start next loop for segment
u32Index++;
bNodeIsResponding = true; bNodeIsResponding = true;
u32Index = QUEUE_MESSAGE_OTA_SIZE;//this will end the loop through all OTA messages u32Index = QUEUE_MESSAGE_OTA_SIZE; //this will end the loop through all OTA messages
break; break;
case OTA_Abort: //abort this OTA process case OTA_Abort: //abort this OTA process
bAbort = true; bAbort = true;
bNodeIsResponding = true; bNodeIsResponding = true;
break; break;
default: default:
//receives wrong OTA message type from node --> back to queue
//vMeshOtaUtilAddOtaMessageToQueue(&sMeshPacket);
break; break;
} }
} }
@ -167,16 +198,6 @@ esp_err_t errMeshOtaPartitionAccessMeshTransmit(const mesh_addr_t* const cpcMesh
//received from wrong node --> back to queue //received from wrong node --> back to queue
vMeshOtaUtilAddOtaMessageToQueue(&sMeshPacket); vMeshOtaUtilAddOtaMessageToQueue(&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 }//end OTA message loop
if(bNodeIsResponding == false) if(bNodeIsResponding == false)
@ -188,10 +209,23 @@ esp_err_t errMeshOtaPartitionAccessMeshTransmit(const mesh_addr_t* const cpcMesh
} }
u32SegmentCounter++; u32SegmentCounter++;
}//end of partition segment loop }//end of partition segment loop
vMeshOtaUtilClearOtaMessageQueue(cpcMeshNodeAddr); vMeshOtaUtilClearOtaMessageQueue(cpcMeshNodeAddr); //remove all OTA messages from remote node
return err; return err;
} }
/**
* @fn esp_err_t errMeshOtaPartitionAccessMeshReceive(bool* const cpbNewOTAImage, const mesh_addr_t* const cpcMeshNodeAddr)
* @brief Downloads and writes the image from the remote node
* @param cpbNewOTAImage pointer to boolean to signal if a new image was successfully received
* @param cpcMeshNodeAddr pointer to mesh node addr to receive the image segments from
* @return ESP32 error code
* @author Hendrik Schutter
* @date 21.01.2021
*
* Receives the images segments from remote node
* Writtes segments to OTA partition
* Handles OTA process
*/
esp_err_t errMeshOtaPartitionAccessMeshReceive(bool* const cpbNewOTAImage, const mesh_addr_t* const cpcMeshNodeAddr) esp_err_t errMeshOtaPartitionAccessMeshReceive(bool* const cpbNewOTAImage, const mesh_addr_t* const cpcMeshNodeAddr)
{ {
esp_err_t err = ESP_OK; esp_err_t err = ESP_OK;
@ -201,8 +235,8 @@ esp_err_t errMeshOtaPartitionAccessMeshReceive(bool* const cpbNewOTAImage, const
bool bNodeIsResponding = false; //remote node is still active bool bNodeIsResponding = false; //remote node is still active
uint32_t u32OTABytesWritten = 0U; //counter unsed for progress log uint32_t u32OTABytesWritten = 0U; //counter unsed for progress log
static esp_ota_handle_t otaHandle; //OTA process handle static esp_ota_handle_t otaHandle; //OTA process handle
*cpbNewOTAImage = false; *cpbNewOTAImage = false; //set default to false
uint32_t u32SegmentCounter = 0U; uint32_t u32SegmentCounter = 0U; //counter of segments unsed for progress log
ERROR_CHECK(esp_ota_begin(pOTAPartition, OTA_SIZE_UNKNOWN, &otaHandle)); //start ota update process ERROR_CHECK(esp_ota_begin(pOTAPartition, OTA_SIZE_UNKNOWN, &otaHandle)); //start ota update process
@ -230,24 +264,21 @@ esp_err_t errMeshOtaPartitionAccessMeshReceive(bool* const cpbNewOTAImage, const
{ {
case OTA_Complete: //signal end of this OTA process, fall through because same behavior as OTA_Data case OTA_Complete: //signal end of this OTA process, fall through because same behavior as OTA_Data
bComplete = true; bComplete = true;
ESP_LOGI(LOG_TAG, "OTA-RX: rec Complete --> last segment"); //fall through
//fall through
case OTA_Data: //data segement received case OTA_Data: //data segement received
bNodeIsResponding = true; bNodeIsResponding = true;
ERROR_CHECK(esp_ota_write(otaHandle, sMeshPacket.au8Payload, OTA_MESH_SEGMENT_SIZE)); ERROR_CHECK(esp_ota_write(otaHandle, sMeshPacket.au8Payload, OTA_MESH_SEGMENT_SIZE));
u32OTABytesWritten = ((u32SegmentCounter+1) * OTA_MESH_SEGMENT_SIZE); u32OTABytesWritten = ((u32SegmentCounter+1) * OTA_MESH_SEGMENT_SIZE); //calc bytes that are written in this ota process
vMeshOtaUtilPrintOTAProgress(&(pOTAPartition->size), &u32OTABytesWritten, Receiver); vMeshOtaUtilPrintOTAProgress(&(pOTAPartition->size), &u32OTABytesWritten, Receiver);
u32Index = QUEUE_MESSAGE_OTA_SIZE; //this will end the loop through all OTA messages u32Index = QUEUE_MESSAGE_OTA_SIZE; //this will end the loop through all OTA messages
break; break;
case OTA_Abort: //abort this OTA process case OTA_Abort: //abort this OTA process
bAbort = true; bAbort = true;
bNodeIsResponding = true; bNodeIsResponding = true;
ESP_LOGI(LOG_TAG, "OTA-RX: rec Abort"); ESP_LOGE(LOG_TAG, "OTA-RX: receives abort --> abort this OTA process on this node");
//this will end the loop through all OTA messages //this will end the loop through all OTA messages
break; break;
default: default:
//receives wrong OTA message type from node --> back to queue
//vMeshOtaUtilAddOtaMessageToQueue(&sMeshPacket);
break; break;
} }
} }
@ -256,16 +287,6 @@ esp_err_t errMeshOtaPartitionAccessMeshReceive(bool* const cpbNewOTAImage, const
//received from wrong node --> back to queue //received from wrong node --> back to queue
vMeshOtaUtilAddOtaMessageToQueue(&sMeshPacket); vMeshOtaUtilAddOtaMessageToQueue(&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 }//end of OTA message loop
if(bNodeIsResponding == false) if(bNodeIsResponding == false)
@ -284,7 +305,6 @@ esp_err_t errMeshOtaPartitionAccessMeshReceive(bool* const cpbNewOTAImage, const
if(bAbort == false) if(bAbort == false)
{ {
//no error while ota write --> send OTA_ACK packet //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; sMeshPacket.type = OTA_ACK;
err = errMeshNetworkSendMeshPacket(cpcMeshNodeAddr, &sMeshPacket); err = errMeshNetworkSendMeshPacket(cpcMeshNodeAddr, &sMeshPacket);
} }
@ -305,7 +325,7 @@ esp_err_t errMeshOtaPartitionAccessMeshReceive(bool* const cpbNewOTAImage, const
{ {
//all OTA segments received --> validate //all OTA segments received --> validate
ESP_LOGI(LOG_TAG, "OTA-RX: validate image "); ESP_LOGI(LOG_TAG, "OTA-RX: validate image ");
ERROR_CHECK(esp_ota_end(otaHandle)); ERROR_CHECK(esp_ota_end(otaHandle)); //validate image
ERROR_CHECK(esp_ota_set_boot_partition(pOTAPartition)); ERROR_CHECK(esp_ota_set_boot_partition(pOTAPartition));
if(err == ESP_OK) if(err == ESP_OK)
{ {

View File

@ -1,17 +1,32 @@
/**
* @file Mesh_OTA_Util.c
* @brief Utility and helper functions to perfrom mesh OTA updates
* @author Hendrik Schutter
* @date 21.01.2021
*/
#include "Mesh_OTA_Util.h" #include "Mesh_OTA_Util.h"
#include "Mesh_OTA_Globals.h" #include "Mesh_OTA_Globals.h"
static const char *LOG_TAG = "mesh_ota"; static const char *LOG_TAG = "mesh_ota";
/**
* @fn bool bMeshOtaUtilNewerVersion(const char* cpu8Local, const char* cpu8Remote)
* @brief compares to version strings
* @param cpu8Local local image version string
* @param cpu8Remote remote image version string
* @return bool
* @author Hendrik Schutter
* @date 21.01.2021
*
* Returns true if remote is newer
*/
bool bMeshOtaUtilNewerVersion(const char* cpu8Local, const char* cpu8Remote) bool bMeshOtaUtilNewerVersion(const char* cpu8Local, const char* cpu8Remote)
{ {
/*
* Return true if remote version is newer (higher) than local version
*/
char u8LocalTmp[12]; //local version char u8LocalTmp[12]; //local version
char u8RemoteTmp[12]; //remote version char u8RemoteTmp[12]; //remote version
char* pu8saveptrLocal; //context for strok_r char* pu8saveptrLocal = NULL; //context for strok_r
char* pu8saveptrRemote; //context for strok_r char* pu8saveptrRemote = NULL; //context for strok_r
bool bReturn = false; //flag to stop loop bool bReturn = false; //flag to stop loop
uint8_t u8Index = 0; //numbers counter in version string uint8_t u8Index = 0; //numbers counter in version string
@ -34,6 +49,18 @@ bool bMeshOtaUtilNewerVersion(const char* cpu8Local, const char* cpu8Remote)
return bReturn; return bReturn;
} }
/**
* @fn esp_err_t errMeshOtaUtilExtractVersionNumber(const char* cpu8Data, uint32_t* const cpcu32DataLenght, char* const pc8RemoteVersionNumber)
* @brief extract version number from image data
* @param cpu8Data image data buffer
* @param cpcu32DataLenght pointer to lenght of image data
* @param pc8RemoteVersionNumber pointer version number
* @return ESP32 error code
* @author Hendrik Schutters
* @date 21.01.2021
*
* Search version number in raw image data
*/
esp_err_t errMeshOtaUtilExtractVersionNumber(const char* cpu8Data, uint32_t* const cpcu32DataLenght, char* const pc8RemoteVersionNumber) esp_err_t errMeshOtaUtilExtractVersionNumber(const char* cpu8Data, uint32_t* const cpcu32DataLenght, char* const pc8RemoteVersionNumber)
{ {
uint32_t u32StartOffset; uint32_t u32StartOffset;
@ -51,14 +78,25 @@ esp_err_t errMeshOtaUtilExtractVersionNumber(const char* cpu8Data, uint32_t* con
return err; return err;
} }
/**
* @fn esp_err_t errMeshOtaUtilFindImageStart(const char* const cpu8Data, const uint32_t* const cpcu32DataLenght, uint32_t* const cpu32StartOffset)
* @brief find start offset from image raw data
* @param cpu8Data image data buffer
* @param cpcu32DataLenght pointer to lenght of image data
* @param cpu32StartOffset pointer to determined offset
* @return ESP32 error code
* @author Hendrik Schutter
* @date 21.01.2021
*
* Search offset in raw image data from server (exclude HTTP response)
*/
esp_err_t errMeshOtaUtilFindImageStart(const char* const cpu8Data, const uint32_t* const cpcu32DataLenght, uint32_t* const cpu32StartOffset) esp_err_t errMeshOtaUtilFindImageStart(const char* const cpu8Data, const uint32_t* const cpcu32DataLenght, uint32_t* const cpu32StartOffset)
{ {
/*
Offset value // Offset value
0 = 0xE9 (first byte in image --> magic byte) // 0 = 0xE9 (first byte in image --> magic byte)
48 = first digit of version number // 48 = first digit of version number
*/
esp_err_t errReturn = ESP_OK; esp_err_t errReturn = ESP_OK;
bool bImageStartOffsetFound = false; bool bImageStartOffsetFound = false;
uint32_t u32DataIndex = 0; uint32_t u32DataIndex = 0;
@ -129,13 +167,21 @@ esp_err_t errMeshOtaUtilFindImageStart(const char* const cpu8Data, const uint32_
return errReturn; return errReturn;
} }
/**
* @fn esp_err_t errMeshOtaUtilSendOTAVersionRequest(const mesh_addr_t* const cpcMeshReceiverAddr)
* @brief send OTA_Version_Request to node
* @param cpcMeshReceiverAddr node addr
* @return ESP32 error code
* @author Hendrik Schutter
* @date 21.01.2021
*/
esp_err_t errMeshOtaUtilSendOTAVersionRequest(const mesh_addr_t* const cpcMeshReceiverAddr) esp_err_t errMeshOtaUtilSendOTAVersionRequest(const mesh_addr_t* const cpcMeshReceiverAddr)
{ {
esp_err_t err = ESP_OK; esp_err_t err = ESP_OK;
MESH_PACKET_t packet; MESH_PACKET_t packet;
packet.type = OTA_Version_Request; packet.type = OTA_Version_Request;
const esp_partition_t* pBootPartition; //pointer to boot partition (that will booted after reset) const esp_partition_t* pBootPartition = NULL; //pointer to boot partition (that will booted after reset)
esp_app_desc_t bootPartitionDesc; //Metadata from boot partition 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 pBootPartition = esp_ota_get_boot_partition(); //get boot partition (that will booted after reset), not the running partition
@ -145,25 +191,43 @@ esp_err_t errMeshOtaUtilSendOTAVersionRequest(const mesh_addr_t* const cpcMeshRe
return err; return err;
} }
/**
* @fn esp_err_t errMeshOtaUtilSendOTAVersionResponse(const mesh_addr_t* const cpcMeshReceiverAddr)
* @brief send OTA_Version_Response to node
* @param cpcMeshReceiverAddr node addr
* @return ESP32 error code
* @author Hendrik Schutter
* @date 21.01.2021
*/
esp_err_t errMeshOtaUtilSendOTAVersionResponse(const mesh_addr_t* const cpcMeshReceiverAddr) esp_err_t errMeshOtaUtilSendOTAVersionResponse(const mesh_addr_t* const cpcMeshReceiverAddr)
{ {
esp_err_t err = ESP_OK; esp_err_t err = ESP_OK;
MESH_PACKET_t packet; MESH_PACKET_t packet;
packet.type = OTA_Version_Response; packet.type = OTA_Version_Response;
const esp_partition_t* pBootPartition; //pointer to boot partition (that will booted after reset) const esp_partition_t* pBootPartition = NULL; //pointer to boot partition (that will booted after reset)
esp_app_desc_t bootPartitionDesc; //Metadata from boot partition 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 pBootPartition = esp_ota_get_boot_partition(); //get boot partition (that will booted after reset), not the running partition
ERROR_CHECK(esp_ota_get_partition_description(pBootPartition, &bootPartitionDesc)); //get metadate of partition ERROR_CHECK(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 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", cpcMeshReceiverAddr->addr[5]); ESP_LOGD(LOG_TAG, "Send OTA_Version_Response to 0x%x", cpcMeshReceiverAddr->addr[5]);
err = errMeshNetworkSendMeshPacket(cpcMeshReceiverAddr, &packet); err = errMeshNetworkSendMeshPacket(cpcMeshReceiverAddr, &packet);
return err; return err;
} }
/**
* @fn void vMeshOtaUtilPrintOTAProgress(const uint32_t* const cpcu32TotalImageSize, const uint32_t* const cpcu32BytesWritten, const OTA_MESH_ROLE_t ceRole)
* @brief print LOG for OTA process progress
* @param cpcu32TotalImageSize size of OTA partition
* @param cpcu32BytesWritten actual bytes written
* @param ceRole role if this OTA process
* @return void
* @author Hendrik Schutter
* @date 21.01.2021
*/
void vMeshOtaUtilPrintOTAProgress(const uint32_t* const cpcu32TotalImageSize, const uint32_t* const cpcu32BytesWritten, const OTA_MESH_ROLE_t ceRole) void vMeshOtaUtilPrintOTAProgress(const uint32_t* const cpcu32TotalImageSize, const uint32_t* const cpcu32BytesWritten, const OTA_MESH_ROLE_t ceRole)
{ {
uint32_t u32Percentage = 0U; uint32_t u32Percentage = 0U;
@ -196,6 +260,14 @@ void vMeshOtaUtilPrintOTAProgress(const uint32_t* const cpcu32TotalImageSize, co
} }
} }
/**
* @fn void vMeshOtaUtilAddAllNeighboursToQueue(void)
* @brief add all neigbhours (children and parent) to queue
* @param void
* @return void
* @author Hendrik Schutter
* @date 21.01.2021
*/
void vMeshOtaUtilAddAllNeighboursToQueue(void) void vMeshOtaUtilAddAllNeighboursToQueue(void)
{ {
esp_err_t err = ESP_OK; esp_err_t err = ESP_OK;
@ -209,7 +281,6 @@ void vMeshOtaUtilAddAllNeighboursToQueue(void)
if(err == ESP_OK) if(err == ESP_OK)
{ {
vMeshOtaUtilAddNodeToPossibleUpdatableQueue(addrParent.addr); vMeshOtaUtilAddNodeToPossibleUpdatableQueue(addrParent.addr);
ESP_LOGI(LOG_TAG, "added parent");
} }
err = ESP_OK; //reset error code err = ESP_OK; //reset error code
@ -219,10 +290,17 @@ void vMeshOtaUtilAddAllNeighboursToQueue(void)
for (uint16_t u16Index = 0; ((u16Index < u16ChildrenSize) && (err == ESP_OK)); u16Index++) for (uint16_t u16Index = 0; ((u16Index < u16ChildrenSize) && (err == ESP_OK)); u16Index++)
{ {
vMeshOtaUtilAddNodeToPossibleUpdatableQueue(childrenAddr[u16Index].addr); vMeshOtaUtilAddNodeToPossibleUpdatableQueue(childrenAddr[u16Index].addr);
ESP_LOGI(LOG_TAG, "added child");
} }
} }
/**
* @fn void vMeshOtaUtilClearOtaMessageQueue(const mesh_addr_t* const cpcMeshNodeAddr)
* @brief remode all OTA messages from this node in queue
* @param cpcMeshNodeAddr node addr
* @return void
* @author Hendrik Schutter
* @date 21.01.2021
*/
void vMeshOtaUtilClearOtaMessageQueue(const mesh_addr_t* const cpcMeshNodeAddr) void vMeshOtaUtilClearOtaMessageQueue(const mesh_addr_t* const cpcMeshNodeAddr)
{ {
MESH_PACKET_t sMeshPacket; //packet for sending and receiving MESH_PACKET_t sMeshPacket; //packet for sending and receiving
@ -235,14 +313,18 @@ void vMeshOtaUtilClearOtaMessageQueue(const mesh_addr_t* const cpcMeshNodeAddr)
//received OTA message is NOT from cpcMeshNodeAddr --> keep it in queue //received OTA message is NOT from cpcMeshNodeAddr --> keep it in queue
vMeshOtaUtilAddOtaMessageToQueue(&sMeshPacket); vMeshOtaUtilAddOtaMessageToQueue(&sMeshPacket);
} }
else
{
ESP_LOGI(LOG_TAG, "Removed type %i from node 0x%x", sMeshPacket.type, cpcMeshNodeAddr->addr[5]);
}
} }
}//end OTA message loop }//end OTA message loop
} }
/**
* @fn void vMeshOtaUtilClearNeighboursQueue(const mesh_addr_t* const cpcMeshNodeAddr)
* @brief remode all instances of this node in queue
* @param cpcMeshNodeAddr node addr
* @return void
* @author Hendrik Schutter
* @date 21.01.2021
*/
void vMeshOtaUtilClearNeighboursQueue(const mesh_addr_t* const cpcMeshNodeAddr) void vMeshOtaUtilClearNeighboursQueue(const mesh_addr_t* const cpcMeshNodeAddr)
{ {
mesh_addr_t sNode; //packet for sending and receiving mesh_addr_t sNode; //packet for sending and receiving
@ -255,15 +337,18 @@ void vMeshOtaUtilClearNeighboursQueue(const mesh_addr_t* const cpcMeshNodeAddr)
//node is NOT cpcMeshNodeAddr --> keep it in queue //node is NOT cpcMeshNodeAddr --> keep it in queue
vMeshOtaUtilAddNodeToPossibleUpdatableQueue(cpcMeshNodeAddr->addr); vMeshOtaUtilAddNodeToPossibleUpdatableQueue(cpcMeshNodeAddr->addr);
} }
else
{
ESP_LOGI(LOG_TAG, "Removed node 0x%x", cpcMeshNodeAddr->addr[5]);
}
} }
}//end OTA message loop }//end OTA message loop
} }
/**
* @fn void vMeshOtaUtilAddNodeToPossibleUpdatableQueue(const uint8_t* const cpcu8MAC)
* @brief add node instance to queue
* @param cpcu8MAC MAC addr of node
* @return void
* @author Hendrik Schutter
* @date 21.01.2021
*/
void vMeshOtaUtilAddNodeToPossibleUpdatableQueue(const uint8_t* const cpcu8MAC) void vMeshOtaUtilAddNodeToPossibleUpdatableQueue(const uint8_t* const cpcu8MAC)
{ {
//send payload to node queues //send payload to node queues
@ -276,10 +361,18 @@ void vMeshOtaUtilAddNodeToPossibleUpdatableQueue(const uint8_t* const cpcu8MAC)
} }
else 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]); ESP_LOGD(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]);
} }
} }
/**
* @fn void vMeshOtaUtilAddOtaMessageToQueue(const MESH_PACKET_t* const cpcuMeshPacket)
* @brief add OTA message to queue
* @param cpcuMeshPacket OTA message
* @return void
* @author Hendrik Schutter
* @date 21.01.2021
*/
void vMeshOtaUtilAddOtaMessageToQueue(const MESH_PACKET_t* const cpcuMeshPacket) void vMeshOtaUtilAddOtaMessageToQueue(const MESH_PACKET_t* const cpcuMeshPacket)
{ {
//send ota packet to packet queue //send ota packet to packet queue
@ -292,14 +385,14 @@ void vMeshOtaUtilAddOtaMessageToQueue(const MESH_PACKET_t* const cpcuMeshPacket)
switch (cpcuMeshPacket->type) switch (cpcuMeshPacket->type)
{ {
case OTA_Abort: case OTA_Abort:
ESP_LOGI(LOG_TAG, "added ota message to queue: OTA_Abort from 0x%x", cpcuMeshPacket->meshSenderAddr.addr[5]); ESP_LOGD(LOG_TAG, "added ota message to queue: OTA_Abort from 0x%x", cpcuMeshPacket->meshSenderAddr.addr[5]);
break; break;
case OTA_Version_Request: case OTA_Version_Request:
ESP_LOGI(LOG_TAG, "added ota message to queue: OTA_Version_Request from 0x%x", cpcuMeshPacket->meshSenderAddr.addr[5]); ESP_LOGD(LOG_TAG, "added ota message to queue: OTA_Version_Request from 0x%x", cpcuMeshPacket->meshSenderAddr.addr[5]);
break; break;
case OTA_Version_Response: case OTA_Version_Response:
ESP_LOGI(LOG_TAG, "added ota message to queue: OTA_Version Response from 0x%x", cpcuMeshPacket->meshSenderAddr.addr[5]); ESP_LOGD(LOG_TAG, "added ota message to queue: OTA_Version Response from 0x%x", cpcuMeshPacket->meshSenderAddr.addr[5]);
break; break;
default: default:
break; break;
@ -307,14 +400,20 @@ void vMeshOtaUtilAddOtaMessageToQueue(const MESH_PACKET_t* const cpcuMeshPacket)
} }
} }
void vMeshOtaUtilChangeStateOfServerWorker(const bool cbState) //allow access via function ptn to network_handler /**
* @fn void vMeshOtaUtilChangeStateOfServerWorker(const bool cbState)
* @brief callback for mesh network if connectivity to server changed
* @param cbState boolean state
* @return void
* @author Hendrik Schutter
* @date 21.01.2021
*/
void vMeshOtaUtilChangeStateOfServerWorker(const bool cbState)
{ {
static bool bLastState = false; static bool bLastState = false;
if(cbState != bLastState) //change only if necessary if(cbState != bLastState) //change only if necessary
{ {
ESP_LOGI(LOG_TAG, "server worker change handler");
if(cbState == true) if(cbState == true)
{ {
if (xSemaphoreGive(bsStartStopServerWorker) != pdTRUE) if (xSemaphoreGive(bsStartStopServerWorker) != pdTRUE)

View File

@ -1,3 +1,12 @@
/**
* @file Mesh_Network.h
* @brief Mesh network layer used by OTA and APP
* @author Hendrik Schutter, init based in ESP32-IDE code
* @date 20.01.2021
*
* Additional Infos: Start network and send and receive data.
*/
#ifndef H_MESH_NETWORK #ifndef H_MESH_NETWORK
#define H_MESH_NETWORK #define H_MESH_NETWORK

View File

@ -1,3 +1,10 @@
/**
* @file Mesh_OTA.h
* @brief Start and implement OTA updates via HTTPS from server and other mesh nodes (bidirectional)
* @author Hendrik Schutter
* @date 21.01.2021
*/
#ifndef H_MESH_OTA #ifndef H_MESH_OTA
#define H_MESH_OTA #define H_MESH_OTA

View File

@ -1,3 +1,11 @@
/**
* @file Mesh_OTA_Globals.h
* @brief global variables unsed in Mesh_OTA
* @author Hendrik Schutter
* @date 21.01.2021
*
*/
#ifndef H_MESH_OTA_GLOBALS #ifndef H_MESH_OTA_GLOBALS
#define H_MESH_OTA_GLOBALS #define H_MESH_OTA_GLOBALS

View File

@ -1,3 +1,13 @@
/**
* @file Mesh_OTA_Partition_Access.h
* @brief Write and read partition if requested from Mesh_OTA
* @author Hendrik Schutter
* @date 21.01.2021
*
* Additional Infos: Write image via HTTPS
* Receive or transmit via Mesh
*/
#ifndef H_MESH_OTA_PARTITION_ACCESS #ifndef H_MESH_OTA_PARTITION_ACCESS
#define H_MESH_OTA_PARTITION_ACCESS #define H_MESH_OTA_PARTITION_ACCESS

View File

@ -1,3 +1,10 @@
/**
* @file Mesh_OTA_Util.h
* @brief Utility and helper functions to perfrom mesh OTA updates
* @author Hendrik Schutter
* @date 21.01.2021
*/
#ifndef H_MESH_OTA_UTIL #ifndef H_MESH_OTA_UTIL
#define H_MESH_OTA_UTIL #define H_MESH_OTA_UTIL