diff options
Diffstat (limited to 'src/MTS_IO_TelitRadio.cpp')
| -rw-r--r-- | src/MTS_IO_TelitRadio.cpp | 314 | 
1 files changed, 314 insertions, 0 deletions
| diff --git a/src/MTS_IO_TelitRadio.cpp b/src/MTS_IO_TelitRadio.cpp index be31b03..52b5664 100644 --- a/src/MTS_IO_TelitRadio.cpp +++ b/src/MTS_IO_TelitRadio.cpp @@ -24,8 +24,14 @@  #include <mts/MTS_Thread.h>  #include <mts/MTS_Text.h> +#include <unistd.h> +  using namespace MTS::IO; +const size_t TelitRadio::FILE_CHUNK_SIZE = 1024; +const std::string TelitRadio::CMD_ABORT_UPLOAD = "+++"; + +  TelitRadio::TelitRadio(const std::string& sName, const std::string& sRadioPort)  : CellularRadio(sName, sRadioPort)  { @@ -730,3 +736,311 @@ ICellularRadio::CODE TelitRadio::setCellularMode(CELLULAR_MODES networks) {      }      return SUCCESS;  } + +ICellularRadio::CODE TelitRadio::updateFumoLocal(int fd, ICellularRadio::UpdateCb& stepCb) { +    CODE rc = FAILURE; + +    rc = fumoLocalInject(fd, stepCb); +    if (rc != SUCCESS) { +        return rc; +    } + +    rc = fumoLocalApply(stepCb); + +    return rc; +} + +ICellularRadio::CODE TelitRadio::fumoLocalInject(int fd, ICellularRadio::UpdateCb& stepCb) { +    CODE rc = FAILURE; +    FOTA_GROUP group = getFotaGroup(); + +    do { +        callNextStep(stepCb, "FUMO Info: downloading the firmware"); + +        if ((group == VALUE_GROUP_A) || (group == VALUE_GROUP_B) || (group == VALUE_GROUP_D)) { +            rc = fumoWriteGroupsABD(fd, stepCb); +            if (rc != SUCCESS) { +                printError("Failed to inject the delta file."); +                callNextStep(stepCb, "FUMO Error: failed to download the firmware file"); +                break; +            } +        } else if (group == VALUE_GROUP_C) { +            //TODO Not Implemented TelitRadio::fumoWriteGroupC +            printError("Failed to inject the delta file."); +            callNextStep(stepCb, "FUMO Error: not implemented"); +            rc = NOT_APPLICABLE; +            break; +        } else { +            printError("Delta firmware upgrade is not supported for this type of radio modem"); +            callNextStep(stepCb, "FUMO Error: delta firmware upgrade is not supported for this type of radio modem"); +            rc = NOT_APPLICABLE; +            break; +        } + +        callNextStep(stepCb, "FUMO Info: firmware downloaded successfully"); + +    } while (false); + +    return rc; +} + +ICellularRadio::CODE TelitRadio::fumoLocalApply(ICellularRadio::UpdateCb& stepCb) { +    ICellularRadio::CODE rc; +    std::string sCmd; +    FOTA_GROUP group = getFotaGroup(); + +    rc = getTelitFirmware(m_sTelitFirmware); +    if (rc != SUCCESS) { +        callNextStep(stepCb, "FUMO Error: Failed to obtain current firmware version"); +        return rc; +    } +    printInfo("Current firmware version: %s", m_sTelitFirmware.c_str()); + +    if ((group == VALUE_GROUP_A) || (group == VALUE_GROUP_D)) { +        // Send "AT#OTAUP=0,0" command to start the upgrade. OK response follows shortly. +        sCmd  = "AT#OTAUP=0,0"; +    } else if ((group == VALUE_GROUP_B) || (group == VALUE_GROUP_C)) { +        // Send "AT#OTAUP=2" command to start the upgrade. OK response follows shortly. +        sCmd  = "AT#OTAUP=2"; +    } else { +        printError("Delta firmware upgrade is not supported for this type of radio modem"); +        callNextStep(stepCb, "FUMO Error: delta firmware upgrade is not supported for this type of radio modem"); +        return NOT_APPLICABLE; +    } + +    rc = sendBasicCommand(sCmd, 10000); + +    if (rc != SUCCESS) { +        printError("FUMO failed, OK not received from the radio"); +        callNextStep(stepCb, "FUMO Error: failed to apply the firmware"); +        return rc; +    } + +    const uint32_t duDetachTimeout = 10000;  // wait for 10 seconds for the radio to detach + +    do { +        printInfo("Applying the radio firmware"); +        callNextStep(stepCb, "FUMO Info: applying the radio firmware"); + +        // Wait for the radio to detach from the USB bus +        MTS::Thread::sleep(duDetachTimeout); + +        rc = fumoWaitUpgradeFinished(stepCb); + +        if (rc != SUCCESS) { +            break; +        } + +        rc = fumoCheckNewFirmware(stepCb); + +    } while (false); + + +    if (rc == SUCCESS) { +        printInfo("Radio firmware applied successfully"); +        callNextStep(stepCb, "FUMO Done: radio firmware applied successfully"); +    } else { +        printError("Radio firmware has not been updated"); +        callNextStep(stepCb, "FUMO Error: radio firmware has not been updated"); +    } + +    return rc; +} + +TelitRadio::FOTA_GROUP TelitRadio::getFotaGroup() { +    return VALUE_UNKNOWN; +} + +ICellularRadio::CODE TelitRadio::fumoWriteGroupsABD(int fd, ICellularRadio::UpdateCb& stepCb) { +    size_t dPayloadLength; +    size_t nChunks; +    CODE rc; + +    rc = getFileSize(fd, dPayloadLength); +    if (rc != SUCCESS) { +        return rc; +    } + +    rc = sizeToChunks(dPayloadLength, FILE_CHUNK_SIZE, nChunks); +    if (rc != SUCCESS) { +        return rc; +    } + +    printTrace("File size: %d bytes and %d chunks", dPayloadLength, nChunks); +    printTrace("Starting file upload..."); + +    rc = startWrite(); +    if (rc != SUCCESS) { +        return rc; +    } + +    printTrace("File upload started."); +    callNextStep(stepCb, "FILE Info: Started file upload"); + +    size_t nChunksPerCent = (nChunks / 100) + 1; +    size_t nFragmentLength = 0; +    std::array<char, FILE_CHUNK_SIZE> vBuffer; + +    for (size_t iChunk = 1; iChunk < (nChunks + 1); iChunk++) { + +        rc = readChunk(fd, vBuffer.data(), vBuffer.size(), nFragmentLength); +        if (rc != SUCCESS) { +            break; +        } + +        rc = sendData(vBuffer.data(), nFragmentLength); +        if (rc != SUCCESS) { +            break; +        } + +        if (stepCb && ((iChunk % nChunksPerCent) == 0)) { +            size_t dPercentsCompleted = iChunk / nChunksPerCent; +            callNextStep(stepCb, "FILE Info: Uploaded " + MTS::Text::format(dPercentsCompleted) + "%"); +        } +    } + +    if (rc != SUCCESS) { +        callNextStep(stepCb, "FILE Error: Upload failed due to internal error"); +    } else { +        callNextStep(stepCb, "FILE Info: Upload finished successfully"); +    } + +    // send +++ +    abortWrite(); +    return rc; +} + + +ICellularRadio::CODE TelitRadio::startWrite() { +    const std::vector<std::string> vBailStrings{ ICellularRadio::RSP_CONNECT, ICellularRadio::RSP_ERROR }; +    const int dTimeout = 1000; //ms +    std::string sCommand, sResult; + +    sCommand = "AT#OTAUPW"; + +    sResult = sendCommand(sCommand, vBailStrings, dTimeout); +    if (sResult.find(ICellularRadio::RSP_CONNECT) == std::string::npos) { +        printError("Radio is not ready to accept the file: [%s]", sResult.c_str()); +        return FAILURE; +    } + +    return SUCCESS; +} + +ICellularRadio::CODE TelitRadio::abortWrite() { +    /* +     * To prevent the “+++” from being mistaken for data, the following sequence should be followed: +     * 1) Do not input any character within 1s or longer before inputting “+++”. +     * 2) Input “+++” within 1s, and no other characters can be inputted during the time. +     * 3) Do not input any character within 1s after “+++” has been inputted. +     */ +    sleep(1); +    return sendBasicCommand(CMD_ABORT_UPLOAD, 2000, 0x00); +} + +ICellularRadio::CODE TelitRadio::getTelitFirmware(std::string& sFirmware) { +    /* +     * Currently, AT+CGMR command is used to determine the radio firmware version. +     * +     * AT+CGMR +     *   M0F.670006 +     * +     * Perhaps in the future we will use AT#SWPKGV command. +     * +     * AT#SWPKGV +     *   25.20.676-P0F.670690 +     *   M0F.670006 +     *   P0F.670690 +     *   A0F.670006 +     */ + +    printTrace("%s| Get Telit-specific firmware version", getName().c_str()); +    sFirmware = ICellularRadio::VALUE_NOT_SUPPORTED; +    std::string sCmd("AT+CGMR"); +    std::string sResult = sendCommand(sCmd); +    size_t pos = sResult.find(ICellularRadio::RSP_OK); +    if (pos == std::string::npos) { +        printWarning("%s| Unable to get firmware from radio using command [%s]", getName().c_str(), sCmd.c_str()); +        return FAILURE; +    } + +    sFirmware = MTS::Text::trim(sResult.substr(0, pos)); +    if(sFirmware.size() == 0) { +        printWarning("%s| Unable to get firmware from radio using command [%s]", getName().c_str(), sCmd.c_str()); +        return FAILURE; +    } + +    return SUCCESS; +} + +ICellularRadio::CODE TelitRadio::fumoWaitUpgradeFinished(ICellularRadio::UpdateCb& stepCb) { +    const uint32_t duAttachTimeout = 300000;       // wait for 300 seconds for the radio to attach +    const uint32_t duUrcTimeout = 60 * 1000;       // wait for 1 minutes for the next URC message +    const std::string sFotaUrcPrefix = "#OTAEV:";  // prefix for the URC notification messages +    const std::string sFotaUrcEndSuccess = "Module Upgraded To New Fw"; +    const std::string sFotaUrcEndFailed = "OTA Fw Upgrade Failed"; +    const std::vector<std::string> vFotaBailStrings{ sFotaUrcPrefix }; + +    CODE rc = FAILURE; +    std::string sResponse; + +    // It's now detached. Try to reconnect +    if (!resetConnection(duAttachTimeout)) { +        printError("Can't connect to the radio in %d ms", (duAttachTimeout)); +        callNextStep(stepCb, "FUMO Error: unable to obtain radio after reset"); +        return ERROR; +    } + +    while (true) { + +        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); +            callNextStep(stepCb, "FUMO Error: timeout, radio is not responding"); +            rc = ERROR; +            break; +        } + +        if (sResponse.find(sFotaUrcEndSuccess) != std::string::npos) { +            printTrace("Radio module upgraded to new firmware"); +            callNextStep(stepCb, "FUMO Info: radio module upgraded to new firmware"); +            rc = SUCCESS; +            break; +        } + +        if (sResponse.find(sFotaUrcEndFailed) != std::string::npos) { +            printTrace("Radio module firmware upgrade failed"); +            callNextStep(stepCb, "FUMO Error: firmware upgrade failed"); +            rc = ERROR; +            break; +        } + +    } + +    return rc; +} + +ICellularRadio::CODE TelitRadio::fumoCheckNewFirmware(ICellularRadio::UpdateCb& stepCb) { +    CODE rc = SUCCESS; +    std::string sTelitFirmware; + +    rc = getTelitFirmware(sTelitFirmware); + +    if (rc != SUCCESS) { +        callNextStep(stepCb, "FUMO Error: Failed to obtain current firmware version"); +        return rc; +    } + +    printInfo("Firmware version before the upgrade: %s", m_sTelitFirmware.c_str()); +    printInfo("Current firmware version: %s", sTelitFirmware.c_str()); + +    if (sTelitFirmware == m_sTelitFirmware) { +        // Radio will not reset anymore, firmware version left the same, not updated +        printError("Radio firmware version not changed after upgrade"); +        rc = FAILURE; +    } + +    return rc; +} | 
