diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | include/mts/MTS_IO_CellularRadioFactory.h | 2 | ||||
-rw-r--r-- | include/mts/MTS_IO_ME910C1NARadio.h | 57 | ||||
-rw-r--r-- | include/mts/MTS_IO_ME910C1NVRadio.h | 77 | ||||
-rw-r--r-- | include/mts/MTS_IO_ME910C1WWRadio.h | 23 | ||||
-rw-r--r-- | src/MTS_IO_CellularRadioFactory.cpp | 12 | ||||
-rw-r--r-- | src/MTS_IO_ICellularRadio.cpp | 16 | ||||
-rw-r--r-- | src/MTS_IO_ME910C1NARadio.cpp | 127 | ||||
-rw-r--r-- | src/MTS_IO_ME910C1NVRadio.cpp | 623 | ||||
-rw-r--r-- | src/MTS_IO_ME910C1WWRadio.cpp | 593 |
10 files changed, 615 insertions, 917 deletions
@@ -33,8 +33,6 @@ OBJS += \ src/MTS_IO_LE910EU1Radio.o \ src/MTS_IO_LE910C1NSRadio.o \ src/MTS_IO_LE910C1APRadio.o \ - src/MTS_IO_ME910C1NARadio.o \ - src/MTS_IO_ME910C1NVRadio.o \ src/MTS_IO_ME910C1WWRadio.o \ src/MTS_IO_ME910Radio.o \ src/MTS_IO_LockFile.o \ diff --git a/include/mts/MTS_IO_CellularRadioFactory.h b/include/mts/MTS_IO_CellularRadioFactory.h index 9b36489..e57ca5e 100644 --- a/include/mts/MTS_IO_CellularRadioFactory.h +++ b/include/mts/MTS_IO_CellularRadioFactory.h @@ -49,8 +49,6 @@ namespace MTS { ICellularRadio* createLE910EU1(const std::string& sPort = ICellularRadio::DEFAULT_RADIO_PORT) const; ICellularRadio* createLE910C1NS(const std::string& sPort = ICellularRadio::DEFAULT_RADIO_PORT) const; ICellularRadio* createLE910C1AP(const std::string& sPort = ICellularRadio::DEFAULT_RADIO_PORT) const; - ICellularRadio* createME910C1NA(const std::string& sPort = ICellularRadio::DEFAULT_RADIO_PORT) const; - ICellularRadio* createME910C1NV(const std::string& sPort = ICellularRadio::DEFAULT_RADIO_PORT) const; ICellularRadio* createME910C1WW(const std::string& sPort = ICellularRadio::DEFAULT_RADIO_PORT) const; ICellularRadio* createGE910(const std::string& sPort = ICellularRadio::DEFAULT_RADIO_PORT) const; ICellularRadio* createDE910(const std::string& sPort = ICellularRadio::DEFAULT_RADIO_PORT) const; diff --git a/include/mts/MTS_IO_ME910C1NARadio.h b/include/mts/MTS_IO_ME910C1NARadio.h deleted file mode 100644 index e8120bd..0000000 --- a/include/mts/MTS_IO_ME910C1NARadio.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2015 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.h - \brief A brief description - \date Jan 19, 2015 - \author sgodinez - - A more elaborate description -*/ -#ifndef MTS_IO_ME910C1NARADIO_H_ -#define MTS_IO_ME910C1NARADIO_H_ - -#include <mts/MTS_IO_ME910Radio.h> - -namespace MTS { - namespace IO { - - class ME910C1NARadio : public ME910Radio { - - public: - static const std::string MODEL_NAME; - - ME910C1NARadio(const std::string& sPort); - virtual ~ME910C1NARadio(){}; - - virtual CODE setActiveFirmware(const Json::Value& jArgs); - - virtual CODE getActiveFirmware(std::string& sFwId); - - protected: - - private: - - }; - } -} - -#endif /* MTS_IO_ME910C1NARADIO_H_ */ diff --git a/include/mts/MTS_IO_ME910C1NVRadio.h b/include/mts/MTS_IO_ME910C1NVRadio.h deleted file mode 100644 index 3d0b3b0..0000000 --- a/include/mts/MTS_IO_ME910C1NVRadio.h +++ /dev/null @@ -1,77 +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.h - \brief A brief description - \date May 1, 2018 - \author mykyta.dorokhin - - A more elaborate description -*/ -#ifndef MTS_IO_ME910C1NVRadio_H_ -#define MTS_IO_ME910C1NVRadio_H_ - -#include <mts/MTS_IO_ME910Radio.h> - -namespace MTS { - namespace IO { - - class ME910C1NVRadio : public ME910Radio { - - public: - static const std::string MODEL_NAME; - - ME910C1NVRadio(const std::string& sPort); - virtual ~ME910C1NVRadio(){}; - - virtual CODE updateFumo(const Json::Value& jArgs, UpdateCb& stepCb); - virtual CODE getCarrier(std::string& sCarrier); - - 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; - }; - } -} - -#endif /* MTS_IO_ME910C1NVRadio_H_ */ diff --git a/include/mts/MTS_IO_ME910C1WWRadio.h b/include/mts/MTS_IO_ME910C1WWRadio.h index d45d86a..9605862 100644 --- a/include/mts/MTS_IO_ME910C1WWRadio.h +++ b/include/mts/MTS_IO_ME910C1WWRadio.h @@ -36,10 +36,33 @@ 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_CellularRadioFactory.cpp b/src/MTS_IO_CellularRadioFactory.cpp index b86f207..08c6315 100644 --- a/src/MTS_IO_CellularRadioFactory.cpp +++ b/src/MTS_IO_CellularRadioFactory.cpp @@ -31,8 +31,6 @@ #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> @@ -56,8 +54,6 @@ CellularRadioFactory::CellularRadioFactory() { 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; @@ -175,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 89318ef..9f8955e 100644 --- a/src/MTS_IO_ICellularRadio.cpp +++ b/src/MTS_IO_ICellularRadio.cpp @@ -163,12 +163,6 @@ MTS::IO::ICellularRadio::CODE MTS::IO::ICellularRadio::convertModelToMtsShortCod } 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; @@ -289,12 +283,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; @@ -431,10 +419,6 @@ 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) { 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; +} + |