summaryrefslogtreecommitdiff
path: root/src/MTS_IO_TelitRadio.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/MTS_IO_TelitRadio.cpp')
-rw-r--r--src/MTS_IO_TelitRadio.cpp666
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;
+}