diff options
Diffstat (limited to 'src/MTS_IO_TelitRadio.cpp')
-rw-r--r-- | src/MTS_IO_TelitRadio.cpp | 666 |
1 files changed, 666 insertions, 0 deletions
diff --git a/src/MTS_IO_TelitRadio.cpp b/src/MTS_IO_TelitRadio.cpp new file mode 100644 index 0000000..340c0ac --- /dev/null +++ b/src/MTS_IO_TelitRadio.cpp @@ -0,0 +1,666 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + * + */ + +#include <mts/MTS_IO_TelitRadio.h> + +#include <mts/MTS_Logger.h> +#include <mts/MTS_Thread.h> +#include <mts/MTS_Text.h> + +using namespace MTS::IO; + +TelitRadio::TelitRadio(const std::string& sName, const std::string& sRadioPort) +: CellularRadio(sName, sRadioPort) +{ +} + +bool TelitRadio::resetRadio(uint32_t iTimeoutMillis) { + + printInfo("%s| Rebooting radio", getName().c_str()); + if(sendBasicCommand("AT#REBOOT") == SUCCESS) { + if(iTimeoutMillis > 5000) { + MTS::Thread::sleep(5000); + iTimeoutMillis -= 5000; + } + return resetConnection(iTimeoutMillis); + } + + return false; +} + + +ICellularRadio::CODE TelitRadio::getModel(std::string& sModel) { + printTrace("%s| Get Model", getName().c_str()); + //Always returns SUCCESS because the model should be m_sName + sModel = getName(); + std::string sCmd("ATI4"); + std::string sResult = sendCommand(sCmd); + if (sResult.find("OK") == std::string::npos) { + printWarning("%s| Unable to get model from radio. Returning [%s]", getName().c_str(), getName().c_str()); + return SUCCESS; + } else { + sModel = extractModelFromResult(sResult); + if(sModel.size() == 0) { + printWarning("%s| Unable to get model from radio. Returning [%s]", getName().c_str(), getName().c_str()); + return SUCCESS; + } + } + + printDebug("%s| Extracted [%s] from [%s] query", getName().c_str(), sModel.c_str(), sCmd.c_str()); + if(sModel != getName()) { + printWarning("%s| Model identified [%s] does not match expected [%s]. Returning [%s]", + getName().c_str(), sModel.c_str(), getName().c_str(), sModel.c_str()); + } + + return SUCCESS; +} + +ICellularRadio::CODE TelitRadio::getIccid(std::string& sIccid) { + printTrace("%s| Get ICCID", getName().c_str()); + sIccid = ICellularRadio::VALUE_NOT_SUPPORTED; + std::string sCmd("AT#CCID"); + std::string sResult = CellularRadio::sendCommand(sCmd); + size_t end = sResult.find(ICellularRadio::RSP_OK); + if (end == std::string::npos) { + printWarning("%s| Unable to get ICCID from radio using command [%s]", getName().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]", getName().c_str(), sCmd.c_str()); + return FAILURE; + } + } + return SUCCESS; +} + +ICellularRadio::CODE TelitRadio::getService(std::string& sService) { + printTrace("%s| Get Service", getName().c_str()); + sService = ICellularRadio::VALUE_NOT_SUPPORTED; + std::string sCmd("AT#PSNT?"); + std::string sResult = CellularRadio::sendCommand(sCmd); + size_t end = sResult.find(ICellularRadio::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(","); + 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 = ICellularRadio::VALUE_UNKNOWN; break; + } + + printDebug("%s| Service ID: [%d][%s]", getName().c_str(), iService, sService.c_str()); + } + return SUCCESS; +} + +ICellularRadio::CODE TelitRadio::getNetwork(std::string& sNetwork) { + Json::Value jData; + + printTrace("%s| Get Network", getName().c_str()); + sNetwork = ICellularRadio::VALUE_NOT_SUPPORTED; + + if(getNetworkStatus(jData) == SUCCESS) { + if(jData.isMember(ICellularRadio::KEY_NETWORK)) { + sNetwork = jData[ICellularRadio::KEY_NETWORK].asString(); + return SUCCESS; + } + } + return FAILURE; +} + +/* AT#RFSTS - NETWORK STATUS + + (GSM network) + #RFSTS:<PLMN>,<ARFCN>,<RSSI>,<LAC>,<RAC>,<TXPWR>,<MM>,<RR>,<NOM>,<CID>,<IMSI>,<NetNameAsc>,<SD>,<ABND> + Where: + <PLMN> - Country code and operator code(MCC, MNC) + <ARFCN> - GSM Assigned Radio Channel + <RSSI> - Received Signal Strength Indication + <LAC> - Localization Area Code + <RAC> - Routing Area Code + <TXPWR> - Tx Power + <MM> - Mobility Management state + <RR> - Radio Resource state + <NOM> - Network Operator Mode + <CID> - Cell ID + <IMSI> - International Mobile Subscriber Identity + <NetNameAsc> - Operator name + <SD> - Service Domain + 0 - No Service + 1 - CS only + 2 - PS only + 3 - CS+PS + <ABND> - Active Band + 1 - GSM 850 + 2 - GSM 900 + 3 - DCS 1800 + 4 - PCS 1900 + + + (WCDMA network) + #RFSTS: + <PLMN>,<UARFCN>,<PSC>,<Ec/Io>,<RSCP>, RSSI>,<LAC>,<RAC>,<TXPWR>,<DRX>,<MM>,<RRC>,<NOM>,<BLER>,<CID>,<IMSI>, + <NetNameAsc>,<SD>,<nAST>[,<nUARFCN><nPSC>,<nEc/Io>] + Where: + <PLMN> - Country code and operator code(MCC, MNC) + <UARFCN> - UMTS Assigned Radio Channel + <PSC> - Active PSC(Primary Synchronization Code) + <Ec/Io> - Active Ec/Io(chip energy per total wideband power in dBm) + <RSCP> - Active RSCP (Received Signal Code Power in dBm) + <RSSI> - Received Signal Strength Indication + <LAC> - Localization Area Code + <RAC> - Routing Area Code + <TXPWR> - Tx Power + <DRX> - Discontinuous reception cycle Length (cycle length in ms) + <MM> - Mobility Management state + <RR> - Radio Resource state + <NOM> - Network Operator Mode + <BLER> - Block Error Rate (e.g., 005 means 0.5 %) + <CID> - Cell ID + <IMSI> - International Mobile Station ID + <NetNameAsc> - Operator name + <SD> - Service Domain (see above) + <nAST> - Number of Active Set (Maximum 6) + <nUARFCN> UARFCN of n th active set + <nPSC> PSC of n th active set + <nEc/Io > Ec/Io of n th active Set + + (LTE Network) + #RFSTS: + <PLMN> - + <EARFCN> - + <RSRP> - + <RSSI> - + <RSRQ> - + <TAC> - + [<TXPWR>] - + <DRX> - + <MM> - + <RRC> - + <CID> - + <IMSI> - + [<NetNameAsc>] - + <SD> - + <ABND> - +*/ +ICellularRadio::CODE TelitRadio::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", getName().c_str()); + + //Always get common network stats because this should never fail + //This way the basic stats are always returned even if AT#RFSTS fails below + getCommonNetworkStats(jData); + + std::string sCmd; + std::string sResult; + // LE910 radios have a bug where issuing AT#RFSTS with a locked SIM + // will cause the radio to stop responding until a radio power cycle + // Telit Support Portal Case #5069697 + // LE910C1-NS is an LE910, so we stop the scan after the 0. + if (getName().find("LE910") != std::string::npos) { + sCmd = "AT+CPIN?"; + sResult = sendCommand(sCmd); + if (sResult.find("+CPIN:") == std::string::npos) { + printDebug("%s| AT+CPIN? 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; //return SUCCESS because getCommonNetworkStats() succeeded at top of this function + } + if (sResult.find("SIM PIN") != std::string::npos) { + printError("%s| The SIM is locked and must first be unlocked", getName().c_str()); + printTrace("%s| Network Status:\n%s\n", getName().c_str(), jData.toStyledString().c_str()); + return SUCCESS; //return SUCCESS because getCommonNetworkStats() succeeded at top of this function + } + } + + sCmd = "AT#RFSTS"; + sResult = sendCommand(sCmd, DEFAULT_BAIL_STRINGS, 200); + if (sResult.find("#RFSTS:") == std::string::npos) { + //On LTE radios without signal, this case will run because AT#RFSTS just returns "OK" + printDebug("%s| 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; //return SUCCESS because getCommonNetworkStats() succeeded at top of this function + } + + size_t start = sResult.find(":") + 1; //Position right after "#RFSTS:" + std::vector<std::string> vParts = MTS::Text::split(MTS::Text::trim(sResult.substr(start)), ","); + + if (vParts.size() < 3) { + printDebug("%s| Network Status command reponse is an unknown format: [%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; //return SUCCESS because getCommonNetworkStats() succeeded at top of this function + } else { + //Country Code and Operator Code + std::vector<std::string> vPLMN = MTS::Text::split(vParts[0], ' '); + if(vPLMN.size() == 2) { + jData[ICellularRadio::KEY_MCC] = MTS::Text::strip(vPLMN[0], '"'); + jData[ICellularRadio::KEY_MNC] = MTS::Text::strip(vPLMN[1], '"'); + } + + jData[ICellularRadio::KEY_CHANNEL] = vParts[1]; + } + + if (vParts.size() == GSM_NETWORK_FORMAT ) { + //Parse as GSM Network Format + jData[ICellularRadio::KEY_RSSIDBM] = vParts[2]; + jData[ICellularRadio::KEY_LAC] = vParts[3]; + jData[ICellularRadio::KEY_RAC] = vParts[4]; + jData[ICellularRadio::KEY_TXPWR] = vParts[5]; + jData[ICellularRadio::KEY_MM] = vParts[6]; + jData[ICellularRadio::KEY_RR] = vParts[7]; + jData[ICellularRadio::KEY_NOM] = vParts[8]; + jData[ICellularRadio::KEY_CID] = vParts[9]; + jData[ICellularRadio::KEY_IMSI] = MTS::Text::strip(vParts[10], '"'); + jData[ICellularRadio::KEY_NETWORK] = MTS::Text::strip(vParts[11], '"'); + if(MTS::Text::parse(iValue, vParts[12]) && convertServiceDomainToString((SERVICEDOMAIN)iValue, sValue) == SUCCESS) { + jData[ICellularRadio::KEY_SD] = sValue; + } + if(MTS::Text::parse(iValue, vParts[13]) && convertActiveBandToString((ACTIVEBAND)iValue, sValue) == SUCCESS) { + jData[ICellularRadio::KEY_ABND] = sValue; + } + // IN003567 ME910C1 radios have some odd behavior with regards to WCDMA. The ordering of the fields from #RFSTS are + // the same as LTE up to the 16th field (for ME901C1-WW anyway). Drop into LTE parsing for ME910C1-WW. + } else if((vParts.size() >= WCDMA_NETWORK_FORMAT) && (getName().find("ME910C1-WW") == std::string::npos)) { + Json::Value jDebug; + + //Parse as WCDMA Network Format + + jDebug[ICellularRadio::KEY_PSC] = vParts[2]; + jDebug[ICellularRadio::KEY_ECIO] = vParts[3]; + jDebug[ICellularRadio::KEY_RSCP] = vParts[4]; + + jData[ICellularRadio::KEY_RSSIDBM] = vParts[5]; + jData[ICellularRadio::KEY_LAC] = vParts[6]; + jData[ICellularRadio::KEY_RAC] = vParts[7]; + + jDebug[ICellularRadio::KEY_TXPWR] = vParts[8]; + jDebug[ICellularRadio::KEY_DRX] = vParts[9]; + jDebug[ICellularRadio::KEY_MM] = vParts[10]; + jDebug[ICellularRadio::KEY_RR] = vParts[11]; + jDebug[ICellularRadio::KEY_NOM] = vParts[12]; + + if(vParts[13].size() != 0) { + jDebug[ICellularRadio::KEY_BLER] = vParts[13]; + } else { + jDebug[ICellularRadio::KEY_BLER] = "000"; + } + + jData[ICellularRadio::KEY_CID] = vParts[14]; + jData[ICellularRadio::KEY_IMSI] = MTS::Text::strip(vParts[15], '"'); + jData[ICellularRadio::KEY_NETWORK] = MTS::Text::strip(vParts[16], '"'); + + // Get the radio band given the channel (UARFCN) + RadioBandMap radioBandMap(vParts[1], CellularRadio::ICellularRadio::VALUE_TYPE_CDMA); + jData[ICellularRadio::KEY_ABND] = radioBandMap.getRadioBandName(); + + if(MTS::Text::parse(iValue, vParts[17]) && convertServiceDomainToString((SERVICEDOMAIN)iValue, sValue) == SUCCESS) { + jDebug[ICellularRadio::KEY_SD] = sValue; + } + //Ignoring Active Set Values + // <nAST> - Number of Active Set (Maximum 6) + // <nUARFCN> - UARFCN of n th active set + // <nPSC> - PSC of n th active set + // <nEc/Io > - Ec/Io of n th active Set + + jData[ICellularRadio::KEY_DEBUG] = jDebug; + } else if(vParts.size() >= LTE_NETWORK_FORMAT) { + Json::Value jDebug; + + //Parse as LTE Network Format + + // + // MD: It is noticed that LTE Network format may vary depending on the firmware version: + // + // <PLMN>,<EARFCN>,<RSRP>,<RSSI>,<RSRQ>,<TAC>,[<TXPWR>],<DRX>,<MM>,<RRC>,<CID>,<IMSI>,[<NetNameAsc>],<SD>,<ABND>,<SINR> + // Ex 1: #RFSTS: "310 260",2300,-98,-63,-14,AA06,,128,19,0,0501D02,"310260754792598","T-Mobile",3,4,197 + // + // <PLMN>,<EARFCN>,<RSRP>,<RSSI>,<RSRQ>,<TAC>,<RAC>,[<TXPWR>],<DRX>,<MM>,<RRC>,<CID>,<IMSI>,[<NetNameAsc>],<SD>,<ABND> + // Ex 2: #RFSTS:"310 410",5780,-105,-73,-14,4603,255,,128,19,0,0000098,"310410536498694","AT&T",3,17 + // #RFSTS:"311 480",1150,-96,-66,-9.0,bf35,FF,0,0,19,1,"2ED1B0E","311480148817753","Verizon",2,2,720000,10800 + // #RFSTS:"310 410",2175,-120,-89,-17.5,4612,FF,0,0,19,1,"4E5E916","310410807276607","AT&T",3,4 + // + // Additional <RAC> parameter in the second example shifts the rest of the parameters. Here we are trying to figure out + // which format is currently produced based on <NetNameAsc> field position which always has double quotation marks. + // + if (vParts[13].find("\"") != std::string::npos) { + // parse the RAC and then remove it from the vector + jData[ICellularRadio::KEY_RAC] = vParts[6]; + vParts.erase(vParts.begin() + 6); + } + + jDebug["rsrp"] = vParts[2]; + jDebug[ICellularRadio::KEY_RSSIDBM] = vParts[3]; + jDebug["rsrq"] = vParts[4]; + + jData["tac"] = vParts[5]; + jDebug[ICellularRadio::KEY_TXPWR] = vParts[6]; + jData[ICellularRadio::KEY_DRX] = vParts[7]; + jDebug[ICellularRadio::KEY_MM] = vParts[8]; + jDebug["rrc"] = vParts[9]; + jData[ICellularRadio::KEY_CID] = MTS::Text::strip(vParts[10], '"'); + jData[ICellularRadio::KEY_IMSI] = MTS::Text::strip(vParts[11], '"'); + jData[ICellularRadio::KEY_NETWORK] = MTS::Text::strip(vParts[12], '"'); + + // Get the radio band given the channel (EARFCN) + RadioBandMap radioBandMap(vParts[1], ICellularRadio::VALUE_TYPE_LTE); + jData[ICellularRadio::KEY_ABND] = radioBandMap.getRadioBandName(); + + jData[ICellularRadio::KEY_LAC] = queryLteLac(); + + if(MTS::Text::parse(iValue, vParts[13]) && convertServiceDomainToString((SERVICEDOMAIN)iValue, sValue) == SUCCESS) { + jDebug[ICellularRadio::KEY_SD] = sValue; + } + + jData[ICellularRadio::KEY_DEBUG] = jDebug; + } + + printTrace("%s| Network Status:\n%s\n", getName().c_str(), jData.toStyledString().c_str()); + return SUCCESS; +} + +ICellularRadio::CODE TelitRadio::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; +} + +ICellularRadio::CODE TelitRadio::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; +} + +ICellularRadio::CODE TelitRadio::setMdn(const Json::Value& jArgs) { + printTrace("%s| Set MDN", getName().c_str()); + + if(!jArgs["mdn"].isString()) { + return INVALID_ARGS; + } + + std::string sCmd("AT#SNUM=1,\""); + sCmd += jArgs["mdn"].asString() + "\""; + + std::string sResult = sendCommand(sCmd, DEFAULT_BAIL_STRINGS, 1000); + size_t end = sResult.find(ICellularRadio::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; +} + +bool TelitRadio::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<std::string> 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 = ICellularRadio::VALUE_CARRIER_SPRINT; + bResult = true; + } else + if(cId == '1') { + sCarrier = ICellularRadio::VALUE_CARRIER_AERIS; + bResult = true; + } else + if(cId == '2') { + sCarrier = ICellularRadio::VALUE_CARRIER_VERIZON; + bResult = true; + } else + if(cId == '3') { + sCarrier = ICellularRadio::VALUE_CARRIER_USCELLULAR; + bResult = true; + } + } + } + } + + return bResult; +} + +bool TelitRadio::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<std::string> 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; + +} + +ICellularRadio::CODE TelitRadio::getRadioNetworkMode(RADIO_NETWORK_MODE &mode) +{ + std::string sCmd("AT+WS46?"); + std::string cmdResult = sendCommand(sCmd); + if (cmdResult.find("+WS46:") == std::string::npos) { + printDebug("%s| AT+WS46? returned unexpected response: [%s][%s]", getName().c_str(), sCmd.c_str(), cmdResult.c_str()); + return FAILURE; + } + switch (stoi(MTS::Text::split(cmdResult, ':')[1])) { + case 12: mode = ICellularRadio::RADIO_NETWORK_MODE_GSM_ONLY; break; + case 22: mode = ICellularRadio::RADIO_NETWORK_MODE_UMTS_ONLY; break; + case 25: mode = ICellularRadio::RADIO_NETWORK_MODE_AUTO; break; + default: mode = ICellularRadio::RADIO_NETWORK_MODE_UNKNOWN; break; + } + return SUCCESS; +} + +ICellularRadio::CODE TelitRadio::setRadioNetworkMode(RADIO_NETWORK_MODE mode) +{ + std::string value; + switch (mode) { + case ICellularRadio::RADIO_NETWORK_MODE_GSM_ONLY: value = "12"; break; + case ICellularRadio::RADIO_NETWORK_MODE_UMTS_ONLY: value = "22"; break; + case ICellularRadio::RADIO_NETWORK_MODE_AUTO: value = "25"; break; + default: return FAILURE; + } + std::string sCmd("AT+WS46="); + sCmd += value; + std::string cmdResult = sendCommand(sCmd); + if (cmdResult.find(ICellularRadio::RSP_OK) == std::string::npos) { + printDebug("%s| AT+WS46? returned unexpected response: [%s][%s]", getName().c_str(), sCmd.c_str(), cmdResult.c_str()); + return FAILURE; + } + return SUCCESS; +} + +ICellularRadio::CODE TelitRadio::getIsSimInserted(bool& bData) { + printTrace("%s| Get SIM insertion status", getName().c_str()); + std::string sCmd("AT#SIMDET?"); + std::string sResult = sendCommand(sCmd); + + const std::string sPrefix = "#SIMDET: "; + size_t start = sResult.find(sPrefix); + size_t end = sResult.rfind(ICellularRadio::RSP_OK); + + if (end == std::string::npos) { + printWarning("%s| Unable to get SIM insertion status from radio using command [%s]", getName().c_str(), sCmd.c_str()); + return FAILURE; + } + + if (start == std::string::npos) { + printDebug("%s| AT#SIMDET? returned unexpected response: [%s][%s]", getName().c_str(), sCmd.c_str(), sResult.c_str()); + return FAILURE; + } + + // #SIMDET: <mode>,<simin> + start += sPrefix.size(); + std::vector<std::string> vParts = MTS::Text::split(MTS::Text::trim(sResult.substr(start, end-start)), ','); + + if(vParts.size() != 2) { + printWarning("%s| Unable to parse SIM insertion status from response [%s]", getName().c_str(), sResult.c_str()); + return FAILURE; + } + + if (vParts[1] == "1") { // <simin> + bData = true; + } else { + bData = false; + } + + return SUCCESS; +} + +ICellularRadio::CODE TelitRadio::getSimLockAttempts(int& iAttemptsPin, int& iAttemptsPuk) { + std::string sLockStatus; + ICellularRadio::CODE retCode; + + retCode = getSimLockStatus(sLockStatus); + if (retCode != SUCCESS) { + printWarning("%s| Unable determine the number of SIM unlock attempts: SIM lock status is unavailable [%s]", getName().c_str(), sLockStatus.c_str()); + return retCode; + } + + return getSimLockAttempts(iAttemptsPin, iAttemptsPuk, sLockStatus); +} + +ICellularRadio::CODE TelitRadio::getSimLockAttempts(int& iAttemptsPin, int& iAttemptsPuk, const std::string& sLockStatus) { + printTrace("%s| Get SIM unlock attempts left", getName().c_str()); + std::string sCmd("AT#PCT"); + std::string sResult = sendCommand(sCmd, DEFAULT_BAIL_STRINGS, 500); + std::string sValue; + int iValue; + + const std::string sPrefix = "#PCT: "; + size_t start = sResult.find(sPrefix); + size_t end = sResult.rfind(ICellularRadio::RSP_OK); + + if (end == std::string::npos) { + printWarning("%s| Unable to get SIM unlock attempts from radio using command [%s]", getName().c_str(), sCmd.c_str()); + return FAILURE; + } + + if (start == std::string::npos) { + printDebug("%s| AT#PCT? returned unexpected response: [%s][%s]", getName().c_str(), sCmd.c_str(), sResult.c_str()); + return FAILURE; + } + + // #PCT: <n> + start += sPrefix.size(); + sValue = MTS::Text::trim(sResult.substr(start, end-start)); + + if (!MTS::Text::parse(iValue, sValue)) { + printWarning("%s| Unable to parse SIM unlock attempts from response [%s]", getName().c_str(), sResult.c_str()); + return FAILURE; + } + + if (sLockStatus == "READY" || sLockStatus == "SIM PIN") { + iAttemptsPin = iValue; // Some PIN attempts left, maximum PUK attempts left + iAttemptsPuk = 10; + } else { + iAttemptsPin = 0; // No PIN attempts left + iAttemptsPuk = iValue; + } + + return SUCCESS; +} |