diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/MTS_IO_QuectelRadio.cpp | 179 | 
1 files changed, 178 insertions, 1 deletions
| diff --git a/src/MTS_IO_QuectelRadio.cpp b/src/MTS_IO_QuectelRadio.cpp index 2ed11b0..25d2a30 100644 --- a/src/MTS_IO_QuectelRadio.cpp +++ b/src/MTS_IO_QuectelRadio.cpp @@ -25,6 +25,7 @@  #include <mts/MTS_Logger.h>  #include <mts/MTS_Thread.h>  #include <mts/MTS_Text.h> +#include <mts/MTS_Timer.h>  #include <unistd.h> @@ -576,7 +577,34 @@ ICellularRadio::CODE QuectelRadio::removeDeltaFirmwareFile() {  }  ICellularRadio::CODE QuectelRadio::applyDeltaFirmwareFile(ICellularRadio::UpdateCb& stepCb) { -    return ERROR;  // not implemented +    ICellularRadio::CODE rc; +    std::string sCmd; + +    // Send "AT+QFOTADL" command to start the upgrade. OK responce follows shortly. +    sCmd  = "AT+QFOTADL=\""; +    sCmd += VALUE_MTS_DELTA_PATH; +    sCmd += "\""; + +    rc = sendBasicCommand(sCmd, 1000); + +    if (rc != SUCCESS) { +        if(stepCb) { +            stepCb(Json::Value("FUMO Error: failed to apply the firmware")); +        } +        return rc; +    } + +    rc = waitApplyDeltaFirmware(stepCb); +    if (rc != SUCCESS) { +        if(stepCb) { +            stepCb(Json::Value("FUMO Error: failed to apply the firmware")); +        } +        //return rc; +    } + +    // TODO: Check the new firmware version + +    return rc;  }  ICellularRadio::CODE QuectelRadio::getServiceDomain(ICellularRadio::SERVICEDOMAIN& sd) { @@ -951,6 +979,155 @@ 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) { +    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\""; +    const std::string sFotaUrcProgress = "\"UPDATING\""; +    const std::string sFotaUrcEnd = "\"END\""; +    const std::vector<std::string> vFotaBailStrings{ sFotaUrcPrefix }; + +    CODE rc = ERROR; +    std::string sResponse; + +    while (true) {  // breaks on "FOTA","END" +        sResponse = sendCommand("", vFotaBailStrings, duUrcTimeout, 0x00); +        printTrace("Radio response: [%s]", sResponse.c_str()); + +        if (sResponse.find(sFotaUrcPrefix) == std::string::npos) { +            printError("No URC messages from the radio in %d ms", duUrcTimeout); + +            if(stepCb) { +                stepCb(Json::Value("FUMO error: timeout, radio is not responding")); +            } + +            break; +        } + +        const auto vParts = MTS::Text::split(MTS::Text::trim(sResponse), ',', 3); +        const std::string& sStage = vParts[1]; +        if (sStage == sFotaUrcEnd) { +            // FOTA finished +            printTrace("Got FOTA END message"); +            const std::string& sCode = vParts[2]; + +            if (sCode == "0") { +                // finished successfully +                rc = SUCCESS; +                break; +            } +            // attempt failed, the radio attempts to recover +            rc = FAILURE; +            break; +        } else if (sStage == sFotaUrcStart) { +            printTrace("Got FOTA START message"); +        } else if (sStage == sFotaUrcProgress) { +            printTrace("Got FOTA progress message"); +            const std::string& sPercents = vParts[2]; +            printInfo("FOTA progress: [%s]", sPercents.c_str()); +        } else { +            printInfo("FOTA unexpected URC code: [%s]", sStage.c_str()); +        } +    } + +    return rc; +} + +ICellularRadio::CODE QuectelRadio::waitNewFirmware(ICellularRadio::UpdateCb& stepCb) { +    MTS::Timer oTimer; +    oTimer.start(); +    std::string sFirmware; +    CODE rc = FAILURE; + +    while (oTimer.getSeconds() < (5 * 60)) { // 5 minutes + +        MTS::Thread::sleep(10000); + +        if (getFirmware(sFirmware) != SUCCESS) { +            // The radio is probably unavailable +            resetConnection(100); +            continue; +        } + +#if 0 +        if (sFirmware == m_sFw && sFirmwareBuild == m_sFwBuild) { +            // Have the same firmware. The radio resets several time +            // before the firmware is actually get upgraded. So keep polling. +            continue; +        } +#endif + +        // The firmware numbers have changed +        printTrace("Current firmware: %s", sFirmware.c_str()); +        rc = SUCCESS; +        break; + +    } +    oTimer.stop(); + +    if (rc == SUCCESS) { +        if(stepCb) { +            stepCb(Json::Value("FUMO done: radio firmware applied successfully")); +        } +    } +    else { +        if(stepCb) { +            stepCb(Json::Value("FUMO error: radio firmware has not been updated")); +        } +    } + +    return rc; +} +  ICellularRadio::CODE QuectelRadio::startFileUpload(const std::string& sTargetFilename, size_t nBytes) {      const std::vector<std::string> vBailStrings{ ICellularRadio::RSP_CONNECT, ICellularRadio::RSP_ERROR };      const int dTimeout = 1000; //ms | 
