diff options
-rw-r--r-- | include/mts/MTS_IO_ME910C1WWRadio.h | 22 | ||||
-rw-r--r-- | src/MTS_IO_ME910C1WWRadio.cpp | 604 |
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 |