/*
* 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;
}