From 2c3296b5239b5d27f5df4d61a9609ace6d70904f Mon Sep 17 00:00:00 2001 From: Serhii Kostiuk Date: Fri, 3 Jul 2020 17:59:47 +0300 Subject: Quectel Delta Radio Firmware Upgrade support - libmts-io implementation Started code cleanup before finishing the procedure. Renamed functions related to the delta radio firmware upgrade to follow established patterns: - uploadDeltaFirmwareFile -> fumoLocalInject - applyDeltaFirmwareFile -> fumoLocalApply - removeDeltaFirmwareFile -> fumoLocalCleanup - new function: updateFumoLocal - encapsulates all the magic for radios that may not support separate stages for the delta upload and delta apply --- include/mts/MTS_IO_CellularRadio.h | 7 ++- include/mts/MTS_IO_ICellularRadio.h | 55 ++++++++++------ include/mts/MTS_IO_QuectelRadio.h | 12 ++-- src/MTS_IO_CellularRadio.cpp | 18 ++++-- src/MTS_IO_QuectelRadio.cpp | 121 ++++++++++++++++++------------------ 5 files changed, 116 insertions(+), 97 deletions(-) diff --git a/include/mts/MTS_IO_CellularRadio.h b/include/mts/MTS_IO_CellularRadio.h index e65e7cd..e3941c3 100644 --- a/include/mts/MTS_IO_CellularRadio.h +++ b/include/mts/MTS_IO_CellularRadio.h @@ -99,9 +99,10 @@ namespace MTS { CODE updateDc(const Json::Value& jArgs, UpdateCb& stepCb) override; CODE updatePrl(const Json::Value& jArgs, UpdateCb& stepCb) override; CODE updateFumo(const Json::Value& jArgs, UpdateCb& stepCb) override; - CODE uploadDeltaFirmwareFile(int fd, UpdateCb& stepCb) override; - CODE removeDeltaFirmwareFile() override; - CODE applyDeltaFirmwareFile(UpdateCb& stepCb) override; + CODE updateFumoLocal(int fd, UpdateCb& stepCb) override; + CODE fumoLocalInject(int fd, UpdateCb& stepCb) override; + CODE fumoLocalApply(UpdateCb& stepCb) override; + CODE fumoLocalCleanup() override; CODE resetHfa(const Json::Value& jArgs, UpdateCb& stepCb) override; CODE activate(const Json::Value& jArgs, UpdateCb& stepCb) override; CODE startOmaDm(UpdateCb& stepCb) override; diff --git a/include/mts/MTS_IO_ICellularRadio.h b/include/mts/MTS_IO_ICellularRadio.h index 3259041..e1edbcd 100644 --- a/include/mts/MTS_IO_ICellularRadio.h +++ b/include/mts/MTS_IO_ICellularRadio.h @@ -429,54 +429,69 @@ namespace MTS { virtual CODE updateFumo(const Json::Value& jArgs, UpdateCb& stepCb) = 0; /** - * @brief uploadDeltaFirmwareFile - upload delta file to the radio's internal memory. + * @brief updateFumoLocal - Performs the radio firmware upgrade using local firmware image. * - * This command uploads (injects) the whole delta firmware image to some place that - * can be later used by the radio to perform the Delta Radio Firmware Upgrade. - * - * This delta firmware image is NOT validated on the firmware image upload step. + * This command uploads (injects) the whole delta firmware image to the radio, performs the + * upgrade and waits for it to complete. * - * @param fd - file sescriptor of a file that shall be uploaded to the radio. - * @param stepCb - the callback to receive status updates during the upload. - * @return CODE::SUCCESS when the file was successfully uploaded, + * @param fd - file descriptor of a file that shall be injected to the radio. + * @param stepCb - callback to receive status updates during the firmware upgrade. + * @return CODE::SUCCESS when the firmware upgrade was successful, * CODE::INVALID_ARGS when the file can't be opened for reading, + * CODE::FAILURE when upgrade failed on the radio side, * CODE::NOT_APPLICABLE when not supported by this radio, * CODE::ERROR otherwise. */ - virtual CODE uploadDeltaFirmwareFile(int fd, UpdateCb& stepCb) = 0; + virtual CODE updateFumoLocal(int fd, UpdateCb& stepCb) = 0; /** - * @brief removeDeltaFirmwareFile - remove the delta file from the radio's internal memory. + * @brief fumoLocalInject - upload delta file to the radio's internal memory. * - * This command allows to remove the old delta firmware image from the radio's internal - * memory for cases when it's no longer needed. + * This command uploads (injects) the whole delta firmware image to some place that + * can be later used by the radio to perform the Delta Radio Firmware Upgrade. + * + * This delta firmware image is NOT validated on the firmware image upload step. * * @param fd - file sescriptor of a file that shall be uploaded to the radio. - * @return CODE::SUCCESS when the file was successfully deleted, - * CODE::FAILURE when the file can't be deleted (i.e. no such file), + * @param stepCb - callback to receive status updates during the upload. + * @return CODE::SUCCESS when the file was successfully uploaded, + * CODE::INVALID_ARGS when the file can't be opened for reading, * CODE::NOT_APPLICABLE when not supported by this radio, * CODE::ERROR otherwise. */ - virtual CODE removeDeltaFirmwareFile() = 0; + virtual CODE fumoLocalInject(int fd, UpdateCb& stepCb) = 0; /** - * @brief applyDeltaFirmwareFile - apply the delta file that was previously uploaded. + * @brief fumoLocalApply - apply the delta file that was previously uploaded. * * This commands initializes and tracks the progress of the delta firmware upgrade * procedure using the delta firmware image file that was previously uploaded - * into internal radio's memory. + * into internal memory of the radio. * - * See ICellularRadio::removeDeltaFirmwareFile to upload the file and prepare + * See ICellularRadio::fumoLocalInject to upload the file and prepare * for the upgrade. * - * @param fd - file sescriptor of a file that shall be uploaded to the radio. + * @param fd - file descriptor of a file that shall be uploaded to the radio. * @param stepCb - the callback to receive status updates during the upgrade. + * @return CODE::SUCCESS when the firmware upgrade was successful, + * CODE::FAILURE when upgrade failed on the radio side, + * CODE::NOT_APPLICABLE when not supported by this radio, + * CODE::ERROR otherwise. + */ + virtual CODE fumoLocalApply(UpdateCb& stepCb) = 0; + + /** + * @brief fumoLocalCleanup - remove the delta file from the radio's internal memory. + * + * This command allows to remove the old delta firmware image from the radio's internal + * memory for cases when it's no longer needed. + * * @return CODE::SUCCESS when the file was successfully deleted, * CODE::FAILURE when the file can't be deleted (i.e. no such file), * CODE::NOT_APPLICABLE when not supported by this radio, * CODE::ERROR otherwise. */ - virtual CODE applyDeltaFirmwareFile(UpdateCb& stepCb) = 0; + virtual CODE fumoLocalCleanup() = 0; /* * jArgs = { diff --git a/include/mts/MTS_IO_QuectelRadio.h b/include/mts/MTS_IO_QuectelRadio.h index cb455d8..b805ed8 100644 --- a/include/mts/MTS_IO_QuectelRadio.h +++ b/include/mts/MTS_IO_QuectelRadio.h @@ -45,9 +45,10 @@ namespace MTS { CODE setCellularMode(CELLULAR_MODES networks) override; - CODE uploadDeltaFirmwareFile(int fd, UpdateCb& stepCb) override; - CODE removeDeltaFirmwareFile() override; - CODE applyDeltaFirmwareFile(UpdateCb& stepCb) override; + CODE updateFumoLocal(int fd, UpdateCb& stepCb) override; + CODE fumoLocalInject(int fd, UpdateCb& stepCb) override; + CODE fumoLocalCleanup() override; + CODE fumoLocalApply(UpdateCb& stepCb) override; protected: QuectelRadio(const std::string& sName, const std::string& sRadioPort); @@ -76,9 +77,8 @@ namespace MTS { static inline uint16_t bytesToUint16(uint8_t high, uint8_t low); static CODE getFileSize(int fd, size_t& nBytes, size_t& nFileChunks); static CODE readChunk(int fd, char* pChunk, size_t dChunkSize, size_t& nReadBytes); - CODE waitApplyDeltaFirmware(UpdateCb& stepCb); - CODE waitFotaFinish(UpdateCb& stepCb); - CODE waitNewFirmware(UpdateCb& stepCb); + CODE fumoWaitUpgradeFinished(UpdateCb& stepCb); + CODE fumoWaitNewFirmware(UpdateCb& stepCb); }; } } diff --git a/src/MTS_IO_CellularRadio.cpp b/src/MTS_IO_CellularRadio.cpp index 55f719f..bb7cd40 100644 --- a/src/MTS_IO_CellularRadio.cpp +++ b/src/MTS_IO_CellularRadio.cpp @@ -1051,20 +1051,26 @@ ICellularRadio::CODE CellularRadio::updateFumo(const Json::Value&, UpdateCb&) { return NOT_APPLICABLE; } -ICellularRadio::CODE CellularRadio::uploadDeltaFirmwareFile(int, ICellularRadio::UpdateCb&) { - printTrace("%s| Upload Delta Firmware Upgrade File: not applicable", m_sName.c_str()); +ICellularRadio::CODE CellularRadio::updateFumoLocal(int, ICellularRadio::UpdateCb&) { + printTrace("%s| Update Local Firmware Update Management Object", m_sName.c_str()); return NOT_APPLICABLE; } -ICellularRadio::CODE CellularRadio::removeDeltaFirmwareFile() { - printTrace("%s| Remove Delta Firmware Upgrade File: not applicable", m_sName.c_str()); +ICellularRadio::CODE CellularRadio::fumoLocalInject(int, ICellularRadio::UpdateCb&) { + printTrace("%s| Inject Delta Firmware Image File: not applicable", m_sName.c_str()); return NOT_APPLICABLE; } -ICellularRadio::CODE CellularRadio::applyDeltaFirmwareFile(ICellularRadio::UpdateCb&) { - printTrace("%s| Apply Delta Firmware Upgrade File: not applicable", m_sName.c_str()); +ICellularRadio::CODE CellularRadio::fumoLocalApply(ICellularRadio::UpdateCb&) { + printTrace("%s| Apply Delta Firmware Image File: not applicable", m_sName.c_str()); + + return NOT_APPLICABLE; +} + +ICellularRadio::CODE CellularRadio::fumoLocalCleanup() { + printTrace("%s| Cleanup Delta Firmware Image File: not applicable", m_sName.c_str()); return NOT_APPLICABLE; } diff --git a/src/MTS_IO_QuectelRadio.cpp b/src/MTS_IO_QuectelRadio.cpp index 25d2a30..7b67431 100644 --- a/src/MTS_IO_QuectelRadio.cpp +++ b/src/MTS_IO_QuectelRadio.cpp @@ -540,7 +540,21 @@ ICellularRadio::CODE QuectelRadio::startOmaDm(ICellularRadio::UpdateCb& stepCb) return eCode; } -ICellularRadio::CODE QuectelRadio::uploadDeltaFirmwareFile(int fd, ICellularRadio::UpdateCb& stepCb) { +ICellularRadio::CODE QuectelRadio::updateFumoLocal(int fd, ICellularRadio::UpdateCb& stepCb) { + CODE rc; + + rc = fumoLocalInject(fd, stepCb); + if (rc != SUCCESS) { + return rc; + } + + rc = fumoLocalApply(stepCb); + (void)fumoLocalCleanup(); // try to cleanup the injected file but cleanup errors are not fatal + + return rc; +} + +ICellularRadio::CODE QuectelRadio::fumoLocalInject(int fd, ICellularRadio::UpdateCb& stepCb) { CODE rc = FAILURE; bool bIsFilePresent = false; @@ -552,7 +566,7 @@ ICellularRadio::CODE QuectelRadio::uploadDeltaFirmwareFile(int fd, ICellularRadi } if (bIsFilePresent) { - rc = removeDeltaFirmwareFile(); + rc = fumoLocalCleanup(); } if (rc != SUCCESS) { @@ -571,16 +585,16 @@ ICellularRadio::CODE QuectelRadio::uploadDeltaFirmwareFile(int fd, ICellularRadi return rc; } -ICellularRadio::CODE QuectelRadio::removeDeltaFirmwareFile() { +ICellularRadio::CODE QuectelRadio::fumoLocalCleanup() { printTrace("Removing the delta upgrade file: %s", VALUE_MTS_DELTA_NAME.c_str()); return removeFile(VALUE_MTS_DELTA_NAME); } -ICellularRadio::CODE QuectelRadio::applyDeltaFirmwareFile(ICellularRadio::UpdateCb& stepCb) { +ICellularRadio::CODE QuectelRadio::fumoLocalApply(ICellularRadio::UpdateCb& stepCb) { ICellularRadio::CODE rc; std::string sCmd; - // Send "AT+QFOTADL" command to start the upgrade. OK responce follows shortly. + // Send "AT+QFOTADL" command to start the upgrade. OK response follows shortly. sCmd = "AT+QFOTADL=\""; sCmd += VALUE_MTS_DELTA_PATH; sCmd += "\""; @@ -594,16 +608,48 @@ ICellularRadio::CODE QuectelRadio::applyDeltaFirmwareFile(ICellularRadio::Update return rc; } - rc = waitApplyDeltaFirmware(stepCb); - if (rc != SUCCESS) { + const uint32_t duDetachTimeout = 10000; // wait for 10 seconds for the radio to detach + const uint32_t duAttachTimeout = 30000; // wait for 30 seconds for the radio to attach + const int dMaxAttempts = 5; // the radio makes 5 attempts to update the firmware + + for (int i = 0; i < dMaxAttempts; i++) { + + printInfo("Waiting for the radio to enter recovery mode"); if(stepCb) { - stepCb(Json::Value("FUMO Error: failed to apply the firmware")); + stepCb(Json::Value("FUMO Info: waiting for the radio to enter recovery mode")); } - //return rc; - } - // TODO: Check the new firmware version + // Wait for the radio to detach from the USB bus + MTS::Thread::sleep(duDetachTimeout); + + // It's now detached. Try to reconnect + if (!resetConnection(duAttachTimeout)) { + printError("Can't connect to the radio in %d ms", (duAttachTimeout)); + + if(stepCb) { + stepCb(Json::Value("FUMO error: failed to connect to the radio in recovery mode")); + } + break; + } + + // It's now back on the bus. Wait for the URC messages. + rc = fumoWaitUpgradeFinished(stepCb); + if (rc == ERROR) { + // unrecoverable error + break; + } + + if (rc != SUCCESS) { + // attempt failed, radio reboots and starts its next attempt + continue; + } + + // attempt finished + break; + } + // Wait for the radio to finish update and reboot + rc = fumoWaitNewFirmware(stepCb); return rc; } @@ -979,56 +1025,7 @@ ICellularRadio::CODE QuectelRadio::readChunk(int fd, char* pChunk, size_t dChunk return rc; } -ICellularRadio::CODE QuectelRadio::waitApplyDeltaFirmware(ICellularRadio::UpdateCb& stepCb) { - const uint32_t duDetachTimeout = 10000; // wait for 10 seconds for the radio to detach - const uint32_t duAttachTimeout = 30000; // wait for 30 seconds for the radio to attach - const int dMaxAttempts = 5; // the radio makes 5 attempts to update the firmware - - CODE rc = FAILURE; - std::string sResponse; - - for (int i = 0; i < dMaxAttempts; i++) { - - printInfo("Waiting for the radio to enter recovery mode"); - if(stepCb) { - stepCb(Json::Value("FUMO Info: waiting for the radio to enter recovery mode")); - } - - // Wait for the radio to detach from the USB bus - MTS::Thread::sleep(duDetachTimeout); - - // It's now detached. Try to reconnect - if (!resetConnection(duAttachTimeout)) { - printError("Can't connect to the radio in %d ms", (duAttachTimeout)); - - if(stepCb) { - stepCb(Json::Value("FUMO error: failed to connect to the radio in recovery mode")); - } - break; - } - - // It's now back on the bus. Wait for the URC messages. - rc = waitFotaFinish(stepCb); - if (rc == ERROR) { - // unrecoverable error - break; - } - - if (rc != SUCCESS) { - // attempt failed, radio reboots and starts its next attempt - continue; - } - - // attempt finished - break; - } - - // Wait for the radio to finish update and reboot - rc = waitNewFirmware(stepCb); - return rc; -} - -ICellularRadio::CODE QuectelRadio::waitFotaFinish(ICellularRadio::UpdateCb& stepCb) { +ICellularRadio::CODE QuectelRadio::fumoWaitUpgradeFinished(ICellularRadio::UpdateCb& stepCb) { const uint32_t duUrcTimeout = 4 * 60 * 1000; // wait for 4 minutes for the next URC message const std::string sFotaUrcPrefix = "+QIND: \"FOTA\""; // prefix for the URC notification messages const std::string sFotaUrcStart = "\"START\""; @@ -1082,7 +1079,7 @@ ICellularRadio::CODE QuectelRadio::waitFotaFinish(ICellularRadio::UpdateCb& step return rc; } -ICellularRadio::CODE QuectelRadio::waitNewFirmware(ICellularRadio::UpdateCb& stepCb) { +ICellularRadio::CODE QuectelRadio::fumoWaitNewFirmware(ICellularRadio::UpdateCb& stepCb) { MTS::Timer oTimer; oTimer.start(); std::string sFirmware; -- cgit v1.2.3