summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/MTS_IO_CellularRadio.cpp122
-rw-r--r--src/MTS_IO_CellularRadioFactory.cpp18
-rw-r--r--src/MTS_IO_ICellularRadio.cpp26
-rw-r--r--src/MTS_IO_LE910SV1Radio.cpp36
-rw-r--r--src/MTS_IO_ME910C1NARadio.cpp127
-rw-r--r--src/MTS_IO_ME910C1NVRadio.cpp623
-rw-r--r--src/MTS_IO_ME910C1WWRadio.cpp593
7 files changed, 745 insertions, 800 deletions
diff --git a/src/MTS_IO_CellularRadio.cpp b/src/MTS_IO_CellularRadio.cpp
index 6f45da4..50fdf5c 100644
--- a/src/MTS_IO_CellularRadio.cpp
+++ b/src/MTS_IO_CellularRadio.cpp
@@ -306,7 +306,7 @@ ICellularRadio::CODE CellularRadio::getSimStatusSummary(Json::Value& jData) {
}
if (!bIsSimInserted) {
- // There is no left much to do. Return one field only.
+ // There is not much left to do. Return one field only.
jData[KEY_IS_SIM_INSERTED] = bIsSimInserted;
break;
}
@@ -314,6 +314,16 @@ ICellularRadio::CODE CellularRadio::getSimStatusSummary(Json::Value& jData) {
// The following code assumes that the SIM card is inserted
retCode = getSimLockStatus(sSimLockStatus);
if (retCode != SUCCESS) {
+ /* IN:4033:
+ *
+ * On some devices #SIMDET reports "inserted" but +CPIN? returns ERROR when there is
+ * no SIM card in the slot. It's also the case when only plastic holder is inserted
+ * instead of the SIM itself.
+ *
+ * Interpret this error as "SIM card not detected" for such cases.
+ */
+ jData[KEY_IS_SIM_INSERTED] = false;
+ retCode = SUCCESS;
break;
}
@@ -694,6 +704,14 @@ void CellularRadio::getCommonNetworkStats(Json::Value& jData) {
jData[ICellularRadio::KEY_NETWORK_REG] = sNetworkReg;
}
}
+
+ std::string sCurrentCellMode;
+ CELLULAR_MODES eModes;
+ if (getCellularMode(eModes) == SUCCESS) {
+ if (convertCellModesToString(eModes, sCurrentCellMode) == SUCCESS) {
+ jData[ICellularRadio::KEY_CELL_MODE] = sCurrentCellMode;
+ }
+ }
}
ICellularRadio::CODE CellularRadio::getSimLockStatus(std::string& sData)
@@ -736,41 +754,79 @@ void CellularRadio::initMipProfile(Json::Value& jData) {
jData[ICellularRadio::KEY_MIP_MNHASS] = false;
}
-ICellularRadio::CODE CellularRadio::getRegistration(REGISTRATION& eRegistration) {
- std::string sCmd;
- std::string sResp;
+const std::vector<std::string> CellularRadio::getRegistrationCommands() {
+ std::string sType;
+ convertModelToType(getName(), sType);
- // LE910C1-NS is an LE910, so we stop the scan after the 0.
- // NOTE: Eventually this may need to be changed to try all three of CREG, CGREG, and CEREG
- if ((m_sName.find("LE910") != std::string::npos) || (m_sName.find("ME910") != std::string::npos)) {
- // use AT+CGREG instead for LE910 models
- sCmd = "AT+CGREG?";
- sResp = "+CGREG: ";
- }
- else {
- sCmd = "AT+CREG?";
- sResp = "+CREG: ";
+ if (sType == VALUE_TYPE_LTE) {
+ return { "CREG", "CGREG", "CEREG" };
+ } else {
+ return { "CREG", "CGREG" };
}
+}
+ICellularRadio::REGISTRATION CellularRadio::parseRegResponse(std::string sResult) {
+ size_t start = sResult.find(',');
+ size_t stop = sResult.find(' ', start);
+ std::string sRegStat = sResult.substr(start + 1, stop - start - 1);
+ int32_t value;
+ sscanf(sRegStat.c_str(), "%d", &value);
+
+ return (ICellularRadio::REGISTRATION)value;
+}
+
+ICellularRadio::CODE CellularRadio::getRegistration(REGISTRATION& eRegistration, const std::string& sType) {
+ std::string sCmd = "AT+" + sType + "?";
+ std::string sResp = "+" + sType + ": ";
std::string sResult = sendCommand(sCmd, DEFAULT_BAIL_STRINGS, 5000);
if (sResult.find(sResp) == std::string::npos) {
if(sResult.size() == 0) {
- printDebug("%s| Registration command returned no response: [%s]", m_sName.c_str());
+ printDebug("%s| Registration command returned no response", m_sName.c_str());
return NO_RESPONSE;
}
printDebug("%s| Registration command returned unexpected response: [%s]", m_sName.c_str(), sResult.c_str());
return FAILURE;
}
- size_t start = sResult.find(',');
- size_t stop = sResult.find(' ', start);
- std::string sRegStat = sResult.substr(start + 1, stop - start - 1);
- int32_t value;
- sscanf(sRegStat.c_str(), "%d", &value);
- eRegistration = (REGISTRATION)value;
+ eRegistration = parseRegResponse(sResult);
return SUCCESS;
}
+ICellularRadio::CODE CellularRadio::getRegistration(REGISTRATION& eRegistration) {
+ /* REGISTRATION_PRIORITY:
+ * REGISTERED = 0
+ * ROAMING = 1
+ * DENIED = 2
+ * SEARCHING = 3
+ * NOT_REGISTERED = 4
+ * UNKNOWN = 5
+ */
+ uint8_t uRegPriority[] = { 4, 0, 3, 2, 5, 1 };
+ ICellularRadio::CODE ret = ERROR;
+ REGISTRATION eReg = UNKNOWN;
+ eRegistration = UNKNOWN;
+
+ // We need to check CREG, CGREG, and CEREG for possible success.
+ // Depending on the radio, carrier, roaming, sim card, cellular mode and some other factors the registration
+ // will come back differently depending on the type of connection that is possible.
+
+ const auto & commands = getRegistrationCommands();
+ for (const auto & cmd : commands) {
+ ret = getRegistration(eReg, cmd);
+ if (ret != SUCCESS) {
+ break;
+ }
+
+ if (eReg == REGISTERED || eReg == ROAMING) {
+ eRegistration = eReg;
+ break;
+ }
+ eRegistration = (uRegPriority[eRegistration] > uRegPriority[eReg]) ? eReg : eRegistration;
+ }
+
+ return ret;
+}
+
ICellularRadio::CODE CellularRadio::getCellularMode(CELLULAR_MODES &networks) {
networks = CELLULAR_MODE_NA;
std::string cmdResult = sendCommand("AT+COPS?");
@@ -813,6 +869,30 @@ ICellularRadio::CODE CellularRadio::convertRegistrationToString(REGISTRATION eRe
return eCode;
}
+ICellularRadio::CODE CellularRadio::convertCellModesToString(ICellularRadio::CELLULAR_MODES eCellModes, std::string& sCellModes) {
+ std::string sResult;
+
+ if (eCellModes & CELLULAR_MODE_2G) {
+ sResult += "2g,";
+ }
+ if (eCellModes & CELLULAR_MODE_3G) {
+ sResult += "3g,";
+ }
+ if (eCellModes & CELLULAR_MODE_4G) {
+ sResult += "4g,";
+ }
+ if (eCellModes & CELLULAR_MODE_5G) {
+ sResult += "5g,";
+ }
+
+ if (!sResult.empty()) {
+ sResult.pop_back(); // remove trailing comma
+ }
+
+ sCellModes = sResult;
+ return SUCCESS;
+}
+
ICellularRadio::CODE CellularRadio::unlockSimCard(const Json::Value& jArgs) {
printTrace("%s| Unlock the SIM card using PIN code", m_sName.c_str());
diff --git a/src/MTS_IO_CellularRadioFactory.cpp b/src/MTS_IO_CellularRadioFactory.cpp
index 4ee8756..08c6315 100644
--- a/src/MTS_IO_CellularRadioFactory.cpp
+++ b/src/MTS_IO_CellularRadioFactory.cpp
@@ -25,13 +25,12 @@
#include <mts/MTS_IO_LE910C4NFRadio.h>
#include <mts/MTS_IO_LE910NA1Radio.h>
#include <mts/MTS_IO_LE910SVGRadio.h>
+#include <mts/MTS_IO_LE910SV1Radio.h>
#include <mts/MTS_IO_LE910EUGRadio.h>
#include <mts/MTS_IO_LE910C4EURadio.h>
#include <mts/MTS_IO_LE910EU1Radio.h>
#include <mts/MTS_IO_LE910C1NSRadio.h>
#include <mts/MTS_IO_LE910C1APRadio.h>
-#include <mts/MTS_IO_ME910C1NARadio.h>
-#include <mts/MTS_IO_ME910C1NVRadio.h>
#include <mts/MTS_IO_LE866A1JSRadio.h>
#include <mts/MTS_IO_ME910C1WWRadio.h>
#include <mts/MTS_IO_GE910Radio.h>
@@ -49,13 +48,12 @@ CellularRadioFactory::CellularRadioFactory() {
m_mCreationMap[LE910C4NFRadio::MODEL_NAME] = &CellularRadioFactory::createLE910C4NF;
m_mCreationMap[LE910NA1Radio::MODEL_NAME] = &CellularRadioFactory::createLE910NA1;
m_mCreationMap[LE910SVGRadio::MODEL_NAME] = &CellularRadioFactory::createLE910SVG;
+ m_mCreationMap[LE910SV1Radio::MODEL_NAME] = &CellularRadioFactory::createLE910SV1;
m_mCreationMap[LE910EUGRadio::MODEL_NAME] = &CellularRadioFactory::createLE910EUG;
m_mCreationMap[LE910C4EURadio::MODEL_NAME] = &CellularRadioFactory::createLE910C4EU;
m_mCreationMap[LE910EU1Radio::MODEL_NAME] = &CellularRadioFactory::createLE910EU1;
m_mCreationMap[LE910C1NSRadio::MODEL_NAME] = &CellularRadioFactory::createLE910C1NS;
m_mCreationMap[LE910C1APRadio::MODEL_NAME] = &CellularRadioFactory::createLE910C1AP;
- m_mCreationMap[ME910C1NARadio::MODEL_NAME] = &CellularRadioFactory::createME910C1NA;
- m_mCreationMap[ME910C1NVRadio::MODEL_NAME] = &CellularRadioFactory::createME910C1NV;
m_mCreationMap[ME910C1WWRadio::MODEL_NAME] = &CellularRadioFactory::createME910C1WW;
m_mCreationMap[GE910Radio::MODEL_NAME] = &CellularRadioFactory::createGE910;
m_mCreationMap[DE910Radio::MODEL_NAME] = &CellularRadioFactory::createDE910;
@@ -149,6 +147,10 @@ ICellularRadio* CellularRadioFactory::createLE910SVG(const std::string& sPort) c
return new LE910SVGRadio(sPort);
}
+ICellularRadio *CellularRadioFactory::createLE910SV1(const std::string& sPort) const {
+ return new LE910SV1Radio(sPort);
+}
+
ICellularRadio* CellularRadioFactory::createLE910EUG(const std::string& sPort) const {
return new LE910EUGRadio(sPort);
}
@@ -169,14 +171,6 @@ ICellularRadio* CellularRadioFactory::createLE910C1AP(const std::string& sPort)
return new LE910C1APRadio(sPort);
}
-ICellularRadio* CellularRadioFactory::createME910C1NA(const std::string& sPort) const {
- return new ME910C1NARadio(sPort);
-}
-
-ICellularRadio* CellularRadioFactory::createME910C1NV(const std::string& sPort) const {
- return new ME910C1NVRadio(sPort);
-}
-
ICellularRadio* CellularRadioFactory::createME910C1WW(const std::string& sPort) const {
return new ME910C1WWRadio(sPort);
}
diff --git a/src/MTS_IO_ICellularRadio.cpp b/src/MTS_IO_ICellularRadio.cpp
index 4e7809e..53c8faa 100644
--- a/src/MTS_IO_ICellularRadio.cpp
+++ b/src/MTS_IO_ICellularRadio.cpp
@@ -49,11 +49,13 @@ const char *MTS::IO::ICellularRadio::KEY_MSID = "msid"; //!< Mobil Stat
const char *MTS::IO::ICellularRadio::KEY_MDN = "mdn"; //!< Mobile Directory Number : Actual phone number dialed to reach radio
const char *MTS::IO::ICellularRadio::KEY_ICCID = "iccid"; //!< Integrated Circuit Card Identifier
const char *MTS::IO::ICellularRadio::KEY_MSL = "msl"; //!< Master Subsidy Lock
+const char *MTS::IO::ICellularRadio::KEY_SUPPORTED_CELL_MODES = "supportedCellularModes"; //!< Comma-separated list of all supported cellular modes (2g,3g,4g)
//Dynamic Data
const char *MTS::IO::ICellularRadio::KEY_ROAMING = "roaming"; //!< Indicates whether or not using Home Network
const char *MTS::IO::ICellularRadio::KEY_DATETIME = "datetime"; //!< Date and Time from tower
const char *MTS::IO::ICellularRadio::KEY_SERVICE = "service"; //!< Service Connection Type [GPRS, EGPRS, WCDMA, HSDPA, 1xRTT, EVDO]
+const char *MTS::IO::ICellularRadio::KEY_CELL_MODE = "cellularMode"; //!< Specifies the cellular mode that is currently used by the modem [2g, 3g, 4g]
const char *MTS::IO::ICellularRadio::KEY_NETWORK = "network"; //!< Cellular Service Provider
const char *MTS::IO::ICellularRadio::KEY_NETWORK_REG = "netreg"; //!< Network Registration
const char *MTS::IO::ICellularRadio::KEY_CID = "cid"; //!< Cellular ID = Tower in HEX
@@ -154,18 +156,15 @@ MTS::IO::ICellularRadio::CODE MTS::IO::ICellularRadio::convertModelToMtsShortCod
} else if (sModel.find("LE910-SVG") == 0) {
sCode = "LVW2";
eCode = SUCCESS;
+ } else if (sModel.find("LE910-SV1") == 0) {
+ sCode = "LVW3";
+ eCode = SUCCESS;
} else if (sModel.find("LE910C1-NS") == 0) {
sCode = "LSP3";
eCode = SUCCESS;
} else if (sModel.find("LE910C1-AP") == 0) {
sCode = "LAP3";
eCode = SUCCESS;
- } else if (sModel.find("ME910C1-NA") == 0) {
- sCode = "MAT1";
- eCode = SUCCESS;
- } else if (sModel.find("ME910C1-NV") == 0) {
- sCode = "MVW1";
- eCode = SUCCESS;
} else if (sModel.find("ME910C1-WW") == 0) {
sCode = "MNG2";
eCode = SUCCESS;
@@ -268,6 +267,9 @@ MTS::IO::ICellularRadio::CODE MTS::IO::ICellularRadio::convertModelToType(const
} else if (sModel.find("LE910-SVG") == 0) {
sType = VALUE_TYPE_LTE;
eCode = SUCCESS;
+ } else if (sModel.find("LE910-SV1") == 0) {
+ sType = VALUE_TYPE_LTE;
+ eCode = SUCCESS;
} else if (sModel.find("LE910-EUG") == 0) {
sType = VALUE_TYPE_LTE;
eCode = SUCCESS;
@@ -283,12 +285,6 @@ MTS::IO::ICellularRadio::CODE MTS::IO::ICellularRadio::convertModelToType(const
} else if (sModel.find("LE910C1-AP") == 0) {
sType = VALUE_TYPE_LTE;
eCode = SUCCESS;
- } else if (sModel.find("ME910C1-NA") == 0) {
- sType = VALUE_TYPE_LTE;
- eCode = SUCCESS;
- } else if (sModel.find("ME910C1-NV") == 0) {
- sType = VALUE_TYPE_LTE;
- eCode = SUCCESS;
} else if (sModel.find("ME910C1-WW") == 0) {
sType = VALUE_TYPE_LTE;
eCode = SUCCESS;
@@ -425,14 +421,12 @@ std::string MTS::IO::ICellularRadio::extractModelFromResult(const std::string& s
sModel = "LE910C4-NF";
} else if(sResult.find("LE910-NA1") != std::string::npos) {
sModel = "LE910-NA1";
- } else if(sResult.find("ME910C1-NA") != std::string::npos) {
- sModel = "ME910C1-NA";
- } else if(sResult.find("ME910C1-NV") != std::string::npos) {
- sModel = "ME910C1-NV";
} else if(sResult.find("ME910C1-WW") != std::string::npos) {
sModel = "ME910C1-WW";
} else if(sResult.find("LE910-SVG") != std::string::npos) {
sModel = "LE910-SVG";
+ } else if(sResult.find("LE910-SV1") != std::string::npos) {
+ sModel = "LE910-SV1";
} else if(sResult.find("LE910-EUG") != std::string::npos) {
sModel = "LE910-EUG";
} else if(sResult.find("LE910C4-EU") != std::string::npos) {
diff --git a/src/MTS_IO_LE910SV1Radio.cpp b/src/MTS_IO_LE910SV1Radio.cpp
new file mode 100644
index 0000000..8f0d116
--- /dev/null
+++ b/src/MTS_IO_LE910SV1Radio.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2019 by Multi-Tech Systems
+ *
+ * This file is part of libmts-io.
+ *
+ * libmts-io is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * libmts-io is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libmts-io. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <mts/MTS_IO_LE910SV1Radio.h>
+
+using namespace MTS::IO;
+
+const std::string LE910SV1Radio::MODEL_NAME("LE910-SV1");
+
+LE910SV1Radio::LE910SV1Radio(const std::string& sPort)
+: LE910Radio(MODEL_NAME, sPort)
+{
+
+}
+
+ICellularRadio::CODE LE910SV1Radio::getCarrier(std::string& sCarrier) {
+ sCarrier = "Verizon";
+ return SUCCESS;
+}
diff --git a/src/MTS_IO_ME910C1NARadio.cpp b/src/MTS_IO_ME910C1NARadio.cpp
deleted file mode 100644
index 8c9992e..0000000
--- a/src/MTS_IO_ME910C1NARadio.cpp
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2017 by Multi-Tech Systems
- *
- * This file is part of libmts-io.
- *
- * libmts-io is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * libmts-io is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with libmts-io. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-/*!
- \file MTS_IO_ME910C1NARadio.cpp
- \brief A brief description
-
- A more elaborate description
-*/
-#include <mts/MTS_Text.h>
-#include <mts/MTS_Logger.h>
-#include <mts/MTS_IO_ME910C1NARadio.h>
-
-using namespace MTS::IO;
-
-const std::string ME910C1NARadio::MODEL_NAME("ME910C1-NA");
-
-ME910C1NARadio::ME910C1NARadio(const std::string& sPort)
-: ME910Radio(MODEL_NAME, sPort)
-{
-
-}
-
-CellularRadio::CODE ME910C1NARadio::setActiveFirmware(const Json::Value& jArgs) {
- CellularRadio::CODE rc;
-
- // Set command allows enabling a specific firmware image on products
- // embedding 2 different firmware images:
- //
- // "AT#FWSWITCH=<image_number>[,<storage_conf>]"
- // <image_number> - Firmware Image To Be Enabled
- // 0 – Image 1 (Default)
- // 1 – Image 2
- // <storage_conf> - Setting Storage Configuration
- // 0 – Save the <image_number> value in RAM
- // 1 – Save the <image_number> value in NVM
-
- printTrace("%s| Set Active Firmware Image Number", getName().c_str());
-
- if(!jArgs["fwid"].isString()) {
- return INVALID_ARGS;
- }
-
- if (jArgs["fwid"].asString() != "1" && jArgs["fwid"].asString() != "0") {
- return INVALID_ARGS;
- }
-
- // LE910-NA1 and LE910-NA V2 is orderable in single image or dual image (single SKU)
- // configuration. So issue the test command first
- rc = sendBasicCommand("AT#FWSWITCH=?");
- if (rc == ERROR) {
- printTrace("%s| FWSWITCH is not supported", getName().c_str());
- return NOT_APPLICABLE;
- }
- else if (rc != SUCCESS) {
- return rc;
- }
-
- std::string sCmd = "AT#FWSWITCH=";
- sCmd += jArgs["fwid"].asString();
- sCmd += ",1";
-
- printTrace("%s| Issuing %s command", getName().c_str(), sCmd.c_str());
-
- return sendBasicCommand(sCmd, 5000);
-}
-
-CellularRadio::CODE ME910C1NARadio::getActiveFirmware(std::string& sFwId) {
- std::string sCmd;
- CellularRadio::CODE rc;
- //
- // Read command reports the current active firmware image:
- // AT#FWSWITCH?
- // #FWSWITCH: 1
- //
- // OK
- //
- printTrace("%s| Get Active Firmware Image Number", getName().c_str());
-
- // LE910-NA1 and LE910-NA V2 is orderable in single image or dual image (single SKU)
- // configuration. So issue the test command first
- sCmd = "AT#FWSWITCH=?";
- rc = sendBasicCommand(sCmd);
- if (rc == ERROR) {
- printTrace("%s| FWSWITCH is not supported", getName().c_str());
- return NOT_APPLICABLE;
- }
- else if (rc != SUCCESS) {
- return rc;
- }
-
- sCmd = "AT#FWSWITCH?";
- std::string sResult = sendCommand(sCmd);
- size_t end = sResult.find(RSP_OK);
- if (end == std::string::npos) {
- printWarning("%s| Unable to get active image number from radio using command [%s]",
- getName().c_str(),
- sCmd.c_str());
- return FAILURE;
- }
-
- size_t start = sResult.find("#FWSWITCH:") + sizeof("#FWSWITCH:");
- sFwId = MTS::Text::trim(sResult.substr(start, end-start));
- if(sFwId.size() == 0) {
- printWarning("%s| Firmware Image Number is empty", getName().c_str());
- return FAILURE;
- }
-
- return SUCCESS;
-}
diff --git a/src/MTS_IO_ME910C1NVRadio.cpp b/src/MTS_IO_ME910C1NVRadio.cpp
deleted file mode 100644
index 0af5f24..0000000
--- a/src/MTS_IO_ME910C1NVRadio.cpp
+++ /dev/null
@@ -1,623 +0,0 @@
-/*
- * Copyright (C) 2018 by Multi-Tech Systems
- *
- * This file is part of libmts-io.
- *
- * libmts-io is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * libmts-io is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with libmts-io. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-/*!
- \file MTS_IO_ME910C1NVRadio.cpp
- \brief A brief description
- \date May 1, 2018
- \author mykyta.dorokhin
-
- A more elaborate description
-*/
-#include <fstream>
-#include <mts/MTS_Text.h>
-#include <mts/MTS_Logger.h>
-#include <mts/MTS_Thread.h>
-#include <mts/MTS_Timer.h>
-#include <mts/MTS_IO_ME910C1NVRadio.h>
-
-using namespace MTS::IO;
-
-const std::string ME910C1NVRadio::MODEL_NAME("ME910C1-NV");
-
-const std::string ME910C1NVRadio::KEY_FUMO_PDPID("pdpid"); // optional (default : "3")
-const std::string ME910C1NVRadio::KEY_FUMO_PDPTYPE("pdptype"); // optional (default : "IPV4V6")
-const std::string ME910C1NVRadio::KEY_FUMO_APN("apn"); // optional (default : "")
-const std::string ME910C1NVRadio::KEY_FUMO_ADDRESS("address");
-const std::string ME910C1NVRadio::KEY_FUMO_DIR("dir");
-const std::string ME910C1NVRadio::KEY_FUMO_FILE("file");
-const std::string ME910C1NVRadio::KEY_FUMO_USER("user");
-const std::string ME910C1NVRadio::KEY_FUMO_PASSWORD("password");
-const std::string ME910C1NVRadio::KEY_FUMO_DRYRUN("dryrun");
-
-ME910C1NVRadio::ME910C1NVRadio(const std::string& sPort)
-: ME910Radio(MODEL_NAME, sPort)
-{
-
-}
-
-ICellularRadio::CODE ME910C1NVRadio::getCarrier(std::string& sCarrier) {
- sCarrier = "Verizon";
- return SUCCESS;
-}
-
-ICellularRadio::CODE ME910C1NVRadio::doGetFirmwareNumbers(std::string &sFirmware, std::string &sFirmwareBuild) {
- ICellularRadio::CODE rc = FAILURE;
-
- rc = getFirmware(sFirmware);
- if (rc != SUCCESS){
- return rc;
- }
-
- rc = getFirmwareBuild(sFirmwareBuild);
- if (rc != SUCCESS){
- return rc;
- }
-
- return rc;
-}
-
-ICellularRadio::CODE ME910C1NVRadio::doFumoReadConfig(const Json::Value& jArgs, Json::Value &jConfig)
-{
- ICellularRadio::CODE rc = INVALID_ARGS;
- std::string sPath;
-
- do
- {
- if (!jArgs["config-file"].isString()) {
- rc = INVALID_ARGS;
- break;
- }
-
- sPath = jArgs["config-file"].asString();
-
- std::ifstream file(sPath.c_str());
- if (!file.is_open()) {
- printError("Failed to open file [%s]", sPath.c_str());
- break;
- }
-
- file.seekg(0, std::ios::end);
- size_t size = file.tellg();
- std::string buffer(size, ' ');
- file.seekg(0);
- file.read(&buffer[0], size);
- file.close();
-
- Json::Features features = Json::Features::strictMode();
- Json::Reader reader(features);
- if (!reader.parse(buffer, jConfig)) {
- printError("Error parsing FOTA configuration file");
- break;
- }
-
- //
- // set default values if missing
- //
- if (!jConfig.isMember(KEY_FUMO_PDPID)) {
- jConfig[KEY_FUMO_PDPID] = std::string("3");
- }
-
- if (!jConfig.isMember(KEY_FUMO_PDPTYPE)) {
- jConfig[KEY_FUMO_PDPTYPE] = std::string("IPV4V6");
- }
-
- if (!jConfig.isMember(KEY_FUMO_APN)) {
- jConfig[KEY_FUMO_APN] = std::string("");
- }
-
- //
- // validate
- //
- if (!jConfig[KEY_FUMO_PDPID].isString()) {
- printError("Error loading FOTA configuration: PDP context id is not set");
- break;
- }
-
- if (jConfig[KEY_FUMO_PDPID].asString().empty()) {
- printError("Error loading FOTA configuration: context id is empty");
- break;
- }
-
- if (!jConfig[KEY_FUMO_PDPTYPE].isString()) {
- printError("Error loading FOTA configuration: PDP type is not set");
- break;
- }
-
- if (jConfig[KEY_FUMO_PDPTYPE].asString().empty()) {
- printError("Error loading FOTA configuration: PDP type is empty");
- break;
- }
-
- // Note : allow empty APN
- if (!jConfig[KEY_FUMO_APN].isString()) {
- printError("Error loading FOTA configuration: APN is not set");
- break;
- }
-
- if (!jConfig[KEY_FUMO_ADDRESS].isString()) {
- printError("Error loading FOTA configuration: address is not set");
- break;
- }
-
- if (jConfig[KEY_FUMO_ADDRESS].asString().empty()) {
- printError("Error loading FOTA configuration: address is empty");
- break;
- }
-
- // Note: allow empty dir
- if (!jConfig[KEY_FUMO_DIR].isString()) {
- printError("Error loading FOTA configuration: directory is not set");
- break;
- }
-
- if (!jConfig[KEY_FUMO_FILE].isString()) {
- printError("Error loading FOTA configuration: filename is not set");
- break;
- }
-
- if (jConfig[KEY_FUMO_FILE].asString().empty()) {
- printError("Error loading FOTA configuration: filename is empty");
- break;
- }
-
- // Note: allow empty username/password
- if (!jConfig[KEY_FUMO_USER].isString()) {
- printError("Error loading FOTA configuration: username is not set");
- break;
- }
-
- if (!jConfig[KEY_FUMO_PASSWORD].isString()) {
- printError("Error loading FOTA configuration: password is not set");
- break;
- }
-
- rc = SUCCESS;
- }
- while(0);
-
- return rc;
-}
-
-ICellularRadio::CODE ME910C1NVRadio::doFumoSetup(const Json::Value &jConfig, UpdateCb& stepCb)
-{
- ICellularRadio::CODE rc = FAILURE;
- std::string sCmd;
-
- std::string sContextId = jConfig[KEY_FUMO_PDPID].asString();
- std::string sApn = jConfig[KEY_FUMO_APN].asString();
- std::string sPdpType = jConfig[KEY_FUMO_PDPTYPE].asString();
-
-
- do
- {
- //
- // Execution command is used to activate or deactivate either the GSM
- // context or the specified PDP context.
- //
- // AT#SGACT=<cid>,<stat>[,<userId>,<pwd>]
- //
- sCmd = "AT#SGACT=" + sContextId + ",0";
- rc = sendBasicCommand(sCmd);
- if (rc != SUCCESS) {
- if(stepCb) {
- stepCb(Json::Value("FUMO Error: Failed to deactivate PDP context"));
- }
- break;
- }
-
- //
- // Read current Firmware numbers (let it be after AT#SGACT not to confuse users)
- //
- rc = doGetFirmwareNumbers(m_sFw, m_sFwBuild);
- if (rc != SUCCESS) {
- if(stepCb) {
- stepCb(Json::Value("FUMO Error: Failed to obtain current firmware version"));
- }
- break;
- }
-
- //
- // Set command specifies PDP context parameter values for a PDP context identified by
- // the (local) context identification parameter <cid>.
- //
- // AT+CGDCONT= [<cid>[,<PDP_type>[,<APN>[,<PDP_addr>[,<d_comp>[,<h_comp>[,<pd1>[,...[,pdN]]]]]]]]]
- //
- sCmd = "AT+CGDCONT=" + sContextId + ",\"" + sPdpType + "\"";
- if (!sApn.empty()) {
- sCmd += ",\"" + sApn + "\"";
- }
- rc = sendBasicCommand(sCmd, 1000);
- if (rc != SUCCESS) {
- if(stepCb) {
- stepCb(Json::Value("FUMO Error: Failed to setup PDP context"));
- }
- break;
- }
-
- //
- // Set command sets the socket configuration parameters.
- //
- // AT#SCFG==<connId>,<cid>,<pktSz>,<maxTo>,<connTo>,<txTo>
- // <connId> - socket connection identifier
- // <cid> - PDP context identifier
- // <pktSz> - packet size to be used by the TCP/UDP/IP stack for data sending.
- // <maxTo> - exchange timeout (or socket inactivity timeout); if there’s no
- // data exchange within this timeout period the connection is closed (timeout value in seconds).
- // <connTo> - connection timeout; if we can’t establish a connection to the
- // remote within this timeout period, an error is raised timeout value in hundreds of milliseconds.
- // <txTo> - data sending timeout; after this period data are sent also if they’re
- // less than max packet size (timeout value in hundreds of milliseconds).
- //
- sCmd = "AT#SCFG=1," + sContextId + ",300,90,600,50";
- rc = sendBasicCommand(sCmd);
- if (rc != SUCCESS) {
- if(stepCb) {
- stepCb(Json::Value("FUMO Error: Failed to set connection configuration parameters"));
- }
- break;
- }
-
- //
- // Activate PDP context
- //
- sCmd = "AT#SGACT=" + sContextId + ",1";
- rc = sendBasicCommand(sCmd, 60 * 1000);
- if (rc != SUCCESS) {
- if(stepCb) {
- stepCb(Json::Value("FUMO Error: Failed to activate PDP context"));
- }
- break;
- }
- }
- while (0);
-
- return rc;
-}
-
-ICellularRadio::CODE ME910C1NVRadio::doFumoFtp(const Json::Value &jConfig, UpdateCb& stepCb)
-{
- ICellularRadio::CODE rc = FAILURE;
- std::string sCmd;
- std::string sResult;
-
- //
- // Set command sets the time-out used when opening either the FTP control
- // channel or the FTP traffic channel.
- //
- // AT#FTPTO= [<tout>]
- // <tout> - time-out in 100 ms units
- //
- rc = sendBasicCommand("AT#FTPTO=2400");
- if (rc != SUCCESS) {
- if(stepCb) {
- stepCb(Json::Value("FUMO Error: Failed to setup connection timeout"));
- }
- return rc;
- }
-
- //
- // Execution command opens an FTP connection toward the FTP server.
- //
- // AT#FTPOPEN=[<server:port>,<username>,<password>[,<mode>]]
- //
- sCmd = "AT#FTPOPEN=";
- sCmd += "\"" + jConfig[KEY_FUMO_ADDRESS].asString() + "\",";
- sCmd += "\"" + jConfig[KEY_FUMO_USER].asString() + "\",";
- sCmd += "\"" + jConfig[KEY_FUMO_PASSWORD].asString() + "\",1";
- rc = sendBasicCommand(sCmd, 60 * 1000);
- if (rc != SUCCESS) {
- if(stepCb) {
- stepCb(Json::Value("FUMO Error: Failed to open connection"));
- }
- return rc;
- }
-
- if (stepCb) {
- stepCb(Json::Value("FUMO Info: connection opened"));
- }
-
- do
- {
- //
- // Set command, issued during an FTP connection, sets the file transfer type.
- //
- // AT#FTPTYPE=[<type>]
- // <type> - file transfer type:
- // 0 - binary
- // 1 - ascii
- //
- rc = sendBasicCommand("AT#FTPTYPE=0", 1000);
- if (rc != SUCCESS) {
- if(stepCb) {
- stepCb(Json::Value("FUMO Error: failed to set file transfer type"));
- }
- break;
- }
-
- //
- // Execution command, issued during an FTP connection, changes the
- // working directory on FTP server.
- //
- // AT#FTPCWD=[<dirname>]
- //
- sCmd = "AT#FTPCWD=\"/";
- if (!jConfig[KEY_FUMO_DIR].asString().empty()) {
- sCmd += jConfig[KEY_FUMO_DIR].asString() + "/";
- }
- sCmd += "\"";
- rc = sendBasicCommand(sCmd, 60 * 1000);
- if (rc != SUCCESS) {
- if(stepCb) {
- stepCb(Json::Value("FUMO Error: failed to change working directory on the server"));
- }
- break;
- }
-
- if (stepCb) {
- stepCb(Json::Value("FUMO Info: downloading the firmware"));
- }
-
- //
- // Start FTP transfer
- //
- sCmd = "AT#FTPGETOTA=";
- sCmd += "\"" + jConfig[KEY_FUMO_FILE].asString() + "\",1,1";
- sendBasicCommand(sCmd);
-
- //
- // Noticed that after successful AT#FTPGETOTA the radio resets the connection.
- // and the response code (OK, ERROR.. ) not always reach the host. Therefore
- // we send the AT#FTPGETOTA with relatively small timeout and then poll with AT
- // until we get valid response. After that, using AT#FTPMSG we can check the
- // result of the last FTP command (which is AT#FTPGETOTA in our case).
- MTS::Timer oTimer;
-
- oTimer.start();
-
- while (oTimer.getSeconds() < (30 * 60)) // 30 min
- {
- MTS::Thread::sleep(5000);
-
- rc = sendBasicCommand("AT");
- if (rc == SUCCESS) {
- break;
- }
-
- resetConnection(1);
- }
- oTimer.stop();
-
- if (rc != SUCCESS) {
- if(stepCb) {
- stepCb(Json::Value("FUMO Error: unable to obtain radio after reset"));
- }
- break;
- }
-
- //
- // Now check the FTP status
- //
- std::string sResult = sendCommand("AT#FTPMSG");
-
- printTrace("RADIO| AT#FTPMSG result [%s]", sResult.c_str());
-
- if (sResult.find(ICellularRadio::RSP_OK) == std::string::npos) {
- rc = FAILURE;
- if(stepCb) {
- stepCb(Json::Value("FUMO Error: failed to download the firmware file"));
- }
- break;
- }
- if (sResult.find("#FTPMSG: 550") != std::string::npos) {
- // FTP(550) : File not found
- rc = FAILURE;
- if(stepCb) {
- stepCb(Json::Value("FUMO Error: file not found"));
- }
- break;
- }
- if (sResult.find("#FTPMSG: 226") == std::string::npos) {
- // FTP(226) : Successfully transferred
- rc = FAILURE;
- if(stepCb) {
- stepCb(Json::Value("FUMO Error: failed to download the firmware file"));
- }
- break;
- }
- }
- while (0);
-
- //
- // Execution command closes an FTP connection.
- //
- // AT#FTPCLOSE
- //
- ICellularRadio::CODE rcclose = sendBasicCommand("AT#FTPCLOSE", 60 * 1000);
- if (rcclose != SUCCESS && rc == SUCCESS) {
- if(stepCb) {
- // Only one "FUMO Error" message should be sent
- stepCb(Json::Value("FUMO Error: Failed to close FTP connection"));
- }
- rc = rcclose;
- }
-
- if (rc == SUCCESS) {
- if(stepCb) {
- stepCb(Json::Value("FUMO Info: firmware downloaded successfully"));
- }
- }
-
- return rc;
-}
-
-ICellularRadio::CODE ME910C1NVRadio::doFumoCleanup(const Json::Value &jConfig, UpdateCb& stepCb)
-{
- ICellularRadio::CODE rc = FAILURE;
- std::string sCmd;
-
- std::string sContextId = jConfig[KEY_FUMO_PDPID].asString();
-
- //
- // Deactivate PDP context
- //
- sCmd = "AT#SGACT=" + sContextId + ",0";
- rc = sendBasicCommand(sCmd, 10000);
- if (rc != SUCCESS) {
- if(stepCb) {
- stepCb(Json::Value("FUMO Error: Failed to deactivate PDP context"));
- }
- }
- return rc;
-}
-
-ICellularRadio::CODE ME910C1NVRadio::doFumoApplyFirmware(const Json::Value &jConfig, UpdateCb& stepCb)
-{
- ICellularRadio::CODE rc = FAILURE;
-
- if (jConfig.isMember(KEY_FUMO_DRYRUN)) {
- if(stepCb) {
- stepCb(Json::Value("FUMO Info: applying the radio firmware"));
- }
- return SUCCESS;
- }
-
- rc = sendBasicCommand("AT#OTAUP=0", 10000);
- if (rc != SUCCESS) {
- if(stepCb) {
- stepCb(Json::Value("FUMO Error: failed to apply the firmware"));
- }
- return rc;
- }
-
- if(stepCb) {
- stepCb(Json::Value("FUMO Info: applying the radio firmware"));
- }
-
- return rc;
-}
-
-ICellularRadio::CODE ME910C1NVRadio::doFumoWaitNewFirmware(const Json::Value &jConfig, UpdateCb& stepCb)
-{
- std::string sFirmware;
- std::string sFirmwareBuild;
- ICellularRadio::CODE rc = FAILURE;
-
- if (jConfig.isMember(KEY_FUMO_DRYRUN)) {
- if(stepCb) {
- stepCb(Json::Value("FUMO done: radio firmware applied successfully"));
- }
- return SUCCESS;
- }
-
- // The radio is expected to send "#OTAEV: Module Upgraded To New Fw" unsolicited message
- // on success. However, for some reason, we do not see this message.
-
- MTS::Timer oTimer;
- oTimer.start();
-
- while (oTimer.getSeconds() < (5 * 60)) { // 5 minutes
-
- MTS::Thread::sleep(10000);
-
- if (doGetFirmwareNumbers(sFirmware, sFirmwareBuild) != SUCCESS) {
- // The radio is probably unavailable
- resetConnection(100);
- continue;
- }
-
- 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;
- }
-
- // The firmware numbers have changed
- 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 ME910C1NVRadio::doFumoPerform(const Json::Value &jConfig, UpdateCb& stepCb)
-{
- ICellularRadio::CODE rc = FAILURE;
-
- UpdateCb dummyCb;
-
- // Set the PDP context for the FOTA
- rc = doFumoSetup(jConfig, stepCb);
- if (rc != SUCCESS) {
- return rc;
- }
-
- // Download FW over FTP
- rc = doFumoFtp(jConfig, stepCb);
- if (rc != SUCCESS) {
- doFumoCleanup(jConfig, dummyCb);
- return rc;
- }
-
- // Clean up before applying the FW file
- rc = doFumoCleanup(jConfig, stepCb);
- if (rc != SUCCESS) {
- return rc;
- }
-
- // Apply the FW file
- rc = doFumoApplyFirmware(jConfig, stepCb);
- if (rc != SUCCESS) {
- return rc;
- }
-
- rc = doFumoWaitNewFirmware(jConfig, stepCb);
-
- return rc;
-}
-
-ICellularRadio::CODE ME910C1NVRadio::updateFumo(const Json::Value& jArgs, UpdateCb& stepCb)
-{
- Json::Value jConfig(Json::objectValue);
- ICellularRadio::CODE rc = FAILURE;
-
- rc = doFumoReadConfig(jArgs, jConfig);
- if (rc != SUCCESS) {
- if(stepCb) {
- stepCb(Json::Value("FUMO Error: bad configuration parameters"));
- }
- return rc;
- }
-
- return doFumoPerform(jConfig, stepCb);
-}
diff --git a/src/MTS_IO_ME910C1WWRadio.cpp b/src/MTS_IO_ME910C1WWRadio.cpp
index 0469d5d..32c64b3 100644
--- a/src/MTS_IO_ME910C1WWRadio.cpp
+++ b/src/MTS_IO_ME910C1WWRadio.cpp
@@ -17,15 +17,27 @@
* along with libmts-io. If not, see <http://www.gnu.org/licenses/>.
*
*/
-
+#include <fstream>
#include <mts/MTS_Text.h>
#include <mts/MTS_Logger.h>
+#include <mts/MTS_Thread.h>
+#include <mts/MTS_Timer.h>
#include <mts/MTS_IO_ME910C1WWRadio.h>
using namespace MTS::IO;
const std::string ME910C1WWRadio::MODEL_NAME("ME910C1-WW");
+const std::string ME910C1WWRadio::KEY_FUMO_PDPID("pdpid"); // optional (default : "3")
+const std::string ME910C1WWRadio::KEY_FUMO_PDPTYPE("pdptype"); // optional (default : "IPV4V6")
+const std::string ME910C1WWRadio::KEY_FUMO_APN("apn"); // optional (default : "")
+const std::string ME910C1WWRadio::KEY_FUMO_ADDRESS("address");
+const std::string ME910C1WWRadio::KEY_FUMO_DIR("dir");
+const std::string ME910C1WWRadio::KEY_FUMO_FILE("file");
+const std::string ME910C1WWRadio::KEY_FUMO_USER("user");
+const std::string ME910C1WWRadio::KEY_FUMO_PASSWORD("password");
+const std::string ME910C1WWRadio::KEY_FUMO_DRYRUN("dryrun");
+
ME910C1WWRadio::ME910C1WWRadio(const std::string& sPort)
: ME910Radio(MODEL_NAME, sPort)
{
@@ -119,3 +131,582 @@ ICellularRadio::CODE ME910C1WWRadio::getActiveFirmware(std::string& sFwId) {
return SUCCESS;
}
+ICellularRadio::CODE ME910C1WWRadio::doGetFirmwareNumbers(std::string &sFirmware, std::string &sFirmwareBuild) {
+ ICellularRadio::CODE rc = FAILURE;
+
+ rc = getFirmware(sFirmware);
+ if (rc != SUCCESS){
+ return rc;
+ }
+
+ rc = getFirmwareBuild(sFirmwareBuild);
+ if (rc != SUCCESS){
+ return rc;
+ }
+
+ return rc;
+}
+
+ICellularRadio::CODE ME910C1WWRadio::doFumoReadConfig(const Json::Value& jArgs, Json::Value &jConfig) {
+ ICellularRadio::CODE rc = INVALID_ARGS;
+ std::string sPath;
+
+ do
+ {
+ if (!jArgs["config-file"].isString()) {
+ rc = INVALID_ARGS;
+ break;
+ }
+
+ sPath = jArgs["config-file"].asString();
+
+ std::ifstream file(sPath.c_str());
+ if (!file.is_open()) {
+ printError("Failed to open file [%s]", sPath.c_str());
+ break;
+ }
+
+ file.seekg(0, std::ios::end);
+ size_t size = file.tellg();
+ std::string buffer(size, ' ');
+ file.seekg(0);
+ file.read(&buffer[0], size);
+ file.close();
+
+ Json::Features features = Json::Features::strictMode();
+ Json::Reader reader(features);
+ if (!reader.parse(buffer, jConfig)) {
+ printError("Error parsing FOTA configuration file");
+ break;
+ }
+
+ //
+ // set default values if missing
+ //
+ if (!jConfig.isMember(KEY_FUMO_PDPID)) {
+ jConfig[KEY_FUMO_PDPID] = std::string("3");
+ }
+
+ if (!jConfig.isMember(KEY_FUMO_PDPTYPE)) {
+ jConfig[KEY_FUMO_PDPTYPE] = std::string("IPV4V6");
+ }
+
+ if (!jConfig.isMember(KEY_FUMO_APN)) {
+ jConfig[KEY_FUMO_APN] = std::string("");
+ }
+
+ //
+ // validate
+ //
+ if (!jConfig[KEY_FUMO_PDPID].isString()) {
+ printError("Error loading FOTA configuration: PDP context id is not set");
+ break;
+ }
+
+ if (jConfig[KEY_FUMO_PDPID].asString().empty()) {
+ printError("Error loading FOTA configuration: context id is empty");
+ break;
+ }
+
+ if (!jConfig[KEY_FUMO_PDPTYPE].isString()) {
+ printError("Error loading FOTA configuration: PDP type is not set");
+ break;
+ }
+
+ if (jConfig[KEY_FUMO_PDPTYPE].asString().empty()) {
+ printError("Error loading FOTA configuration: PDP type is empty");
+ break;
+ }
+
+ // Note : allow empty APN
+ if (!jConfig[KEY_FUMO_APN].isString()) {
+ printError("Error loading FOTA configuration: APN is not set");
+ break;
+ }
+
+ if (!jConfig[KEY_FUMO_ADDRESS].isString()) {
+ printError("Error loading FOTA configuration: address is not set");
+ break;
+ }
+
+ if (jConfig[KEY_FUMO_ADDRESS].asString().empty()) {
+ printError("Error loading FOTA configuration: address is empty");
+ break;
+ }
+
+ // Note: allow empty dir
+ if (!jConfig[KEY_FUMO_DIR].isString()) {
+ printError("Error loading FOTA configuration: directory is not set");
+ break;
+ }
+
+ if (!jConfig[KEY_FUMO_FILE].isString()) {
+ printError("Error loading FOTA configuration: filename is not set");
+ break;
+ }
+
+ if (jConfig[KEY_FUMO_FILE].asString().empty()) {
+ printError("Error loading FOTA configuration: filename is empty");
+ break;
+ }
+
+ // Note: allow empty username/password
+ if (!jConfig[KEY_FUMO_USER].isString()) {
+ printError("Error loading FOTA configuration: username is not set");
+ break;
+ }
+
+ if (!jConfig[KEY_FUMO_PASSWORD].isString()) {
+ printError("Error loading FOTA configuration: password is not set");
+ break;
+ }
+
+ rc = SUCCESS;
+ }
+ while(0);
+
+ return rc;
+}
+
+ICellularRadio::CODE ME910C1WWRadio::doFumoSetup(const Json::Value &jConfig, UpdateCb& stepCb) {
+ ICellularRadio::CODE rc = FAILURE;
+ std::string sCmd;
+
+ std::string sContextId = jConfig[KEY_FUMO_PDPID].asString();
+ std::string sApn = jConfig[KEY_FUMO_APN].asString();
+ std::string sPdpType = jConfig[KEY_FUMO_PDPTYPE].asString();
+
+
+ do
+ {
+ //
+ // Execution command is used to activate or deactivate either the GSM
+ // context or the specified PDP context.
+ //
+ // AT#SGACT=<cid>,<stat>[,<userId>,<pwd>]
+ //
+ sCmd = "AT#SGACT=" + sContextId + ",0";
+ rc = sendBasicCommand(sCmd);
+ if (rc != SUCCESS) {
+ if(stepCb) {
+ stepCb(Json::Value("FUMO Error: Failed to deactivate PDP context"));
+ }
+ break;
+ }
+
+ //
+ // Read current Firmware numbers (let it be after AT#SGACT not to confuse users)
+ //
+ rc = doGetFirmwareNumbers(m_sFw, m_sFwBuild);
+ if (rc != SUCCESS) {
+ if(stepCb) {
+ stepCb(Json::Value("FUMO Error: Failed to obtain current firmware version"));
+ }
+ break;
+ }
+
+ //
+ // Set command specifies PDP context parameter values for a PDP context identified by
+ // the (local) context identification parameter <cid>.
+ //
+ // AT+CGDCONT= [<cid>[,<PDP_type>[,<APN>[,<PDP_addr>[,<d_comp>[,<h_comp>[,<pd1>[,...[,pdN]]]]]]]]]
+ //
+ sCmd = "AT+CGDCONT=" + sContextId + ",\"" + sPdpType + "\"";
+ if (!sApn.empty()) {
+ sCmd += ",\"" + sApn + "\"";
+ }
+ rc = sendBasicCommand(sCmd, 1000);
+ if (rc != SUCCESS) {
+ if(stepCb) {
+ stepCb(Json::Value("FUMO Error: Failed to setup PDP context"));
+ }
+ break;
+ }
+
+ //
+ // Set command sets the socket configuration parameters.
+ //
+ // AT#SCFG==<connId>,<cid>,<pktSz>,<maxTo>,<connTo>,<txTo>
+ // <connId> - socket connection identifier
+ // <cid> - PDP context identifier
+ // <pktSz> - packet size to be used by the TCP/UDP/IP stack for data sending.
+ // <maxTo> - exchange timeout (or socket inactivity timeout); if there’s no
+ // data exchange within this timeout period the connection is closed (timeout value in seconds).
+ // <connTo> - connection timeout; if we can’t establish a connection to the
+ // remote within this timeout period, an error is raised timeout value in hundreds of milliseconds.
+ // <txTo> - data sending timeout; after this period data are sent also if they’re
+ // less than max packet size (timeout value in hundreds of milliseconds).
+ //
+ sCmd = "AT#SCFG=1," + sContextId + ",300,90,600,50";
+ rc = sendBasicCommand(sCmd);
+ if (rc != SUCCESS) {
+ if(stepCb) {
+ stepCb(Json::Value("FUMO Error: Failed to set connection configuration parameters"));
+ }
+ break;
+ }
+
+ //
+ // Activate PDP context
+ //
+ sCmd = "AT#SGACT=" + sContextId + ",1";
+ rc = sendBasicCommand(sCmd, 60 * 1000);
+ if (rc != SUCCESS) {
+ if(stepCb) {
+ stepCb(Json::Value("FUMO Error: Failed to activate PDP context"));
+ }
+ break;
+ }
+ }
+ while (0);
+
+ return rc;
+}
+
+ICellularRadio::CODE ME910C1WWRadio::doFumoFtp(const Json::Value &jConfig, UpdateCb& stepCb) {
+ ICellularRadio::CODE rc = FAILURE;
+ std::string sCmd;
+ std::string sResult;
+
+ //
+ // Set command sets the time-out used when opening either the FTP control
+ // channel or the FTP traffic channel.
+ //
+ // AT#FTPTO= [<tout>]
+ // <tout> - time-out in 100 ms units
+ //
+ rc = sendBasicCommand("AT#FTPTO=2400");
+ if (rc != SUCCESS) {
+ if(stepCb) {
+ stepCb(Json::Value("FUMO Error: Failed to setup connection timeout"));
+ }
+ return rc;
+ }
+
+ //
+ // Execution command opens an FTP connection toward the FTP server.
+ //
+ // AT#FTPOPEN=[<server:port>,<username>,<password>[,<mode>]]
+ //
+ sCmd = "AT#FTPOPEN=";
+ sCmd += "\"" + jConfig[KEY_FUMO_ADDRESS].asString() + "\",";
+ sCmd += "\"" + jConfig[KEY_FUMO_USER].asString() + "\",";
+ sCmd += "\"" + jConfig[KEY_FUMO_PASSWORD].asString() + "\",1";
+ rc = sendBasicCommand(sCmd, 60 * 1000);
+ if (rc != SUCCESS) {
+ if(stepCb) {
+ stepCb(Json::Value("FUMO Error: Failed to open connection"));
+ }
+ return rc;
+ }
+
+ if (stepCb) {
+ stepCb(Json::Value("FUMO Info: connection opened"));
+ }
+
+ do
+ {
+ //
+ // Set command, issued during an FTP connection, sets the file transfer type.
+ //
+ // AT#FTPTYPE=[<type>]
+ // <type> - file transfer type:
+ // 0 - binary
+ // 1 - ascii
+ //
+ rc = sendBasicCommand("AT#FTPTYPE=0", 1000);
+ if (rc != SUCCESS) {
+ if(stepCb) {
+ stepCb(Json::Value("FUMO Error: failed to set file transfer type"));
+ }
+ break;
+ }
+
+ //
+ // Execution command, issued during an FTP connection, changes the
+ // working directory on FTP server.
+ //
+ // AT#FTPCWD=[<dirname>]
+ //
+ sCmd = "AT#FTPCWD=\"/";
+ if (!jConfig[KEY_FUMO_DIR].asString().empty()) {
+ sCmd += jConfig[KEY_FUMO_DIR].asString() + "/";
+ }
+ sCmd += "\"";
+ rc = sendBasicCommand(sCmd, 60 * 1000);
+ if (rc != SUCCESS) {
+ if(stepCb) {
+ stepCb(Json::Value("FUMO Error: failed to change working directory on the server"));
+ }
+ break;
+ }
+
+ if (stepCb) {
+ stepCb(Json::Value("FUMO Info: downloading the firmware"));
+ }
+
+ //
+ // Start FTP transfer
+ //
+ sCmd = "AT#FTPGETOTA=";
+ sCmd += "\"" + jConfig[KEY_FUMO_FILE].asString() + "\",1,1";
+ sendBasicCommand(sCmd);
+
+ //
+ // Noticed that after successful AT#FTPGETOTA the radio resets the connection.
+ // and the response code (OK, ERROR.. ) not always reach the host. Therefore
+ // we send the AT#FTPGETOTA with relatively small timeout and then poll with AT
+ // until we get valid response. After that, using AT#FTPMSG we can check the
+ // result of the last FTP command (which is AT#FTPGETOTA in our case).
+ MTS::Timer oTimer;
+
+ oTimer.start();
+
+ while (oTimer.getSeconds() < (30 * 60)) // 30 min
+ {
+ MTS::Thread::sleep(5000);
+
+ rc = sendBasicCommand("AT");
+ if (rc == SUCCESS) {
+ break;
+ }
+
+ resetConnection(1);
+ }
+ oTimer.stop();
+
+ if (rc != SUCCESS) {
+ if(stepCb) {
+ stepCb(Json::Value("FUMO Error: unable to obtain radio after reset"));
+ }
+ break;
+ }
+
+ //
+ // Now check the FTP status
+ //
+ std::string sResult = sendCommand("AT#FTPMSG");
+
+ printTrace("RADIO| AT#FTPMSG result [%s]", sResult.c_str());
+
+ if (sResult.find(ICellularRadio::RSP_OK) == std::string::npos) {
+ rc = FAILURE;
+ if(stepCb) {
+ stepCb(Json::Value("FUMO Error: failed to download the firmware file"));
+ }
+ break;
+ }
+ if (sResult.find("#FTPMSG: 550") != std::string::npos) {
+ // FTP(550) : File not found
+ rc = FAILURE;
+ if(stepCb) {
+ stepCb(Json::Value("FUMO Error: file not found"));
+ }
+ break;
+ }
+ if (sResult.find("#FTPMSG: 226") == std::string::npos) {
+ // FTP(226) : Successfully transferred
+ rc = FAILURE;
+ if(stepCb) {
+ stepCb(Json::Value("FUMO Error: failed to download the firmware file"));
+ }
+ break;
+ }
+ }
+ while (0);
+
+ //
+ // Execution command closes an FTP connection.
+ //
+ // AT#FTPCLOSE
+ //
+ ICellularRadio::CODE rcclose = sendBasicCommand("AT#FTPCLOSE", 60 * 1000);
+ if (rcclose != SUCCESS && rc == SUCCESS) {
+ if(stepCb) {
+ // Only one "FUMO Error" message should be sent
+ stepCb(Json::Value("FUMO Error: Failed to close FTP connection"));
+ }
+ rc = rcclose;
+ }
+
+ if (rc == SUCCESS) {
+ if(stepCb) {
+ stepCb(Json::Value("FUMO Info: firmware downloaded successfully"));
+ }
+ }
+
+ return rc;
+}
+
+ICellularRadio::CODE ME910C1WWRadio::doFumoCleanup(const Json::Value &jConfig, UpdateCb& stepCb) {
+ ICellularRadio::CODE rc = FAILURE;
+ std::string sCmd;
+
+ std::string sContextId = jConfig[KEY_FUMO_PDPID].asString();
+
+ //
+ // Deactivate PDP context
+ //
+ sCmd = "AT#SGACT=" + sContextId + ",0";
+ rc = sendBasicCommand(sCmd, 10000);
+ if (rc != SUCCESS) {
+ if(stepCb) {
+ stepCb(Json::Value("FUMO Error: Failed to deactivate PDP context"));
+ }
+ }
+ return rc;
+}
+
+ICellularRadio::CODE ME910C1WWRadio::doFumoApplyFirmware(const Json::Value &jConfig, UpdateCb& stepCb) {
+ ICellularRadio::CODE rc = FAILURE;
+
+ if (jConfig.isMember(KEY_FUMO_DRYRUN)) {
+ if(stepCb) {
+ stepCb(Json::Value("FUMO Info: applying the radio firmware"));
+ }
+ return SUCCESS;
+ }
+
+ rc = sendBasicCommand("AT#OTAUP=0", 10000);
+ if (rc != SUCCESS) {
+ if(stepCb) {
+ stepCb(Json::Value("FUMO Error: failed to apply the firmware"));
+ }
+ return rc;
+ }
+
+ if(stepCb) {
+ stepCb(Json::Value("FUMO Info: applying the radio firmware"));
+ }
+
+ return rc;
+}
+
+ICellularRadio::CODE ME910C1WWRadio::doFumoWaitNewFirmware(const Json::Value &jConfig, UpdateCb& stepCb) {
+ std::string sFirmware;
+ std::string sFirmwareBuild;
+ ICellularRadio::CODE rc = FAILURE;
+
+ if (jConfig.isMember(KEY_FUMO_DRYRUN)) {
+ if(stepCb) {
+ stepCb(Json::Value("FUMO done: radio firmware applied successfully"));
+ }
+ return SUCCESS;
+ }
+
+ // The radio is expected to send "#OTAEV: Module Upgraded To New Fw" unsolicited message
+ // on success. However, for some reason, we do not see this message.
+
+ MTS::Timer oTimer;
+ oTimer.start();
+
+ while (oTimer.getSeconds() < (5 * 60)) { // 5 minutes
+
+ MTS::Thread::sleep(10000);
+
+ if (doGetFirmwareNumbers(sFirmware, sFirmwareBuild) != SUCCESS) {
+ // The radio is probably unavailable
+ resetConnection(100);
+ continue;
+ }
+
+ 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;
+ }
+
+ // The firmware numbers have changed
+ 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 ME910C1WWRadio::doFumoPerform(const Json::Value &jConfig, UpdateCb& stepCb) {
+ ICellularRadio::CODE rc = FAILURE;
+
+ UpdateCb dummyCb;
+
+ // Set the PDP context for the FOTA
+ rc = doFumoSetup(jConfig, stepCb);
+ if (rc != SUCCESS) {
+ return rc;
+ }
+
+ // Download FW over FTP
+ rc = doFumoFtp(jConfig, stepCb);
+ if (rc != SUCCESS) {
+ doFumoCleanup(jConfig, dummyCb);
+ return rc;
+ }
+
+ // Clean up before applying the FW file
+ rc = doFumoCleanup(jConfig, stepCb);
+ if (rc != SUCCESS) {
+ return rc;
+ }
+
+ // Apply the FW file
+ rc = doFumoApplyFirmware(jConfig, stepCb);
+ if (rc != SUCCESS) {
+ return rc;
+ }
+
+ rc = doFumoWaitNewFirmware(jConfig, stepCb);
+
+ return rc;
+}
+
+ICellularRadio::CODE ME910C1WWRadio::updateFumo(const Json::Value& jArgs, UpdateCb& stepCb) {
+ Json::Value jConfig(Json::objectValue);
+ ICellularRadio::CODE rc = FAILURE;
+ std::string sFwId;
+
+ do
+ {
+ rc = getActiveFirmware(sFwId);
+ if (rc != SUCCESS) {
+ if(stepCb) {
+ stepCb(Json::Value("FUMO Error: failed to obtain current active firmware id"));
+ }
+ break;
+ }
+
+ // For Verizon Only
+ if (sFwId != "1") {
+ if(stepCb) {
+ stepCb(Json::Value("FUMO Error: fumo is not supported"));
+ }
+ break;
+ }
+
+ rc = doFumoReadConfig(jArgs, jConfig);
+ if (rc != SUCCESS) {
+ if(stepCb) {
+ stepCb(Json::Value("FUMO Error: bad configuration parameters"));
+ }
+ break;
+ }
+
+ rc = doFumoPerform(jConfig, stepCb);
+ }
+ while(0);
+
+ return rc;
+}
+