diff options
author | Jesse Gilles <jgilles@multitech.com> | 2015-04-20 17:14:31 -0500 |
---|---|---|
committer | Jesse Gilles <jgilles@multitech.com> | 2015-04-20 17:14:31 -0500 |
commit | d84d880627bcc1e1898a8f96b861bc25863ec86c (patch) | |
tree | e7db4eef6a8e8254eaa6ba0c7e5d56098af19d16 /src/MTS_IO_CdmaRadio.cpp | |
download | libmts-io-d84d880627bcc1e1898a8f96b861bc25863ec86c.tar.gz libmts-io-d84d880627bcc1e1898a8f96b861bc25863ec86c.tar.bz2 libmts-io-d84d880627bcc1e1898a8f96b861bc25863ec86c.zip |
initial commit
Diffstat (limited to 'src/MTS_IO_CdmaRadio.cpp')
-rw-r--r-- | src/MTS_IO_CdmaRadio.cpp | 1297 |
1 files changed, 1297 insertions, 0 deletions
diff --git a/src/MTS_IO_CdmaRadio.cpp b/src/MTS_IO_CdmaRadio.cpp new file mode 100644 index 0000000..66ce820 --- /dev/null +++ b/src/MTS_IO_CdmaRadio.cpp @@ -0,0 +1,1297 @@ +/* + * 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_CdmaRadio.cpp + \brief A brief description + \date Nov 19, 2014 + \author sgodinez + + A more elaborate description +*/ + +#include <mts/MTS_IO_CdmaRadio.h> +#include <mts/MTS_Text.h> +#include <mts/MTS_Logger.h> +#include <mts/MTS_Thread.h> + +using namespace MTS::IO; + +CdmaRadio::CdmaRadio(const std::string& sName, const std::string& sPort) +: CellularRadio(sName, sPort) +{ + +} + +CdmaRadio::~CdmaRadio() { + +} + +CellularRadio::CODE CdmaRadio::getImei(std::string& sImei) { + printTrace("%s| Get IMEI", getName().c_str()); + return getMeid(sImei); +} + +CellularRadio::CODE CdmaRadio::getMeid(std::string& sMeid) { + printTrace("%s| Get MEID", getName().c_str()); + sMeid = VALUE_NOT_SUPPORTED; + std::string sCmd("AT#MEIDESN?"); + std::string sResult = CellularRadio::sendCommand(sCmd); + size_t pos = sResult.find(RSP_OK); + if (pos == std::string::npos) { + printWarning("%s| Unable to get MEID from radio using command [%s]", getName().c_str(), sCmd.c_str()); + return FAILURE; + } + + size_t start = sResult.find("#MEIDESN:") + sizeof("#MEIDESN:"); + size_t stop = sResult.find(","); + + if(stop != std::string::npos && stop > start) { + sMeid = sResult.substr(start, stop - start); + } else { + return FAILURE; + } + + return SUCCESS; +} + +CellularRadio::CODE CdmaRadio::getMsid(std::string& sMsid) { + printTrace("%s| Get MSID", getName().c_str()); + sMsid = VALUE_NOT_SUPPORTED; + std::string sCmd("AT$MSID?"); + std::string sResult = CellularRadio::sendCommand(sCmd); + size_t end = sResult.find(RSP_OK); + if (end == std::string::npos) { + printWarning("%s| Unable to get MSID from radio using command [%s]", getName().c_str(), sCmd.c_str()); + return FAILURE; + } + + size_t start = sResult.find("$MSID:") + sizeof("$MSID:"); + sMsid = MTS::Text::trim(sResult.substr(start, end-start)); + if(sMsid.size() == 0) { + printWarning("%s| MSID is empty", getName().c_str()); + } + + return SUCCESS; +} + +CellularRadio::CODE CdmaRadio::getCarrier(std::string& sCarrier) { + if(m_sCarrier != "") { + sCarrier = m_sCarrier; + return SUCCESS; + } + + std::string sFirmware; + CODE code = getFirmware(sFirmware); + if(code != SUCCESS) { + return code; + } + + if(!getCarrierFromFirmware(sFirmware, sCarrier)) { + return FAILURE; + } + + m_sCarrier = sCarrier; + + return SUCCESS; +} + +CellularRadio::CODE CdmaRadio::getNetwork(std::string& sNetwork) { + return getCarrier(sNetwork); +} + +CellularRadio::CODE CdmaRadio::getSimStatus(std::string& sSimStatus) { + printTrace("%s| Get SIM Status", getName().c_str()); + sSimStatus = VALUE_NOT_SUPPORTED; + return NOT_APPLICABLE; +} + +CellularRadio::CODE CdmaRadio::getIccid(std::string& sIccid) { + printTrace("%s| Get ICCID", getName().c_str()); + sIccid = VALUE_NOT_SUPPORTED; + return NOT_APPLICABLE; +} + +CellularRadio::CODE CdmaRadio::getLac(std::string& sLac) { + printTrace("%s| Get LAC", getName().c_str()); + sLac = VALUE_NOT_SUPPORTED; + return NOT_APPLICABLE; +} + +CellularRadio::CODE CdmaRadio::getService(std::string& sService) { + printTrace("%s| Get Service", getName().c_str()); + sService = VALUE_NOT_SUPPORTED; + std::string sCmd("AT+SERVICE?"); + std::string sResult = CellularRadio::sendCommand(sCmd); + size_t end = sResult.find(RSP_OK); + if (end == std::string::npos) { + printWarning("%s| Unable to get Service from radio using command [%s]", getName().c_str(), sCmd.c_str()); + return FAILURE; + } + + size_t start = sResult.find("+SERVICE:"); + if(start != std::string::npos) { + start += sizeof("+SERVICE:"); + std::string sPsnt = MTS::Text::trim(sResult.substr(start, end-start)); + int32_t iService; + sscanf(sPsnt.c_str(), "%d", &iService); + + switch(iService) { + case 0: sService = "No Service"; break; + case 1: sService = "1xRTT"; break; + case 2: sService = "EVDO"; break; //Release 0 + case 3: sService = "EVDO"; break; //Release A + case 4: sService = "GPRS"; break; + default: sService = VALUE_UNKNOWN; break; + } + + printDebug("%s| Service ID: [%d][%s]", getName().c_str(), iService, sService.c_str()); + } + return SUCCESS; +} + +CellularRadio::CODE CdmaRadio::getHardware(std::string& sHardware) { + printTrace("%s| Get Hardware", getName().c_str()); + sHardware = VALUE_NOT_SUPPORTED; + std::string sCmd("AT#HWREV"); + std::string sResult = CellularRadio::sendCommand(sCmd); + size_t pos = sResult.find(RSP_OK); + if (pos == std::string::npos) { + printWarning("%s| Unable to get hardware from radio using command [%s]", getName().c_str(), sCmd.c_str()); + return FAILURE; + } + + sHardware = MTS::Text::trim(sResult.substr(0, pos)); + if(sHardware.size() == 0) { + printWarning("%s| Unable to get hardware from radio using command [%s]", getName().c_str(), sCmd.c_str()); + return FAILURE; + } + + return SUCCESS; +} + +CellularRadio::CODE CdmaRadio::getMdn(std::string& sMdn) { + printTrace("%s| Get MDN", getName().c_str()); + sMdn = VALUE_NOT_SUPPORTED; + std::string sCmd("AT+CNUM"); + std::string sResult = CellularRadio::sendCommand(sCmd); + size_t end = sResult.find(RSP_OK); + if (end == std::string::npos) { + printWarning("%s| Unable to get MDN from radio using command [%s]", getName().c_str(), sCmd.c_str()); + return FAILURE; + } + + size_t start = sResult.find("CNUM:"); + std::vector<std::string> vParts = MTS::Text::split(sResult.substr(start + sizeof("CNUM:"), end), ","); + if(vParts.size() == 3) { + sMdn = vParts[1]; + if(sMdn.size() == 0) { + printWarning("%s| MDN is empty. Device may need to be activated", getName().c_str(), sCmd.c_str()); + } + } else { + printWarning("%s| Unable to parse MDN from radio using command [%s][%s]", getName().c_str(), sCmd.c_str(), sResult.c_str()); + return FAILURE; + } + + return SUCCESS; +} + +CellularRadio::CODE CdmaRadio::validateMsl(const Json::Value& jArgs) { + printTrace("%s| Validate MSL", getName().c_str()); + + if(!jArgs["msl"].isString()) { + return INVALID_ARGS; + } + + std::string sCarrier; + getCarrier(sCarrier); + + if(sCarrier != "Aeris" && sCarrier != "Sprint") { + return NOT_APPLICABLE; + } + + std::string sMdn; + if(getMdn(sMdn) != SUCCESS) { + return FAILURE; + } + + Json::Value jMdn(Json::objectValue); + jMdn["mdn"] = sMdn; + jMdn["msl"] = jArgs["msl"]; + + return setMdn(jMdn); +} + +CellularRadio::CODE CdmaRadio::setMdn(const Json::Value& jArgs) { + printTrace("%s| Set MDN", getName().c_str()); + + if(!jArgs["mdn"].isString()) { + printError("%s| Arguments missing \"mdn\"", getName().c_str()); + return INVALID_ARGS; + } + + std::string sCarrier; + getCarrier(sCarrier); + + std::string sCmd("AT$MDN="); + if(sCarrier == "Sprint") { + + if(!jArgs["msl"].isString()) { + printError("%s| Arguments missing \"msl\"", getName().c_str()); + return INVALID_ARGS; + } + sCmd += jArgs["msl"].asString() + ","; + } else if(sCarrier == "Aeris") { + //AT$MDN=<Last Six Digits of HEX MEID>,<MDN> + sCmd += getMeidLastSix() + ","; + } + + //Strip spaces and hyphens + std::string sMdn = jArgs["mdn"].asString(); + sMdn = MTS::Text::strip(sMdn, '-'); + sMdn = MTS::Text::strip(sMdn, '('); + sMdn = MTS::Text::strip(sMdn, ')'); + sMdn = MTS::Text::strip(sMdn, ' '); + + + sCmd += sMdn; + + std::string sResult = sendCommand(sCmd); + size_t end = sResult.find(RSP_OK); + if (end == std::string::npos) { + printWarning("%s| Unable to set MDN for radio using command [%s]", getName().c_str(), sCmd.c_str()); + return FAILURE; + } + + return SUCCESS; +} + +CellularRadio::CODE CdmaRadio::setMsid(const Json::Value& jArgs) { + printTrace("%s| Set MSID", getName().c_str()); + if(!jArgs["msid"].isString()) { + printError("%s| Arguments missing \"msid\"", getName().c_str()); + return INVALID_ARGS; + } + + std::string sCarrier; + getCarrier(sCarrier); + + std::string sCmd("AT$MSID="); + if(sCarrier == "Sprint") { + if(!jArgs["msl"].isString()) { + printError("%s| Arguments missing \"msl\"", getName().c_str()); + return INVALID_ARGS; + } + sCmd += jArgs["msl"].asString() + ","; + } else if(sCarrier == "Aeris") { + //AT$MSID=<Last Six Digits of HEX MEID>,<MSID> + sCmd += getMeidLastSix() + ","; + } + + + sCmd += jArgs["msid"].asString(); + + std::string sResult = sendCommand(sCmd); + size_t end = sResult.find(RSP_OK); + if (end == std::string::npos) { + printWarning("%s| Unable to set MSID for radio using command [%s]", getName().c_str(), sCmd.c_str()); + return FAILURE; + } + + return SUCCESS; +} + +CellularRadio::CODE CdmaRadio::getMipProfile(Json::Value& jMipProfile) { + printTrace("%s| Get MIP Active Profile", getName().c_str()); + + initMipProfile(jMipProfile); + + std::string sCarrier; + getCarrier(sCarrier); + + if(sCarrier == "Aeris" || sCarrier == "Sprint") { + std::string sCmd("AT$QCMIPGETP"); + std::string sResult = MTS::Text::trim(sendCommand(sCmd)); + if (sResult.find(RSP_OK) == std::string::npos) { + printWarning("%s| Unable to get active MIP profile for radio using command [%s]", getName().c_str(), sCmd.c_str()); + return FAILURE; + } + + std::vector<std::string> vLine = MTS::Text::split(sResult, "\r\n"); + + //ACTIVE MIP PROFILE + std::string sLine = vLine[0]; + std::vector<std::string> vParts = MTS::Text::split(sLine, ':', 2); + if(vParts.size() == 2 && vParts[0] == "Profile") { + if(vParts[1].find("Enabled") != std::string::npos) { + jMipProfile[KEY_MIP_ENABLED] = true; + } else { + jMipProfile[KEY_MIP_ENABLED] = false; + } + int32_t id; + sscanf(vParts[1].c_str(), "%d", &id); + jMipProfile[KEY_MIP_ID] = id; + + } else { + printWarning("%s| Unable to parse active MIP profile from line [%s]", getName().c_str(), sLine.c_str()); + } + + + splitAndAssign(vLine[1], "NAI", jMipProfile, KEY_MIP_NAI); + splitAndAssign(vLine[2], "Home Addr", jMipProfile, KEY_MIP_HOMEADDRESS); + splitAndAssign(vLine[3], "Primary HA", jMipProfile, KEY_MIP_PRIMARYHA); + splitAndAssign(vLine[4], "Secondary HA", jMipProfile, KEY_MIP_SECONDARYHA); + splitAndAssign(vLine[5], "MN-AAA SPI", jMipProfile, KEY_MIP_MNAAASPI); + splitAndAssign(vLine[6], "MN-HA SPI", jMipProfile, KEY_MIP_MNHASPI); + + //Reverse Tunneling + sLine = vLine[7]; + vParts = MTS::Text::split(sLine, ':', 2); + if(vParts.size() == 2 && vParts[0] == "Rev Tun") { + if(vParts[1] == "1") { + jMipProfile[KEY_MIP_REVTUN] = true; + } else { + jMipProfile[KEY_MIP_REVTUN] = false; + } + } else { + printWarning("%s| Unable to parse Reverse Tunneling from line [%s]", getName().c_str(), sLine.c_str()); + } + + //MN-AAA SS + sLine = vLine[8]; + vParts = MTS::Text::split(sLine, ':', 2); + if(vParts.size() == 2 && vParts[0] == "MN-AAA SS") { + if(vParts[1] == "Set") { + jMipProfile[KEY_MIP_MNAAASS] = true; + } else { + jMipProfile[KEY_MIP_MNAAASS] = false; + } + } else { + printWarning("%s| Unable to parse MN-AAA SS from line [%s]", getName().c_str(), sLine.c_str()); + } + + //MN-HA SS + sLine = vLine[9]; + vParts = MTS::Text::split(sLine, ':', 2); + if(vParts.size() == 2 && vParts[0] == "MN-HA SS") { + if(vParts[1] == "Set") { + jMipProfile[KEY_MIP_MNHASS] = true; + } else { + jMipProfile[KEY_MIP_MNHASS] = false; + } + } else { + printWarning("%s| Unable to parse MN-HA SS from line [%s]", getName().c_str(), sLine.c_str()); + } + } + + + return SUCCESS; +} + + +CellularRadio::CODE CdmaRadio::setMipActiveProfile(const Json::Value& jArgs) { + printTrace("%s| Set MIP Active Profile", getName().c_str()); + + if(!jArgs["activeProfile"].isString()) { + return INVALID_ARGS; + } + + std::string sCmd("AT$QCMIPP="); + sCmd += jArgs["activeProfile"].asString(); + + std::string sResult = sendCommand(sCmd); + size_t end = sResult.find(RSP_OK); + if (end == std::string::npos) { + printWarning("%s| Unable to set Active profile for radio using command [%s]", getName().c_str(), sCmd.c_str()); + return FAILURE; + } + + return SUCCESS; +} + +CellularRadio::CODE CdmaRadio::setMipNai(const Json::Value& jArgs) { + printTrace("%s| Set MIP NAI", getName().c_str()); + + if(!jArgs["nai"].isString()) { + return INVALID_ARGS; + } + + std::string sCmd("AT$QCMIPNAI="); + sCmd += jArgs["nai"].asString() + ",1"; + + std::string sResult = sendCommand(sCmd); + size_t end = sResult.find(RSP_OK); + if (end == std::string::npos) { + printWarning("%s| Unable to set NAI for radio using command [%s]", getName().c_str(), sCmd.c_str()); + return FAILURE; + } + + return SUCCESS; +} + +CellularRadio::CODE CdmaRadio::setMipHomeIp(const Json::Value& jArgs) { + printTrace("%s| Set MIP Home IP", getName().c_str()); + + if(!jArgs["homeIp"].isString()) { + return INVALID_ARGS; + } + + std::string sCmd("AT$QCMIPHA="); + sCmd += jArgs["homeIp"].asString() + ",1"; + + std::string sResult = sendCommand(sCmd); + size_t end = sResult.find(RSP_OK); + if (end == std::string::npos) { + printWarning("%s| Unable to set Home IP profile for radio using command [%s]", getName().c_str(), sCmd.c_str()); + return FAILURE; + } + + return SUCCESS; +} + +CellularRadio::CODE CdmaRadio::setMipPrimaryHa(const Json::Value& jArgs) { + printTrace("%s| Set MIP Primary HA", getName().c_str()); + + if(!jArgs["primaryHa"].isString()) { + return INVALID_ARGS; + } + + std::string sCmd("AT$QCMIPPHA="); + sCmd += jArgs["primaryHa"].asString() + ",1"; + + std::string sResult = sendCommand(sCmd); + size_t end = sResult.find(RSP_OK); + if (end == std::string::npos) { + printWarning("%s| Unable to set Primary HA for radio using command [%s]", getName().c_str(), sCmd.c_str()); + return FAILURE; + } + + return SUCCESS; +} + +CellularRadio::CODE CdmaRadio::setMipSecondaryHa(const Json::Value& jArgs) { + printTrace("%s| Set MIP Secondary HA", getName().c_str()); + + if(!jArgs["secondaryHa"].isString()) { + return INVALID_ARGS; + } + + std::string sCmd("AT$QCMIPSHA="); + sCmd += jArgs["secondaryHa"].asString() + ",1"; + + std::string sResult = sendCommand(sCmd); + size_t end = sResult.find(RSP_OK); + if (end == std::string::npos) { + printWarning("%s| Unable to set Secondary HA for radio using command [%s]", getName().c_str(), sCmd.c_str()); + return FAILURE; + } + + return SUCCESS; +} + +CellularRadio::CODE CdmaRadio::setMipMnAaaSpi(const Json::Value& jArgs) { + printTrace("%s| Set MIP MN-AAA SPI", getName().c_str()); + + if(!jArgs["mnAaaSpi"].isString()) { + return INVALID_ARGS; + } + + std::string sCmd("AT$QCMIPMASPI="); + sCmd += jArgs["mnAaaSpi"].asString() + ",1"; + + std::string sResult = sendCommand(sCmd); + size_t end = sResult.find(RSP_OK); + if (end == std::string::npos) { + printWarning("%s| Unable to set MN-AAA SPI for radio using command [%s]", getName().c_str(), sCmd.c_str()); + return FAILURE; + } + + return SUCCESS; +} + +CellularRadio::CODE CdmaRadio::setMipMnHaSpi(const Json::Value& jArgs) { + printTrace("%s| Set MIP MN-HA SPI", getName().c_str()); + + if(!jArgs["mnHaSpi"].isString()) { + return INVALID_ARGS; + } + + std::string sCmd("AT$QCMIPMHSPI="); + sCmd += jArgs["mnHaSpi"].asString() + ",1"; + + std::string sResult = sendCommand(sCmd); + size_t end = sResult.find(RSP_OK); + if (end == std::string::npos) { + printWarning("%s| Unable to set MN-HA SPI for radio using command [%s]", getName().c_str(), sCmd.c_str()); + return FAILURE; + } + + return SUCCESS; +} + +CellularRadio::CODE CdmaRadio::setMipRevTun(const Json::Value& jArgs) { + printTrace("%s| Set MIP Rev Tun", getName().c_str()); + + if(!jArgs["revTun"].isString()) { + return INVALID_ARGS; + } + + std::string sCmd("AT$QCMIPRT="); + sCmd += jArgs["revTun"].asString() + ",1"; + + std::string sResult = sendCommand(sCmd); + size_t end = sResult.find(RSP_OK); + if (end == std::string::npos) { + printWarning("%s| Unable to set Rev Tun for radio using command [%s]", getName().c_str(), sCmd.c_str()); + return FAILURE; + } + + return SUCCESS; +} + +CellularRadio::CODE CdmaRadio::setMipMnAaaSs(const Json::Value& jArgs) { + printTrace("%s| Set MIP MN-AAA SS", getName().c_str()); + + if(!jArgs["mnAaaSs"].isString()) { + return INVALID_ARGS; + } + + std::string sCmd("AT$QCMIPMASS="); + sCmd += jArgs["mnAaaSs"].asString() + ",1"; + + std::string sResult = sendCommand(sCmd); + size_t end = sResult.find(RSP_OK); + if (end == std::string::npos) { + printWarning("%s| Unable to set MN-AAA SS for radio using command [%s]", getName().c_str(), sCmd.c_str()); + return FAILURE; + } + + return SUCCESS; +} + +CellularRadio::CODE CdmaRadio::setMipMnHaSs(const Json::Value& jArgs) { + printTrace("%s| Set MIP MN-HA SS", getName().c_str()); + + if(!jArgs["mnHaSs"].isString()) { + return INVALID_ARGS; + } + + std::string sCmd("AT$QCMIPMHSS="); + sCmd += jArgs["mnHaSs"].asString() + ",1"; + + std::string sResult = sendCommand(sCmd); + size_t end = sResult.find(RSP_OK); + if (end == std::string::npos) { + printWarning("%s| Unable to set MN-HA SS for radio using command [%s]", getName().c_str(), sCmd.c_str()); + return FAILURE; + } + + return SUCCESS; +} + +CellularRadio::CODE CdmaRadio::updateDc(const Json::Value& jArgs, UpdateCb& stepCb) { + printTrace("%s| Update Device Configuration", getName().c_str()); + + std::string sCarrier; + getCarrier(sCarrier); + + if(sCarrier != "Sprint") { + return NOT_APPLICABLE; + } + + CellularRadio::CODE result = FAILURE; + std::size_t pos = 0; + std::size_t end = 0; + + IsNeedMoreData isNeedMoreData = [&stepCb, &result, &pos, &end, this](const std::string& iterationData, const std::string& allData)->bool { + + if(iterationData.empty()) { + //No new data + return true; + } + + end = allData.find(NL, pos); + printTrace("%s| Update DC Callback Started", this->getName().c_str()); + + while(end != std::string::npos) { + size_t next; + std::string sLine = MTS::Text::getLine(allData, pos, next); + + printTrace("%s| Line: [%s]", this->getName().c_str(), sLine.c_str()); + + if(sLine == "#906") { + // DC DM session started + if(stepCb) { + stepCb(Json::Value("DC Info: DM session started")); + } + } else if(sLine == "#918") { + // DC Done, success + result = SUCCESS; + if(stepCb) { + stepCb(Json::Value("DC Done: success")); + } + return false; + } else if(sLine == "#924") { + // DC Done, no profile + result = SUCCESS; + if(stepCb) { + stepCb(Json::Value("DC Done: no profile")); + } + return false; + } else if(sLine == "#911") { + // DC Error: credential error + result = ERROR; + if(stepCb) { + stepCb(Json::Value("DC Error: credential error")); + } + return false; + } else if(sLine == "#912") { + // DC Error: unreachable server + result = ERROR; + if(stepCb) { + stepCb(Json::Value("DC Error: unreachable server")); + } + return false; + } else if(sLine == "#913") { + // DC Error: network error + result = ERROR; + if(stepCb) { + stepCb(Json::Value("DC Error: network error")); + } + return false; + } else if(sLine == "#915") { + // DC Error: update fails with other reasons + result = ERROR; + if(stepCb) { + stepCb(Json::Value("DC Error: update fails with other reasons")); + } + return false; + }else if(sLine == RSP_ERROR) { + result = ERROR; + return false; + } + + //Set cursors for next iteration + if(next != std::string::npos) { + pos = next; + } + end = allData.find(NL, pos); + } + + printTrace("%s| Update DC Callback Finished", this->getName().c_str()); + return true; + }; + + sendCommand("AT+OMADM=2", isNeedMoreData, 5 * 60000); + return result; +} + +CellularRadio::CODE CdmaRadio::updatePrl(const Json::Value& jArgs, UpdateCb& stepCb) { + printTrace("%s| Update Preferred Roaming List", getName().c_str()); + + std::string sCarrier; + getCarrier(sCarrier); + + if(sCarrier != "Sprint") { + return NOT_APPLICABLE; + } + + CellularRadio::CODE result = FAILURE; + std::size_t pos = 0; + std::size_t end = 0; + + IsNeedMoreData isNeedMoreData = [&stepCb, &result, &pos, &end, this](const std::string& iterationData, const std::string& allData)->bool { + + if(iterationData.empty()) { + //No new data + return true; + } + + end = allData.find(NL, pos); + printTrace("%s| Update PRL Callback Started", this->getName().c_str()); + + while(end != std::string::npos) { + size_t next; + std::string sLine = MTS::Text::getLine(allData, pos, next); + + printTrace("%s| Line: [%s]", this->getName().c_str(), sLine.c_str()); + + if(sLine == "#905") { + // PRL DM session started + if(stepCb) { + stepCb(Json::Value("PRL Info: DM session started")); + } + } else if(sLine == "#909") { + // PRL Done, success + result = SUCCESS; + if(stepCb) { + stepCb(Json::Value("PRL Done: success")); + } + return false; + } else if(sLine == "#910") { + // PRL Done, no PRL update + result = SUCCESS; + if(stepCb) { + stepCb(Json::Value("PRL Done: no PRL update")); + } + return false; + } else if(sLine == "#911") { + // PRL Error: credential error + result = ERROR; + if(stepCb) { + stepCb(Json::Value("PRL Error: credential error")); + } + return false; + } else if(sLine == "#912") { + // PRL Error: unreachable server + result = ERROR; + if(stepCb) { + stepCb(Json::Value("PRL Error: unreachable server")); + } + return false; + } else if(sLine == "#913") { + // PRL Error: network error + result = ERROR; + if(stepCb) { + stepCb(Json::Value("PRL Error: network error")); + } + return false; + } else if(sLine == "#915") { + // PRL Error: update fails with other reasons + result = ERROR; + if(stepCb) { + stepCb(Json::Value("PRL Error: update fails with other reasons")); + } + return false; + } else if(sLine == RSP_ERROR) { + result = ERROR; + return false; + } + + //Set cursors for next iteration + if(next != std::string::npos) { + pos = next; + } + end = allData.find(NL, pos); + } + + printTrace("%s| Update PRL Callback Finished", this->getName().c_str()); + return true; + }; + + sendCommand("AT+PRL=2", isNeedMoreData, 5 * 60000); + return result; +} + +CellularRadio::CODE CdmaRadio::updateFumo(const Json::Value& jArgs, UpdateCb& stepCb) { + printTrace("%s| Update Firmware Update Management Object", getName().c_str()); + + std::string sCarrier; + getCarrier(sCarrier); + + if(sCarrier != "Sprint") { + return NOT_APPLICABLE; + } + + CellularRadio::CODE result = FAILURE; + std::size_t pos = 0; + std::size_t end = 0; + + IsNeedMoreData isNeedMoreData = [&stepCb, &result, &pos, &end, this](const std::string& iterationData, const std::string& allData)->bool { + + if(iterationData.empty()) { + //No new data + return true; + } + + end = allData.find(NL, pos); + printTrace("%s| Update FUMO Callback Started", this->getName().c_str()); + + while(end != std::string::npos) { + size_t next; + std::string sLine = MTS::Text::getLine(allData, pos, next); + + printTrace("%s| Line: [%s]", this->getName().c_str(), sLine.c_str()); + + if(sLine == "#907") { + // FUMO DM session started + if(stepCb) { + stepCb(Json::Value("FUMO Info: DM session started")); + } + } else if(sLine == "#916") { + // FUMO Done, no firmware update + result = SUCCESS; + if(stepCb) { + stepCb(Json::Value("FUMO Done: no firmware update")); + } + return false; + } else if(sLine == "#911") { + // FUMO Error: credential error + result = ERROR; + if(stepCb) { + stepCb(Json::Value("FUMO Error: credential error")); + } + return false; + } else if(sLine == "#912") { + // FUMO Error: unreachable server + result = ERROR; + if(stepCb) { + stepCb(Json::Value("FUMO Error: unreachable server")); + } + return false; + } else if(sLine == "#913") { + // FUMO Error: network error + result = ERROR; + if(stepCb) { + stepCb(Json::Value("FUMO Error: network error")); + } + return false; + } else if(sLine == "#915") { + // FUMO Error: update fails with other reasons + result = ERROR; + if(stepCb) { + stepCb(Json::Value("FUMO Error: update fails with other reasons")); + } + return false; + } else if(sLine == "#919") { + // FUMO Firmware downloaded successfully + if(stepCb) { + stepCb(Json::Value("FUMO Info: firmware downloaded successfully")); + } + } else if(sLine == "#920:") { + // FUMO Firmware download progress (percent) + if(stepCb) { + stepCb(Json::Value(std::string("FUMO Info: firmware download progress ") + allData.substr(pos + 5, end + 5 - pos))); + } + } else if(sLine == "#921:") { + // FUMO Firmware size get from the OMA-DM server (byte) + if(stepCb) { + stepCb(Json::Value(std::string("FUMO Info: firmware size get from the OMA-DM server ") + allData.substr(pos + 5, end + 5 - pos) + " byte")); + } + } else if(sLine == "#921") { /// Info: check after check "#921:" + // FUMO Firmware download start + if(stepCb) { + stepCb(Json::Value("FUMO Info: firmware downloaded successfully")); + } + } else if(sLine == "#929: 200") { + // FUMO Done, success + result = SUCCESS; + if(stepCb) { + stepCb(Json::Value("FUMO Done: update success")); + } + return false; + } else if(sLine == "#929: 402") { + // FUMO Error, firmware corrupted, CRC error + result = ERROR; + if(stepCb) { + stepCb(Json::Value("FUMO Error: firmware corrupted, CRC error")); + } + return false; + } else if(sLine == "#929: 403") { + // FUMO Error, firmware package mismatch + result = ERROR; + if(stepCb) { + stepCb(Json::Value("FUMO Error: firmware package mismatch")); + } + return false; + } else if(sLine == "#929: 404") { + // FUMO Error, firmware signature failed + result = ERROR; + if(stepCb) { + stepCb(Json::Value("FUMO Error: firmware signature failed")); + } + return false; + } else if(sLine == "#929: 406") { + // FUMO Error, firmware update authentication failed + result = ERROR; + if(stepCb) { + stepCb(Json::Value("FUMO Error: firmware update authentication failed")); + } + return false; + } else if(sLine == "#929: 410") { + // FUMO Error, firmware update general error + result = ERROR; + if(stepCb) { + stepCb(Json::Value("FUMO Error: firmware update general error")); + } + return false; + } else if(sLine == "#930") { + // FUMO Reporting of Firmware Update result to server + if(stepCb) { + stepCb(Json::Value("FUMO Info: reporting of firmware update result to server")); + } + } else if(sLine == RSP_ERROR) { + result = ERROR; + return false; + } + + //Set cursors for next iteration + if(next != std::string::npos) { + pos = next; + } + end = allData.find(NL, pos); + } + + printTrace("%s| Update FUMO Callback Finished", this->getName().c_str()); + return true; + }; + + sendCommand("AT+FUMO=2", isNeedMoreData, 30 * 60000); + return result; +} + +CellularRadio::CODE CdmaRadio::resetHfa(const Json::Value& jArgs, UpdateCb& stepCb) { + printTrace("%s| HFA Reset (after device reboot HFA will occur)", getName().c_str()); + + std::string sCarrier; + getCarrier(sCarrier); + + if(sCarrier != "Sprint") { + return NOT_APPLICABLE; + } + + if(!jArgs["msl"].isString()) { + return INVALID_ARGS; + } + + CellularRadio::CODE result = FAILURE; + std::size_t pos = 0; + std::size_t end = 0; + + IsNeedMoreData isNeedMoreData = [&stepCb, &result, &pos, &end, this](const std::string& iterationData, const std::string& allData)->bool { + /* Expected Events: + * #900 - DM Client ready + * #904 - HFA Started + * #914 - HFA Done - HFA Success + * #905 - PRL - Session started + * #909 - PRL - Done - PRL success + * #907 - FUMO - Firmware DM session started or started again until no more updates are available + * #916 - FUMO - Firmware Done, No firmware update + */ + + + if(iterationData.empty()) { + //No new data + return true; + } + + end = allData.find(NL, pos); + printTrace("%s| HFA Reset Callback Started", this->getName().c_str()); + + while(end != std::string::npos) { + size_t next; + std::string sLine = MTS::Text::getLine(allData, pos, next); + + printTrace("%s| Line: [%s]", this->getName().c_str(), sLine.c_str()); + + if(sLine == "#900") { + if(stepCb) { + stepCb(Json::Value("RTN Info: DM Client Ready")); + } + } else if(sLine == "#904") { + if(stepCb) { + stepCb(Json::Value("RTN Info: HFA - Session Started")); + } + } else if(sLine == "#914") { + if(stepCb) { + stepCb(Json::Value("RTN Info: HFA - Session Completed Successfully")); + } + } else if(sLine == "#905") { + if(stepCb) { + stepCb(Json::Value("RTN Info: PRL - Session Started")); + } + } else if(sLine == "#909") { + if(stepCb) { + stepCb(Json::Value("RTN Info: PRL - Session Completed Successfully")); + } + } else if(sLine == "#907") { + if(stepCb) { + stepCb(Json::Value("RTN Info: Firmware DM - Session Started")); + } + } else if(sLine == "#916") { + // RTN Done, success + result = SUCCESS; + if(stepCb) { + stepCb(Json::Value("RTN Done: Firmware DM - Session Completed Successfully")); + } + return false; + } else if(sLine == RSP_ERROR) { + result = ERROR; + return false; + } else if(sLine == RSP_OK) { + //The Device will reboot now, so reset the connection + if(stepCb) { + stepCb(Json::Value("RTN Info: Resetting Radio")); + } + + //TODO: Investigate a better way of to handle + // recapturing the radio port after reset + + //Sleep for a few seconds while resetting + MTS::Thread::sleep(5000); + + //Try to reconnect to radio + if(!this->resetConnection(10000)) { + printError("%s| Unable to obtain radio after reset", this->getName().c_str()); + if(stepCb) { + stepCb(Json::Value("RTN Error: Unable to obtain radio after reset")); + } + result = ERROR; + return false; + } + } + + //Set cursors for next iteration + if(next != std::string::npos) { + pos = next; + } + end = allData.find(NL, pos); + } + + printTrace("%s| HFA Reset Callback Finished", this->getName().c_str()); + return true; + }; + + std::string sCmd("AT#SPRTN=\""); + sCmd += jArgs["msl"].asString() + "\""; + sendCommand(sCmd, isNeedMoreData, 5 * 60000); + return result; +} + +CellularRadio::CODE CdmaRadio::activate(const Json::Value& jArgs, UpdateCb& stepCb) { + printTrace("%s| Activation", getName().c_str()); + + std::string sActivationCmd; + std::string sCarrier; + getCarrier(sCarrier); + + if(sCarrier == "Aeris") { + + if(!jArgs["msid"].isString()) { + printError("%s| Arguments missing \"msid\"", getName().c_str()); + return INVALID_ARGS; + } + + if(!jArgs["mdn"].isString()) { + printError("%s| Arguments missing \"mdn\"", getName().c_str()); + return INVALID_ARGS; + } + + std::string sMsid = jArgs["msid"].asString(); + std::string sMdn = jArgs["mdn"].asString(); + if(sMdn.size() != 10) { + printError("%s| MDN not valid. Expected length of 10: [%s][%d]", getName().c_str(), sMdn.c_str(), sMdn.size()); + return INVALID_ARGS; + } + + if(sMsid.size() != 10) { + printError("%s| MIN not valid. Expected length of 10: [%s][%d]", getName().c_str(), sMsid.c_str(), sMsid.size()); + return INVALID_ARGS; + } + + //Set MDN & MSID + CellularRadio::CODE code; + code = setMdn(jArgs); + if(code != SUCCESS) { + return code; + } + + code = setMsid(jArgs); + if(code != SUCCESS) { + return code; + } + + resetRadio(10000); + + return SUCCESS; + + } else if(sCarrier == "Verizon") { + sActivationCmd = "AT+CDV*22899\r"; + } else { + return NOT_APPLICABLE; + } + + CellularRadio::CODE result = FAILURE; + std::size_t pos = 0; + std::size_t end = 0; + + IsNeedMoreData isNeedMoreData = [&stepCb, &result, &pos, &end, this](const std::string& iterationData, const std::string& allData)->bool { + //Verizon Activation + /* Expected Events: + * OK + * #OTASP: 0 //Start OTASP + * #OTASP: 1 //Start OTASP Commit + * #OTASP: 2 //End OTASP + * + * ERRORS: + * NO CARRIER //Account Plan Not Active + * #OTASP: 5 //Activation Failed + */ + + + if(iterationData.empty()) { + //No new data + return true; + } + + end = allData.find(NL, pos); + printTrace("%s| Activation Reset Callback Started", this->getName().c_str()); + + while(end != std::string::npos) { + size_t next; + std::string sLine = MTS::Text::getLine(allData, pos, next); + + printTrace("%s| Line: [%s]", this->getName().c_str(), sLine.c_str()); + + if(sLine == RSP_OK) { + if(stepCb) { + stepCb(Json::Value("Activation Info: Over-the-Air Programming in Process")); + } + } else if(sLine == "#OTASP: 0") { + if(stepCb) { + stepCb(Json::Value("Activation Info: Saving Radio Configurations")); + } + } else if(sLine == "#OTASP: 1") { + if(stepCb) { + stepCb(Json::Value("Activation Info: Restarting Radio")); + } + } else if(sLine == "#OTASP: 2") { + if(stepCb) { + stepCb(Json::Value("Activation Info: Activation Completed Successfully")); + } + //Sleep for a few seconds while radio resets + MTS::Thread::sleep(5000); + this->resetConnection(10000); + result = SUCCESS; + return false; + } else if(sLine == "#OTASP: 5") { + if(stepCb) { + stepCb(Json::Value("Activation Error: Activation Failed")); + } + return false; + } else if(sLine == "NO CARRIER") { + if(stepCb) { + stepCb(Json::Value("Activation Error: Account Plan May Not Be Active")); + } + result = ERROR; + return false; + } else if(sLine == RSP_ERROR) { + result = ERROR; + return false; + } + + //Set cursors for next iteration + if(next != std::string::npos) { + pos = next; + } + end = allData.find(NL, pos); + } + + printTrace("%s| Activation Callback Finished", this->getName().c_str()); + return true; + }; + + sendCommand(sActivationCmd, isNeedMoreData, 5 * 60000); + return result; +} + +CellularRadio::CODE CdmaRadio::getNetworkStatus(Json::Value& jData) { + printTrace("%s| Get Network Status", getName().c_str()); + + getCommonNetworkStats(jData); + + std::string sCarrier; + getCarrier(sCarrier); + + if(sCarrier == VALUE_CARRIER_SPRINT) { + Json::Value& jDebug = jData["debug"]; + std::string sCmd("AT$DEBUG?"); + std::string sResult = MTS::Text::trim(sendCommand(sCmd)); + if (sResult.find(RSP_OK) != std::string::npos) { + std::vector<std::string> vCategories = MTS::Text::split(sResult, "\r\n\r\n"); + for(size_t i = 0 ; i < vCategories.size(); i++) { + std::vector<std::string> vLine = MTS::Text::split(vCategories[i], "\r\n"); + if(vLine[0] == "1x Engineering") { + Json::Value& j1x = jDebug["1xrtt"]; + splitAndAssign(vLine[1], "State", j1x, "state"); + splitAndAssign(vLine[3], "Channel", j1x, "channel"); + splitAndAssign(vLine[4], "Band Class", j1x, "bandClass"); + splitAndAssign(vLine[5], "SID", j1x, "sid"); + splitAndAssign(vLine[6], "NID", j1x, "nid"); + splitAndAssign(vLine[7], "Base ID", j1x, "baseId"); + splitAndAssign(vLine[8], "PN", j1x, "pn"); + splitAndAssign(vLine[9], "P_rev", j1x, "pRev"); + splitAndAssign(vLine[10], "Lat", j1x, "lat"); + splitAndAssign(vLine[11], "Lon", j1x, "lon"); + splitAndAssign(vLine[12], "Rx Pwr", j1x, "rxPwr"); + splitAndAssign(vLine[13], "Rx Ec/Io", j1x, "rxEcIo"); + splitAndAssign(vLine[14], "Rx FER", j1x, "rxFer"); + splitAndAssign(vLine[15], "Tx Pwr", j1x, "txPwr"); + splitAndAssign(vLine[16], "Active Set", j1x, "activeSet"); + splitAndAssign(vLine[17], "Neighbor Set", j1x, "neighborSet"); + } else if(vLine[0] == "EVDO Engineering") { + Json::Value& jEvdo = jDebug["evdo"]; + splitAndAssign(vLine[1], "State", jEvdo, "state"); + splitAndAssign(vLine[2], "Mac Index", jEvdo, "macIndex"); + splitAndAssign(vLine[3], "Channel", jEvdo, "channel"); + splitAndAssign(vLine[4], "Color Code", jEvdo, "colorCode"); + splitAndAssign(vLine[5], "Sector ID", jEvdo, "sectorId"); + splitAndAssign(vLine[6], "PN", jEvdo, "pn"); + splitAndAssign(vLine[7], "Rx Pwr", jEvdo, "rxPwr"); + splitAndAssign(vLine[8], "Rx PER", jEvdo, "rxPer"); + splitAndAssign(vLine[9], "Pilot Energy", jEvdo, "pilotEnergy"); + splitAndAssign(vLine[10], "DRC", jEvdo, "drc"); + splitAndAssign(vLine[11], "SINR", jEvdo, "sinr"); + splitAndAssign(vLine[12], "AN-AAA", jEvdo, "anAaa"); + splitAndAssign(vLine[13], "IP Address", jEvdo, "ipAddress"); + } else if(vLine[0] == "Configuration") { + Json::Value& jConf = jDebug["configuration"]; + splitAndAssign(vLine[1], "Technology", jConf, "technology"); + splitAndAssign(vLine[2], "1x Diversity", jConf, "1xDiversity"); + splitAndAssign(vLine[3], "EVDO Diversity", jConf, "evdoDiversity"); + splitAndAssign(vLine[4], "QLIC", jConf, "qlic"); + splitAndAssign(vLine[5], "PRL", jConf, "prl"); + splitAndAssign(vLine[6], "Chipset", jConf, "chipset"); + splitAndAssign(vLine[7], "AMSS version", jConf, "amssVersion"); + splitAndAssign(vLine[8], "Device version", jConf, "deviceVersion"); + splitAndAssign(vLine[9], "Hardware version", jConf, "hardwareVersion"); + splitAndAssign(vLine[10], "Browser", jConf, "browser"); + splitAndAssign(vLine[11], "Multimedia Version", jConf, "multimediaVersion"); + } + } + + } else { + printDebug("%s| SPRINT Network Status command returned unexpected response: [%s][%s]", getName().c_str(), sCmd.c_str(), sResult.c_str()); + } + } + + + printTrace("%s| Network Status:\n%s\n", getName().c_str(), jData.toStyledString().c_str()); + + return SUCCESS; +} + +std::string CdmaRadio::getMeidLastSix() { + std::string sMeid; + if(getMeid(sMeid) != SUCCESS || sMeid.size() != 14) { + return ""; + } + return sMeid.substr(8); +} |