From 1afb3c7bb338eba0410f85be8e5eaf192a7c4857 Mon Sep 17 00:00:00 2001 From: Serhii Kostiuk Date: Tue, 4 Aug 2020 10:20:54 +0300 Subject: Quectel EG25-G Delta Radio Firmware Upgrade support - libmts-io implementation During testing with L4G1 device I discovered some inconsistencies in behaviour between EG25-G device and EG95 devices (EG95-NA and EG95-E). EG25-G device that I have on hands does not allow to perform downgrades using delta images. When there is an attempt to apply a downgrade delta image it behaves as the following: - radio prints `OK` - radio prints `+QIND: "FOTA",502` - radio is not rebooted While EG95 radios always reboot at least once to apply the firmware image. Even if it is not valid. Also I noticed that detach from the serial bus may take more than 10 seconds in some rare cases. Thus we need to wait not a fixed amount of time but until the radio actually detaches from the bus. This commit attempts to address the findings described above. --- include/mts/MTS_IO_QuectelRadio.h | 3 +++ src/MTS_IO_QuectelRadio.cpp | 49 +++++++++++++++++++++++++++++++++++---- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/include/mts/MTS_IO_QuectelRadio.h b/include/mts/MTS_IO_QuectelRadio.h index 58e3d25..0f24db8 100644 --- a/include/mts/MTS_IO_QuectelRadio.h +++ b/include/mts/MTS_IO_QuectelRadio.h @@ -86,6 +86,9 @@ namespace MTS { CODE fumoWaitUpgradeFinished(UpdateCb& stepCb); CODE fumoWaitNewFirmware(UpdateCb& stepCb); + /// Parse error code in early FUMO URC result received before the first attempt to flash the firmware + std::string getFumoEarlyErrorCode(const std::string& sRadioInput); + /// Get value from container by its index, use default value if not found. Non-template version. const std::string& getByIndex(const std::vector& vector, size_t index, const std::string& defaultValue) { if (index >= vector.size()) { diff --git a/src/MTS_IO_QuectelRadio.cpp b/src/MTS_IO_QuectelRadio.cpp index 601674b..7d205e7 100644 --- a/src/MTS_IO_QuectelRadio.cpp +++ b/src/MTS_IO_QuectelRadio.cpp @@ -608,8 +608,12 @@ ICellularRadio::CODE QuectelRadio::fumoLocalCleanup() { } ICellularRadio::CODE QuectelRadio::fumoLocalApply(ICellularRadio::UpdateCb& stepCb) { + const std::string sFotaUrcPrefix = "+QIND: \"FOTA\""; // prefix for URC notification messages + const std::vector vFotaBailStrings{ sFotaUrcPrefix }; + ICellularRadio::CODE rc; std::string sCmd; + std::string sResponse; rc = getVendorFirmware(m_sQuectelFirmware); if (rc != SUCCESS) { @@ -631,8 +635,8 @@ ICellularRadio::CODE QuectelRadio::fumoLocalApply(ICellularRadio::UpdateCb& step return rc; } - 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 uint32_t duDetachTimeout = 15000; // wait up to 15 seconds for the radio to detach + const uint32_t duAttachTimeout = 30000; // wait up to 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++) { @@ -640,8 +644,22 @@ ICellularRadio::CODE QuectelRadio::fumoLocalApply(ICellularRadio::UpdateCb& step printInfo("Waiting for the radio to enter recovery mode"); callNextStep(stepCb, "FUMO Info: waiting for the radio to enter recovery mode"); - // Wait for the radio to detach from the USB bus - MTS::Thread::sleep(duDetachTimeout); + // Wait for new FOTA responses. Exits preliminary if radio detached. + sResponse = sendCommand("", vFotaBailStrings, duDetachTimeout, 0x00); + printTrace("Radio response: [%s]", sResponse.c_str()); + + if (i == 0 && sResponse.find(sFotaUrcPrefix) != std::string::npos) { + // FOTA responce code received before radio detach, image can't be applied. + // EG25-G radio prints a message in +QIND: "FOTA",ERR_CODE format in this case. + std::string sErrorCode = getFumoEarlyErrorCode(sResponse); + + printError("Preliminary termination of FUMO procedure: [%s]", sErrorCode.c_str()); + callNextStep(stepCb, "FUMO Error: radio returned error code " + sErrorCode); + + // We got a response from the radio but FOTA failed + rc = FAILURE; + break; + } // It's now detached. Try to reconnect if (!resetConnection(duAttachTimeout)) { @@ -1116,6 +1134,29 @@ ICellularRadio::CODE QuectelRadio::fumoWaitNewFirmware(ICellularRadio::UpdateCb& return rc; } +std::string QuectelRadio::getFumoEarlyErrorCode(const std::string& sRadioInput) { + const std::string sFotaPrefix = "+QIND: \"FOTA\","; + const char cLineEnd = ICellularRadio::CR; + + // sRadioInput may contain several lines. We need to find the line with '+QIND: "FOTA",' in it + auto pLineStart = sRadioInput.find(sFotaPrefix); + + if (pLineStart == std::string::npos) { + // FOTA line not found at all + return "-1"; + } + + // Parse the error code + auto pErrorStart = pLineStart + sFotaPrefix.length(); + auto pLineEnd = sRadioInput.find(cLineEnd, pErrorStart); + + // Filter the error code + std::string sSubString = sRadioInput.substr(pErrorStart, pLineEnd - pErrorStart); + std::string sResult = MTS::Text::trim(sSubString); + + return sResult; +} + ICellularRadio::CODE QuectelRadio::startFileUpload(const std::string& sTargetFilename, size_t nBytes) { const std::vector vBailStrings{ ICellularRadio::RSP_CONNECT, ICellularRadio::RSP_ERROR }; const int dTimeout = 1000; //ms -- cgit v1.2.3