/* * Copyright (C) 2019 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 . * */ #include "mts/MTS_IO_CellularRadio.h" #include #include #include #include #include #include using namespace MTS::IO; namespace { typedef struct { const char *name; int32_t low; int32_t high; } *pNameRangeMap, nameRangeMap; const unsigned int NUM_GSM_BANDS = 7; const unsigned int NUM_WCDMA_BANDS = 6; const unsigned int NUM_LTE_BANDS = 42; // http://niviuk.free.fr/gsm_band.php const nameRangeMap GSMband[] = { {"GSM 450", 259, 293}, {"GSM 480", 306, 340}, {"GSM 750", 438, 511}, {"GSM 850", 128, 251}, {"GSM 900 P", 1, 124}, {"GSM 900 E/R", 955, 1023}, {"GSM DCS 1800/1900", 512, 885}, }; // http://niviuk.free.fr/umts_band.php const nameRangeMap WCDMAband[] = { {"BAND I", 10592, 10838}, {"BAND II", 9662, 9938}, {"BAND III", 1162, 1513}, {"BAND IV", 1537, 1738}, {"BAND V", 4357, 4458}, {"BAND VI", 4387, 4413} }; // http://niviuk.free.fr/lte_band.php const nameRangeMap EULTRAband[] = { {"EUTRAN BAND1", 0, 599}, {"EUTRAN BAND2", 600, 1199}, {"EUTRAN BAND3", 1200, 1949}, {"EUTRAN BAND4", 1950, 2399}, {"EUTRAN BAND5", 2400, 2649}, {"EUTRAN BAND6", 2650, 2749}, {"EUTRAN BAND7", 2750, 3449}, {"EUTRAN BAND8", 3450, 3799}, {"EUTRAN BAND9", 3800, 4149}, {"EUTRAN BAND10", 4150, 4749}, {"EUTRAN BAND11", 4750, 4999}, {"EUTRAN BAND12", 5000, 5179}, {"EUTRAN BAND13", 5180, 5279}, {"EUTRAN BAND14", 5280, 5379}, {"EUTRAN BAND17", 5730, 5849}, {"EUTRAN BAND18", 5850, 5999}, {"EUTRAN BAND19", 6000, 6149}, {"EUTRAN BAND20", 6150, 6449}, {"EUTRAN BAND21", 6450, 6525}, {"EUTRAN BAND22", 6600, 7399}, {"EUTRAN BAND23", 7500, 7699}, {"EUTRAN BAND24", 7700, 8039}, {"EUTRAN BAND25", 8040, 8689}, {"EUTRAN BAND26", 8690, 9039}, {"EUTRAN BAND27", 9040, 9209}, {"EUTRAN BAND28", 9210, 9659}, {"EUTRAN BAND29", 9660, 9769}, {"EUTRAN BAND30", 9770, 9869}, {"EUTRAN BAND31", 9870, 9919}, {"EUTRAN BAND32", 9920, 10359}, {"EUTRAN BAND33", 36000, 36199}, {"EUTRAN BAND34", 36200, 36349}, {"EUTRAN BAND35", 36350, 36949}, {"EUTRAN BAND36", 36950, 37549}, {"EUTRAN BAND37", 37550, 37749}, {"EUTRAN BAND38", 37750, 38249}, {"EUTRAN BAND39", 38250, 38649}, {"EUTRAN BAND40", 38650, 39649}, {"EUTRAN BAND41", 39650, 41589}, {"EUTRAN BAND42", 41590, 43589}, {"EUTRAN BAND43", 43590, 45589}, {"EUTRAN BAND44", 45590, 46589} }; } 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::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()); printDebug("%s| Recovering 'echo' after connection reset", m_sName.c_str()); // see CellularRadio::initialize setEcho(m_bEchoEnabled); 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::getFirmware(std::string& sFirmware) { printTrace("%s| Get Firmware", m_sName.c_str()); sFirmware = VALUE_NOT_SUPPORTED; std::string sCmd("AT+CGMR"); std::string sResult = 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::getFirmwareBuild(std::string& sFirmwareBuild) { sFirmwareBuild = VALUE_NOT_SUPPORTED; return FAILURE; } 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 = 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 = 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 = 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::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 = 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 = 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::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::getModemLocation(std::string&) { printTrace("%s|CellularRadio getModemLocation - not supported", m_sName.c_str()); return FAILURE; } 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: - - - - - - [] - - - - - - [] - - - */ // Get the LAC for the LTE radio that's not in the #RFSTS response std::string CellularRadio::queryLteLac() { std::string CGREGstring; std::string originalCGREG; std::string result; CGREGstring = queryCGREGstring(); if (CGREGstring == RSP_ERROR) { originalCGREG = "0"; } else { originalCGREG = CGREGstring.at(CGREGstring.find(",") - 1); //Position right before first comma ("+CGREG: 0,1") } // Temporarily set CGREG=2 to get more info setCGREG("2"); CGREGstring = queryCGREGstring(); if (CGREGstring == RSP_ERROR) { result = VALUE_UNKNOWN; } else { size_t start = CGREGstring.find(":") + 1; //Position right after "#RFSTS:" std::vector vParts = MTS::Text::split(MTS::Text::trim(CGREGstring.substr(start)), ","); if(vParts.size() < 3) { result = VALUE_UNAVAILABLE; } else { result = MTS::Text::strip(vParts[2], '"'); } } setCGREG(originalCGREG); return result; } void CellularRadio::setCGREG(std::string value) { std::string sCmd("AT+CGREG=" + value); std::string cmdResult(sendCommand(sCmd)); if (cmdResult.find("OK") == std::string::npos) { printDebug("%s| AT#CGREG=%s returned unexpected response: [%s][%s]", m_sName.c_str(), value.c_str(), sCmd.c_str(), cmdResult.c_str()); } } std::string CellularRadio::queryCGREGstring() { std::string sCmd("AT+CGREG?"); std::string cmdResult(sendCommand(sCmd)); if (cmdResult.find("+CGREG:") == std::string::npos) { printDebug("%s| AT#CGREG? returned unexpected response: [%s][%s]", m_sName.c_str(), sCmd.c_str(), cmdResult.c_str()); return RSP_ERROR; } return cmdResult; } 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; } std::string sNetworkReg; REGISTRATION eReg; if (getRegistration(eReg) == SUCCESS) { if (convertRegistrationToString(eReg, sNetworkReg) == SUCCESS) { jData[KEY_NETWORK_REG] = sNetworkReg; } } } 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; // LE910C1-NS is an LE910, so we stop the scan after the 0. 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&) { printTrace("%s| Validate MSL", m_sName.c_str()); return NOT_APPLICABLE; } CellularRadio::CODE CellularRadio::setMsid(const Json::Value&) { printTrace("%s| Set MSID", m_sName.c_str()); return NOT_APPLICABLE; } CellularRadio::CODE CellularRadio::getMipProfile(Json::Value&) { printTrace("%s| Get MIP Active Profile", m_sName.c_str()); return NOT_APPLICABLE; } CellularRadio::CODE CellularRadio::setMipActiveProfile(const Json::Value&) { printTrace("%s| Set MIP Active Profile", m_sName.c_str()); return NOT_APPLICABLE; } CellularRadio::CODE CellularRadio::setMipNai(const Json::Value&) { printTrace("%s| Set MIP NAI", m_sName.c_str()); return NOT_APPLICABLE; } CellularRadio::CODE CellularRadio::setMipHomeIp(const Json::Value&) { printTrace("%s| Set MIP Home IP", m_sName.c_str()); return NOT_APPLICABLE; } CellularRadio::CODE CellularRadio::setMipPrimaryHa(const Json::Value&) { printTrace("%s| Set MIP Primary HA", m_sName.c_str()); return NOT_APPLICABLE; } CellularRadio::CODE CellularRadio::setMipSecondaryHa(const Json::Value&) { printTrace("%s| Set MIP Secondary HA", m_sName.c_str()); return NOT_APPLICABLE; } CellularRadio::CODE CellularRadio::setMipMnAaaSpi(const Json::Value&) { printTrace("%s| Set MIP MN-AAA SPI", m_sName.c_str()); return NOT_APPLICABLE; } CellularRadio::CODE CellularRadio::setMipMnHaSpi(const Json::Value&) { printTrace("%s| Set MIP MN-HA SPI", m_sName.c_str()); return NOT_APPLICABLE; } CellularRadio::CODE CellularRadio::setMipRevTun(const Json::Value&) { printTrace("%s| Set MIP Rev Tun", m_sName.c_str()); return NOT_APPLICABLE; } CellularRadio::CODE CellularRadio::setMipMnAaaSs(const Json::Value&) { printTrace("%s| Set MIP MN-AAA SS", m_sName.c_str()); return NOT_APPLICABLE; } CellularRadio::CODE CellularRadio::setMipMnHaSs(const Json::Value&) { printTrace("%s| Set MIP MN-HA SS", m_sName.c_str()); return NOT_APPLICABLE; } CellularRadio::CODE CellularRadio::updateDc(const Json::Value&, UpdateCb&) { printTrace("%s| Update Device Configuration", m_sName.c_str()); return NOT_APPLICABLE; } CellularRadio::CODE CellularRadio::updatePrl(const Json::Value&, UpdateCb&) { printTrace("%s| Update Preferred Roaming List", m_sName.c_str()); return NOT_APPLICABLE; } CellularRadio::CODE CellularRadio::updateFumo(const Json::Value&, UpdateCb&) { printTrace("%s| Update Firmware Update Management Object", m_sName.c_str()); return NOT_APPLICABLE; } CellularRadio::CODE CellularRadio::resetHfa(const Json::Value&, UpdateCb&) { printTrace("%s| HFA Reset", m_sName.c_str()); return NOT_APPLICABLE; } CellularRadio::CODE CellularRadio::activate(const Json::Value&, UpdateCb&) { printTrace("%s| Activation", m_sName.c_str()); return NOT_APPLICABLE; } CellularRadio::CODE CellularRadio::setActiveFirmware(const Json::Value&) { printTrace("%s| Set Active Firmware Image Number: not applicable", m_sName.c_str()); return NOT_APPLICABLE; } CellularRadio::CODE CellularRadio::getActiveFirmware(std::string& sFwId) { printTrace("%s| Get Active Firmware Image Number: not applicable", m_sName.c_str()); sFwId = VALUE_NOT_SUPPORTED; 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 ICellularRadio::sendCommand(m_apIo, sCmd, vBail, timeoutMillis, ESC); } std::string CellularRadio::sendCommand(const std::string& sCmd, MTS::IO::CellularRadio::IsNeedMoreData& isNeedMoreData, int32_t timeoutMillis, const char& ESC) { return ICellularRadio::sendCommand(m_apIo, sCmd, isNeedMoreData, timeoutMillis, ESC); } 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, "2" for Verizon, and "3" for U.S. Cellular. 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; } else if(cId == '1') { sCarrier = VALUE_CARRIER_AERIS; bResult = true; } else if(cId == '2') { sCarrier = VALUE_CARRIER_VERIZON; bResult = true; } else if(cId == '3') { sCarrier = VALUE_CARRIER_USCELLULAR; 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; } 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; } 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; } const char *CellularRadio::RadioBandMap::getRadioBandName() { const char *band = CellularRadio::VALUE_UNKNOWN; if (m_sRadioType == VALUE_TYPE_LTE) { band = getLTEBand(m_iChannel); } else if (m_sRadioType == VALUE_TYPE_CDMA) { band = getCDMABand(m_iChannel); } else if (m_sRadioType == 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 = VALUE_UNKNOWN; int32_t chan = strtol(channel.c_str(), NULL, 10); if (radioType == VALUE_TYPE_LTE) { band = getLTEBand(chan); } else if (radioType == VALUE_TYPE_CDMA) { band = getCDMABand(chan); } else if (radioType == VALUE_TYPE_GSM) { band = getGSMBand(chan); } return band; }