summaryrefslogtreecommitdiff
path: root/src/MTS_IO_TelitRadio.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/MTS_IO_TelitRadio.cpp')
-rw-r--r--src/MTS_IO_TelitRadio.cpp314
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;
+}