/* * 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 . * */ /*! \file MTS_IO_CellularRadio.cpp \brief A brief description \date Nov 5, 2014 \author sgodinez A more elaborate description */ /*! \file MTS_CELL_CellularRadio.cpp \brief A brief description \date Nov 4, 2014 \author sgodinez A more elaborate description */ #include #include #include #include #include #include #include #include #include #include #include #include using namespace MTS::IO; const char CellularRadio::ETX = 0x03; //Ends socket connection const char CellularRadio::DLE = 0x10; //Escapes ETX and DLE within Payload const char CellularRadio::CR = 0x0D; const char CellularRadio::NL = 0x0A; const char CellularRadio::CTRL_Z = 0x1A; const std::string CellularRadio::RSP_ERROR("ERROR"); const std::string CellularRadio::RSP_OK("OK"); const std::string CellularRadio::DEFAULT_RADIO_PORT("/dev/modem_at1"); const std::string CellularRadio::DEFAULT_RADIO_DIR("/var/run/radio/"); const std::string CellularRadio::VALUE_UNKNOWN("Unknown"); const std::string CellularRadio::VALUE_UNAVAILABLE("Unavailable"); const std::string CellularRadio::VALUE_NOT_SUPPORTED("Not Supported"); const std::string CellularRadio::VALUE_NOT_REGISTERED("NOT REGISTERED"); const std::string CellularRadio::VALUE_REGISTERED("REGISTERED"); const std::string CellularRadio::VALUE_SEARCHING("SEARCHING"); const std::string CellularRadio::VALUE_DENIED("DENIED"); const std::string CellularRadio::VALUE_ROAMING("ROAMING"); //Static Data const std::string CellularRadio::KEY_TYPE("type"); //!< GSM or CDMA const std::string CellularRadio::KEY_CODE("code"); //!< Product Code : H5, H6, C2, EV3, G3 const std::string CellularRadio::KEY_MODEL("model"); //!< Model : HE910, LE910, CE910, DE910, GE910 const std::string CellularRadio::KEY_MANUFACTURER("manufacturer"); //!< Manufacturer: Telit const std::string CellularRadio::KEY_HARDWARE("hardware"); //!< Radio Hardware Version const std::string CellularRadio::KEY_FIRMWARE("firmware"); //!< Radio Firmware Version const std::string CellularRadio::KEY_CARRIER("carrier"); //!< Cellular Service Provider (Home Network) const std::string CellularRadio::VALUE_CARRIER_VERIZON("Verizon"); const std::string CellularRadio::VALUE_CARRIER_AERIS("Aeris"); const std::string CellularRadio::VALUE_CARRIER_SPRINT("Sprint"); const std::string CellularRadio::VALUE_CARRIER_ATT("AT&T"); const std::string CellularRadio::VALUE_CARRIER_TMOBILE("T-Mobile"); const std::string CellularRadio::KEY_IMEI("imei"); //!< International Mobile Station Equipment Identity const std::string CellularRadio::KEY_MEID("meid"); //!< Mobile Equipment Identifier const std::string CellularRadio::KEY_IMSI("imsi"); //!< International Mobile Subscriber Identity const std::string CellularRadio::KEY_MSID("msid"); //!< Mobil Station ID / Mobile Identification Number (MSID/MIN) (CDMA-Only) const std::string CellularRadio::KEY_MDN("mdn"); //!< Mobile Directory Number : Actual phone number dialed to reach radio const std::string CellularRadio::KEY_ICCID("iccid"); //!< Integrated Circuit Card Identifier const std::string CellularRadio::KEY_MSL("msl"); //!< Master Subsidy Lock //Dynamic Data const std::string CellularRadio::KEY_ROAMING("roaming"); //!< Indicates whether or not using Home Network const std::string CellularRadio::KEY_DATETIME("datetime"); //!< Date and Time from tower const std::string CellularRadio::KEY_SERVICE("service"); //!< Service Connection Type [GPRS, EGPRS, WCDMA, HSDPA, 1xRTT, EVDO] const std::string CellularRadio::KEY_NETWORK("network"); //!< Cellular Service Provider const std::string CellularRadio::KEY_CID("cid"); //!< Cellular ID (Tower) in HEX const std::string CellularRadio::KEY_LAC("lac"); //!< Location Area Code in HEX const std::string CellularRadio::KEY_RAC("rac"); //!< Routing Area Code in HEX const std::string CellularRadio::KEY_RSSI("rssi"); //!< Signal Strength const std::string CellularRadio::KEY_RSSIDBM("rssidBm"); //!< Signal Strength in dBm const std::string CellularRadio::KEY_MCC("mcc"); //!< Country Code const std::string CellularRadio::KEY_MNC("mnc"); //!< Operator Code const std::string CellularRadio::KEY_CHANNEL("channel"); //!< ARFCN or UARFCN Assigned Radio Channel const std::string CellularRadio::KEY_TXPWR("txpwr"); //!< Transmit Power const std::string CellularRadio::KEY_PSC("psc"); //!< Active Primary Synchronization Code (PSC) const std::string CellularRadio::KEY_ECIO("ecio"); //!< Active Ec/Io (chip energy per total wideband power in dBm) const std::string CellularRadio::KEY_RSCP("rscp"); //!< Active RSCP (Received Signal Code Power in dBm) const std::string CellularRadio::KEY_DRX("drx"); //!< Discontinuous reception cycle length (ms) const std::string CellularRadio::KEY_MM("mm"); //!< Mobility Management State const std::string CellularRadio::KEY_RR("rr"); //!< Radio Resource State const std::string CellularRadio::KEY_NOM("nom"); //!< Network Operator Mode const std::string CellularRadio::KEY_ABND("abnd"); //!< Active Band const std::string CellularRadio::KEY_BLER("bler"); //!< Block Error Rate (percentage) const std::string CellularRadio::KEY_SD("sd"); //!< Service Domain const std::string CellularRadio::KEY_DEBUG("debug"); //!< Debug Information const std::string CellularRadio::KEY_MIP("mipProfile"); //!< Mobile IP Information const std::string CellularRadio::KEY_MIP_ID("id"); //!< Mobile IP ID const std::string CellularRadio::KEY_MIP_ENABLED("enabled"); //!< Mobile IP Enabled/Disabled const std::string CellularRadio::KEY_MIP_NAI("nai"); //!< Network Access Identifier const std::string CellularRadio::KEY_MIP_HOMEADDRESS("homeAddress"); //!< Home Address const std::string CellularRadio::KEY_MIP_PRIMARYHA("primaryAddress"); //!< Primary Home Agent const std::string CellularRadio::KEY_MIP_SECONDARYHA("secondaryAddress"); //!< Secondary Home Agent const std::string CellularRadio::KEY_MIP_MNAAASPI("mnAaaSpi"); //!< Mobile Node Authentication, Authorization, and Accounting Server Security Parameter Index const std::string CellularRadio::KEY_MIP_MNHASPI("mnHaSpi"); //!< Mobile Node Home Agent Security Server Parameter Index const std::string CellularRadio::KEY_MIP_REVTUN("revTun"); //!< Reverse Tunneling Enabled const std::string CellularRadio::KEY_MIP_MNAAASS("mnAaaSs"); //!< Mobile Node Authentication, Authorization, and Accounting Server Shared Secret const std::string CellularRadio::KEY_MIP_MNHASS("mnHaSs"); //!< Mobile Node Home Agent Shared Secret const std::string CellularRadio::VALUE_TYPE_GSM("GSM"); const std::string CellularRadio::VALUE_TYPE_LTE("LTE"); const std::string CellularRadio::VALUE_TYPE_CDMA("CDMA"); const std::string CellularRadio::VALUE_SD_NO_SERVICE("NO SERVICE"); const std::string CellularRadio::VALUE_SD_CS_ONLY("CS ONLY"); const std::string CellularRadio::VALUE_SD_PS_ONLY("PS ONLY"); const std::string CellularRadio::VALUE_SD_CSPS("CS+PS"); const std::string CellularRadio::VALUE_ABND_GSM_850("GSM 850"); const std::string CellularRadio::VALUE_ABND_GSM_900("GSM 900"); const std::string CellularRadio::VALUE_ABND_DCS_1800("DCS 1800"); const std::string CellularRadio::VALUE_ABND_PCS_1900("PCS 1900"); const std::vector CellularRadio::DEFAULT_BAIL_STRINGS = { CellularRadio::RSP_OK, CellularRadio::RSP_ERROR }; CellularRadio::CellularRadio(const std::string& sName, const std::string& sRadioPort) : m_sName(sName) , m_sRadioPort(sRadioPort) , m_bEchoEnabled(false) , m_bEnableEchoOnClose(false) { m_apIo.reset(new MTS::IO::SerialConnection( MTS::IO::SerialConnection::Builder(m_sRadioPort) .baudRate(115200) .useLockFile() .build())); } CellularRadio::~CellularRadio() { shutdown(); m_apIo.reset(); } bool CellularRadio::initialize(uint32_t iTimeoutMillis) { if(!m_apIo->open(iTimeoutMillis)) { printError("%s| Failed to open radio port [%s]", m_sName.c_str(), m_sRadioPort.c_str()); return false; } bool bEnabled; CODE eCode = getEcho(bEnabled); if(eCode == SUCCESS && bEnabled) { printDebug("%s| Disabling 'echo'", m_sName.c_str()); setEcho(false); m_bEnableEchoOnClose = true; } return true; } bool CellularRadio::resetRadio(uint32_t iTimeoutMillis) { printInfo("%s| Rebooting radio", m_sName.c_str()); if(sendBasicCommand("AT#REBOOT") == SUCCESS) { if(iTimeoutMillis > 5000) { MTS::Thread::sleep(5000); iTimeoutMillis -= 5000; } return resetConnection(iTimeoutMillis); } return false; } bool CellularRadio::resetConnection(uint32_t iTimeoutMillis) { //Close Current Connection if(!m_apIo.isNull()) { m_apIo->close(); } m_apIo.reset(new MTS::IO::SerialConnection( MTS::IO::SerialConnection::Builder(m_sRadioPort) .baudRate(115200) .useLockFile() .build())); //Try to obtain the device port over the given period of time MTS::Timer oTimer; oTimer.start(); uint64_t iCurrentTime = 0; while(iCurrentTime < iTimeoutMillis) { if(!m_apIo->open(iTimeoutMillis - iCurrentTime)) { printWarning("%s| Failed to re-open radio port [%s]", m_sName.c_str(), m_sRadioPort.c_str()); } else { printInfo("%s| Successfully re-opened radio port [%s]", m_sName.c_str(), m_sRadioPort.c_str()); break; } ::usleep(500000); //500 millis iCurrentTime = oTimer.getMillis(); } oTimer.stop(); return !m_apIo->isClosed(); } void CellularRadio::shutdown() { if(!m_apIo.isNull()) { if(m_bEnableEchoOnClose) { printDebug("%s| Enabling 'echo'", m_sName.c_str()); setEcho(true); m_bEnableEchoOnClose = false; } m_apIo->close(); } } const std::string& CellularRadio::getName() const { return m_sName; } CellularRadio::CODE CellularRadio::getModel(std::string& sModel) { printTrace("%s| Get Model", m_sName.c_str()); //Always returns SUCCESS because the model should be m_sName sModel = m_sName; std::string sCmd("ATI4"); std::string sResult = CellularRadio::sendCommand(m_apIo, sCmd); if (sResult.find("OK") == std::string::npos) { printWarning("%s| Unable to get model from radio. Returning [%s]", m_sName.c_str(), m_sName.c_str()); return SUCCESS; } else { sModel = CellularRadio::extractModelFromResult(sResult); if(sModel.size() == 0) { printWarning("%s| Unable to get model from radio. Returning [%s]", m_sName.c_str(), m_sName.c_str()); return SUCCESS; } } printDebug("%s| Extracted [%s] from [%s] query", m_sName.c_str(), sModel.c_str(), sCmd.c_str()); if(sModel != m_sName) { printWarning("%s| Model identified [%s] does not match expected [%s]. Returning [%s]", m_sName.c_str(), sModel.c_str(), m_sName.c_str(), sModel.c_str()); } return SUCCESS; } CellularRadio::CODE CellularRadio::convertModelToMtsShortCode(const std::string& sModel, std::string& sCode) { CODE eCode = FAILURE; if(sModel.find("HE910-D") == 0) { sCode = "H5"; eCode = SUCCESS; } else if (sModel.find("HE910-EUD") == 0) { sCode = "H6"; eCode = SUCCESS; } else if (sModel.find("LE910-NAG") == 0) { sCode = "LAT1"; eCode = SUCCESS; } else if (sModel.find("LE910-SVG") == 0) { sCode = "LVW2"; eCode = SUCCESS; } else if (sModel.find("LE910-EUG") == 0) { sCode = "LEU1"; eCode = SUCCESS; } else if (sModel.find("GE910") == 0) { sCode = "G3"; eCode = SUCCESS; } else if (sModel.find("CE910") == 0) { sCode = "C2"; eCode = SUCCESS; } else if (sModel.find("DE910") == 0) { sCode = "EV3"; eCode = SUCCESS; } else { sCode = VALUE_NOT_SUPPORTED; printError("RADIO| Could not identify MTS short code from model. [%s]", sModel.c_str()); eCode = ERROR; } return eCode; } CellularRadio::CODE CellularRadio::convertServiceDomainToString(SERVICEDOMAIN eSd, std::string& sSd) { CODE eCode = FAILURE; switch(eSd) { case NO_SERVICE: sSd = VALUE_SD_NO_SERVICE; eCode = SUCCESS; break; case CS_ONLY: sSd = VALUE_SD_CS_ONLY; eCode = SUCCESS; break; case PS_ONLY: sSd = VALUE_SD_PS_ONLY; eCode = SUCCESS; break; case CSPS: sSd = VALUE_SD_CSPS; eCode = SUCCESS; break; default: sSd = VALUE_UNKNOWN; eCode = FAILURE; break; } return eCode; } CellularRadio::CODE CellularRadio::convertActiveBandToString(ACTIVEBAND eBand, std::string& sBand) { CODE eCode = FAILURE; switch(eBand) { case GSM_850: sBand = VALUE_ABND_GSM_850; eCode = SUCCESS; break; case GSM_900: sBand = VALUE_ABND_GSM_900; eCode = SUCCESS; break; case DCS_1800: sBand = VALUE_ABND_DCS_1800; eCode = SUCCESS; break; case PCS_1900: sBand = VALUE_ABND_PCS_1900; eCode = SUCCESS; break; default: sBand = VALUE_UNKNOWN; eCode = FAILURE; break; } return eCode; } CellularRadio::CODE CellularRadio::convertModelToType(const std::string& sModel, std::string& sType) { CODE eCode = FAILURE; sType = VALUE_NOT_SUPPORTED; if(sModel.find("HE910-D") == 0) { sType = VALUE_TYPE_GSM; eCode = SUCCESS; } else if (sModel.find("HE910-EUD") == 0) { sType = VALUE_TYPE_GSM; eCode = SUCCESS; } else if (sModel.find("LE910-NAG") == 0) { sType = VALUE_TYPE_LTE; eCode = SUCCESS; } else if (sModel.find("LE910-SVG") == 0) { sType = VALUE_TYPE_LTE; eCode = SUCCESS; } else if (sModel.find("LE910-EUG") == 0) { sType = VALUE_TYPE_LTE; eCode = SUCCESS; } else if (sModel.find("GE910") == 0) { sType = VALUE_TYPE_GSM; eCode = SUCCESS; } else if (sModel.find("CE910") == 0) { sType = VALUE_TYPE_CDMA; eCode = SUCCESS; } else if (sModel.find("DE910") == 0) { sType = VALUE_TYPE_CDMA; eCode = SUCCESS; } else { sType = VALUE_TYPE_GSM; eCode = ERROR; printError("RADIO| Could not identify type from model. [%s]. Assuming [%s]", sModel.c_str(), sType.c_str()); } return eCode; } CellularRadio::CODE CellularRadio::getFirmware(std::string& sFirmware) { printTrace("%s| Get Firmware", m_sName.c_str()); sFirmware = VALUE_NOT_SUPPORTED; std::string sCmd("AT+CGMR"); std::string sResult = CellularRadio::sendCommand(sCmd); size_t pos = sResult.find(RSP_OK); if (pos == std::string::npos) { printWarning("%s| Unable to get firmware from radio using command [%s]", m_sName.c_str(), sCmd.c_str()); return FAILURE; } sFirmware = MTS::Text::trim(sResult.substr(0, pos)); if(sFirmware.size() == 0) { printWarning("%s| Unable to get firmware from radio using command [%s]", m_sName.c_str(), sCmd.c_str()); return FAILURE; } m_sFirmware = sFirmware; return SUCCESS; } CellularRadio::CODE CellularRadio::getHardware(std::string& sHardware) { printTrace("%s| Get Hardware", m_sName.c_str()); sHardware = VALUE_NOT_SUPPORTED; if(m_sFirmware.size() == 0) { getFirmware(m_sFirmware); } if(getHardwareVersionFromFirmware(m_sFirmware, sHardware)) { return SUCCESS; } return FAILURE; } CellularRadio::CODE CellularRadio::getManufacturer(std::string& sManufacturer) { printTrace("%s| Get Manufacturer", m_sName.c_str()); sManufacturer = VALUE_NOT_SUPPORTED; std::string sCmd("AT+GMI"); std::string sResult = CellularRadio::sendCommand(sCmd); size_t pos = sResult.find(RSP_OK); if (pos == std::string::npos) { printWarning("%s| Unable to get manufacturer from radio using command [%s]", m_sName.c_str(), sCmd.c_str()); return FAILURE; } sManufacturer = MTS::Text::trim(sResult.substr(0, pos)); if(sManufacturer.size() == 0) { printWarning("%s| Unable to get manufacturer from radio using command [%s]", m_sName.c_str(), sCmd.c_str()); return FAILURE; } return SUCCESS; } CellularRadio::CODE CellularRadio::getImei(std::string& sImei) { printTrace("%s| Get IMEI", m_sName.c_str()); sImei = VALUE_NOT_SUPPORTED; std::string sCmd("AT+CGSN"); std::string sResult = CellularRadio::sendCommand(sCmd); size_t pos = sResult.find(RSP_OK); if (pos == std::string::npos) { printWarning("%s| Unable to get IMEI from radio using command [%s]", m_sName.c_str(), sCmd.c_str()); return FAILURE; } sImei = MTS::Text::trim(sResult.substr(0, pos)); if(sImei.size() == 0) { printWarning("%s| Unable to get IMEI from radio using command [%s]", m_sName.c_str(), sCmd.c_str()); return FAILURE; } return SUCCESS; } CellularRadio::CODE CellularRadio::getMeid(std::string& sMeid) { printTrace("%s| Get MEID", m_sName.c_str()); return getImei(sMeid); } CellularRadio::CODE CellularRadio::getImsi(std::string& sImsi) { printTrace("%s| Get IMSI", m_sName.c_str()); sImsi = VALUE_NOT_SUPPORTED; std::string sCmd("AT+CIMI"); std::string sResult = CellularRadio::sendCommand(sCmd); size_t pos = sResult.find(RSP_OK); if (pos == std::string::npos) { printWarning("%s| Unable to get IMSI from radio using command [%s]", m_sName.c_str(), sCmd.c_str()); return FAILURE; } sImsi = MTS::Text::trim(sResult.substr(0, pos)); if(sImsi.size() == 0) { printWarning("%s| Unable to get IMSI from radio using command [%s]", m_sName.c_str(), sCmd.c_str()); return FAILURE; } return SUCCESS; } CellularRadio::CODE CellularRadio::getSimStatus(std::string& sSimStatus) { printTrace("%s| Get SIM Status", getName().c_str()); sSimStatus = VALUE_UNKNOWN; return FAILURE; } CellularRadio::CODE CellularRadio::getIccid(std::string& sIccid) { printTrace("%s| Get ICCID", m_sName.c_str()); sIccid = VALUE_NOT_SUPPORTED; std::string sCmd("AT#CCID"); std::string sResult = CellularRadio::sendCommand(sCmd); size_t end = sResult.find(RSP_OK); if (end == std::string::npos) { printWarning("%s| Unable to get ICCID from radio using command [%s]", m_sName.c_str(), sCmd.c_str()); return FAILURE; } size_t start = sResult.find("#CCID:"); if(start != std::string::npos) { start += sizeof("#CCID:"); sIccid = MTS::Text::trim(sResult.substr(start, end-start)); if(sIccid.size() == 0) { printWarning("%s| Unable to get ICCID from radio using command [%s]", m_sName.c_str(), sCmd.c_str()); return FAILURE; } } return SUCCESS; } CellularRadio::CODE CellularRadio::getService(std::string& sService) { printTrace("%s| Get Service", m_sName.c_str()); sService = VALUE_NOT_SUPPORTED; std::string sCmd("AT#PSNT?"); 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]", m_sName.c_str(), sCmd.c_str()); return FAILURE; } size_t start = sResult.find(","); if(start != std::string::npos) { start += 1; //comma 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 = "GPRS"; break; case 1: sService = "EGPRS"; break; case 2: sService = "WCDMA"; break; case 3: sService = "HSDPA"; break; case 4: sService = "LTE"; break; default: sService = VALUE_UNKNOWN; break; } printDebug("%s| Service ID: [%d][%s]", m_sName.c_str(), iService, sService.c_str()); } return SUCCESS; } CellularRadio::CODE CellularRadio::getLac(std::string& sLac) { Json::Value jData; printTrace("%s| Get LAC", m_sName.c_str()); sLac = VALUE_NOT_SUPPORTED; if(getNetworkStatus(jData) == SUCCESS) { if(jData.isMember(KEY_LAC)) { sLac = jData[KEY_LAC].asString(); return SUCCESS; } } return FAILURE; } CellularRadio::CODE CellularRadio::getMdn(std::string& sMdn) { printTrace("%s| Get MDN", m_sName.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]", m_sName.c_str(), sCmd.c_str()); return FAILURE; } size_t start = sResult.find("CNUM:"); if(start != std::string::npos) { start += sizeof("CNUM:"); std::vector vParts = MTS::Text::split(sResult.substr(start, end - start), ','); if(vParts.size() < 3) { printWarning("%s| Unable to parse MDN from response [%s]", m_sName.c_str(), sResult.c_str()); return FAILURE; } sMdn = MTS::Text::strip(vParts[1], '"'); if(sMdn.size() == 0) { printWarning("%s| Unable to get MDN from radio using command [%s]. MDN may not be set.", m_sName.c_str(), sCmd.c_str()); } } else { sMdn = ""; printWarning("%s| Unable to get MDN from radio using command [%s]. MDN may not be set.", m_sName.c_str(), sCmd.c_str()); } return SUCCESS; } CellularRadio::CODE CellularRadio::getMsid(std::string& sMsid) { printTrace("%s| Get MSID", m_sName.c_str()); sMsid = ""; std::string sImsi; if(getImsi(sImsi) == SUCCESS) { if(sImsi.size() >= 10) { sMsid = sImsi.substr(sImsi.size() - 10); printTrace("IMSI: [%s] MEID [%s]", sImsi.c_str(), sMsid.c_str()); return SUCCESS; } } printWarning("%s| Unable to get MSID from radio", m_sName.c_str()); return FAILURE; } CellularRadio::CODE CellularRadio::getType(std::string& sType) { printTrace("%s| Get Type", m_sName.c_str()); sType = VALUE_NOT_SUPPORTED; return FAILURE; } CellularRadio::CODE CellularRadio::getCarrier(std::string& sCarrier) { printTrace("%s| Get Carrier", m_sName.c_str()); if(m_sCarrier == "") { Json::Value jData; if(getNetworkStatus(jData) == SUCCESS) { if(jData.isMember(KEY_MCC) && jData.isMember(KEY_MNC)) { std::string sMcc = jData[KEY_MCC].asString(); std::string sMnc = jData[KEY_MNC].asString(); Json::Value jLookup = MccMncTable::getInstance()->lookup(sMcc, sMnc); printTrace("%s| MCC-MNC Lookup: [%s][%s][%s]", m_sName.c_str(), sMcc.c_str(), sMnc.c_str(), jLookup.toStyledString().c_str()); if(jLookup.isMember(KEY_CARRIER)) { m_sCarrier = jLookup[KEY_CARRIER].asString(); } else { printWarning("%s| MCC-MNC Lookup did not contain carrier", m_sName.c_str()); return FAILURE; } } else { printWarning("%s| Network Status did no contain MCC or MNC", m_sName.c_str()); return FAILURE; } } else { return FAILURE; } } sCarrier = m_sCarrier; return SUCCESS; } CellularRadio::CODE CellularRadio::getTower(std::string& sTower) { Json::Value jData; printTrace("%s| Get Tower", m_sName.c_str()); sTower = VALUE_NOT_SUPPORTED; if(getNetworkStatus(jData) == SUCCESS) { if(jData.isMember(KEY_CID)) { sTower = jData[KEY_CID].asString(); return SUCCESS; } } return FAILURE; } CellularRadio::CODE CellularRadio::getTime(std::string& sDate, std::string& sTime, std::string& sTimeZone) { Json::Value jData; printTrace("%s| Get Time", m_sName.c_str()); sDate = ""; sTime = ""; sTimeZone = ""; std::string sCmd("AT+CCLK?"); std::string sResult = CellularRadio::sendCommand(sCmd); size_t end = sResult.find(RSP_OK); if (end == std::string::npos) { printWarning("%s| Unable to get Time from radio using command [%s]", m_sName.c_str(), sCmd.c_str()); return FAILURE; } size_t start = sResult.find("CCLK: "); if(start != std::string::npos) { start += sizeof("CCLK: "); std::string sValue = MTS::Text::trim(sResult.substr(start, end - start)); sValue = MTS::Text::strip(sValue, '"'); std::vector vParts = MTS::Text::split(sValue, ','); if(vParts.size() != 2) { printWarning("%s| Unable to parse Date from response [%s]", m_sName.c_str(), sResult.c_str()); return FAILURE; } std::vector vDateParts = MTS::Text::split(vParts[0], '/'); if(vDateParts.size() != 3) { printWarning("%s| Unable to parse Date from response [%s]", m_sName.c_str(), sResult.c_str()); return FAILURE; } //The Date format is YY/MM/DD -> Change to MM/DD/YY sDate = vDateParts[1] + "/" + vDateParts[2] + "/" + vDateParts[0]; vParts = MTS::Text::split(vParts[1], '-'); if(vParts.size() != 2) { printWarning("%s| Unable to parse Time from response [%s]", m_sName.c_str(), sResult.c_str()); return FAILURE; } sTime = vParts[0]; int32_t iZoneUnits; //the difference, expressed in quarters of an hour, between the local time and GMT if(!MTS::Text::parse(iZoneUnits, MTS::Text::strip(vParts[1], '+'))) { printWarning("%s| Unable to parse Time Zone from response [%s]", m_sName.c_str(), sResult.c_str()); return FAILURE; } int32_t iZone = iZoneUnits/4; //Divide by 4 to get hours difference int32_t iZonePartial = (iZoneUnits % 4) * 15; //Remainder in minutes std::string sPlusSign = "+"; if(iZonePartial < 0) { //Remove negative sign from partial and clear plus sign component iZonePartial *= -1; sPlusSign = ""; } std::stringstream ss; ss << sPlusSign << iZone; if(iZonePartial != 0) { ss << ":" << iZonePartial; } sTimeZone = ss.str(); return SUCCESS; } else { printWarning("%s| Unable to get Time from radio using command [%s]", m_sName.c_str(), sCmd.c_str()); } return FAILURE; } CellularRadio::CODE CellularRadio::getRoaming(bool& bRoaming) { Json::Value jData; printTrace("%s| Get Roaming", m_sName.c_str()); bRoaming = false; REGISTRATION eReg; if(getRegistration(eReg) == SUCCESS) { bRoaming = (eReg == ROAMING); return SUCCESS; } return FAILURE; } CellularRadio::CODE CellularRadio::getNetwork(std::string& sNetwork) { Json::Value jData; printTrace("%s| Get Network", m_sName.c_str()); sNetwork = VALUE_NOT_SUPPORTED; if(getNetworkStatus(jData) == SUCCESS) { if(jData.isMember(KEY_NETWORK)) { sNetwork = jData[KEY_NETWORK].asString(); return SUCCESS; } } return FAILURE; } CellularRadio::CODE CellularRadio::getSignalStrength(int32_t& rssi) { printTrace("%s| Get Signal Strength", m_sName.c_str()); std::string sCmd("AT+CSQ"); std::string sResult = sendCommand(sCmd); if (sResult.find("+CSQ: ") == std::string::npos) { printDebug("%s| Signal Strength command returned unexpected response: [%s]", m_sName.c_str(), sResult.c_str()); return FAILURE; } size_t start = sResult.find(':'); size_t stop = sResult.find(',', start); if(start == std::string::npos || stop == std::string::npos) { printDebug("%s| Signal Strength command returned malformed response: [%s]", m_sName.c_str(), sResult.c_str()); return FAILURE; } std::string signal = sResult.substr(start + 2, stop - start - 2); sscanf(signal.c_str(), "%d", &rssi); printDebug("%s| Signal Strength: [%d]", m_sName.c_str(), rssi); return SUCCESS; } CellularRadio::CODE CellularRadio::convertSignalStrengthTodBm(const int32_t& iRssi, int32_t& iDbm) { //Telit Conversion if(iRssi < 0 || iRssi == 99) { return FAILURE; } if(iRssi == 0) { iDbm = -113; } else if(iRssi == 1) { iDbm = -111; } else if(iRssi <= 30) { //28 steps between 2 and 30 //54 dbm between 53 and 109 float stepSize = 54.0 / 28.0; iDbm = -109 + (int)(stepSize * (iRssi-2)); } else { iDbm = -51; } return SUCCESS; } CellularRadio::CODE CellularRadio::convertdBmToSignalStrength(const int32_t& iDBm, int32_t& iRssi) { //Telit Conversion if(iDBm <= -113) { iRssi = 0; } else if(iDBm <= -111) { iRssi = 1; } else if(iDBm <= -53) { //54 dbm between -109 and -53 //28 steps between 2 and 30 float stepSize = 28.0/54.0; iRssi = ((iDBm + 109)*stepSize) + 2; } else { iRssi = 31; } return SUCCESS; } CellularRadio::CODE CellularRadio::getEcho(bool& bEnabled) { printTrace("%s| Echo Test", m_sName.c_str()); std::string sResult = sendCommand("AT"); if(sResult.size() == 0) { return NO_RESPONSE; } if(sResult.find("AT") != std::string::npos) { bEnabled = true; } else { bEnabled = false; } m_bEchoEnabled = bEnabled; return SUCCESS; } CellularRadio::CODE CellularRadio::setEcho(bool bEnabled) { CODE eCode = FAILURE; if(bEnabled) { eCode = sendBasicCommand("ATE1"); m_bEchoEnabled = (eCode == SUCCESS ) ? true : m_bEchoEnabled; } else { eCode = sendBasicCommand("ATE0"); m_bEchoEnabled = (eCode == SUCCESS ) ? false : m_bEchoEnabled; } return eCode; } CellularRadio::CODE CellularRadio::getStaticInformation(Json::Value& jData) { printTrace("%s| Get Static Information", m_sName.c_str()); printTrace("%s| Static Information:\n%s\n", m_sName.c_str(), jData.toStyledString().c_str()); return FAILURE; } /* AT#RFSTS - NETWORK STATUS (GSM network) #RFSTS:,,,,,,,,,,,,, Where: - Country code and operator code(MCC, MNC) - GSM Assigned Radio Channel - Received Signal Strength Indication - Localization Area Code - Routing Area Code - Tx Power - Mobility Management state - Radio Resource state - Network Operator Mode - Cell ID - International Mobile Subscriber Identity - Operator name - Service Domain 0 - No Service 1 - CS only 2 - PS only 3 - CS+PS - Active Band 1 - GSM 850 2 - GSM 900 3 - DCS 1800 4 - PCS 1900 (WCDMA network) #RFSTS: ,,,,, RSSI>,,,,,,,,,,, ,,[,,] Where: - Country code and operator code(MCC, MNC) - UMTS Assigned Radio Channel - Active PSC(Primary Synchronization Code) - Active Ec/Io(chip energy per total wideband power in dBm) - Active RSCP (Received Signal Code Power in dBm) - Received Signal Strength Indication - Localization Area Code - Routing Area Code - Tx Power - Discontinuous reception cycle Length (cycle length in ms) - Mobility Management state - Radio Resource state - Network Operator Mode - Block Error Rate (e.g., 005 means 0.5 %) - Cell ID - International Mobile Station ID - Operator name - Service Domain (see above) - Number of Active Set (Maximum 6) UARFCN of n th active set PSC of n th active set Ec/Io of n th active Set (LTE Network) #RFSTS: - - - - - - [] - - - - - - [] - - - */ CellularRadio::CODE CellularRadio::getNetworkStatus(Json::Value& jData) { int32_t iValue; std::string sValue; const uint32_t GSM_NETWORK_FORMAT = 14; const uint32_t WCDMA_NETWORK_FORMAT = 19; const uint32_t LTE_NETWORK_FORMAT = 16; printTrace("%s| Get Network Status", m_sName.c_str()); std::string sCmd("AT#RFSTS"); std::string sResult = sendCommand(sCmd, DEFAULT_BAIL_STRINGS, 200); if (sResult.find("#RFSTS:") == std::string::npos) { printDebug("%s| Network Status command returned unexpected response: [%s][%s]", m_sName.c_str(), sCmd.c_str(), sResult.c_str()); return FAILURE; } size_t start = sResult.find(":") + 1; //Position right after "#RFSTS:" std::vector vParts = MTS::Text::split(MTS::Text::trim(sResult.substr(start)), ","); if(vParts.size() >= 3) { //Country Code and Operator Code std::vector vPLMN = MTS::Text::split(vParts[0], ' '); if(vPLMN.size() == 2) { jData[KEY_MCC] = MTS::Text::strip(vPLMN[0], '"'); jData[KEY_MNC] = MTS::Text::strip(vPLMN[1], '"'); } jData[KEY_CHANNEL] = vParts[1]; } else { //Unknown Format return FAILURE; } if(vParts.size() == GSM_NETWORK_FORMAT ) { //Parse as GSM Network Format jData[KEY_RSSIDBM] = vParts[2]; jData[KEY_LAC] = vParts[3]; jData[KEY_RAC] = vParts[4]; jData[KEY_TXPWR] = vParts[5]; jData[KEY_MM] = vParts[6]; jData[KEY_RR] = vParts[7]; jData[KEY_NOM] = vParts[8]; jData[KEY_CID] = vParts[9]; jData[KEY_IMSI] = MTS::Text::strip(vParts[10], '"'); jData[KEY_NETWORK] = MTS::Text::strip(vParts[11], '"'); if(MTS::Text::parse(iValue, vParts[12]) && convertServiceDomainToString((SERVICEDOMAIN)iValue, sValue) == SUCCESS) { jData[KEY_SD] = sValue; } if(MTS::Text::parse(iValue, vParts[13]) && convertActiveBandToString((ACTIVEBAND)iValue, sValue) == SUCCESS) { jData[KEY_ABND] = sValue; } } else if(vParts.size() >= WCDMA_NETWORK_FORMAT) { Json::Value jDebug; //Parse as WCDMA Network Format jDebug[KEY_PSC] = vParts[2]; jDebug[KEY_ECIO] = vParts[3]; jDebug[KEY_RSCP] = vParts[4]; jData[KEY_RSSIDBM] = vParts[5]; jData[KEY_LAC] = vParts[6]; jData[KEY_RAC] = vParts[7]; jDebug[KEY_TXPWR] = vParts[8]; jDebug[KEY_DRX] = vParts[9]; jDebug[KEY_MM] = vParts[10]; jDebug[KEY_RR] = vParts[11]; jDebug[KEY_NOM] = vParts[12]; if(vParts[13].size() != 0) { jDebug[KEY_BLER] = vParts[13]; } else { jDebug[KEY_BLER] = "000"; } jData[KEY_CID] = vParts[14]; jData[KEY_IMSI] = MTS::Text::strip(vParts[15], '"'); jData[KEY_NETWORK] = MTS::Text::strip(vParts[16], '"'); // Get the radio band given the channel (UARFCN) RadioBandMap radioBandMap(vParts[1], CellularRadio::VALUE_TYPE_CDMA); jData[KEY_ABND] = radioBandMap.getRadioBandName(); if(MTS::Text::parse(iValue, vParts[17]) && convertServiceDomainToString((SERVICEDOMAIN)iValue, sValue) == SUCCESS) { jDebug[KEY_SD] = sValue; } //Ignoring Active Set Values // - Number of Active Set (Maximum 6) // - UARFCN of n th active set // - PSC of n th active set // - Ec/Io of n th active Set jData[KEY_DEBUG] = jDebug; } else if(vParts.size() >= LTE_NETWORK_FORMAT) { Json::Value jDebug; //Parse as LTE Network Format jDebug["rsrp"] = vParts[2]; jDebug[KEY_RSSIDBM] = vParts[3]; jDebug["rsrq"] = vParts[4]; jData["tac"] = vParts[5]; jData[KEY_RAC] = vParts[6]; jDebug[KEY_TXPWR] = vParts[7]; //Odd empty index at 7 jData[KEY_DRX] = vParts[8]; jDebug[KEY_MM] = vParts[9]; jDebug["rrc"] = vParts[10]; jData[KEY_CID] = vParts[11]; jData[KEY_IMSI] = MTS::Text::strip(vParts[12], '"'); jData[KEY_NETWORK] = MTS::Text::strip(vParts[13], '"'); // Get the radio band given the channel (EARFCN) RadioBandMap radioBandMap(vParts[1], CellularRadio::VALUE_TYPE_LTE); jData[KEY_ABND] = radioBandMap.getRadioBandName(); // Get the LAC for the LTE radio that's not in the #RFSTS response sCmd = "AT+CGREG=2"; sResult = sendCommand(sCmd); if (sResult.find("OK") == std::string::npos) { printDebug("%s| AT#CGREG=2 returned unexpected response: [%s][%s]", m_sName.c_str(), sCmd.c_str(), sResult.c_str()); } sCmd = "AT+CGREG?"; sResult = sendCommand(sCmd); if (sResult.find("+CGREG:") == std::string::npos) { printDebug("%s| AT#CGREG? returned unexpected response: [%s][%s]", m_sName.c_str(), sCmd.c_str(), sResult.c_str()); jData[KEY_LAC] = CellularRadio::VALUE_UNKNOWN; } else { size_t start = sResult.find(":") + 1; //Position right after "#RFSTS:" std::vector vParts = MTS::Text::split(MTS::Text::trim(sResult.substr(start)), ","); jData[KEY_LAC] = MTS::Text::strip(vParts[2], '"'); } if(MTS::Text::parse(iValue, vParts[14]) && convertServiceDomainToString((SERVICEDOMAIN)iValue, sValue) == SUCCESS) { jDebug[KEY_SD] = sValue; } jData[KEY_DEBUG] = jDebug; } getCommonNetworkStats(jData); printTrace("%s| Network Status:\n%s\n", m_sName.c_str(), jData.toStyledString().c_str()); return SUCCESS; } void CellularRadio::getCommonNetworkStats(Json::Value& jData) { bool bRoaming = false; if(getRoaming(bRoaming) == SUCCESS) { jData[KEY_ROAMING] = bRoaming; } int32_t iRssi; if(getSignalStrength(iRssi) == SUCCESS) { jData[KEY_RSSI] = iRssi; int32_t dBm; if(!jData.isMember(KEY_RSSIDBM) && convertSignalStrengthTodBm(iRssi, dBm) == SUCCESS) { //Add RSSI in dBm format jData[KEY_RSSIDBM] = MTS::Text::format(dBm); } } std::string sService; if(getService(sService) == SUCCESS) { jData[KEY_SERVICE] = sService; } std::string sDate, sTime, sTimeZone; if(getTime(sDate, sTime, sTimeZone) == SUCCESS) { jData[KEY_DATETIME] = sDate + " " + sTime + " GMT" + sTimeZone; } } void CellularRadio::initMipProfile(Json::Value& jData) { jData[KEY_MIP_ID] = 0; jData[KEY_MIP_ENABLED] = false; jData[KEY_MIP_NAI] = VALUE_UNKNOWN; jData[KEY_MIP_HOMEADDRESS] = VALUE_UNKNOWN; jData[KEY_MIP_PRIMARYHA] = VALUE_UNKNOWN; jData[KEY_MIP_SECONDARYHA] = VALUE_UNKNOWN; jData[KEY_MIP_MNAAASPI] = VALUE_UNKNOWN; jData[KEY_MIP_MNHASPI] = VALUE_UNKNOWN; jData[KEY_MIP_MNAAASS] = false; jData[KEY_MIP_MNHASS] = false; } CellularRadio::CODE CellularRadio::getRegistration(REGISTRATION& eRegistration) { std::string sCmd; std::string sResp; if (m_sName.find("LE910-") != std::string::npos) { // use AT+CGREG instead for LE910 models sCmd = "AT+CGREG?"; sResp = "+CGREG: "; } else { sCmd = "AT+CREG?"; sResp = "+CREG: "; } std::string sResult = sendCommand(sCmd, DEFAULT_BAIL_STRINGS, 5000); if (sResult.find(sResp) == std::string::npos) { if(sResult.size() == 0) { printDebug("%s| Registration command returned no response: [%s]", m_sName.c_str()); return NO_RESPONSE; } printDebug("%s| Registration command returned unexpected response: [%s]", m_sName.c_str(), sResult.c_str()); return FAILURE; } size_t start = sResult.find(','); size_t stop = sResult.find(' ', start); std::string sRegStat = sResult.substr(start + 1, stop - start - 1); int32_t value; sscanf(sRegStat.c_str(), "%d", &value); eRegistration = (REGISTRATION)value; return SUCCESS; } CellularRadio::CODE CellularRadio::convertRegistrationToString(REGISTRATION eRegistration, std::string& sRegistration) { CODE eCode = FAILURE; switch (eRegistration) { case NOT_REGISTERED: sRegistration = VALUE_NOT_REGISTERED; eCode = SUCCESS; break; case REGISTERED: sRegistration = VALUE_REGISTERED; eCode = SUCCESS; break; case SEARCHING: sRegistration = VALUE_SEARCHING; eCode = SUCCESS; break; case DENIED: sRegistration = VALUE_DENIED; eCode = SUCCESS; break; case UNKNOWN: sRegistration = VALUE_UNKNOWN; eCode = SUCCESS; break; case ROAMING: sRegistration = VALUE_ROAMING; eCode = SUCCESS; break; } return eCode; } CellularRadio::CODE CellularRadio::validateMsl(const Json::Value& jArgs) { printTrace("%s| Validate MSL", m_sName.c_str()); return NOT_APPLICABLE; } CellularRadio::CODE CellularRadio::setMdn(const Json::Value& jArgs) { printTrace("%s| Set MDN", m_sName.c_str()); if(!jArgs["mdn"].isString()) { return INVALID_ARGS; } std::string sCmd("AT#SNUM=1,\""); sCmd += jArgs["mdn"].asString() + "\""; 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]", m_sName.c_str(), sCmd.c_str()); return FAILURE; } return SUCCESS; } CellularRadio::CODE CellularRadio::setMsid(const Json::Value& jArgs) { printTrace("%s| Set MSID", m_sName.c_str()); return NOT_APPLICABLE; } CellularRadio::CODE CellularRadio::getMipProfile(Json::Value& jMipProfile) { printTrace("%s| Get MIP Active Profile", m_sName.c_str()); return NOT_APPLICABLE; } CellularRadio::CODE CellularRadio::setMipActiveProfile(const Json::Value& jArgs) { printTrace("%s| Set MIP Active Profile", m_sName.c_str()); return NOT_APPLICABLE; } CellularRadio::CODE CellularRadio::setMipNai(const Json::Value& jArgs) { printTrace("%s| Set MIP NAI", m_sName.c_str()); return NOT_APPLICABLE; } CellularRadio::CODE CellularRadio::setMipHomeIp(const Json::Value& jArgs) { printTrace("%s| Set MIP Home IP", m_sName.c_str()); return NOT_APPLICABLE; } CellularRadio::CODE CellularRadio::setMipPrimaryHa(const Json::Value& jArgs) { printTrace("%s| Set MIP Primary HA", m_sName.c_str()); return NOT_APPLICABLE; } CellularRadio::CODE CellularRadio::setMipSecondaryHa(const Json::Value& jArgs) { printTrace("%s| Set MIP Secondary HA", m_sName.c_str()); return NOT_APPLICABLE; } CellularRadio::CODE CellularRadio::setMipMnAaaSpi(const Json::Value& jArgs) { printTrace("%s| Set MIP MN-AAA SPI", m_sName.c_str()); return NOT_APPLICABLE; } CellularRadio::CODE CellularRadio::setMipMnHaSpi(const Json::Value& jArgs) { printTrace("%s| Set MIP MN-HA SPI", m_sName.c_str()); return NOT_APPLICABLE; } CellularRadio::CODE CellularRadio::setMipRevTun(const Json::Value& jArgs) { printTrace("%s| Set MIP Rev Tun", m_sName.c_str()); return NOT_APPLICABLE; } CellularRadio::CODE CellularRadio::setMipMnAaaSs(const Json::Value& jArgs) { printTrace("%s| Set MIP MN-AAA SS", m_sName.c_str()); return NOT_APPLICABLE; } CellularRadio::CODE CellularRadio::setMipMnHaSs(const Json::Value& jArgs) { printTrace("%s| Set MIP MN-HA SS", m_sName.c_str()); return NOT_APPLICABLE; } CellularRadio::CODE CellularRadio::updateDc(const Json::Value& jArgs, UpdateCb& stepCb) { printTrace("%s| Update Device Configuration", m_sName.c_str()); return NOT_APPLICABLE; } CellularRadio::CODE CellularRadio::updatePrl(const Json::Value& jArgs, UpdateCb& stepCb) { printTrace("%s| Update Preferred Roaming List", m_sName.c_str()); return NOT_APPLICABLE; } CellularRadio::CODE CellularRadio::updateFumo(const Json::Value& jArgs, UpdateCb& stepCb) { printTrace("%s| Update Firmware Update Management Object", m_sName.c_str()); return NOT_APPLICABLE; } CellularRadio::CODE CellularRadio::resetHfa(const Json::Value& jArgs, UpdateCb& stepCb) { printTrace("%s| HFA Reset", m_sName.c_str()); return NOT_APPLICABLE; } CellularRadio::CODE CellularRadio::activate(const Json::Value& jArgs, UpdateCb& stepCb) { printTrace("%s| Activation", m_sName.c_str()); return NOT_APPLICABLE; } CellularRadio::CODE CellularRadio::sendBasicCommand(const std::string& sCmd, int32_t iTimeoutMillis, const char& ESC) { std::string response = sendCommand(sCmd, DEFAULT_BAIL_STRINGS, iTimeoutMillis, ESC); if (response.size() == 0) { return NO_RESPONSE; } else if (response.find(RSP_OK) != std::string::npos) { return SUCCESS; } else if (response.find(RSP_ERROR) != std::string::npos) { return ERROR; } else { return FAILURE; } } std::string CellularRadio::sendCommand(const std::string& sCmd, const std::vector& vBail, int32_t timeoutMillis, const char& ESC) { return sendCommand(m_apIo, sCmd, vBail, timeoutMillis, ESC); } std::string CellularRadio::sendCommand(MTS::AutoPtr& apIo, const std::string& sCmd, const std::vector& vBail, int32_t timeoutMillis, const char& ESC) { IsNeedMoreData isNeedMoreData = [&vBail](const std::string& iterationData, const std::string& allData)->bool { for(size_t i = 0; i < vBail.size(); i++) { const std::string& sBail = vBail[i]; if(sBail.size() > 0) { if(allData.find(sBail) != std::string::npos) { //Return when bail string is found printTrace("RADIO| Found bail string [%s]", sBail.c_str()); return false; } } } return true; }; return sendCommand(apIo, sCmd, isNeedMoreData, timeoutMillis, ESC); } std::string CellularRadio::sendCommand(const std::string& sCmd, MTS::IO::CellularRadio::IsNeedMoreData& isNeedMoreData, int32_t timeoutMillis, const char& ESC) { return sendCommand(m_apIo, sCmd, isNeedMoreData, timeoutMillis, ESC); } std::string CellularRadio::sendCommand(MTS::AutoPtr& apIo, const std::string& sCmd, IsNeedMoreData& isNeedMoreData, int32_t timeoutMillis, const char& ESC) { if(MTS::Logger::getPrintLevel() >= MTS::Logger::PrintLevel::TRACE_LEVEL) { printTrace("RADIO| Sending command [%s]", sCmd.c_str()); } if(apIo.isNull()) { printError("RADIO| IO is not set in sendCommand"); return ""; } int32_t iResult; if(ESC == 0x00) { iResult = apIo->write(sCmd.data(), sCmd.size()); } else { std::string sNewCmd(sCmd); sNewCmd.push_back(ESC); iResult = apIo->write(sNewCmd.data(), sNewCmd.size()); } if(iResult == -1) { printError("RADIO| Failed to send command to radio"); return ""; } bool done = false; const uint32_t capacity = 1024; char buffer[capacity]; std::string sResult; Timer timer; timer.start(); do { int32_t iterationTimeout = 100; int bytesRead = apIo->read((char*)buffer, capacity, iterationTimeout); if(bytesRead == -1) { printError("RADIO| Failed to read from radio"); break; } std::string sIteration((char*)buffer, bytesRead); sResult += sIteration; if(isNeedMoreData && !isNeedMoreData(sIteration, sResult)) { printTrace("RADIO| No more data needed"); return sResult; } if(timeoutMillis >= 0) { done = (timer.getMillis() >= (uint64_t)timeoutMillis); } else { //Do not stop looping until bail string is found } } while(!done); //Timed out return sResult; } CellularRadio::CODE CellularRadio::test(MTS::AutoPtr& apIo, uint32_t timeoutSeconds) { printTrace("RADIO| Basic Test"); uint32_t count = 0; std::string sCmd("AT"); do { std::string sResult = sendCommand(apIo, sCmd); if (sResult.find(RSP_OK) == std::string::npos) { printTrace("RADIO| Waiting for basic radio communication [%s] ...", sResult.c_str()); } else { break; } count++; } while (count < timeoutSeconds); if(count == timeoutSeconds) { printWarning("RADIO| Basic radio communication FAILED"); return NO_RESPONSE; } return SUCCESS; } std::string CellularRadio::extractModelFromResult(const std::string& sResult) { std::string sModel(CellularRadio::VALUE_NOT_SUPPORTED); if(sResult.find("HE910-D") != std::string::npos) { sModel = "HE910-D"; } else if(sResult.find("HE910-EUD") != std::string::npos) { sModel = "HE910-EUD"; } else if(sResult.find("LE910-NAG") != std::string::npos) { sModel = "LE910-NAG"; } else if(sResult.find("LE910-SVG") != std::string::npos) { sModel = "LE910-SVG"; } else if(sResult.find("LE910-EUG") != std::string::npos) { sModel = "LE910-EUG"; } else if(sResult.find("GE910") != std::string::npos) { sModel = "GE910"; } else if(sResult.find("DE910-DUAL") != std::string::npos) { sModel = "DE910-DUAL"; } else if(sResult.find("CE910") != std::string::npos) { sModel = "CE910"; } return sModel; } std::string CellularRadio::getCodeAsString(CODE eCode) { switch(eCode) { case SUCCESS: return "SUCCESS"; case ERROR: return "ERROR"; case FAILURE: return "FAILURE"; case NO_RESPONSE: return "NO RESPONSE"; default: return "UNKNOWN"; } } bool CellularRadio::splitAndAssign(const std::string& sLine, const std::string& sKey, Json::Value& jParent, const std::string& sJsonKey, Json::ValueType eType) { std::vector vParts = MTS::Text::split(sLine, ":", 2); if(vParts.size() == 2 && vParts[0] == sKey) { if(eType == Json::ValueType::stringValue) { jParent[sJsonKey] = MTS::Text::trim(vParts[1]); } else if (eType == Json::ValueType::intValue || eType == Json::ValueType::uintValue) { //TODO: printWarning("%s| Unable to parse requested type from line [%s]", getName().c_str(), sKey.c_str(), sLine.c_str()); return false; } else if(eType == Json::ValueType::realValue) { //TODO: printWarning("%s| Unable to parse requested type from line [%s]", getName().c_str(), sKey.c_str(), sLine.c_str()); return false; } else if(eType == Json::ValueType::booleanValue) { //TODO: printWarning("%s| Unable to parse requested type from line [%s]", getName().c_str(), sKey.c_str(), sLine.c_str()); return false; } else { printWarning("%s| Unable to parse requested type from line [%s]", getName().c_str(), sKey.c_str(), sLine.c_str()); return false; } } else { printWarning("%s| Unable to parse %s from line [%s]", getName().c_str(), sKey.c_str(), sLine.c_str()); return false; } return true; } bool CellularRadio::getCarrierFromFirmware(const std::string& sFirmware, std::string& sCarrier) { // Telit Radios // H.ab.zyx => 3 Main Components // "H" = Hardware -> 15 = DE910 family, 18 = CE910 family, 12 = HE910 family // "a" = Hardware version // "b" = Software Major Version // "z" = is the product type, i.e. DUAL or SC // "y" = is the carrier variant // "x" = is the firmware version // Telit will do their best to keep the carrier variant as "0" for Sprint, "1" for Aeris, and "2" for Verizon. const uint32_t CARRIER_INDEX = 1; //y in [zyx] bool bResult = false; std::vector vParts = MTS::Text::split(sFirmware, '.'); if(vParts.size() == 3) { //CDMA firmware version notation if(vParts[0] == "15" || vParts[0] == "18") { //DE910 or CE910 -> Good good std::string sID = vParts[2]; if(sID.size() == 3) { char cId = sID[CARRIER_INDEX]; //Good good if(cId == '0') { sCarrier = VALUE_CARRIER_SPRINT; bResult = true; } if(cId == '1') { sCarrier = VALUE_CARRIER_AERIS; bResult = true; } if(cId == '2') { sCarrier = VALUE_CARRIER_VERIZON; bResult = true; } } } } return bResult; } bool CellularRadio::getHardwareVersionFromFirmware(const std::string& sFirmware, std::string& sHardware) { // Telit Radios // H.ab.zyx => 3 Main Components // "H" = Hardware -> 15 = DE910 family, 18 = CE910 family, 12 = HE910 family // "a" = Hardware version // "b" = Software Major Version // "z" = is the product type, i.e. DUAL or SC // "y" = is the carrier variant // "x" = is the firmware version // Telit will do their best to keep the carrier variant as "0" for Sprint, "1" for Aeris, and "2" for Verizon. const uint32_t HARDWARE_INDEX = 0; //a in [ab] bool bResult = false; std::vector vParts = MTS::Text::split(sFirmware, '.'); if(vParts.size() == 3) { //GSM Hardware Version if(!(vParts[0] == "15" || vParts[0] == "18")) { //Not DE910 or CE910 -> Good good std::string sVersion = vParts[1]; if(sVersion.size() == 2) { sHardware = "1."; sHardware += sVersion[HARDWARE_INDEX]; bResult = true; } } } return bResult; } const char *CellularRadio::RadioBandMap::getLTEBand(const int32_t channel) { for (unsigned int ii = 0; ii < NUM_LTE_BANDS; ii++) { if (EULTRAband[ii].low <= channel && EULTRAband[ii].high >= channel) { return EULTRAband[ii].name; } } return VALUE_UNKNOWN.c_str(); } const char *CellularRadio::RadioBandMap::getCDMABand(const int channel) { for (unsigned int ii = 0; ii < NUM_WCDMA_BANDS; ii++) { if (WCDMAband[ii].low <= channel && WCDMAband[ii].high >= channel) { return WCDMAband[ii].name; } } return VALUE_UNKNOWN.c_str(); } const char *CellularRadio::RadioBandMap::getGSMBand(const int channel) { for (unsigned int ii = 0; ii < NUM_GSM_BANDS; ii++) { if (GSMband[ii].low <= channel && GSMband[ii].high >= channel) { return GSMband[ii].name; } } return VALUE_UNKNOWN.c_str(); } const char *CellularRadio::RadioBandMap::getRadioBandName() { const char *band = CellularRadio::VALUE_UNKNOWN.c_str(); if (m_sRadioType == CellularRadio::VALUE_TYPE_LTE) { band = getLTEBand(m_iChannel); } else if (m_sRadioType == CellularRadio::VALUE_TYPE_CDMA) { band = getCDMABand(m_iChannel); } else if (m_sRadioType == CellularRadio::VALUE_TYPE_GSM) { band = getGSMBand(m_iChannel); } return band; } const char *CellularRadio::RadioBandMap::getRadioBandName(const std::string &channel, const std::string &radioType) { const char *band = CellularRadio::VALUE_UNKNOWN.c_str(); int32_t chan = strtol(channel.c_str(), NULL, 10); if (radioType == CellularRadio::VALUE_TYPE_LTE) { band = getLTEBand(chan); } else if (radioType == CellularRadio::VALUE_TYPE_CDMA) { band = getCDMABand(chan); } else if (radioType == CellularRadio::VALUE_TYPE_GSM) { band = getGSMBand(chan); } return band; }