summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/mts/MTS_IO_ME910C1WWRadio.h22
-rw-r--r--src/MTS_IO_ME910C1WWRadio.cpp604
2 files changed, 1 insertions, 625 deletions
diff --git a/include/mts/MTS_IO_ME910C1WWRadio.h b/include/mts/MTS_IO_ME910C1WWRadio.h
index 9605862..d4b4098 100644
--- a/include/mts/MTS_IO_ME910C1WWRadio.h
+++ b/include/mts/MTS_IO_ME910C1WWRadio.h
@@ -36,33 +36,11 @@ namespace MTS {
ICellularRadio::CODE setActiveFirmware(const Json::Value& jArgs);
ICellularRadio::CODE getActiveFirmware(std::string& sFwId);
- virtual CODE updateFumo(const Json::Value& jArgs, UpdateCb& stepCb);
-
protected:
- CODE doGetFirmwareNumbers(std::string &sFirmware, std::string &sFirmwareBuild);
-
private:
- static const std::string KEY_FUMO_PDPID; //!< PDP context id (default 3)
- static const std::string KEY_FUMO_PDPTYPE; //!< PDP context type (default IPV4V6)
- static const std::string KEY_FUMO_APN; //!< APN (default empty)
- static const std::string KEY_FUMO_ADDRESS; //!< FTP server address
- static const std::string KEY_FUMO_DIR; //!< Directory
- static const std::string KEY_FUMO_FILE; //!< Name of the upgrade file
- static const std::string KEY_FUMO_USER; //!< Username
- static const std::string KEY_FUMO_PASSWORD; //!< Password
- static const std::string KEY_FUMO_DRYRUN; //!< If set, do not apply the downloaded firmware
- CODE doFumoPerform(const Json::Value &jConfig, UpdateCb& stepCb);
- CODE doFumoReadConfig(const Json::Value& jArgs, Json::Value &jConfig);
- CODE doFumoSetup(const Json::Value &jConfig, UpdateCb& stepCb);
- CODE doFumoFtp(const Json::Value &jConfig, UpdateCb& stepCb);
- CODE doFumoCleanup(const Json::Value &jConfig, UpdateCb& stepCb);
- CODE doFumoApplyFirmware(const Json::Value &jConfig, UpdateCb& stepCb);
- CODE doFumoWaitNewFirmware(const Json::Value &jConfig, UpdateCb& stepCb);
- std::string m_sFw;
- std::string m_sFwBuild;
};
}
}
diff --git a/src/MTS_IO_ME910C1WWRadio.cpp b/src/MTS_IO_ME910C1WWRadio.cpp
index 80c2320..bf1be00 100644
--- a/src/MTS_IO_ME910C1WWRadio.cpp
+++ b/src/MTS_IO_ME910C1WWRadio.cpp
@@ -17,27 +17,14 @@
* 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)
{
@@ -129,593 +116,4 @@ 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();
-
-#if defined(JSONCPP_VERSION_HEXA) && (JSONCPP_VERSION_HEXA > 0x010600) // > 1.6.0
- Json::CharReaderBuilder builder;
- std::istringstream ss(buffer);
- if (!Json::parseFromStream(builder, ss, &jConfig, NULL)) {
- printError("Error parsing FOTA configuration file");
- break;
- }
-#else
- Json::Features features = Json::Features::strictMode();
- Json::Reader reader(features);
- if (!reader.parse(buffer, jConfig)) {
- printError("Error parsing FOTA configuration file");
- break;
- }
-#endif
-
- //
- // 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;
-}
-
+} \ No newline at end of file