diff options
| author | Jeff Hatch <jhatch@multitech.com> | 2019-07-23 08:51:41 -0500 | 
|---|---|---|
| committer | Jeff Hatch <jhatch@multitech.com> | 2019-07-23 08:51:41 -0500 | 
| commit | f6f7d0e174d2bf5eb4494e2508c17d3d7fbdc4e9 (patch) | |
| tree | 4f0e44ed31f0e536835260ff5b4849f84289ee9c /src | |
| parent | 86e572b513259e1f7164dd4e4b0f490c870bfc30 (diff) | |
| parent | 0330513b8913d1d7bf14bad99d64ab002b770b7c (diff) | |
| download | libmts-io-f6f7d0e174d2bf5eb4494e2508c17d3d7fbdc4e9.tar.gz libmts-io-f6f7d0e174d2bf5eb4494e2508c17d3d7fbdc4e9.tar.bz2 libmts-io-f6f7d0e174d2bf5eb4494e2508c17d3d7fbdc4e9.zip | |
Merge branch 'quectel-radio' into 'master'
Quectel radio
See merge request !1
Diffstat (limited to 'src')
| -rw-r--r-- | src/MTS_IO_CE910Radio.cpp | 2 | ||||
| -rw-r--r-- | src/MTS_IO_CdmaRadio.cpp | 216 | ||||
| -rw-r--r-- | src/MTS_IO_CellularRadio.cpp | 1338 | ||||
| -rw-r--r-- | src/MTS_IO_CellularRadioFactory.cpp | 61 | ||||
| -rw-r--r-- | src/MTS_IO_DE910Radio.cpp | 2 | ||||
| -rw-r--r-- | src/MTS_IO_EG95Radio.cpp | 47 | ||||
| -rw-r--r-- | src/MTS_IO_GE910Radio.cpp | 4 | ||||
| -rw-r--r-- | src/MTS_IO_HE910Radio.cpp | 4 | ||||
| -rw-r--r-- | src/MTS_IO_ICellularRadio.cpp | 472 | ||||
| -rw-r--r-- | src/MTS_IO_LE866Radio.cpp | 2 | ||||
| -rw-r--r-- | src/MTS_IO_LE910C1APRadio.cpp | 2 | ||||
| -rw-r--r-- | src/MTS_IO_LE910C1NSRadio.cpp | 2 | ||||
| -rw-r--r-- | src/MTS_IO_LE910NA1Radio.cpp | 10 | ||||
| -rw-r--r-- | src/MTS_IO_LE910Radio.cpp | 8 | ||||
| -rw-r--r-- | src/MTS_IO_LE910SVGRadio.cpp | 2 | ||||
| -rw-r--r-- | src/MTS_IO_ME910C1NVRadio.cpp | 70 | ||||
| -rw-r--r-- | src/MTS_IO_ME910C1WWRadio.cpp | 10 | ||||
| -rw-r--r-- | src/MTS_IO_ME910Radio.cpp | 8 | ||||
| -rw-r--r-- | src/MTS_IO_QuectelRadio.cpp | 612 | ||||
| -rw-r--r-- | src/MTS_IO_TelitRadio.cpp | 666 | 
20 files changed, 2285 insertions, 1253 deletions
| diff --git a/src/MTS_IO_CE910Radio.cpp b/src/MTS_IO_CE910Radio.cpp index 7bdf280..d1cad9b 100644 --- a/src/MTS_IO_CE910Radio.cpp +++ b/src/MTS_IO_CE910Radio.cpp @@ -39,7 +39,7 @@ CE910Radio::CE910Radio(const std::string& sPort)  } -CellularRadio::CODE CE910Radio::setRxDiversity(const Json::Value& jArgs) { +ICellularRadio::CODE CE910Radio::setRxDiversity(const Json::Value& jArgs) {  /*  Command string for CE radios:  N/A */          return FAILURE;  } diff --git a/src/MTS_IO_CdmaRadio.cpp b/src/MTS_IO_CdmaRadio.cpp index 5b53f02..f84fd34 100644 --- a/src/MTS_IO_CdmaRadio.cpp +++ b/src/MTS_IO_CdmaRadio.cpp @@ -35,7 +35,7 @@  using namespace MTS::IO;  CdmaRadio::CdmaRadio(const std::string& sName, const std::string& sPort) -: CellularRadio(sName, sPort) +: TelitRadio(sName, sPort)  {  } @@ -44,17 +44,17 @@ CdmaRadio::~CdmaRadio() {  } -CellularRadio::CODE CdmaRadio::getImei(std::string& sImei) { +ICellularRadio::CODE CdmaRadio::getImei(std::string& sImei) {      printTrace("%s| Get IMEI", getName().c_str());      return getMeid(sImei);  } -CellularRadio::CODE CdmaRadio::getMeid(std::string& sMeid) { +ICellularRadio::CODE CdmaRadio::getMeid(std::string& sMeid) {      printTrace("%s| Get MEID", getName().c_str()); -    sMeid = VALUE_NOT_SUPPORTED; +    sMeid = ICellularRadio::VALUE_NOT_SUPPORTED;      std::string sCmd("AT#MEIDESN?"); -    std::string sResult = CellularRadio::sendCommand(sCmd); -    size_t pos = sResult.find(RSP_OK); +    std::string sResult = sendCommand(sCmd); +    size_t pos = sResult.find(ICellularRadio::RSP_OK);      if (pos == std::string::npos) {          printWarning("%s| Unable to get MEID from radio using command [%s]", getName().c_str(), sCmd.c_str());          return FAILURE; @@ -72,12 +72,12 @@ CellularRadio::CODE CdmaRadio::getMeid(std::string& sMeid) {      return SUCCESS;  } -CellularRadio::CODE CdmaRadio::getMsid(std::string& sMsid) { +ICellularRadio::CODE CdmaRadio::getMsid(std::string& sMsid) {      printTrace("%s| Get MSID", getName().c_str()); -    sMsid = VALUE_NOT_SUPPORTED; +    sMsid = ICellularRadio::VALUE_NOT_SUPPORTED;      std::string sCmd("AT$MSID?"); -    std::string sResult = CellularRadio::sendCommand(sCmd); -    size_t end = sResult.find(RSP_OK); +    std::string sResult = sendCommand(sCmd); +    size_t end = sResult.find(ICellularRadio::RSP_OK);      if (end == std::string::npos) {          printWarning("%s| Unable to get MSID from radio using command [%s]", getName().c_str(), sCmd.c_str());          return FAILURE; @@ -92,14 +92,14 @@ CellularRadio::CODE CdmaRadio::getMsid(std::string& sMsid) {      return SUCCESS;  } -CellularRadio::CODE CdmaRadio::getCarrier(std::string& sCarrier) { +ICellularRadio::CODE CdmaRadio::getCarrier(std::string& sCarrier) {      if(m_sCarrier != "") {          sCarrier = m_sCarrier;          return SUCCESS;      }      std::string sFirmware; -    CODE code = getFirmware(sFirmware); +    ICellularRadio::CODE code = getFirmware(sFirmware);      if(code != SUCCESS) {          return code;      } @@ -113,34 +113,34 @@ CellularRadio::CODE CdmaRadio::getCarrier(std::string& sCarrier) {      return SUCCESS;  } -CellularRadio::CODE CdmaRadio::getNetwork(std::string& sNetwork) { +ICellularRadio::CODE CdmaRadio::getNetwork(std::string& sNetwork) {      return getCarrier(sNetwork);  } -CellularRadio::CODE CdmaRadio::getSimStatus(std::string& sSimStatus) { +ICellularRadio::CODE CdmaRadio::getSimStatus(std::string& sSimStatus) {      printTrace("%s| Get SIM Status", getName().c_str()); -    sSimStatus = VALUE_NOT_SUPPORTED; +    sSimStatus = ICellularRadio::VALUE_NOT_SUPPORTED;      return NOT_APPLICABLE;  } -CellularRadio::CODE CdmaRadio::getIccid(std::string& sIccid) { +ICellularRadio::CODE CdmaRadio::getIccid(std::string& sIccid) {      printTrace("%s| Get ICCID", getName().c_str()); -    sIccid = VALUE_NOT_SUPPORTED; +    sIccid = ICellularRadio::VALUE_NOT_SUPPORTED;      return NOT_APPLICABLE;  } -CellularRadio::CODE CdmaRadio::getLac(std::string& sLac) { +ICellularRadio::CODE CdmaRadio::getLac(std::string& sLac) {      printTrace("%s| Get LAC", getName().c_str()); -    sLac = VALUE_NOT_SUPPORTED; +    sLac = ICellularRadio::VALUE_NOT_SUPPORTED;      return NOT_APPLICABLE;  } -CellularRadio::CODE CdmaRadio::getService(std::string& sService) { +ICellularRadio::CODE CdmaRadio::getService(std::string& sService) {      printTrace("%s| Get Service", getName().c_str()); -    sService = VALUE_NOT_SUPPORTED; +    sService = ICellularRadio::VALUE_NOT_SUPPORTED;      std::string sCmd("AT+SERVICE?"); -    std::string sResult = CellularRadio::sendCommand(sCmd); -    size_t end = sResult.find(RSP_OK); +    std::string sResult = 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; @@ -159,7 +159,7 @@ CellularRadio::CODE CdmaRadio::getService(std::string& sService) {              case 2: sService = "EVDO"; break; //Release 0              case 3: sService = "EVDO"; break; //Release A              case 4: sService = "GPRS"; break; -            default: sService = VALUE_UNKNOWN; break; +            default: sService = ICellularRadio::VALUE_UNKNOWN; break;          }          printDebug("%s| Service ID: [%d][%s]", getName().c_str(), iService, sService.c_str()); @@ -167,12 +167,12 @@ CellularRadio::CODE CdmaRadio::getService(std::string& sService) {      return SUCCESS;  } -CellularRadio::CODE CdmaRadio::getHardware(std::string& sHardware) { +ICellularRadio::CODE CdmaRadio::getHardware(std::string& sHardware) {      printTrace("%s| Get Hardware", getName().c_str()); -    sHardware = VALUE_NOT_SUPPORTED; +    sHardware = ICellularRadio::VALUE_NOT_SUPPORTED;      std::string sCmd("AT#HWREV"); -    std::string sResult = CellularRadio::sendCommand(sCmd); -    size_t pos = sResult.find(RSP_OK); +    std::string sResult = sendCommand(sCmd); +    size_t pos = sResult.find(ICellularRadio::RSP_OK);      if (pos == std::string::npos) {          printWarning("%s| Unable to get hardware from radio using command [%s]", getName().c_str(), sCmd.c_str());          return FAILURE; @@ -187,12 +187,12 @@ CellularRadio::CODE CdmaRadio::getHardware(std::string& sHardware) {      return SUCCESS;  } -CellularRadio::CODE CdmaRadio::getMdn(std::string& sMdn) { +ICellularRadio::CODE CdmaRadio::getMdn(std::string& sMdn) {      printTrace("%s| Get MDN", getName().c_str()); -    sMdn = VALUE_NOT_SUPPORTED; +    sMdn = ICellularRadio::VALUE_NOT_SUPPORTED;      std::string sCmd("AT+CNUM"); -    std::string sResult = CellularRadio::sendCommand(sCmd); -    size_t end = sResult.find(RSP_OK); +    std::string sResult = sendCommand(sCmd); +    size_t end = sResult.find(ICellularRadio::RSP_OK);      if (end == std::string::npos) {          printWarning("%s| Unable to get MDN from radio using command [%s]", getName().c_str(), sCmd.c_str());          return FAILURE; @@ -213,7 +213,7 @@ CellularRadio::CODE CdmaRadio::getMdn(std::string& sMdn) {      return SUCCESS;  } -CellularRadio::CODE CdmaRadio::validateMsl(const Json::Value& jArgs) { +ICellularRadio::CODE CdmaRadio::validateMsl(const Json::Value& jArgs) {      printTrace("%s| Validate MSL", getName().c_str());      if(!jArgs["msl"].isString()) { @@ -239,7 +239,7 @@ CellularRadio::CODE CdmaRadio::validateMsl(const Json::Value& jArgs) {      return setMdn(jMdn);  } -CellularRadio::CODE CdmaRadio::setMdn(const Json::Value& jArgs) { +ICellularRadio::CODE CdmaRadio::setMdn(const Json::Value& jArgs) {      printTrace("%s| Set MDN", getName().c_str());      if(!jArgs["mdn"].isString()) { @@ -274,7 +274,7 @@ CellularRadio::CODE CdmaRadio::setMdn(const Json::Value& jArgs) {      sCmd += sMdn;      std::string sResult = sendCommand(sCmd); -    size_t end = sResult.find(RSP_OK); +    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; @@ -283,7 +283,7 @@ CellularRadio::CODE CdmaRadio::setMdn(const Json::Value& jArgs) {      return SUCCESS;  } -CellularRadio::CODE CdmaRadio::setMsid(const Json::Value& jArgs) { +ICellularRadio::CODE CdmaRadio::setMsid(const Json::Value& jArgs) {      printTrace("%s| Set MSID", getName().c_str());      if(!jArgs["msid"].isString()) {          printError("%s| Arguments missing \"msid\"", getName().c_str()); @@ -309,7 +309,7 @@ CellularRadio::CODE CdmaRadio::setMsid(const Json::Value& jArgs) {      sCmd += jArgs["msid"].asString();      std::string sResult = sendCommand(sCmd); -    size_t end = sResult.find(RSP_OK); +    size_t end = sResult.find(ICellularRadio::RSP_OK);      if (end == std::string::npos) {          printWarning("%s| Unable to set MSID for radio using command [%s]", getName().c_str(), sCmd.c_str());          return FAILURE; @@ -318,7 +318,7 @@ CellularRadio::CODE CdmaRadio::setMsid(const Json::Value& jArgs) {      return SUCCESS;  } -CellularRadio::CODE CdmaRadio::getMipProfile(Json::Value& jMipProfile) { +ICellularRadio::CODE CdmaRadio::getMipProfile(Json::Value& jMipProfile) {      printTrace("%s| Get MIP Active Profile", getName().c_str());      initMipProfile(jMipProfile); @@ -329,7 +329,7 @@ CellularRadio::CODE CdmaRadio::getMipProfile(Json::Value& jMipProfile) {      if(sCarrier == "Aeris" || sCarrier == "Sprint") {          std::string sCmd("AT$QCMIPGETP");          std::string sResult = MTS::Text::trim(sendCommand(sCmd)); -        if (sResult.find(RSP_OK) == std::string::npos) { +        if (sResult.find(ICellularRadio::RSP_OK) == std::string::npos) {              printWarning("%s| Unable to get active MIP profile for radio using command [%s]", getName().c_str(), sCmd.c_str());              return FAILURE;          } @@ -341,34 +341,34 @@ CellularRadio::CODE CdmaRadio::getMipProfile(Json::Value& jMipProfile) {          std::vector<std::string> vParts = MTS::Text::split(sLine, ':', 2);          if(vParts.size() == 2 && vParts[0] == "Profile") {              if(vParts[1].find("Enabled") != std::string::npos) { -                jMipProfile[KEY_MIP_ENABLED] = true; +                jMipProfile[ICellularRadio::KEY_MIP_ENABLED] = true;              } else { -                jMipProfile[KEY_MIP_ENABLED] = false; +                jMipProfile[ICellularRadio::KEY_MIP_ENABLED] = false;              }              int32_t id;              sscanf(vParts[1].c_str(), "%d", &id); -            jMipProfile[KEY_MIP_ID] = id; +            jMipProfile[ICellularRadio::KEY_MIP_ID] = id;          } else {              printWarning("%s| Unable to parse active MIP profile from line [%s]", getName().c_str(), sLine.c_str());          } -        splitAndAssign(vLine[1], "NAI", jMipProfile, KEY_MIP_NAI); -        splitAndAssign(vLine[2], "Home Addr", jMipProfile, KEY_MIP_HOMEADDRESS); -        splitAndAssign(vLine[3], "Primary HA", jMipProfile, KEY_MIP_PRIMARYHA); -        splitAndAssign(vLine[4], "Secondary HA", jMipProfile, KEY_MIP_SECONDARYHA); -        splitAndAssign(vLine[5], "MN-AAA SPI", jMipProfile, KEY_MIP_MNAAASPI); -        splitAndAssign(vLine[6], "MN-HA SPI", jMipProfile, KEY_MIP_MNHASPI); +        splitAndAssign(vLine[1], "NAI", jMipProfile, ICellularRadio::KEY_MIP_NAI); +        splitAndAssign(vLine[2], "Home Addr", jMipProfile, ICellularRadio::KEY_MIP_HOMEADDRESS); +        splitAndAssign(vLine[3], "Primary HA", jMipProfile, ICellularRadio::KEY_MIP_PRIMARYHA); +        splitAndAssign(vLine[4], "Secondary HA", jMipProfile, ICellularRadio::KEY_MIP_SECONDARYHA); +        splitAndAssign(vLine[5], "MN-AAA SPI", jMipProfile, ICellularRadio::KEY_MIP_MNAAASPI); +        splitAndAssign(vLine[6], "MN-HA SPI", jMipProfile, ICellularRadio::KEY_MIP_MNHASPI);          //Reverse Tunneling          sLine = vLine[7];          vParts = MTS::Text::split(sLine, ':', 2);          if(vParts.size() == 2 && vParts[0] == "Rev Tun") {              if(vParts[1] == "1") { -                jMipProfile[KEY_MIP_REVTUN] = true; +                jMipProfile[ICellularRadio::KEY_MIP_REVTUN] = true;              } else { -                jMipProfile[KEY_MIP_REVTUN] = false; +                jMipProfile[ICellularRadio::KEY_MIP_REVTUN] = false;              }          } else {              printWarning("%s| Unable to parse Reverse Tunneling from line [%s]", getName().c_str(), sLine.c_str()); @@ -379,9 +379,9 @@ CellularRadio::CODE CdmaRadio::getMipProfile(Json::Value& jMipProfile) {          vParts = MTS::Text::split(sLine, ':', 2);          if(vParts.size() == 2 && vParts[0] == "MN-AAA SS") {              if(vParts[1] == "Set") { -                jMipProfile[KEY_MIP_MNAAASS] = true; +                jMipProfile[ICellularRadio::KEY_MIP_MNAAASS] = true;              } else { -                jMipProfile[KEY_MIP_MNAAASS] = false; +                jMipProfile[ICellularRadio::KEY_MIP_MNAAASS] = false;              }          } else {              printWarning("%s| Unable to parse MN-AAA SS from line [%s]", getName().c_str(), sLine.c_str()); @@ -392,9 +392,9 @@ CellularRadio::CODE CdmaRadio::getMipProfile(Json::Value& jMipProfile) {          vParts = MTS::Text::split(sLine, ':', 2);          if(vParts.size() == 2 && vParts[0] == "MN-HA SS") {              if(vParts[1] == "Set") { -                jMipProfile[KEY_MIP_MNHASS] = true; +                jMipProfile[ICellularRadio::KEY_MIP_MNHASS] = true;              } else { -                jMipProfile[KEY_MIP_MNHASS] = false; +                jMipProfile[ICellularRadio::KEY_MIP_MNHASS] = false;              }          } else {              printWarning("%s| Unable to parse MN-HA SS from line [%s]", getName().c_str(), sLine.c_str()); @@ -406,7 +406,7 @@ CellularRadio::CODE CdmaRadio::getMipProfile(Json::Value& jMipProfile) {  } -CellularRadio::CODE CdmaRadio::setMipActiveProfile(const Json::Value& jArgs) { +ICellularRadio::CODE CdmaRadio::setMipActiveProfile(const Json::Value& jArgs) {      printTrace("%s| Set MIP Active Profile", getName().c_str());      if(!jArgs["activeProfile"].isString()) { @@ -417,7 +417,7 @@ CellularRadio::CODE CdmaRadio::setMipActiveProfile(const Json::Value& jArgs) {      sCmd += jArgs["activeProfile"].asString();      std::string sResult = sendCommand(sCmd); -    size_t end = sResult.find(RSP_OK); +    size_t end = sResult.find(ICellularRadio::RSP_OK);      if (end == std::string::npos) {          printWarning("%s| Unable to set Active profile for radio using command [%s]", getName().c_str(), sCmd.c_str());          return FAILURE; @@ -426,7 +426,7 @@ CellularRadio::CODE CdmaRadio::setMipActiveProfile(const Json::Value& jArgs) {      return SUCCESS;  } -CellularRadio::CODE CdmaRadio::setMipNai(const Json::Value& jArgs) { +ICellularRadio::CODE CdmaRadio::setMipNai(const Json::Value& jArgs) {      printTrace("%s| Set MIP NAI", getName().c_str());      if(!jArgs["nai"].isString()) { @@ -437,7 +437,7 @@ CellularRadio::CODE CdmaRadio::setMipNai(const Json::Value& jArgs) {      sCmd += jArgs["nai"].asString() + ",1";      std::string sResult = sendCommand(sCmd); -    size_t end = sResult.find(RSP_OK); +    size_t end = sResult.find(ICellularRadio::RSP_OK);      if (end == std::string::npos) {          printWarning("%s| Unable to set NAI for radio using command [%s]", getName().c_str(), sCmd.c_str());          return FAILURE; @@ -446,7 +446,7 @@ CellularRadio::CODE CdmaRadio::setMipNai(const Json::Value& jArgs) {      return SUCCESS;  } -CellularRadio::CODE CdmaRadio::setMipHomeIp(const Json::Value& jArgs) { +ICellularRadio::CODE CdmaRadio::setMipHomeIp(const Json::Value& jArgs) {      printTrace("%s| Set MIP Home IP", getName().c_str());      if(!jArgs["homeIp"].isString()) { @@ -457,7 +457,7 @@ CellularRadio::CODE CdmaRadio::setMipHomeIp(const Json::Value& jArgs) {      sCmd += jArgs["homeIp"].asString() + ",1";      std::string sResult = sendCommand(sCmd); -    size_t end = sResult.find(RSP_OK); +    size_t end = sResult.find(ICellularRadio::RSP_OK);      if (end == std::string::npos) {          printWarning("%s| Unable to set Home IP profile for radio using command [%s]", getName().c_str(), sCmd.c_str());          return FAILURE; @@ -466,7 +466,7 @@ CellularRadio::CODE CdmaRadio::setMipHomeIp(const Json::Value& jArgs) {      return SUCCESS;  } -CellularRadio::CODE CdmaRadio::setMipPrimaryHa(const Json::Value& jArgs) { +ICellularRadio::CODE CdmaRadio::setMipPrimaryHa(const Json::Value& jArgs) {      printTrace("%s| Set MIP Primary HA", getName().c_str());      if(!jArgs["primaryHa"].isString()) { @@ -477,7 +477,7 @@ CellularRadio::CODE CdmaRadio::setMipPrimaryHa(const Json::Value& jArgs) {      sCmd += jArgs["primaryHa"].asString() + ",1";      std::string sResult = sendCommand(sCmd); -    size_t end = sResult.find(RSP_OK); +    size_t end = sResult.find(ICellularRadio::RSP_OK);      if (end == std::string::npos) {          printWarning("%s| Unable to set Primary HA for radio using command [%s]", getName().c_str(), sCmd.c_str());          return FAILURE; @@ -486,7 +486,7 @@ CellularRadio::CODE CdmaRadio::setMipPrimaryHa(const Json::Value& jArgs) {      return SUCCESS;  } -CellularRadio::CODE CdmaRadio::setMipSecondaryHa(const Json::Value& jArgs) { +ICellularRadio::CODE CdmaRadio::setMipSecondaryHa(const Json::Value& jArgs) {      printTrace("%s| Set MIP Secondary HA", getName().c_str());      if(!jArgs["secondaryHa"].isString()) { @@ -497,7 +497,7 @@ CellularRadio::CODE CdmaRadio::setMipSecondaryHa(const Json::Value& jArgs) {      sCmd += jArgs["secondaryHa"].asString() + ",1";      std::string sResult = sendCommand(sCmd); -    size_t end = sResult.find(RSP_OK); +    size_t end = sResult.find(ICellularRadio::RSP_OK);      if (end == std::string::npos) {          printWarning("%s| Unable to set Secondary HA for radio using command [%s]", getName().c_str(), sCmd.c_str());          return FAILURE; @@ -506,7 +506,7 @@ CellularRadio::CODE CdmaRadio::setMipSecondaryHa(const Json::Value& jArgs) {      return SUCCESS;  } -CellularRadio::CODE CdmaRadio::setMipMnAaaSpi(const Json::Value& jArgs) { +ICellularRadio::CODE CdmaRadio::setMipMnAaaSpi(const Json::Value& jArgs) {      printTrace("%s| Set MIP MN-AAA SPI", getName().c_str());      if(!jArgs["mnAaaSpi"].isString()) { @@ -517,7 +517,7 @@ CellularRadio::CODE CdmaRadio::setMipMnAaaSpi(const Json::Value& jArgs) {      sCmd += jArgs["mnAaaSpi"].asString() + ",1";      std::string sResult = sendCommand(sCmd); -    size_t end = sResult.find(RSP_OK); +    size_t end = sResult.find(ICellularRadio::RSP_OK);      if (end == std::string::npos) {          printWarning("%s| Unable to set MN-AAA SPI for radio using command [%s]", getName().c_str(), sCmd.c_str());          return FAILURE; @@ -526,7 +526,7 @@ CellularRadio::CODE CdmaRadio::setMipMnAaaSpi(const Json::Value& jArgs) {      return SUCCESS;  } -CellularRadio::CODE CdmaRadio::setMipMnHaSpi(const Json::Value& jArgs) { +ICellularRadio::CODE CdmaRadio::setMipMnHaSpi(const Json::Value& jArgs) {      printTrace("%s| Set MIP MN-HA SPI", getName().c_str());      if(!jArgs["mnHaSpi"].isString()) { @@ -537,7 +537,7 @@ CellularRadio::CODE CdmaRadio::setMipMnHaSpi(const Json::Value& jArgs) {      sCmd += jArgs["mnHaSpi"].asString() + ",1";      std::string sResult = sendCommand(sCmd); -    size_t end = sResult.find(RSP_OK); +    size_t end = sResult.find(ICellularRadio::RSP_OK);      if (end == std::string::npos) {          printWarning("%s| Unable to set MN-HA SPI for radio using command [%s]", getName().c_str(), sCmd.c_str());          return FAILURE; @@ -546,7 +546,7 @@ CellularRadio::CODE CdmaRadio::setMipMnHaSpi(const Json::Value& jArgs) {      return SUCCESS;  } -CellularRadio::CODE CdmaRadio::setMipRevTun(const Json::Value& jArgs) { +ICellularRadio::CODE CdmaRadio::setMipRevTun(const Json::Value& jArgs) {      printTrace("%s| Set MIP Rev Tun", getName().c_str());      if(!jArgs["revTun"].isString()) { @@ -557,7 +557,7 @@ CellularRadio::CODE CdmaRadio::setMipRevTun(const Json::Value& jArgs) {      sCmd += jArgs["revTun"].asString() + ",1";      std::string sResult = sendCommand(sCmd); -    size_t end = sResult.find(RSP_OK); +    size_t end = sResult.find(ICellularRadio::RSP_OK);      if (end == std::string::npos) {          printWarning("%s| Unable to set Rev Tun for radio using command [%s]", getName().c_str(), sCmd.c_str());          return FAILURE; @@ -566,7 +566,7 @@ CellularRadio::CODE CdmaRadio::setMipRevTun(const Json::Value& jArgs) {      return SUCCESS;  } -CellularRadio::CODE CdmaRadio::setMipMnAaaSs(const Json::Value& jArgs) { +ICellularRadio::CODE CdmaRadio::setMipMnAaaSs(const Json::Value& jArgs) {      printTrace("%s| Set MIP MN-AAA SS", getName().c_str());      if(!jArgs["mnAaaSs"].isString()) { @@ -577,7 +577,7 @@ CellularRadio::CODE CdmaRadio::setMipMnAaaSs(const Json::Value& jArgs) {      sCmd += jArgs["mnAaaSs"].asString() + ",1";      std::string sResult = sendCommand(sCmd); -    size_t end = sResult.find(RSP_OK); +    size_t end = sResult.find(ICellularRadio::RSP_OK);      if (end == std::string::npos) {          printWarning("%s| Unable to set MN-AAA SS for radio using command [%s]", getName().c_str(), sCmd.c_str());          return FAILURE; @@ -586,7 +586,7 @@ CellularRadio::CODE CdmaRadio::setMipMnAaaSs(const Json::Value& jArgs) {      return SUCCESS;  } -CellularRadio::CODE CdmaRadio::setMipMnHaSs(const Json::Value& jArgs) { +ICellularRadio::CODE CdmaRadio::setMipMnHaSs(const Json::Value& jArgs) {      printTrace("%s| Set MIP MN-HA SS", getName().c_str());      if(!jArgs["mnHaSs"].isString()) { @@ -597,7 +597,7 @@ CellularRadio::CODE CdmaRadio::setMipMnHaSs(const Json::Value& jArgs) {      sCmd += jArgs["mnHaSs"].asString() + ",1";      std::string sResult = sendCommand(sCmd); -    size_t end = sResult.find(RSP_OK); +    size_t end = sResult.find(ICellularRadio::RSP_OK);      if (end == std::string::npos) {          printWarning("%s| Unable to set MN-HA SS for radio using command [%s]", getName().c_str(), sCmd.c_str());          return FAILURE; @@ -606,7 +606,7 @@ CellularRadio::CODE CdmaRadio::setMipMnHaSs(const Json::Value& jArgs) {      return SUCCESS;  } -CellularRadio::CODE CdmaRadio::updateDc(const Json::Value& jArgs, UpdateCb& stepCb) { +ICellularRadio::CODE CdmaRadio::updateDc(const Json::Value& jArgs, UpdateCb& stepCb) {      printTrace("%s| Update Device Configuration", getName().c_str());      std::string sCarrier; @@ -616,7 +616,7 @@ CellularRadio::CODE CdmaRadio::updateDc(const Json::Value& jArgs, UpdateCb& step          return NOT_APPLICABLE;      } -    CellularRadio::CODE result = FAILURE; +    ICellularRadio::CODE result = FAILURE;      std::size_t pos = 0;      std::size_t end = 0; @@ -627,7 +627,7 @@ CellularRadio::CODE CdmaRadio::updateDc(const Json::Value& jArgs, UpdateCb& step              return true;          } -        end = allData.find(NL, pos); +        end = allData.find(ICellularRadio::NL, pos);          printTrace("%s| Update DC Callback Started", this->getName().c_str());          while(end != std::string::npos) { @@ -683,7 +683,7 @@ CellularRadio::CODE CdmaRadio::updateDc(const Json::Value& jArgs, UpdateCb& step                      stepCb(Json::Value("DC Error: update fails with other reasons"));                  }                  return false; -            }else if(sLine == RSP_ERROR) { +            }else if(sLine == ICellularRadio::RSP_ERROR) {                  result = ERROR;                  return false;              } @@ -692,7 +692,7 @@ CellularRadio::CODE CdmaRadio::updateDc(const Json::Value& jArgs, UpdateCb& step              if(next != std::string::npos) {                  pos = next;              } -            end = allData.find(NL, pos); +            end = allData.find(ICellularRadio::NL, pos);          }          printTrace("%s| Update DC Callback Finished", this->getName().c_str()); @@ -703,7 +703,7 @@ CellularRadio::CODE CdmaRadio::updateDc(const Json::Value& jArgs, UpdateCb& step      return result;  } -CellularRadio::CODE CdmaRadio::updatePrl(const Json::Value& jArgs, UpdateCb& stepCb) { +ICellularRadio::CODE CdmaRadio::updatePrl(const Json::Value& jArgs, UpdateCb& stepCb) {      printTrace("%s| Update Preferred Roaming List", getName().c_str());      std::string sCarrier; @@ -713,7 +713,7 @@ CellularRadio::CODE CdmaRadio::updatePrl(const Json::Value& jArgs, UpdateCb& ste          return NOT_APPLICABLE;      } -    CellularRadio::CODE result = FAILURE; +    ICellularRadio::CODE result = FAILURE;      std::size_t pos = 0;      std::size_t end = 0; @@ -724,7 +724,7 @@ CellularRadio::CODE CdmaRadio::updatePrl(const Json::Value& jArgs, UpdateCb& ste              return true;          } -        end = allData.find(NL, pos); +        end = allData.find(ICellularRadio::NL, pos);          printTrace("%s| Update PRL Callback Started", this->getName().c_str());          while(end != std::string::npos) { @@ -780,7 +780,7 @@ CellularRadio::CODE CdmaRadio::updatePrl(const Json::Value& jArgs, UpdateCb& ste                      stepCb(Json::Value("PRL Error: update fails with other reasons"));                  }                  return false; -            } else if(sLine == RSP_ERROR) { +            } else if(sLine == ICellularRadio::RSP_ERROR) {                  result = ERROR;                  return false;              } @@ -789,7 +789,7 @@ CellularRadio::CODE CdmaRadio::updatePrl(const Json::Value& jArgs, UpdateCb& ste              if(next != std::string::npos) {                  pos = next;              } -            end = allData.find(NL, pos); +            end = allData.find(ICellularRadio::NL, pos);          }          printTrace("%s| Update PRL Callback Finished", this->getName().c_str()); @@ -800,7 +800,7 @@ CellularRadio::CODE CdmaRadio::updatePrl(const Json::Value& jArgs, UpdateCb& ste      return result;  } -CellularRadio::CODE CdmaRadio::updateFumo(const Json::Value& jArgs, UpdateCb& stepCb) { +ICellularRadio::CODE CdmaRadio::updateFumo(const Json::Value& jArgs, UpdateCb& stepCb) {      printTrace("%s| Update Firmware Update Management Object", getName().c_str());      std::string sCarrier; @@ -810,7 +810,7 @@ CellularRadio::CODE CdmaRadio::updateFumo(const Json::Value& jArgs, UpdateCb& st          return NOT_APPLICABLE;      } -    CellularRadio::CODE result = FAILURE; +    ICellularRadio::CODE result = FAILURE;      std::size_t pos = 0;      std::size_t end = 0; @@ -821,7 +821,7 @@ CellularRadio::CODE CdmaRadio::updateFumo(const Json::Value& jArgs, UpdateCb& st              return true;          } -        end = allData.find(NL, pos); +        end = allData.find(ICellularRadio::NL, pos);          printTrace("%s| Update FUMO Callback Started", this->getName().c_str());          while(end != std::string::npos) { @@ -937,7 +937,7 @@ CellularRadio::CODE CdmaRadio::updateFumo(const Json::Value& jArgs, UpdateCb& st                  if(stepCb) {                      stepCb(Json::Value("FUMO Info: reporting of firmware update result to server"));                  } -            } else if(sLine == RSP_ERROR) { +            } else if(sLine == ICellularRadio::RSP_ERROR) {                  result = ERROR;                  return false;              } @@ -946,7 +946,7 @@ CellularRadio::CODE CdmaRadio::updateFumo(const Json::Value& jArgs, UpdateCb& st              if(next != std::string::npos) {                  pos = next;              } -            end = allData.find(NL, pos); +            end = allData.find(ICellularRadio::NL, pos);          }          printTrace("%s| Update FUMO Callback Finished", this->getName().c_str()); @@ -957,7 +957,7 @@ CellularRadio::CODE CdmaRadio::updateFumo(const Json::Value& jArgs, UpdateCb& st      return result;  } -CellularRadio::CODE CdmaRadio::resetHfa(const Json::Value& jArgs, UpdateCb& stepCb) { +ICellularRadio::CODE CdmaRadio::resetHfa(const Json::Value& jArgs, UpdateCb& stepCb) {      printTrace("%s| HFA Reset (after device reboot HFA will occur)", getName().c_str());      std::string sCarrier; @@ -971,7 +971,7 @@ CellularRadio::CODE CdmaRadio::resetHfa(const Json::Value& jArgs, UpdateCb& step          return INVALID_ARGS;      } -    CellularRadio::CODE result = FAILURE; +    ICellularRadio::CODE result = FAILURE;      std::size_t pos = 0;      std::size_t end = 0; @@ -992,7 +992,7 @@ CellularRadio::CODE CdmaRadio::resetHfa(const Json::Value& jArgs, UpdateCb& step              return true;          } -        end = allData.find(NL, pos); +        end = allData.find(ICellularRadio::NL, pos);          printTrace("%s| HFA Reset Callback Started", this->getName().c_str());          while(end != std::string::npos) { @@ -1032,10 +1032,10 @@ CellularRadio::CODE CdmaRadio::resetHfa(const Json::Value& jArgs, UpdateCb& step                      stepCb(Json::Value("RTN Done: Firmware DM - Session Completed Successfully"));                  }                  return false; -            } else if(sLine == RSP_ERROR) { +            } else if(sLine == ICellularRadio::RSP_ERROR) {                  result = ERROR;                  return false; -            } else if(sLine == RSP_OK) { +            } else if(sLine == ICellularRadio::RSP_OK) {                  //The Device will reboot now, so reset the connection                  if(stepCb) {                      stepCb(Json::Value("RTN Info: Resetting Radio")); @@ -1062,7 +1062,7 @@ CellularRadio::CODE CdmaRadio::resetHfa(const Json::Value& jArgs, UpdateCb& step              if(next != std::string::npos) {                  pos = next;              } -            end = allData.find(NL, pos); +            end = allData.find(ICellularRadio::NL, pos);          }          printTrace("%s| HFA Reset Callback Finished", this->getName().c_str()); @@ -1075,14 +1075,14 @@ CellularRadio::CODE CdmaRadio::resetHfa(const Json::Value& jArgs, UpdateCb& step      return result;  } -CellularRadio::CODE CdmaRadio::activate(const Json::Value& jArgs, UpdateCb& stepCb) { +ICellularRadio::CODE CdmaRadio::activate(const Json::Value& jArgs, UpdateCb& stepCb) {      printTrace("%s| Activation", getName().c_str());      std::string sActivationCmd;      std::string sCarrier;      getCarrier(sCarrier); -    if(sCarrier == VALUE_CARRIER_AERIS) { +    if(sCarrier == ICellularRadio::VALUE_CARRIER_AERIS) {          if(!jArgs["msid"].isString()) {              printError("%s| Arguments missing \"msid\"", getName().c_str()); @@ -1107,7 +1107,7 @@ CellularRadio::CODE CdmaRadio::activate(const Json::Value& jArgs, UpdateCb& step          }          //Set MDN & MSID -        CellularRadio::CODE code; +        ICellularRadio::CODE code;          code = setMdn(jArgs);          if(code != SUCCESS) {              return code; @@ -1122,15 +1122,15 @@ CellularRadio::CODE CdmaRadio::activate(const Json::Value& jArgs, UpdateCb& step          return SUCCESS; -    } else if(sCarrier == VALUE_CARRIER_VERIZON) { +    } else if(sCarrier == ICellularRadio::VALUE_CARRIER_VERIZON) {          sActivationCmd = "AT+CDV*22899\r"; -    } else if(sCarrier == VALUE_CARRIER_USCELLULAR) { +    } else if(sCarrier == ICellularRadio::VALUE_CARRIER_USCELLULAR) {          sActivationCmd = "AT+CDV*228\r";      } else {          return NOT_APPLICABLE;      } -    CellularRadio::CODE result = FAILURE; +    ICellularRadio::CODE result = FAILURE;      std::size_t pos = 0;      std::size_t end = 0; @@ -1153,7 +1153,7 @@ CellularRadio::CODE CdmaRadio::activate(const Json::Value& jArgs, UpdateCb& step              return true;          } -        end = allData.find(NL, pos); +        end = allData.find(ICellularRadio::NL, pos);          printTrace("%s| Activation Reset Callback Started", this->getName().c_str());          while(end != std::string::npos) { @@ -1162,7 +1162,7 @@ CellularRadio::CODE CdmaRadio::activate(const Json::Value& jArgs, UpdateCb& step              printTrace("%s| Line: [%s]", this->getName().c_str(), sLine.c_str()); -            if(sLine == RSP_OK) { +            if(sLine == ICellularRadio::RSP_OK) {                  if(stepCb) {                      stepCb(Json::Value("Activation Info: Over-the-Air Programming in Process"));                  } @@ -1194,7 +1194,7 @@ CellularRadio::CODE CdmaRadio::activate(const Json::Value& jArgs, UpdateCb& step                  }                  result = ERROR;                  return false; -            } else if(sLine == RSP_ERROR) { +            } else if(sLine == ICellularRadio::RSP_ERROR) {                  result = ERROR;                  return false;              } @@ -1203,7 +1203,7 @@ CellularRadio::CODE CdmaRadio::activate(const Json::Value& jArgs, UpdateCb& step              if(next != std::string::npos) {                  pos = next;              } -            end = allData.find(NL, pos); +            end = allData.find(ICellularRadio::NL, pos);          }          printTrace("%s| Activation Callback Finished", this->getName().c_str()); @@ -1214,7 +1214,7 @@ CellularRadio::CODE CdmaRadio::activate(const Json::Value& jArgs, UpdateCb& step      return result;  } -CellularRadio::CODE CdmaRadio::getNetworkStatus(Json::Value& jData) { +ICellularRadio::CODE CdmaRadio::getNetworkStatus(Json::Value& jData) {      printTrace("%s| Get Network Status", getName().c_str());      getCommonNetworkStats(jData); @@ -1222,11 +1222,11 @@ CellularRadio::CODE CdmaRadio::getNetworkStatus(Json::Value& jData) {      std::string sCarrier;      getCarrier(sCarrier); -    if(sCarrier == VALUE_CARRIER_SPRINT) { +    if(sCarrier == ICellularRadio::VALUE_CARRIER_SPRINT) {          Json::Value& jDebug = jData["debug"];          std::string sCmd("AT$DEBUG?");          std::string sResult = MTS::Text::trim(sendCommand(sCmd)); -        if (sResult.find(RSP_OK) != std::string::npos) { +        if (sResult.find(ICellularRadio::RSP_OK) != std::string::npos) {              std::vector<std::string> vCategories = MTS::Text::split(sResult, "\r\n\r\n");              for(size_t i = 0 ; i < vCategories.size(); i++) {                  std::vector<std::string> vLine = MTS::Text::split(vCategories[i], "\r\n"); diff --git a/src/MTS_IO_CellularRadio.cpp b/src/MTS_IO_CellularRadio.cpp index f89e673..3f0c037 100644 --- a/src/MTS_IO_CellularRadio.cpp +++ b/src/MTS_IO_CellularRadio.cpp @@ -18,125 +18,74 @@   *   */ -#include <mts/MTS_IO_CellularRadio.h> +#include "mts/MTS_IO_CellularRadio.h" + +#include <unistd.h> +  #include <mts/MTS_IO_MccMncTable.h>  #include <mts/MTS_Thread.h>  #include <mts/MTS_Timer.h>  #include <mts/MTS_Logger.h>  #include <mts/MTS_Text.h> -#include <mts/MTS_System.h> -#include <map> -#include <cstring> -#include <sstream> -#include <sys/file.h> -#include <errno.h> -#include <unistd.h> -  using namespace MTS::IO; -const char CellularRadio::ETX    = 0x03;  //Ends socket connection -const char CellularRadio::DLE    = 0x10;  //Escapes ETX and DLE within Payload -const char CellularRadio::CR     = 0x0D; -const char CellularRadio::NL     = 0x0A; -const char CellularRadio::CTRL_Z = 0x1A; - -const std::string CellularRadio::RSP_ERROR("ERROR"); -const std::string CellularRadio::RSP_OK("OK"); - - -const std::string CellularRadio::DEFAULT_RADIO_PORT("/dev/modem_at1"); -const std::string CellularRadio::DEFAULT_RADIO_DIR("/var/run/radio/"); -const std::string CellularRadio::VALUE_UNKNOWN("Unknown"); -const std::string CellularRadio::VALUE_UNAVAILABLE("Unavailable"); -const std::string CellularRadio::VALUE_NOT_SUPPORTED("Not Supported"); - -const std::string CellularRadio::VALUE_NOT_REGISTERED("NOT REGISTERED"); -const std::string CellularRadio::VALUE_REGISTERED("REGISTERED"); -const std::string CellularRadio::VALUE_SEARCHING("SEARCHING"); -const std::string CellularRadio::VALUE_DENIED("DENIED"); -const std::string CellularRadio::VALUE_ROAMING("ROAMING"); - -//Static Data -const std::string CellularRadio::KEY_TYPE("type");                    //!< GSM or CDMA -const std::string CellularRadio::KEY_CODE("code");                    //!< Product Code : H5, H6, C2, EV3, G3 -const std::string CellularRadio::KEY_MODEL("model");                  //!< Model : HE910, LE910, CE910, DE910, GE910 -const std::string CellularRadio::KEY_MANUFACTURER("manufacturer");    //!< Manufacturer: Telit -const std::string CellularRadio::KEY_HARDWARE("hardware");            //!< Radio Hardware Version -const std::string CellularRadio::KEY_FIRMWARE("firmware");            //!< Radio Firmware Version -const std::string CellularRadio::KEY_FIRMWARE_BUILD("firmwarebuild"); //!< Radio Firmware Build - -const std::string CellularRadio::KEY_CARRIER("carrier");   //!< Cellular Service Provider (Home Network) -const std::string CellularRadio::VALUE_CARRIER_VERIZON("Verizon"); -const std::string CellularRadio::VALUE_CARRIER_AERIS("Aeris"); -const std::string CellularRadio::VALUE_CARRIER_SPRINT("Sprint"); -const std::string CellularRadio::VALUE_CARRIER_USCELLULAR("U.S. Cellular"); -const std::string CellularRadio::VALUE_CARRIER_ATT("AT&T"); -const std::string CellularRadio::VALUE_CARRIER_TMOBILE("T-Mobile"); - -const std::string CellularRadio::KEY_IMEI("imei");          //!< International Mobile Station Equipment Identity -const std::string CellularRadio::KEY_MEID("meid");          //!< Mobile Equipment Identifier -const std::string CellularRadio::KEY_IMSI("imsi");          //!< International Mobile Subscriber Identity -const std::string CellularRadio::KEY_MSID("msid");          //!< Mobil Station ID / Mobile Identification Number (MSID/MIN) (CDMA-Only) -const std::string CellularRadio::KEY_MDN("mdn");            //!< Mobile Directory Number : Actual phone number dialed to reach radio -const std::string CellularRadio::KEY_ICCID("iccid");        //!< Integrated Circuit Card Identifier -const std::string CellularRadio::KEY_MSL("msl");            //!< Master Subsidy Lock - -//Dynamic Data -const std::string CellularRadio::KEY_ROAMING("roaming");    //!< Indicates whether or not using Home Network -const std::string CellularRadio::KEY_DATETIME("datetime");  //!< Date and Time from tower -const std::string CellularRadio::KEY_SERVICE("service");    //!< Service Connection Type [GPRS, EGPRS, WCDMA, HSDPA, 1xRTT, EVDO] -const std::string CellularRadio::KEY_NETWORK("network");    //!< Cellular Service Provider -const std::string CellularRadio::KEY_NETWORK_REG("netreg"); //!< Network Registration -const std::string CellularRadio::KEY_CID("cid");            //!< Cellular ID (Tower) in HEX -const std::string CellularRadio::KEY_LAC("lac");            //!< Location Area Code in HEX -const std::string CellularRadio::KEY_RAC("rac");            //!< Routing Area Code in HEX -const std::string CellularRadio::KEY_RSSI("rssi");          //!< Signal Strength -const std::string CellularRadio::KEY_RSSIDBM("rssidBm");    //!< Signal Strength in dBm -const std::string CellularRadio::KEY_MCC("mcc");            //!< Country Code -const std::string CellularRadio::KEY_MNC("mnc");            //!< Operator Code -const std::string CellularRadio::KEY_CHANNEL("channel");    //!< ARFCN or UARFCN Assigned Radio Channel -const std::string CellularRadio::KEY_TXPWR("txpwr");        //!< Transmit Power -const std::string CellularRadio::KEY_PSC("psc");            //!< Active Primary Synchronization Code (PSC) -const std::string CellularRadio::KEY_ECIO("ecio");          //!< Active Ec/Io (chip energy per total wideband power in dBm) -const std::string CellularRadio::KEY_RSCP("rscp");          //!< Active RSCP (Received Signal Code Power in dBm) -const std::string CellularRadio::KEY_DRX("drx");            //!< Discontinuous reception cycle length (ms) -const std::string CellularRadio::KEY_MM("mm");              //!< Mobility Management State -const std::string CellularRadio::KEY_RR("rr");              //!< Radio Resource State -const std::string CellularRadio::KEY_NOM("nom");            //!< Network Operator Mode -const std::string CellularRadio::KEY_ABND("abnd");          //!< Active Band -const std::string CellularRadio::KEY_BLER("bler");          //!< Block Error Rate (percentage) -const std::string CellularRadio::KEY_SD("sd");              //!< Service Domain -const std::string CellularRadio::KEY_DEBUG("debug");        //!< Debug Information - -const std::string CellularRadio::KEY_MIP("mipProfile");                      //!< Mobile IP Information -const std::string CellularRadio::KEY_MIP_ID("id");                           //!< Mobile IP ID -const std::string CellularRadio::KEY_MIP_ENABLED("enabled");                 //!< Mobile IP Enabled/Disabled -const std::string CellularRadio::KEY_MIP_NAI("nai");                         //!< Network Access Identifier -const std::string CellularRadio::KEY_MIP_HOMEADDRESS("homeAddress");         //!< Home Address -const std::string CellularRadio::KEY_MIP_PRIMARYHA("primaryAddress");        //!< Primary Home Agent -const std::string CellularRadio::KEY_MIP_SECONDARYHA("secondaryAddress");    //!< Secondary Home Agent -const std::string CellularRadio::KEY_MIP_MNAAASPI("mnAaaSpi");               //!< Mobile Node Authentication, Authorization, and Accounting Server Security Parameter Index -const std::string CellularRadio::KEY_MIP_MNHASPI("mnHaSpi");                 //!< Mobile Node Home Agent Security Server Parameter Index -const std::string CellularRadio::KEY_MIP_REVTUN("revTun");                   //!< Reverse Tunneling Enabled -const std::string CellularRadio::KEY_MIP_MNAAASS("mnAaaSs");                 //!< Mobile Node Authentication, Authorization, and Accounting Server Shared Secret -const std::string CellularRadio::KEY_MIP_MNHASS("mnHaSs");                   //!< Mobile Node Home Agent Shared Secret - -const std::string CellularRadio::VALUE_TYPE_GSM("GSM"); -const std::string CellularRadio::VALUE_TYPE_LTE("LTE"); -const std::string CellularRadio::VALUE_TYPE_CDMA("CDMA"); - -const std::string CellularRadio::VALUE_SD_NO_SERVICE("NO SERVICE"); -const std::string CellularRadio::VALUE_SD_CS_ONLY("CS ONLY"); -const std::string CellularRadio::VALUE_SD_PS_ONLY("PS ONLY"); -const std::string CellularRadio::VALUE_SD_CSPS("CS+PS"); - -const std::string CellularRadio::VALUE_ABND_GSM_850("GSM 850"); -const std::string CellularRadio::VALUE_ABND_GSM_900("GSM 900"); -const std::string CellularRadio::VALUE_ABND_DCS_1800("DCS 1800"); -const std::string CellularRadio::VALUE_ABND_PCS_1900("PCS 1900"); - -const std::vector<std::string> CellularRadio::DEFAULT_BAIL_STRINGS = { CellularRadio::RSP_OK, CellularRadio::RSP_ERROR }; +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) @@ -164,7 +113,7 @@ bool CellularRadio::initialize(uint32_t iTimeoutMillis) {      }      bool bEnabled; -    CODE eCode = getEcho(bEnabled); +    ICellularRadio::CODE eCode = getEcho(bEnabled);      if(eCode == SUCCESS && bEnabled) {          printDebug("%s| Disabling 'echo'", m_sName.c_str());          setEcho(false); @@ -174,20 +123,6 @@ bool CellularRadio::initialize(uint32_t iTimeoutMillis) {      return true;  } -bool CellularRadio::resetRadio(uint32_t iTimeoutMillis) { - -    printInfo("%s| Rebooting radio", m_sName.c_str()); -    if(sendBasicCommand("AT#REBOOT") == SUCCESS) { -        if(iTimeoutMillis > 5000) { -            MTS::Thread::sleep(5000); -            iTimeoutMillis -= 5000; -        } -        return resetConnection(iTimeoutMillis); -    } - -    return false; -} -  bool CellularRadio::resetConnection(uint32_t iTimeoutMillis) {      //Close Current Connection      if(!m_apIo.isNull()) { @@ -238,211 +173,12 @@ const std::string& CellularRadio::getName() const {      return m_sName;  } - -CellularRadio::CODE CellularRadio::getModel(std::string& sModel) { -    printTrace("%s| Get Model", m_sName.c_str()); -    //Always returns SUCCESS because the model should be m_sName -    sModel = m_sName; -    std::string sCmd("ATI4"); -    std::string sResult = CellularRadio::sendCommand(m_apIo, sCmd); -    if (sResult.find("OK") == std::string::npos) { -        printWarning("%s| Unable to get model from radio.  Returning [%s]", m_sName.c_str(), m_sName.c_str()); -        return SUCCESS; -    } else { -        sModel = CellularRadio::extractModelFromResult(sResult); -        if(sModel.size() == 0) { -            printWarning("%s| Unable to get model from radio.  Returning [%s]", m_sName.c_str(), m_sName.c_str()); -            return SUCCESS; -        } -    } - -    printDebug("%s| Extracted [%s] from [%s] query", m_sName.c_str(), sModel.c_str(), sCmd.c_str()); -    if(sModel != m_sName) { -        printWarning("%s| Model identified [%s] does not match expected [%s]. Returning [%s]", -                     m_sName.c_str(),  sModel.c_str(), m_sName.c_str(), sModel.c_str()); -    } - -    return SUCCESS; -} - -CellularRadio::CODE CellularRadio::convertModelToMtsShortCode(const std::string& sModel, std::string& sCode, CellularRadio *radioObject) { -    CODE eCode = FAILURE; - -    if(sModel.find("HE910-D") == 0) { -        sCode = "H5"; -        eCode = SUCCESS; -    } else if (sModel.find("HE910-EUD") == 0) { -        sCode = "H6"; -        eCode = SUCCESS; -    } else if (sModel.find("LE910-JN1") == 0) { -        sCode = "LDC3"; -        eCode = SUCCESS; -    } else if (sModel.find("LE866A1-JS") == 0) { -        sCode = "LSB3"; -        eCode = SUCCESS; -    } else if (sModel.find("LE910-NAG") == 0) { -        sCode = "LAT1"; -        eCode = SUCCESS; -    } else if (sModel.find("LE910C4-NF") == 0) { -        sCode = "L4N1"; -        eCode = SUCCESS; -    } else if (sModel.find("LE910-NA1") == 0) { -        if (NULL == radioObject) { -            sCode = VALUE_NOT_SUPPORTED; -            eCode = ERROR; -        } else { -            std::string sValue; -            eCode = radioObject->getActiveFirmware(sValue); -            if (eCode == SUCCESS) { -                sCode = "LNA3"; -            } else { -                sCode = "LAT3"; -            } -        } -        eCode = SUCCESS; -    } else if (sModel.find("LE910-SVG") == 0) { -        sCode = "LVW2"; -        eCode = SUCCESS; -    } else if (sModel.find("LE910C1-NS") == 0) { -    	sCode = "LSP3"; -    	eCode = SUCCESS; -    } else if (sModel.find("LE910C1-AP") == 0) { -    	sCode = "LAP3"; -    	eCode = SUCCESS; -    } else if (sModel.find("ME910C1-NA") == 0) { -        sCode = "MAT1"; -        eCode = SUCCESS; -    } else if (sModel.find("ME910C1-NV") == 0) { -        sCode = "MVW1"; -        eCode = SUCCESS; -    } else if (sModel.find("ME910C1-WW") == 0) { -        sCode = "MNG2"; -        eCode = SUCCESS; -    } else if (sModel.find("LE910-EUG") == 0) { -        sCode = "LEU1"; -        eCode = SUCCESS; -    } else if (sModel.find("LE910C4-EU") == 0) { -        sCode = "L4E1"; -        eCode = SUCCESS; -    } else if (sModel.find("LE910-EU1") == 0) { -        sCode = "LEU3"; -        eCode = SUCCESS; -    } else if (sModel.find("GE910") == 0) { -        sCode = "G3"; -        eCode = SUCCESS; -    } else if (sModel.find("CE910") == 0) { -        sCode = "C2"; -        eCode = SUCCESS; -    } else if (sModel.find("DE910") == 0) { -        sCode = "EV3"; -        eCode = SUCCESS; -    } else { -        sCode = VALUE_NOT_SUPPORTED; -        printError("RADIO| Could not identify MTS short code from model. [%s]", sModel.c_str()); -        eCode = ERROR; -    } -    return eCode; -} - -CellularRadio::CODE CellularRadio::convertServiceDomainToString(SERVICEDOMAIN eSd, std::string& sSd) { -    CODE eCode = FAILURE; -    switch(eSd) { -        case NO_SERVICE: sSd = VALUE_SD_NO_SERVICE; eCode = SUCCESS; break; -        case CS_ONLY: sSd = VALUE_SD_CS_ONLY; eCode = SUCCESS; break; -        case PS_ONLY: sSd = VALUE_SD_PS_ONLY; eCode = SUCCESS; break; -        case CSPS: sSd = VALUE_SD_CSPS; eCode = SUCCESS; break; -        default: sSd = VALUE_UNKNOWN; eCode = FAILURE; break; -    } -    return eCode; -} - -CellularRadio::CODE CellularRadio::convertActiveBandToString(ACTIVEBAND eBand, std::string& sBand) { -    CODE eCode = FAILURE; -    switch(eBand) { -        case GSM_850: sBand = VALUE_ABND_GSM_850; eCode = SUCCESS; break; -        case GSM_900: sBand = VALUE_ABND_GSM_900; eCode = SUCCESS; break; -        case DCS_1800: sBand = VALUE_ABND_DCS_1800; eCode = SUCCESS; break; -        case PCS_1900: sBand = VALUE_ABND_PCS_1900; eCode = SUCCESS; break; -        default: sBand = VALUE_UNKNOWN; eCode = FAILURE; break; -    } -    return eCode; -} - -CellularRadio::CODE CellularRadio::convertModelToType(const std::string& sModel, std::string& sType) { -    CODE eCode = FAILURE; -    sType = VALUE_NOT_SUPPORTED; - -    if(sModel.find("HE910-D") == 0) { -        sType = VALUE_TYPE_GSM; -        eCode = SUCCESS; -    } else if (sModel.find("HE910-EUD") == 0) { -        sType = VALUE_TYPE_GSM; -        eCode = SUCCESS; -    } else if (sModel.find("LE910-JN1") == 0) { -        sType = VALUE_TYPE_LTE; -        eCode = SUCCESS; -    } else if (sModel.find("LE866A1-JS") == 0) { -        sType = VALUE_TYPE_LTE; -        eCode = SUCCESS; -    } else if (sModel.find("LE910-NAG") == 0) { -        sType = VALUE_TYPE_LTE; -        eCode = SUCCESS; -    } else if (sModel.find("LE910C4-NF") == 0) { -        sType = VALUE_TYPE_LTE; -        eCode = SUCCESS; -    } else if (sModel.find("LE910-NA1") == 0) { -        sType = VALUE_TYPE_LTE; -        eCode = SUCCESS; -    } else if (sModel.find("LE910-SVG") == 0) { -        sType = VALUE_TYPE_LTE; -        eCode = SUCCESS; -    } else if (sModel.find("LE910-EUG") == 0) { -        sType = VALUE_TYPE_LTE; -        eCode = SUCCESS; -    } else if (sModel.find("LE910C4-EU") == 0) { -        sType = VALUE_TYPE_LTE; -        eCode = SUCCESS; -    } else if (sModel.find("LE910-EU1") == 0) { -        sType = VALUE_TYPE_LTE; -        eCode = SUCCESS; -    } else if (sModel.find("LE910C1-NS") == 0) { -    	sType = VALUE_TYPE_LTE; -    	eCode = SUCCESS; -    } else if (sModel.find("LE910C1-AP") == 0) { -    	sType = VALUE_TYPE_LTE; -    	eCode = SUCCESS; -    } else if (sModel.find("ME910C1-NA") == 0) { -        sType = VALUE_TYPE_LTE; -        eCode = SUCCESS; -    } else if (sModel.find("ME910C1-NV") == 0) { -        sType = VALUE_TYPE_LTE; -        eCode = SUCCESS; -    } else if (sModel.find("ME910C1-WW") == 0) { -        sType = VALUE_TYPE_LTE; -        eCode = SUCCESS; -    } else if (sModel.find("GE910") == 0) { -        sType = VALUE_TYPE_GSM; -        eCode = SUCCESS; -    } else if (sModel.find("CE910") == 0) { -        sType = VALUE_TYPE_CDMA; -        eCode = SUCCESS; -    } else if (sModel.find("DE910") == 0) { -        sType = VALUE_TYPE_CDMA; -        eCode = SUCCESS; -    } else { -        sType = VALUE_TYPE_GSM; -        eCode = ERROR; -        printError("RADIO| Could not identify type from model. [%s].  Assuming [%s]", sModel.c_str(), sType.c_str()); -    } -    return eCode; -} - -CellularRadio::CODE CellularRadio::getFirmware(std::string& sFirmware) { +ICellularRadio::CODE CellularRadio::getFirmware(std::string& sFirmware) {      printTrace("%s| Get Firmware", m_sName.c_str()); -    sFirmware = VALUE_NOT_SUPPORTED; +    sFirmware = ICellularRadio::VALUE_NOT_SUPPORTED;      std::string sCmd("AT+CGMR"); -    std::string sResult = CellularRadio::sendCommand(sCmd); -    size_t pos = sResult.find(RSP_OK); +    std::string sResult = sendCommand(sCmd); +    size_t pos = sResult.find(ICellularRadio::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; @@ -459,14 +195,14 @@ CellularRadio::CODE CellularRadio::getFirmware(std::string& sFirmware) {      return SUCCESS;  } -CellularRadio::CODE CellularRadio::getFirmwareBuild(std::string& sFirmwareBuild) { -    sFirmwareBuild = VALUE_NOT_SUPPORTED; +ICellularRadio::CODE CellularRadio::getFirmwareBuild(std::string& sFirmwareBuild) { +    sFirmwareBuild = ICellularRadio::VALUE_NOT_SUPPORTED;      return FAILURE;  } -CellularRadio::CODE CellularRadio::getHardware(std::string& sHardware) { +ICellularRadio::CODE CellularRadio::getHardware(std::string& sHardware) {      printTrace("%s| Get Hardware", m_sName.c_str()); -    sHardware = VALUE_NOT_SUPPORTED; +    sHardware = ICellularRadio::VALUE_NOT_SUPPORTED;      if(m_sFirmware.size() == 0) {          getFirmware(m_sFirmware); @@ -478,12 +214,12 @@ CellularRadio::CODE CellularRadio::getHardware(std::string& sHardware) {      return FAILURE;  } -CellularRadio::CODE CellularRadio::getManufacturer(std::string& sManufacturer) { +ICellularRadio::CODE CellularRadio::getManufacturer(std::string& sManufacturer) {      printTrace("%s| Get Manufacturer", m_sName.c_str()); -    sManufacturer = VALUE_NOT_SUPPORTED; +    sManufacturer = ICellularRadio::VALUE_NOT_SUPPORTED;      std::string sCmd("AT+GMI"); -    std::string sResult = CellularRadio::sendCommand(sCmd); -    size_t pos = sResult.find(RSP_OK); +    std::string sResult = sendCommand(sCmd); +    size_t pos = sResult.find(ICellularRadio::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; @@ -498,12 +234,15 @@ CellularRadio::CODE CellularRadio::getManufacturer(std::string& sManufacturer) {      return SUCCESS;  } -CellularRadio::CODE CellularRadio::getImei(std::string& sImei) { +ICellularRadio::CODE CellularRadio::getImei(std::string& sImei) {      printTrace("%s| Get IMEI", m_sName.c_str()); -    sImei = VALUE_NOT_SUPPORTED; +    sImei = ICellularRadio::VALUE_NOT_SUPPORTED; + +    // AT+CGSN execution can take up to 300ms according to the Quectel datasheet. Setting timeout to 500ms just for sure.      std::string sCmd("AT+CGSN"); -    std::string sResult = CellularRadio::sendCommand(sCmd); -    size_t pos = sResult.find(RSP_OK); +    std::string sResult = sendCommand(sCmd, DEFAULT_BAIL_STRINGS, 500); + +    size_t pos = sResult.find(ICellularRadio::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; @@ -518,17 +257,20 @@ CellularRadio::CODE CellularRadio::getImei(std::string& sImei) {      return SUCCESS;  } -CellularRadio::CODE CellularRadio::getMeid(std::string& sMeid) { +ICellularRadio::CODE CellularRadio::getMeid(std::string& sMeid) {      printTrace("%s| Get MEID", m_sName.c_str());      return getImei(sMeid);  } -CellularRadio::CODE CellularRadio::getImsi(std::string& sImsi) { +ICellularRadio::CODE CellularRadio::getImsi(std::string& sImsi) {      printTrace("%s| Get IMSI", m_sName.c_str()); -    sImsi = VALUE_NOT_SUPPORTED; +    sImsi = ICellularRadio::VALUE_NOT_SUPPORTED; + +    // AT+CIMI execution can take up to 300ms according to the Quectel datasheet. Setting timeout to 500ms just for sure.      std::string sCmd("AT+CIMI"); -    std::string sResult = CellularRadio::sendCommand(sCmd); -    size_t pos = sResult.find(RSP_OK); +    std::string sResult = sendCommand(sCmd, DEFAULT_BAIL_STRINGS, 500); + +    size_t pos = sResult.find(ICellularRadio::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; @@ -543,76 +285,65 @@ CellularRadio::CODE CellularRadio::getImsi(std::string& sImsi) {      return SUCCESS;  } -CellularRadio::CODE CellularRadio::getSimStatus(std::string& sSimStatus) { +ICellularRadio::CODE CellularRadio::getSimStatus(std::string& sSimStatus) {      printTrace("%s| Get SIM Status", getName().c_str()); -    sSimStatus = VALUE_UNKNOWN; +    sSimStatus = ICellularRadio::VALUE_UNKNOWN;      return FAILURE;  } -CellularRadio::CODE CellularRadio::getIccid(std::string& sIccid) { -    printTrace("%s| Get ICCID", m_sName.c_str()); -    sIccid = VALUE_NOT_SUPPORTED; -    std::string sCmd("AT#CCID"); -    std::string sResult = CellularRadio::sendCommand(sCmd); -    size_t end = sResult.find(RSP_OK); -    if (end == std::string::npos) { -        printWarning("%s| Unable to get ICCID from radio using command [%s]", m_sName.c_str(), sCmd.c_str()); -        return FAILURE; -    } +ICellularRadio::CODE CellularRadio::getSimStatusSummary(Json::Value& jData) { +    bool bIsSimInserted = false; +    bool bIsSimLocked = true; +    int iAttemptsPin = 0; +    int iAttemptsPuk = 0; +    std::string sSimLockStatus; +    ICellularRadio::CODE retCode; -    size_t start = sResult.find("#CCID:"); -    if(start != std::string::npos) { -        start += sizeof("#CCID:"); -        sIccid = MTS::Text::trim(sResult.substr(start, end-start)); -        if(sIccid.size() == 0) { -            printWarning("%s| Unable to get ICCID from radio using command [%s]", m_sName.c_str(), sCmd.c_str()); -            return FAILURE; +    do { +        retCode = getIsSimInserted(bIsSimInserted); +        if (retCode != SUCCESS) { +            break;          } -    } -    return SUCCESS; -} -CellularRadio::CODE CellularRadio::getService(std::string& sService) { -    printTrace("%s| Get Service", m_sName.c_str()); -    sService = VALUE_NOT_SUPPORTED; -    std::string sCmd("AT#PSNT?"); -    std::string sResult = CellularRadio::sendCommand(sCmd); -    size_t end = sResult.find(RSP_OK); -    if (end == std::string::npos) { -        printWarning("%s| Unable to get Service from radio using command [%s]", m_sName.c_str(), sCmd.c_str()); -        return FAILURE; -    } +        if (!bIsSimInserted) { +            // There is no left much to do. Return one field only. +            jData[KEY_IS_SIM_INSERTED] = bIsSimInserted; +            break; +        } -    size_t start = sResult.find(","); -    if(start != std::string::npos) { -        start += 1; //comma -        std::string sPsnt = MTS::Text::trim(sResult.substr(start, end-start)); -        int32_t iService; -        sscanf(sPsnt.c_str(), "%d", &iService); - -        switch(iService) { -            case 0: sService = "GPRS"; break; -            case 1: sService = "EGPRS"; break; -            case 2: sService = "WCDMA"; break; -            case 3: sService = "HSDPA"; break; -            case 4: sService = "LTE"; break; -            default: sService = VALUE_UNKNOWN; break; +        // The following code assumes that the SIM card is inserted +        retCode = getSimLockStatus(sSimLockStatus); +        if (retCode != SUCCESS) { +            break;          } -        printDebug("%s| Service ID: [%d][%s]", m_sName.c_str(), iService, sService.c_str()); -    } -    return SUCCESS; +        bIsSimLocked = (sSimLockStatus != "READY");  // SIM PIN, SIM PUK or other values + +        retCode = getSimLockAttempts(iAttemptsPin, iAttemptsPuk); +        if (retCode != SUCCESS) { +            break; +        } + +        // Everything fetched successfully. Populate the jData object +        jData[KEY_IS_SIM_INSERTED] = bIsSimInserted; +        jData[KEY_IS_SIM_LOCKED] = bIsSimLocked; +        jData[KEY_SIM_LOCK_STATUS] = sSimLockStatus; +        jData[KEY_ATTEMPTS_PIN] = iAttemptsPin; +        jData[KEY_ATTEMPTS_PUK] = iAttemptsPuk; +    } while (false); + +    return retCode;  } -CellularRadio::CODE CellularRadio::getLac(std::string& sLac) { +ICellularRadio::CODE CellularRadio::getLac(std::string& sLac) {      Json::Value jData;      printTrace("%s| Get LAC", m_sName.c_str()); -    sLac = VALUE_NOT_SUPPORTED; +    sLac = ICellularRadio::VALUE_NOT_SUPPORTED;      if(getNetworkStatus(jData) == SUCCESS) { -        if(jData.isMember(KEY_LAC)) { -            sLac = jData[KEY_LAC].asString(); +        if(jData.isMember(ICellularRadio::KEY_LAC)) { +            sLac = jData[ICellularRadio::KEY_LAC].asString();              return SUCCESS;          }      } @@ -620,12 +351,15 @@ CellularRadio::CODE CellularRadio::getLac(std::string& sLac) {      return FAILURE;  } -CellularRadio::CODE CellularRadio::getMdn(std::string& sMdn) { +ICellularRadio::CODE CellularRadio::getMdn(std::string& sMdn) {      printTrace("%s| Get MDN", m_sName.c_str()); -    sMdn = VALUE_NOT_SUPPORTED; +    sMdn = ICellularRadio::VALUE_NOT_SUPPORTED; + +    // AT+CNUM execution can take up to 300ms according to the Quectel datasheet. Setting timeout to 500ms just for sure.      std::string sCmd("AT+CNUM"); -    std::string sResult = CellularRadio::sendCommand(sCmd); -    size_t end = sResult.find(RSP_OK); +    std::string sResult = sendCommand(sCmd, DEFAULT_BAIL_STRINGS, 500); + +    size_t end = sResult.find(ICellularRadio::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; @@ -651,7 +385,7 @@ CellularRadio::CODE CellularRadio::getMdn(std::string& sMdn) {      return SUCCESS;  } -CellularRadio::CODE CellularRadio::getMsid(std::string& sMsid) { +ICellularRadio::CODE CellularRadio::getMsid(std::string& sMsid) {      printTrace("%s| Get MSID", m_sName.c_str());      sMsid = ""; @@ -667,25 +401,25 @@ CellularRadio::CODE CellularRadio::getMsid(std::string& sMsid) {      return FAILURE;  } -CellularRadio::CODE CellularRadio::getType(std::string& sType) { +ICellularRadio::CODE CellularRadio::getType(std::string& sType) {      printTrace("%s| Get Type", m_sName.c_str()); -    sType = VALUE_NOT_SUPPORTED; +    sType = ICellularRadio::VALUE_NOT_SUPPORTED;      return FAILURE;  } -CellularRadio::CODE CellularRadio::getCarrier(std::string& sCarrier) { +ICellularRadio::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(); +            if(jData.isMember(ICellularRadio::KEY_MCC) && jData.isMember(ICellularRadio::KEY_MNC)) { +                std::string sMcc = jData[ICellularRadio::KEY_MCC].asString(); +                std::string sMnc = jData[ICellularRadio::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(); +                if(jLookup.isMember(ICellularRadio::KEY_CARRIER)) { +                    m_sCarrier = jLookup[ICellularRadio::KEY_CARRIER].asString();                  } else {                      printWarning("%s| MCC-MNC Lookup did not contain carrier", m_sName.c_str());                      return FAILURE; @@ -703,22 +437,22 @@ CellularRadio::CODE CellularRadio::getCarrier(std::string& sCarrier) {      return SUCCESS;  } -CellularRadio::CODE CellularRadio::getTower(std::string& sTower) { +ICellularRadio::CODE CellularRadio::getTower(std::string& sTower) {      Json::Value jData;      printTrace("%s| Get Tower", m_sName.c_str()); -    sTower = VALUE_NOT_SUPPORTED; +    sTower = ICellularRadio::VALUE_NOT_SUPPORTED;      if(getNetworkStatus(jData) == SUCCESS) { -        if(jData.isMember(KEY_CID)) { -            sTower = jData[KEY_CID].asString(); +        if(jData.isMember(ICellularRadio::KEY_CID)) { +            sTower = jData[ICellularRadio::KEY_CID].asString();              return SUCCESS;          }      }      return FAILURE;  } -CellularRadio::CODE CellularRadio::getTime(std::string& sDate, std::string& sTime, std::string& sTimeZone) { +ICellularRadio::CODE CellularRadio::getTime(std::string& sDate, std::string& sTime, std::string& sTimeZone) {      Json::Value jData;      printTrace("%s| Get Time", m_sName.c_str()); @@ -727,8 +461,8 @@ CellularRadio::CODE CellularRadio::getTime(std::string& sDate, std::string& sTim      sTimeZone = "";      std::string sCmd("AT+CCLK?"); -    std::string sResult = CellularRadio::sendCommand(sCmd); -    size_t end = sResult.find(RSP_OK); +    std::string sResult = sendCommand(sCmd); +    size_t end = sResult.find(ICellularRadio::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; @@ -793,7 +527,7 @@ CellularRadio::CODE CellularRadio::getTime(std::string& sDate, std::string& sTim      return FAILURE;  } -CellularRadio::CODE CellularRadio::getRoaming(bool& bRoaming) { +ICellularRadio::CODE CellularRadio::getRoaming(bool& bRoaming) {      Json::Value jData;      printTrace("%s| Get Roaming", m_sName.c_str()); @@ -807,25 +541,13 @@ CellularRadio::CODE CellularRadio::getRoaming(bool& bRoaming) {      return FAILURE;  } -CellularRadio::CODE CellularRadio::getNetwork(std::string& sNetwork) { -    Json::Value jData; - -    printTrace("%s| Get Network", m_sName.c_str()); -    sNetwork = VALUE_NOT_SUPPORTED; - -    if(getNetworkStatus(jData) == SUCCESS) { -        if(jData.isMember(KEY_NETWORK)) { -            sNetwork = jData[KEY_NETWORK].asString(); -            return SUCCESS; -        } -    } -    return FAILURE; -} - -CellularRadio::CODE CellularRadio::getSignalStrength(int32_t& rssi) { +ICellularRadio::CODE CellularRadio::getSignalStrength(int32_t& rssi) {      printTrace("%s| Get Signal Strength", m_sName.c_str()); + +    // AT+CSQ execution can take up to 300ms according to the Quectel datasheet. Setting timeout to 500ms just for sure.      std::string sCmd("AT+CSQ"); -    std::string sResult = sendCommand(sCmd); +    std::string sResult = sendCommand(sCmd, DEFAULT_BAIL_STRINGS, 500); +      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; @@ -845,53 +567,12 @@ CellularRadio::CODE CellularRadio::getSignalStrength(int32_t& rssi) {      return SUCCESS;  } -CellularRadio::CODE CellularRadio::getModemLocation(std::string& sLocation) { +ICellularRadio::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) { +ICellularRadio::CODE CellularRadio::getEcho(bool& bEnabled) {      printTrace("%s| Echo Test", m_sName.c_str());      std::string sResult = sendCommand("AT");      if(sResult.size() == 0) { @@ -907,8 +588,8 @@ CellularRadio::CODE CellularRadio::getEcho(bool& bEnabled) {      return SUCCESS;  } -CellularRadio::CODE CellularRadio::setEcho(bool bEnabled) { -    CODE eCode = FAILURE; +ICellularRadio::CODE CellularRadio::setEcho(bool bEnabled) { +    ICellularRadio::CODE eCode = FAILURE;      if(bEnabled) {          eCode = sendBasicCommand("ATE1");          m_bEchoEnabled = (eCode == SUCCESS ) ? true : m_bEchoEnabled; @@ -920,7 +601,7 @@ CellularRadio::CODE CellularRadio::setEcho(bool bEnabled) {      return eCode;  } -CellularRadio::CODE CellularRadio::getStaticInformation(Json::Value& jData) { +ICellularRadio::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()); @@ -928,268 +609,14 @@ CellularRadio::CODE CellularRadio::getStaticInformation(Json::Value& jData) {      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> - -*/ -CellularRadio::CODE CellularRadio::getNetworkStatus(Json::Value& jData) { -    int32_t iValue; -    std::string sValue; -    const uint32_t GSM_NETWORK_FORMAT = 14; -    const uint32_t WCDMA_NETWORK_FORMAT = 19; -    const uint32_t LTE_NETWORK_FORMAT = 16; - -    printTrace("%s| Get Network Status", m_sName.c_str()); - -    //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 (m_sName.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]", m_sName.c_str(), sCmd.c_str(), sResult.c_str()); -            printTrace("%s| Network Status:\n%s\n", m_sName.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", m_sName.c_str()); -            printTrace("%s| Network Status:\n%s\n", m_sName.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]", m_sName.c_str(), sCmd.c_str(), sResult.c_str()); -        printTrace("%s| Network Status:\n%s\n", m_sName.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]", m_sName.c_str(), sCmd.c_str(), sResult.c_str()); -        printTrace("%s| Network Status:\n%s\n", m_sName.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[KEY_MCC] = MTS::Text::strip(vPLMN[0], '"'); -            jData[KEY_MNC] = MTS::Text::strip(vPLMN[1], '"'); -        } - -        jData[KEY_CHANNEL] = vParts[1]; -    } - -    if (vParts.size() == GSM_NETWORK_FORMAT ) { -        //Parse as GSM Network Format -        jData[KEY_RSSIDBM] = vParts[2]; -        jData[KEY_LAC] =  vParts[3]; -        jData[KEY_RAC] = vParts[4]; -        jData[KEY_TXPWR] = vParts[5]; -        jData[KEY_MM] = vParts[6]; -        jData[KEY_RR] = vParts[7]; -        jData[KEY_NOM] = vParts[8]; -        jData[KEY_CID] = vParts[9]; -        jData[KEY_IMSI] = MTS::Text::strip(vParts[10], '"'); -        jData[KEY_NETWORK] = MTS::Text::strip(vParts[11], '"'); -        if(MTS::Text::parse(iValue, vParts[12]) && convertServiceDomainToString((SERVICEDOMAIN)iValue, sValue) == SUCCESS) { -            jData[KEY_SD] = sValue; -        } -        if(MTS::Text::parse(iValue, vParts[13]) && convertActiveBandToString((ACTIVEBAND)iValue, sValue) == SUCCESS) { -            jData[KEY_ABND] = sValue; -        } -      // 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) && (m_sName.find("ME910C1-WW") == std::string::npos)) { -        Json::Value jDebug; - -        //Parse as WCDMA Network Format - -        jDebug[KEY_PSC] = vParts[2]; -        jDebug[KEY_ECIO] = vParts[3]; -        jDebug[KEY_RSCP] = vParts[4]; - -        jData[KEY_RSSIDBM] = vParts[5]; -        jData[KEY_LAC] = vParts[6]; -        jData[KEY_RAC] = vParts[7]; - -        jDebug[KEY_TXPWR] = vParts[8]; -        jDebug[KEY_DRX] = vParts[9]; -        jDebug[KEY_MM] = vParts[10]; -        jDebug[KEY_RR] = vParts[11]; -        jDebug[KEY_NOM] = vParts[12]; - -        if(vParts[13].size() != 0) { -            jDebug[KEY_BLER] = vParts[13]; -        } else { -            jDebug[KEY_BLER] = "000"; -        } - -        jData[KEY_CID] = vParts[14]; -        jData[KEY_IMSI] = MTS::Text::strip(vParts[15], '"'); -        jData[KEY_NETWORK] = MTS::Text::strip(vParts[16], '"'); - -        // Get the radio band given the channel (UARFCN) -        RadioBandMap radioBandMap(vParts[1], CellularRadio::VALUE_TYPE_CDMA); -        jData[KEY_ABND] = radioBandMap.getRadioBandName(); - -        if(MTS::Text::parse(iValue, vParts[17]) && convertServiceDomainToString((SERVICEDOMAIN)iValue, sValue) == SUCCESS) { -            jDebug[KEY_SD] = sValue; -        } -        //Ignoring Active Set Values -        //  <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[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[KEY_RAC] = vParts[6]; -            vParts.erase(vParts.begin() + 6); -        } - -        jDebug["rsrp"] = vParts[2]; -        jDebug[KEY_RSSIDBM] = vParts[3]; -        jDebug["rsrq"] = vParts[4]; - -        jData["tac"] = vParts[5]; -        jDebug[KEY_TXPWR] = vParts[6]; -        jData[KEY_DRX] = vParts[7]; -        jDebug[KEY_MM] = vParts[8]; -        jDebug["rrc"] = vParts[9]; -        jData[KEY_CID] = MTS::Text::strip(vParts[10], '"'); -        jData[KEY_IMSI] = MTS::Text::strip(vParts[11], '"'); -        jData[KEY_NETWORK] = MTS::Text::strip(vParts[12], '"'); - -        // Get the radio band given the channel (EARFCN) -        RadioBandMap radioBandMap(vParts[1], CellularRadio::VALUE_TYPE_LTE); -        jData[KEY_ABND] = radioBandMap.getRadioBandName(); - -        jData[KEY_LAC] = queryLteLac(); - -        if(MTS::Text::parse(iValue, vParts[13]) && convertServiceDomainToString((SERVICEDOMAIN)iValue, sValue) == SUCCESS) { -            jDebug[KEY_SD] = sValue; -        } - -        jData[KEY_DEBUG] = jDebug; -    } - -    printTrace("%s| Network Status:\n%s\n", m_sName.c_str(), jData.toStyledString().c_str()); -    return SUCCESS; -} - -// Get the LAC for the LTE radio that's not in the #RFSTS response +// Get the LAC for the LTE radio that's not in the #RFSTS or +QENG response  std::string CellularRadio::queryLteLac() {      std::string CGREGstring;      std::string originalCGREG;      std::string result;      CGREGstring = queryCGREGstring(); -    if (CGREGstring == RSP_ERROR) { +    if (CGREGstring == ICellularRadio::RSP_ERROR) {          originalCGREG = "0";      } else {          originalCGREG = CGREGstring.at(CGREGstring.find(",") - 1); //Position right before first comma ("+CGREG: 0,1") @@ -1199,13 +626,13 @@ std::string CellularRadio::queryLteLac() {      setCGREG("2");      CGREGstring = queryCGREGstring(); -    if (CGREGstring == RSP_ERROR) { -        result = CellularRadio::VALUE_UNKNOWN; +    if (CGREGstring == ICellularRadio::RSP_ERROR) { +        result = ICellularRadio::VALUE_UNKNOWN;      } else { -        size_t start = CGREGstring.find(":") + 1; //Position right after "#RFSTS:" +        size_t start = CGREGstring.find(":") + 1; //Position right after "+CGREG:"          std::vector<std::string> vParts = MTS::Text::split(MTS::Text::trim(CGREGstring.substr(start)), ",");          if(vParts.size() < 3) { -            result = CellularRadio::VALUE_UNAVAILABLE; +            result = ICellularRadio::VALUE_UNAVAILABLE;          } else {              result = MTS::Text::strip(vParts[2], '"');          } @@ -1220,7 +647,7 @@ 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()); +        printDebug("%s| AT+CGREG=%s returned unexpected response: [%s][%s]", m_sName.c_str(), value.c_str(), sCmd.c_str(), cmdResult.c_str());      }  } @@ -1228,8 +655,8 @@ 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; +        printDebug("%s| AT+CGREG? returned unexpected response: [%s][%s]", m_sName.c_str(), sCmd.c_str(), cmdResult.c_str()); +        return ICellularRadio::RSP_ERROR;      }      return cmdResult;  } @@ -1238,51 +665,78 @@ void CellularRadio::getCommonNetworkStats(Json::Value& jData) {      bool bRoaming = false;      if(getRoaming(bRoaming) == SUCCESS) { -        jData[KEY_ROAMING] = bRoaming; +        jData[ICellularRadio::KEY_ROAMING] = bRoaming;      }      int32_t iRssi;      if(getSignalStrength(iRssi) == SUCCESS) { -        jData[KEY_RSSI] = iRssi; +        jData[ICellularRadio::KEY_RSSI] = iRssi;          int32_t dBm; -        if(!jData.isMember(KEY_RSSIDBM) && convertSignalStrengthTodBm(iRssi, dBm) == SUCCESS) { +        if(!jData.isMember(ICellularRadio::KEY_RSSIDBM) && convertSignalStrengthTodBm(iRssi, dBm) == SUCCESS) {              //Add RSSI in dBm format -            jData[KEY_RSSIDBM] = MTS::Text::format(dBm); +            jData[ICellularRadio::KEY_RSSIDBM] = MTS::Text::format(dBm);          }      }      std::string sService;      if(getService(sService) == SUCCESS) { -        jData[KEY_SERVICE] = sService; +        jData[ICellularRadio::KEY_SERVICE] = sService;      }      std::string sDate, sTime, sTimeZone;      if(getTime(sDate, sTime, sTimeZone) == SUCCESS) { -        jData[KEY_DATETIME] = sDate + " " + sTime + " GMT" + sTimeZone; +        jData[ICellularRadio::KEY_DATETIME] = sDate + " " + sTime + " GMT" + sTimeZone;      }      std::string sNetworkReg; -    CellularRadio::REGISTRATION eReg; +    REGISTRATION eReg;      if (getRegistration(eReg) == SUCCESS) {          if (convertRegistrationToString(eReg, sNetworkReg) == SUCCESS) { -            jData[CellularRadio::KEY_NETWORK_REG] = sNetworkReg; +            jData[ICellularRadio::KEY_NETWORK_REG] = sNetworkReg;          }      }  } +ICellularRadio::CODE CellularRadio::getSimLockStatus(std::string& sData) +{ +    printTrace("%s| Get SIM lock status", m_sName.c_str()); + +    // SIM card may introduce a delay to AT+CPIN? execution. Setting timeout to 1s as set in PPP chat patches. +    std::string sCmd("AT+CPIN?"); +    std::string sResult = sendCommand(sCmd, DEFAULT_BAIL_STRINGS, 1000); + +    const std::string sPrefix = "+CPIN: "; +    size_t start = sResult.find(sPrefix); +    size_t end = sResult.rfind(ICellularRadio::RSP_OK); + +    if (start == std::string::npos || end == std::string::npos) { +        printWarning("%s| Unable to get SIM lock status from radio using command [%s]", m_sName.c_str(), sCmd.c_str()); +        return FAILURE; +    } + +    start += sPrefix.size(); +    sData = MTS::Text::trim(sResult.substr(start, end-start)); +    if(sData.size() == 0) { +        printWarning("%s| Unable to get SIM lock status from radio using command [%s]", m_sName.c_str(), sCmd.c_str()); +        return FAILURE; +    } + +    return SUCCESS; +} +  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) { +    jData[ICellularRadio::KEY_MIP_ID] = 0; +    jData[ICellularRadio::KEY_MIP_ENABLED] = false; +    jData[ICellularRadio::KEY_MIP_NAI] = ICellularRadio::VALUE_UNKNOWN; +    jData[ICellularRadio::KEY_MIP_HOMEADDRESS] = ICellularRadio::VALUE_UNKNOWN; +    jData[ICellularRadio::KEY_MIP_PRIMARYHA] = ICellularRadio::VALUE_UNKNOWN; +    jData[ICellularRadio::KEY_MIP_SECONDARYHA] = ICellularRadio::VALUE_UNKNOWN; +    jData[ICellularRadio::KEY_MIP_MNAAASPI] = ICellularRadio::VALUE_UNKNOWN; +    jData[ICellularRadio::KEY_MIP_MNHASPI] = ICellularRadio::VALUE_UNKNOWN; +    jData[ICellularRadio::KEY_MIP_MNAAASS] = false; +    jData[ICellularRadio::KEY_MIP_MNHASS] = false; +} + +ICellularRadio::CODE CellularRadio::getRegistration(REGISTRATION& eRegistration) {      std::string sCmd;      std::string sResp; @@ -1316,168 +770,167 @@ CellularRadio::CODE CellularRadio::getRegistration(REGISTRATION& eRegistration)      return SUCCESS;  } -CellularRadio::CODE CellularRadio::convertRegistrationToString(REGISTRATION eRegistration, std::string& sRegistration) { +ICellularRadio::CODE CellularRadio::convertRegistrationToString(REGISTRATION eRegistration, std::string& sRegistration) { -    CODE eCode = FAILURE; +    ICellularRadio::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; +        case NOT_REGISTERED: sRegistration = ICellularRadio::VALUE_NOT_REGISTERED; eCode = SUCCESS; break; +        case REGISTERED: sRegistration = ICellularRadio::VALUE_REGISTERED; eCode = SUCCESS; break; +        case SEARCHING: sRegistration = ICellularRadio::VALUE_SEARCHING; eCode = SUCCESS; break; +        case DENIED: sRegistration = ICellularRadio::VALUE_DENIED; eCode = SUCCESS; break; +        case UNKNOWN: sRegistration = ICellularRadio::VALUE_UNKNOWN; eCode = SUCCESS; break; +        case ROAMING: sRegistration = ICellularRadio::VALUE_ROAMING; eCode = SUCCESS; break;      }      return eCode;  } -CellularRadio::CODE CellularRadio::validateMsl(const Json::Value& jArgs) { -    printTrace("%s| Validate MSL", m_sName.c_str()); - -    return NOT_APPLICABLE; -} - -CellularRadio::CODE CellularRadio::setMdn(const Json::Value& jArgs) { -    printTrace("%s| Set MDN", m_sName.c_str()); +ICellularRadio::CODE CellularRadio::unlockSimCard(const Json::Value& jArgs) { +    printTrace("%s| Unlock the SIM card using PIN code", m_sName.c_str()); -    if(!jArgs["mdn"].isString()) { +    if(!jArgs["pin"].isString()) {          return INVALID_ARGS;      } -    std::string sCmd("AT#SNUM=1,\""); -    sCmd += jArgs["mdn"].asString() + "\""; +    std::string sCmd = "AT+CPIN=" + jArgs["pin"].asString(); +    std::string sResult = sendCommand(sCmd, DEFAULT_BAIL_STRINGS, 5000); -    std::string sResult = sendCommand(sCmd, DEFAULT_BAIL_STRINGS, 1000); -    size_t end = sResult.find(RSP_OK); -    if (end == std::string::npos) { -        printWarning("%s| Unable to set MDN for radio using command [%s]", m_sName.c_str(), sCmd.c_str()); +    size_t pos = sResult.find(ICellularRadio::RSP_OK); +    if (pos == std::string::npos) { +        printWarning("%s| Failed to unlock the SIM card using command [%s]", m_sName.c_str(), sCmd.c_str());          return FAILURE;      }      return SUCCESS;  } -CellularRadio::CODE CellularRadio::setMsid(const Json::Value& jArgs) { +ICellularRadio::CODE CellularRadio::validateMsl(const Json::Value&) { +    printTrace("%s| Validate MSL", m_sName.c_str()); + +    return NOT_APPLICABLE; +} + +ICellularRadio::CODE CellularRadio::setMsid(const Json::Value&) {      printTrace("%s| Set MSID", m_sName.c_str());      return NOT_APPLICABLE;  } -CellularRadio::CODE CellularRadio::getMipProfile(Json::Value& jMipProfile) { +ICellularRadio::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& jArgs) { +ICellularRadio::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& jArgs) { +ICellularRadio::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& jArgs) { +ICellularRadio::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& jArgs) { +ICellularRadio::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& jArgs) { +ICellularRadio::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& jArgs) { +ICellularRadio::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& jArgs) { +ICellularRadio::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& jArgs) { +ICellularRadio::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& jArgs) { +ICellularRadio::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& jArgs) { +ICellularRadio::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& jArgs, UpdateCb& stepCb) { +ICellularRadio::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& jArgs, UpdateCb& stepCb) { +ICellularRadio::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& jArgs, UpdateCb& stepCb) { +ICellularRadio::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& jArgs, UpdateCb& stepCb) { +ICellularRadio::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& jArgs, UpdateCb& stepCb) { +ICellularRadio::CODE CellularRadio::activate(const Json::Value&, UpdateCb&) {      printTrace("%s| Activation", m_sName.c_str());      return NOT_APPLICABLE;  } -CellularRadio::CODE CellularRadio::setActiveFirmware(const Json::Value& jArgs) { +ICellularRadio::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) { +ICellularRadio::CODE CellularRadio::getActiveFirmware(std::string& sFwId) {      printTrace("%s| Get Active Firmware Image Number: not applicable", m_sName.c_str()); -    sFwId = VALUE_NOT_SUPPORTED; +    sFwId = ICellularRadio::VALUE_NOT_SUPPORTED;      return NOT_APPLICABLE;  } -CellularRadio::CODE CellularRadio::sendBasicCommand(const std::string& sCmd, int32_t iTimeoutMillis, const char& ESC) { +ICellularRadio::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) { +    } else if (response.find(ICellularRadio::RSP_OK) != std::string::npos) {          return SUCCESS; -    } else if (response.find(RSP_ERROR) != std::string::npos) { +    } else if (response.find(ICellularRadio::RSP_ERROR) != std::string::npos) {          return ERROR;      } else {          return FAILURE; @@ -1485,167 +938,11 @@ CellularRadio::CODE CellularRadio::sendBasicCommand(const std::string& sCmd, int  }  std::string CellularRadio::sendCommand(const std::string& sCmd, const std::vector<std::string>& vBail, int32_t timeoutMillis, const char& ESC) { -    return sendCommand(m_apIo, sCmd, vBail, timeoutMillis, ESC); -} - -std::string CellularRadio::sendCommand(MTS::AutoPtr<MTS::IO::Connection>& apIo, const std::string& sCmd, -                                       const std::vector<std::string>& vBail, int32_t timeoutMillis, const char& ESC) { -    IsNeedMoreData isNeedMoreData = [&vBail](const std::string& iterationData, const std::string& allData)->bool { -        for(size_t i = 0; i < vBail.size(); i++) { -            const std::string& sBail = vBail[i]; -            if(sBail.size() > 0) { -                if(allData.find(sBail) != std::string::npos) { -                    //Return when bail string is found -                    printTrace("RADIO| Found bail string [%s]", sBail.c_str()); -                    return false; -                } -            } -        } -        return true; -    }; - -    return sendCommand(apIo, sCmd, isNeedMoreData, timeoutMillis, ESC); +    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 sendCommand(m_apIo, sCmd, isNeedMoreData, timeoutMillis, ESC); -} - -std::string CellularRadio::sendCommand(MTS::AutoPtr<MTS::IO::Connection>& apIo, const std::string& sCmd, -                                       IsNeedMoreData& isNeedMoreData, int32_t timeoutMillis, const char& ESC) { -    if(MTS::Logger::getPrintLevel() >= MTS::Logger::PrintLevel::TRACE_LEVEL) { -        printTrace("RADIO| Sending command [%s]", sCmd.c_str()); -    } -    if(apIo.isNull()) { -        printError("RADIO| IO is not set in sendCommand"); -        return ""; -    } - -    int32_t iResult; -    if(ESC == 0x00) { -        iResult = apIo->write(sCmd.data(), sCmd.size()); -    } else { -        std::string sNewCmd(sCmd); -        sNewCmd.push_back(ESC); -        iResult = apIo->write(sNewCmd.data(), sNewCmd.size()); -    } - -    if(iResult == -1) { -        printError("RADIO| Failed to send command to radio"); -        return ""; -    } - -    bool done = false; -    const uint32_t capacity = 1024; -    char buffer[capacity]; -    std::string sResult; -    Timer timer; -    timer.start(); -    do { -        int32_t iterationTimeout = 100; -        int bytesRead = apIo->read((char*)buffer, capacity, iterationTimeout); -        if(bytesRead == -1) { -            printError("RADIO| Failed to read from radio"); -            break; -        } - -        std::string sIteration((char*)buffer, bytesRead); -        sResult += sIteration; - -        if(isNeedMoreData && !isNeedMoreData(sIteration, sResult)) { -            printTrace("RADIO| No more data needed"); -            return sResult; -        } -        if(timeoutMillis >= 0) { -            done = (timer.getMillis() >= (uint64_t)timeoutMillis); -        } else { -            //Do not stop looping until bail string is found -        } -    } while(!done); - -    //Timed out -    return sResult; -} - -CellularRadio::CODE CellularRadio::test(MTS::AutoPtr<MTS::IO::Connection>& apIo, uint32_t timeoutSeconds) { -    printTrace("RADIO| Basic Test"); -    uint32_t count = 0; -    std::string sCmd("AT"); -    do { -        std::string sResult = sendCommand(apIo, sCmd); -        if (sResult.find(RSP_OK) == std::string::npos) { -            printTrace("RADIO| Waiting for basic radio communication [%s] ...", sResult.c_str()); -        } else { -            break; -        } -        count++; -    } while (count < timeoutSeconds); - -    if(count == timeoutSeconds) { -        printWarning("RADIO| Basic radio communication FAILED"); -        return NO_RESPONSE; -    } -    return SUCCESS; -} - -std::string CellularRadio::extractModelFromResult(const std::string& sResult) { -    std::string sModel(CellularRadio::VALUE_NOT_SUPPORTED); - -    if(sResult.find("HE910-D") != std::string::npos) { -        sModel = "HE910-D"; -    } else if(sResult.find("HE910-EUD") != std::string::npos) { -        sModel = "HE910-EUD"; -    } else if(sResult.find("LE910-JN1") != std::string::npos) { -        sModel = "LE910-JN1"; -    } else if(sResult.find("LE866A1-JS") != std::string::npos) { -        sModel = "LE866A1-JS"; -    } else if(sResult.find("LE910-NAG") != std::string::npos) { -        sModel = "LE910-NAG"; -    } else if(sResult.find("LE910C4-NF") != std::string::npos) { -        sModel = "LE910C4-NF"; -    } else if(sResult.find("LE910-NA1") != std::string::npos) { -        sModel = "LE910-NA1"; -    } else if(sResult.find("ME910C1-NA") != std::string::npos) { -        sModel = "ME910C1-NA"; -    } else if(sResult.find("ME910C1-NV") != std::string::npos) { -        sModel = "ME910C1-NV"; -    } else if(sResult.find("ME910C1-WW") != std::string::npos) { -        sModel = "ME910C1-WW"; -    } else if(sResult.find("LE910-SVG") != std::string::npos) { -        sModel = "LE910-SVG"; -    } else if(sResult.find("LE910-EUG") != std::string::npos) { -        sModel = "LE910-EUG"; -    } else if(sResult.find("LE910C4-EU") != std::string::npos) { -        sModel = "LE910C4-EU"; -    } else if(sResult.find("LE910-EU1") != std::string::npos) { -        sModel = "LE910-EU1"; -    } else if(sResult.find("LE910C1-NS") != std::string::npos) { -    	sModel = "LE910C1-NS"; -    } else if(sResult.find("LE910C1-AP") != std::string::npos) { -    	sModel = "LE910C1-AP"; -    } else if(sResult.find("GE910") != std::string::npos) { -        sModel = "GE910"; -    } else if(sResult.find("DE910-DUAL") != std::string::npos) { -        sModel = "DE910-DUAL"; -    } else if(sResult.find("CE910") != std::string::npos) { -        sModel = "CE910"; -    } -    return sModel; -} - -std::string CellularRadio::getCodeAsString(CODE eCode) { -    switch(eCode) { -        case SUCCESS: -            return "SUCCESS"; -        case ERROR: -            return "ERROR"; -        case FAILURE: -            return "FAILURE"; -        case NO_RESPONSE: -            return "NO RESPONSE"; -        default: -            return "UNKNOWN"; -    } +    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) { @@ -1680,84 +977,15 @@ bool CellularRadio::splitAndAssign(const std::string& sLine, const std::string&  }  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<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 = 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; -                } -            } -        } -    } +    // Assuming that this function is not supported by the modem until overriden. -    return bResult; +    return false;  }  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<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; +    // Assuming that this function is not supported by the modem until overriden. +    return false;  }  const char *CellularRadio::RadioBandMap::getLTEBand(const int32_t channel) @@ -1769,7 +997,7 @@ const char *CellularRadio::RadioBandMap::getLTEBand(const int32_t channel)              return EULTRAband[ii].name;          }      } -    return VALUE_UNKNOWN.c_str(); +    return ICellularRadio::VALUE_UNKNOWN;  }  const char *CellularRadio::RadioBandMap::getCDMABand(const int channel) @@ -1781,7 +1009,7 @@ const char *CellularRadio::RadioBandMap::getCDMABand(const int channel)              return WCDMAband[ii].name;          }      } -    return VALUE_UNKNOWN.c_str(); +    return ICellularRadio::VALUE_UNKNOWN;  }  const char *CellularRadio::RadioBandMap::getGSMBand(const int channel) @@ -1793,22 +1021,22 @@ const char *CellularRadio::RadioBandMap::getGSMBand(const int channel)              return GSMband[ii].name;          }      } -    return VALUE_UNKNOWN.c_str(); +    return ICellularRadio::VALUE_UNKNOWN;  }  const char *CellularRadio::RadioBandMap::getRadioBandName()  { -    const char *band = CellularRadio::VALUE_UNKNOWN.c_str(); +    const char *band = ICellularRadio::VALUE_UNKNOWN; -    if (m_sRadioType == CellularRadio::VALUE_TYPE_LTE) +    if (m_sRadioType == ICellularRadio::VALUE_TYPE_LTE)      {          band = getLTEBand(m_iChannel);      } -    else if (m_sRadioType == CellularRadio::VALUE_TYPE_CDMA) +    else if (m_sRadioType == ICellularRadio::VALUE_TYPE_CDMA)      {          band = getCDMABand(m_iChannel);      } -    else if (m_sRadioType == CellularRadio::VALUE_TYPE_GSM) +    else if (m_sRadioType == ICellularRadio::VALUE_TYPE_GSM)      {          band = getGSMBand(m_iChannel);      } @@ -1818,17 +1046,17 @@ const char *CellularRadio::RadioBandMap::getRadioBandName()  const char *CellularRadio::RadioBandMap::getRadioBandName(const std::string &channel, const std::string &radioType)  { -    const char *band = CellularRadio::VALUE_UNKNOWN.c_str(); +    const char *band = ICellularRadio::VALUE_UNKNOWN;      int32_t chan = strtol(channel.c_str(), NULL, 10); -    if (radioType == CellularRadio::VALUE_TYPE_LTE) +    if (radioType == ICellularRadio::VALUE_TYPE_LTE)      {          band = getLTEBand(chan);      } -    else if (radioType == CellularRadio::VALUE_TYPE_CDMA) +    else if (radioType == ICellularRadio::VALUE_TYPE_CDMA)      {          band = getCDMABand(chan);      } -    else if (radioType == CellularRadio::VALUE_TYPE_GSM) +    else if (radioType == ICellularRadio::VALUE_TYPE_GSM)      {          band = getGSMBand(chan);      } diff --git a/src/MTS_IO_CellularRadioFactory.cpp b/src/MTS_IO_CellularRadioFactory.cpp index ef87f0e..4ee8756 100644 --- a/src/MTS_IO_CellularRadioFactory.cpp +++ b/src/MTS_IO_CellularRadioFactory.cpp @@ -37,6 +37,7 @@  #include <mts/MTS_IO_GE910Radio.h>  #include <mts/MTS_IO_CE910Radio.h>  #include <mts/MTS_IO_DE910Radio.h> +#include "mts/MTS_IO_EG95Radio.h"  #include <mts/MTS_Logger.h>  using namespace MTS::IO; @@ -60,9 +61,10 @@ CellularRadioFactory::CellularRadioFactory() {      m_mCreationMap[DE910Radio::MODEL_NAME]        = &CellularRadioFactory::createDE910;      m_mCreationMap[CE910Radio::MODEL_NAME]        = &CellularRadioFactory::createCE910;      m_mCreationMap[LE866A1JSRadio::MODEL_NAME]    = &CellularRadioFactory::createLE866A1JS; +    m_mCreationMap[EG95Radio::MODEL_NAME]         = &CellularRadioFactory::createEG95Radio;  } -MTS::IO::CellularRadio* CellularRadioFactory::create(const std::string& sModel, const std::string& sPort) { +ICellularRadio* CellularRadioFactory::create(const std::string& sModel, const std::string& sPort) {      std::string model(sModel); @@ -87,22 +89,22 @@ std::string CellularRadioFactory::identifyRadio(const std::string& sPort) {      apIo.reset(new SerialConnection(SerialConnection::Builder(sPort).baudRate(115200).useLockFile().build()));      while(!apIo->open(30000)) {          printError("CellularRadioFactory| Failed to open radio port [%s]", sPort.c_str()); -        return CellularRadio::VALUE_UNKNOWN; +        return ICellularRadio::VALUE_UNKNOWN;      }      //Attempt basic radio communication -    if(CellularRadio::test(apIo) != CellularRadio::SUCCESS) { +    if(ICellularRadio::test(apIo) != ICellularRadio::SUCCESS) {          printError("CellularRadioFactory| Failed to communicate with radio on port [%s]", sPort.c_str());          apIo->close(); -        return CellularRadio::VALUE_UNKNOWN; +        return ICellularRadio::VALUE_UNKNOWN;      }      //Get model      int count = 0; -    std::string sCmd("ATI4"); +    std::string sCmd("AT+GMM");      std::string sResult;      do { -        sResult = CellularRadio::sendCommand(apIo, sCmd, CellularRadio::DEFAULT_BAIL_STRINGS, 1000, CellularRadio::CR); +        sResult = ICellularRadio::sendCommand(apIo, sCmd, ICellularRadio::DEFAULT_BAIL_STRINGS, 1000, ICellularRadio::CR);          if (sResult.find("OK") == std::string::npos) {              printDebug("RADIO| Attempting to get radio model [%s] ...", sResult.c_str());          } else { @@ -114,83 +116,88 @@ std::string CellularRadioFactory::identifyRadio(const std::string& sPort) {      if(count == 30) {          printDebug("RADIO| Unable to get radio model");          apIo->close(); -        return CellularRadio::VALUE_UNKNOWN; +        return ICellularRadio::VALUE_UNKNOWN;      } -    std::string sModel = CellularRadio::extractModelFromResult(sResult); -    printDebug("RADIO| Extracted [%s] from ATI4 query", sModel.c_str()); +    std::string sModel = ICellularRadio::extractModelFromResult(sResult); +    printDebug("RADIO| Extracted [%s] from AT+GMM query", sModel.c_str());      apIo->close();      return sModel;  } -CellularRadio* CellularRadioFactory::createHE910D(const std::string& sPort) { +ICellularRadio* CellularRadioFactory::createHE910D(const std::string& sPort) const {      return new HE910DRadio(sPort);  } -CellularRadio* CellularRadioFactory::createHE910EUD(const std::string& sPort) { +ICellularRadio* CellularRadioFactory::createHE910EUD(const std::string& sPort) const {      return new HE910EUDRadio(sPort);  } -CellularRadio* CellularRadioFactory::createLE910NAG(const std::string& sPort) { +ICellularRadio* CellularRadioFactory::createLE910NAG(const std::string& sPort) const {      return new LE910NAGRadio(sPort);  } -CellularRadio* CellularRadioFactory::createLE910C4NF(const std::string& sPort) { +ICellularRadio* CellularRadioFactory::createLE910C4NF(const std::string& sPort) const {      return new LE910C4NFRadio(sPort);  } -CellularRadio* CellularRadioFactory::createLE910NA1(const std::string& sPort) { +ICellularRadio* CellularRadioFactory::createLE910NA1(const std::string& sPort) const {      return new LE910NA1Radio(sPort);  } -CellularRadio* CellularRadioFactory::createLE910SVG(const std::string& sPort) { +ICellularRadio* CellularRadioFactory::createLE910SVG(const std::string& sPort) const {      return new LE910SVGRadio(sPort);  } -CellularRadio* CellularRadioFactory::createLE910EUG(const std::string& sPort) { +ICellularRadio* CellularRadioFactory::createLE910EUG(const std::string& sPort) const {      return new LE910EUGRadio(sPort);  } -CellularRadio* CellularRadioFactory::createLE910C4EU(const std::string& sPort) { +ICellularRadio* CellularRadioFactory::createLE910C4EU(const std::string& sPort) const {      return new LE910C4EURadio(sPort);  } -CellularRadio* CellularRadioFactory::createLE910EU1(const std::string& sPort) { +ICellularRadio* CellularRadioFactory::createLE910EU1(const std::string& sPort) const {      return new LE910EU1Radio(sPort);  } -CellularRadio* CellularRadioFactory::createLE910C1NS(const std::string& sPort) { +ICellularRadio* CellularRadioFactory::createLE910C1NS(const std::string& sPort) const {      return new LE910C1NSRadio(sPort);  } -CellularRadio* CellularRadioFactory::createLE910C1AP(const std::string& sPort) { +ICellularRadio* CellularRadioFactory::createLE910C1AP(const std::string& sPort) const {      return new LE910C1APRadio(sPort);  } -CellularRadio* CellularRadioFactory::createME910C1NA(const std::string& sPort) { +ICellularRadio* CellularRadioFactory::createME910C1NA(const std::string& sPort) const {      return new ME910C1NARadio(sPort);  } -CellularRadio* CellularRadioFactory::createME910C1NV(const std::string& sPort) { +ICellularRadio* CellularRadioFactory::createME910C1NV(const std::string& sPort) const {      return new ME910C1NVRadio(sPort);  } -CellularRadio* CellularRadioFactory::createME910C1WW(const std::string& sPort) { +ICellularRadio* CellularRadioFactory::createME910C1WW(const std::string& sPort) const {      return new ME910C1WWRadio(sPort);  } -CellularRadio* CellularRadioFactory::createGE910(const std::string& sPort) { +ICellularRadio* CellularRadioFactory::createGE910(const std::string& sPort) const {      return new GE910Radio(sPort);  } -CellularRadio* CellularRadioFactory::createDE910(const std::string& sPort) { +ICellularRadio* CellularRadioFactory::createDE910(const std::string& sPort) const {      return new DE910Radio(sPort);  } -CellularRadio* CellularRadioFactory::createCE910(const std::string& sPort) { +ICellularRadio* CellularRadioFactory::createCE910(const std::string& sPort) const {      return new CE910Radio(sPort);  } -CellularRadio* CellularRadioFactory::createLE866A1JS(const std::string &sPort) { +ICellularRadio* CellularRadioFactory::createLE866A1JS(const std::string &sPort) const {      return new LE866A1JSRadio(sPort);  } + +ICellularRadio* CellularRadioFactory::createEG95Radio(const std::string& sPort) const +{ +    return new EG95Radio(sPort); +} diff --git a/src/MTS_IO_DE910Radio.cpp b/src/MTS_IO_DE910Radio.cpp index eccb3eb..26668f1 100644 --- a/src/MTS_IO_DE910Radio.cpp +++ b/src/MTS_IO_DE910Radio.cpp @@ -39,7 +39,7 @@ DE910Radio::DE910Radio(const std::string& sPort)  } -CellularRadio::CODE DE910Radio::setRxDiversity(const Json::Value& jArgs) { +ICellularRadio::CODE DE910Radio::setRxDiversity(const Json::Value& jArgs) {  /*  Command string for EV3 radios:  AT#CRXD= */         if (jArgs["enabled"].asString() != "1" && jArgs["enabled"].asString() != "0")         { diff --git a/src/MTS_IO_EG95Radio.cpp b/src/MTS_IO_EG95Radio.cpp new file mode 100644 index 0000000..5c9ed69 --- /dev/null +++ b/src/MTS_IO_EG95Radio.cpp @@ -0,0 +1,47 @@ +/* + * 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_EG95Radio.h> + +using namespace MTS::IO; + +const std::string EG95Radio::MODEL_NAME("EG95"); + +EG95Radio::EG95Radio(const std::string& sPort) +: QuectelRadio(MODEL_NAME, sPort) +{ + +} + +EG95Radio::~EG95Radio() { + +} + +ICellularRadio::CODE EG95Radio::setRxDiversity(const Json::Value& jArgs) { +    /* Command string for EG95 radios:  AT+QCFG="diversity",(0-1) */ +    if (jArgs["enabled"].asString() != "1" && jArgs["enabled"].asString() != "0") { +        return FAILURE; +    } +    std::string sCmd = "AT+QCFG=\"diversity\","; +    sCmd += jArgs["enabled"].asString(); + +    return sendBasicCommand(sCmd); +} diff --git a/src/MTS_IO_GE910Radio.cpp b/src/MTS_IO_GE910Radio.cpp index e402b13..61332b5 100644 --- a/src/MTS_IO_GE910Radio.cpp +++ b/src/MTS_IO_GE910Radio.cpp @@ -34,12 +34,12 @@ using namespace MTS::IO;  const std::string GE910Radio::MODEL_NAME("GE910");  GE910Radio::GE910Radio(const std::string& sPort) -: CellularRadio(MODEL_NAME, sPort) +: TelitRadio(MODEL_NAME, sPort)  {  } -CellularRadio::CODE GE910Radio::setRxDiversity(const Json::Value& jArgs) { +ICellularRadio::CODE GE910Radio::setRxDiversity(const Json::Value& jArgs) {  /*  Command string for GE radios:  N/A */          return FAILURE;  } diff --git a/src/MTS_IO_HE910Radio.cpp b/src/MTS_IO_HE910Radio.cpp index bc08932..4c0a759 100644 --- a/src/MTS_IO_HE910Radio.cpp +++ b/src/MTS_IO_HE910Radio.cpp @@ -32,12 +32,12 @@  using namespace MTS::IO;  HE910Radio::HE910Radio(const std::string& sHE910Model, const std::string& sPort) -: CellularRadio(sHE910Model, sPort) +: TelitRadio(sHE910Model, sPort)  {  } -CellularRadio::CODE HE910Radio::setRxDiversity(const Json::Value& jArgs) { +ICellularRadio::CODE HE910Radio::setRxDiversity(const Json::Value& jArgs) {  /*  Command string for H5 radios:  "AT#RXDIV" */          if (jArgs["enabled"].asString() != "1" && jArgs["enabled"].asString() != "0")          { diff --git a/src/MTS_IO_ICellularRadio.cpp b/src/MTS_IO_ICellularRadio.cpp new file mode 100644 index 0000000..4e7809e --- /dev/null +++ b/src/MTS_IO_ICellularRadio.cpp @@ -0,0 +1,472 @@ +#include "mts/MTS_IO_ICellularRadio.h" + +#include <mts/MTS_Logger.h> +#include <mts/MTS_Timer.h> + +const char MTS::IO::ICellularRadio::ETX    = 0x03;  //Ends socket connection +const char MTS::IO::ICellularRadio::DLE    = 0x10;  //Escapes ETX and DLE within Payload +const char MTS::IO::ICellularRadio::CR     = 0x0D; +const char MTS::IO::ICellularRadio::NL     = 0x0A; +const char MTS::IO::ICellularRadio::CTRL_Z = 0x1A; + +const char *MTS::IO::ICellularRadio::RSP_ERROR = "ERROR"; +const char *MTS::IO::ICellularRadio::RSP_OK = "OK"; + + +const char *MTS::IO::ICellularRadio::DEFAULT_RADIO_PORT = "/dev/modem_at1"; +const char *MTS::IO::ICellularRadio::DEFAULT_RADIO_DIR = "/var/run/radio/"; +const char *MTS::IO::ICellularRadio::VALUE_UNKNOWN = "Unknown"; +const char *MTS::IO::ICellularRadio::VALUE_UNAVAILABLE = "Unavailable"; +const char *MTS::IO::ICellularRadio::VALUE_NOT_SUPPORTED = "Not Supported"; + +const char *MTS::IO::ICellularRadio::VALUE_NOT_REGISTERED = "NOT REGISTERED"; +const char *MTS::IO::ICellularRadio::VALUE_REGISTERED = "REGISTERED"; +const char *MTS::IO::ICellularRadio::VALUE_SEARCHING = "SEARCHING"; +const char *MTS::IO::ICellularRadio::VALUE_DENIED = "DENIED"; +const char *MTS::IO::ICellularRadio::VALUE_ROAMING = "ROAMING"; + +//Static Data +const char *MTS::IO::ICellularRadio::KEY_TYPE = "type";                    //!< GSM or CDMA +const char *MTS::IO::ICellularRadio::KEY_CODE = "code";                    //!< Product Code : H5, H6, C2, EV3, G3 +const char *MTS::IO::ICellularRadio::KEY_MODEL = "model";                  //!< Model : HE910, LE910, CE910, DE910, GE910 +const char *MTS::IO::ICellularRadio::KEY_MANUFACTURER = "manufacturer";    //!< Manufacturer: Telit +const char *MTS::IO::ICellularRadio::KEY_HARDWARE = "hardware";            //!< Radio Hardware Version +const char *MTS::IO::ICellularRadio::KEY_FIRMWARE = "firmware";            //!< Radio Firmware Version +const char *MTS::IO::ICellularRadio::KEY_FIRMWARE_BUILD = "firmwarebuild"; //!< Radio Firmware Build + +const char *MTS::IO::ICellularRadio::KEY_CARRIER = "carrier";   //!< Cellular Service Provider  = Home Network +const char *MTS::IO::ICellularRadio::VALUE_CARRIER_VERIZON = "Verizon"; +const char *MTS::IO::ICellularRadio::VALUE_CARRIER_AERIS = "Aeris"; +const char *MTS::IO::ICellularRadio::VALUE_CARRIER_SPRINT = "Sprint"; +const char *MTS::IO::ICellularRadio::VALUE_CARRIER_USCELLULAR = "U.S. Cellular"; +const char *MTS::IO::ICellularRadio::VALUE_CARRIER_ATT = "AT&T"; +const char *MTS::IO::ICellularRadio::VALUE_CARRIER_TMOBILE = "T-Mobile"; + +const char *MTS::IO::ICellularRadio::KEY_IMEI = "imei";          //!< International Mobile Station Equipment Identity +const char *MTS::IO::ICellularRadio::KEY_MEID = "meid";          //!< Mobile Equipment Identifier +const char *MTS::IO::ICellularRadio::KEY_IMSI = "imsi";          //!< International Mobile Subscriber Identity +const char *MTS::IO::ICellularRadio::KEY_MSID = "msid";          //!< Mobil Station ID / Mobile Identification Number  = MSID/MIN  = CDMA-Only +const char *MTS::IO::ICellularRadio::KEY_MDN = "mdn";            //!< Mobile Directory Number : Actual phone number dialed to reach radio +const char *MTS::IO::ICellularRadio::KEY_ICCID = "iccid";        //!< Integrated Circuit Card Identifier +const char *MTS::IO::ICellularRadio::KEY_MSL = "msl";            //!< Master Subsidy Lock + +//Dynamic Data +const char *MTS::IO::ICellularRadio::KEY_ROAMING = "roaming";    //!< Indicates whether or not using Home Network +const char *MTS::IO::ICellularRadio::KEY_DATETIME = "datetime";  //!< Date and Time from tower +const char *MTS::IO::ICellularRadio::KEY_SERVICE = "service";    //!< Service Connection Type [GPRS, EGPRS, WCDMA, HSDPA, 1xRTT, EVDO] +const char *MTS::IO::ICellularRadio::KEY_NETWORK = "network";    //!< Cellular Service Provider +const char *MTS::IO::ICellularRadio::KEY_NETWORK_REG = "netreg"; //!< Network Registration +const char *MTS::IO::ICellularRadio::KEY_CID = "cid";            //!< Cellular ID  = Tower in HEX +const char *MTS::IO::ICellularRadio::KEY_LAC = "lac";            //!< Location Area Code in HEX +const char *MTS::IO::ICellularRadio::KEY_RAC = "rac";            //!< Routing Area Code in HEX +const char *MTS::IO::ICellularRadio::KEY_RSSI = "rssi";          //!< Signal Strength +const char *MTS::IO::ICellularRadio::KEY_RSSIDBM = "rssidBm";    //!< Signal Strength in dBm +const char *MTS::IO::ICellularRadio::KEY_MCC = "mcc";            //!< Country Code +const char *MTS::IO::ICellularRadio::KEY_MNC = "mnc";            //!< Operator Code +const char *MTS::IO::ICellularRadio::KEY_CHANNEL = "channel";    //!< ARFCN or UARFCN Assigned Radio Channel +const char *MTS::IO::ICellularRadio::KEY_TXPWR = "txpwr";        //!< Transmit Power +const char *MTS::IO::ICellularRadio::KEY_PSC = "psc";            //!< Active Primary Synchronization Code  = PSC +const char *MTS::IO::ICellularRadio::KEY_ECIO = "ecio";          //!< Active Ec/Io  = chip energy per total wideband power in dBm +const char *MTS::IO::ICellularRadio::KEY_RSCP = "rscp";          //!< Active RSCP  = Received Signal Code Power in dBm +const char *MTS::IO::ICellularRadio::KEY_DRX = "drx";            //!< Discontinuous reception cycle length  = ms +const char *MTS::IO::ICellularRadio::KEY_MM = "mm";              //!< Mobility Management State +const char *MTS::IO::ICellularRadio::KEY_RR = "rr";              //!< Radio Resource State +const char *MTS::IO::ICellularRadio::KEY_NOM = "nom";            //!< Network Operator Mode +const char *MTS::IO::ICellularRadio::KEY_ABND = "abnd";          //!< Active Band +const char *MTS::IO::ICellularRadio::KEY_BLER = "bler";          //!< Block Error Rate  = percentage +const char *MTS::IO::ICellularRadio::KEY_SD = "sd";              //!< Service Domain +const char *MTS::IO::ICellularRadio::KEY_DEBUG = "debug";        //!< Debug Information + +const char *MTS::IO::ICellularRadio::KEY_MIP = "mipProfile";                      //!< Mobile IP Information +const char *MTS::IO::ICellularRadio::KEY_MIP_ID = "id";                           //!< Mobile IP ID +const char *MTS::IO::ICellularRadio::KEY_MIP_ENABLED = "enabled";                 //!< Mobile IP Enabled/Disabled +const char *MTS::IO::ICellularRadio::KEY_MIP_NAI = "nai";                         //!< Network Access Identifier +const char *MTS::IO::ICellularRadio::KEY_MIP_HOMEADDRESS = "homeAddress";         //!< Home Address +const char *MTS::IO::ICellularRadio::KEY_MIP_PRIMARYHA = "primaryAddress";        //!< Primary Home Agent +const char *MTS::IO::ICellularRadio::KEY_MIP_SECONDARYHA = "secondaryAddress";    //!< Secondary Home Agent +const char *MTS::IO::ICellularRadio::KEY_MIP_MNAAASPI = "mnAaaSpi";               //!< Mobile Node Authentication, Authorization, and Accounting Server Security Parameter Index +const char *MTS::IO::ICellularRadio::KEY_MIP_MNHASPI = "mnHaSpi";                 //!< Mobile Node Home Agent Security Server Parameter Index +const char *MTS::IO::ICellularRadio::KEY_MIP_REVTUN = "revTun";                   //!< Reverse Tunneling Enabled +const char *MTS::IO::ICellularRadio::KEY_MIP_MNAAASS = "mnAaaSs";                 //!< Mobile Node Authentication, Authorization, and Accounting Server Shared Secret +const char *MTS::IO::ICellularRadio::KEY_MIP_MNHASS = "mnHaSs";                   //!< Mobile Node Home Agent Shared Secret + +const char *MTS::IO::ICellularRadio::VALUE_TYPE_GSM = "GSM"; +const char *MTS::IO::ICellularRadio::VALUE_TYPE_LTE = "LTE"; +const char *MTS::IO::ICellularRadio::VALUE_TYPE_CDMA = "CDMA"; + +const char *MTS::IO::ICellularRadio::KEY_IS_SIM_INSERTED = "isSimInserted";    //!< SIM card insertion indicator. True when a SIM card is inserted +const char *MTS::IO::ICellularRadio::KEY_IS_SIM_LOCKED = "isSimLocked";        //!< SIM card lock status indicator. True when a SIM card is locked by PIN / PUK / other code +const char *MTS::IO::ICellularRadio::KEY_SIM_LOCK_STATUS = "lockStatus";       //!< SIM card lock status string. Either "READY", "SIM PIN", "SIM PUK" or other state +const char *MTS::IO::ICellularRadio::KEY_ATTEMPTS_PIN = "attemptsPin";         //!< The number of attempts left to unlock the SIM card using PIN code +const char *MTS::IO::ICellularRadio::KEY_ATTEMPTS_PUK = "attemptsPuk";         //!< The number of attempts left to unlock the SIM card using PUK code + +const char *MTS::IO::ICellularRadio::VALUE_SD_NO_SERVICE = "NO SERVICE"; +const char *MTS::IO::ICellularRadio::VALUE_SD_CS_ONLY = "CS ONLY"; +const char *MTS::IO::ICellularRadio::VALUE_SD_PS_ONLY = "PS ONLY"; +const char *MTS::IO::ICellularRadio::VALUE_SD_CSPS = "CS+PS"; + +const char *MTS::IO::ICellularRadio::VALUE_ABND_GSM_850 = "GSM 850"; +const char *MTS::IO::ICellularRadio::VALUE_ABND_GSM_900 = "GSM 900"; +const char *MTS::IO::ICellularRadio::VALUE_ABND_DCS_1800 = "DCS 1800"; +const char *MTS::IO::ICellularRadio::VALUE_ABND_PCS_1900 = "PCS 1900"; + +const std::vector<std::string> MTS::IO::ICellularRadio::DEFAULT_BAIL_STRINGS = { MTS::IO::ICellularRadio::RSP_OK, MTS::IO::ICellularRadio::RSP_ERROR }; + +MTS::IO::ICellularRadio::~ICellularRadio() +{ +} + +MTS::IO::ICellularRadio::CODE MTS::IO::ICellularRadio::convertModelToMtsShortCode(const std::string& sModel, std::string& sCode, MTS::IO::ICellularRadio *radioObject) { +    CODE eCode = FAILURE; + +    if(sModel.find("HE910-D") == 0) { +        sCode = "H5"; +        eCode = SUCCESS; +    } else if (sModel.find("HE910-EUD") == 0) { +        sCode = "H6"; +        eCode = SUCCESS; +    } else if (sModel.find("LE910-JN1") == 0) { +        sCode = "LDC3"; +        eCode = SUCCESS; +    } else if (sModel.find("LE866A1-JS") == 0) { +        sCode = "LSB3"; +        eCode = SUCCESS; +    } else if (sModel.find("LE910-NAG") == 0) { +        sCode = "LAT1"; +        eCode = SUCCESS; +    } else if (sModel.find("LE910C4-NF") == 0) { +        sCode = "L4N1"; +        eCode = SUCCESS; +    } else if (sModel.find("LE910-NA1") == 0) { +        if (NULL == radioObject) { +            sCode = VALUE_NOT_SUPPORTED; +            eCode = ERROR; +        } else { +            std::string sValue; +            eCode = radioObject->getActiveFirmware(sValue); +            if (eCode == SUCCESS) { +                sCode = "LNA3"; +            } else { +                sCode = "LAT3"; +            } +        } +        eCode = SUCCESS; +    } else if (sModel.find("LE910-SVG") == 0) { +        sCode = "LVW2"; +        eCode = SUCCESS; +    } else if (sModel.find("LE910C1-NS") == 0) { +    	sCode = "LSP3"; +    	eCode = SUCCESS; +    } else if (sModel.find("LE910C1-AP") == 0) { +    	sCode = "LAP3"; +    	eCode = SUCCESS; +    } else if (sModel.find("ME910C1-NA") == 0) { +        sCode = "MAT1"; +        eCode = SUCCESS; +    } else if (sModel.find("ME910C1-NV") == 0) { +        sCode = "MVW1"; +        eCode = SUCCESS; +    } else if (sModel.find("ME910C1-WW") == 0) { +        sCode = "MNG2"; +        eCode = SUCCESS; +    } else if (sModel.find("LE910-EUG") == 0) { +        sCode = "LEU1"; +        eCode = SUCCESS; +    } else if (sModel.find("LE910C4-EU") == 0) { +        sCode = "L4E1"; +        eCode = SUCCESS; +    } else if (sModel.find("LE910-EU1") == 0) { +        sCode = "LEU3"; +        eCode = SUCCESS; +    } else if (sModel.find("GE910") == 0) { +        sCode = "G3"; +        eCode = SUCCESS; +    } else if (sModel.find("CE910") == 0) { +        sCode = "C2"; +        eCode = SUCCESS; +    } else if (sModel.find("DE910") == 0) { +        sCode = "EV3"; +        eCode = SUCCESS; +    } else if (sModel.find("EG95") == 0) { +        if (NULL == radioObject) { +            sCode = VALUE_NOT_SUPPORTED; +            eCode = ERROR; +        } else { +            std::string sValue; +            eCode = radioObject->getFirmware(sValue); +            if (eCode != SUCCESS) { +                sCode = VALUE_NOT_SUPPORTED; +                eCode = ERROR; +            } else if (sValue.find("EG95E") != std::string::npos) { +                sCode = "LEU7"; +                eCode = SUCCESS; +            } else if (sValue.find("EG95NA") != std::string::npos) { +                sCode = "LNA7"; +                eCode = SUCCESS; +            } else { +                sCode = VALUE_NOT_SUPPORTED; +                eCode = ERROR; +            } +        } +    } else { +        sCode = VALUE_NOT_SUPPORTED; +        printError("RADIO| Could not identify MTS short code from model. [%s]", sModel.c_str()); +        eCode = ERROR; +    } +    return eCode; +} + +MTS::IO::ICellularRadio::CODE MTS::IO::ICellularRadio::convertServiceDomainToString(SERVICEDOMAIN eSd, std::string& sSd) { +    CODE eCode = FAILURE; +    switch(eSd) { +        case NO_SERVICE: sSd = VALUE_SD_NO_SERVICE; eCode = SUCCESS; break; +        case CS_ONLY: sSd = VALUE_SD_CS_ONLY; eCode = SUCCESS; break; +        case PS_ONLY: sSd = VALUE_SD_PS_ONLY; eCode = SUCCESS; break; +        case CSPS: sSd = VALUE_SD_CSPS; eCode = SUCCESS; break; +        default: sSd = VALUE_UNKNOWN; eCode = FAILURE; break; +    } +    return eCode; +} + +MTS::IO::ICellularRadio::CODE MTS::IO::ICellularRadio::convertActiveBandToString(ACTIVEBAND eBand, std::string& sBand) { +    CODE eCode = FAILURE; +    switch(eBand) { +        case GSM_850: sBand = VALUE_ABND_GSM_850; eCode = SUCCESS; break; +        case GSM_900: sBand = VALUE_ABND_GSM_900; eCode = SUCCESS; break; +        case DCS_1800: sBand = VALUE_ABND_DCS_1800; eCode = SUCCESS; break; +        case PCS_1900: sBand = VALUE_ABND_PCS_1900; eCode = SUCCESS; break; +        default: sBand = VALUE_UNKNOWN; eCode = FAILURE; break; +    } +    return eCode; +} + +MTS::IO::ICellularRadio::CODE MTS::IO::ICellularRadio::convertModelToType(const std::string& sModel, std::string& sType) { +    CODE eCode = FAILURE; +    sType = VALUE_NOT_SUPPORTED; + +    if(sModel.find("HE910-D") == 0) { +        sType = VALUE_TYPE_GSM; +        eCode = SUCCESS; +    } else if (sModel.find("HE910-EUD") == 0) { +        sType = VALUE_TYPE_GSM; +        eCode = SUCCESS; +    } else if (sModel.find("LE910-JN1") == 0) { +        sType = VALUE_TYPE_LTE; +        eCode = SUCCESS; +    } else if (sModel.find("LE866A1-JS") == 0) { +        sType = VALUE_TYPE_LTE; +        eCode = SUCCESS; +    } else if (sModel.find("LE910-NAG") == 0) { +        sType = VALUE_TYPE_LTE; +        eCode = SUCCESS; +    } else if (sModel.find("LE910C4-NF") == 0) { +        sType = VALUE_TYPE_LTE; +        eCode = SUCCESS; +    } else if (sModel.find("LE910-NA1") == 0) { +        sType = VALUE_TYPE_LTE; +        eCode = SUCCESS; +    } else if (sModel.find("LE910-SVG") == 0) { +        sType = VALUE_TYPE_LTE; +        eCode = SUCCESS; +    } else if (sModel.find("LE910-EUG") == 0) { +        sType = VALUE_TYPE_LTE; +        eCode = SUCCESS; +    } else if (sModel.find("LE910C4-EU") == 0) { +        sType = VALUE_TYPE_LTE; +        eCode = SUCCESS; +    } else if (sModel.find("LE910-EU1") == 0) { +        sType = VALUE_TYPE_LTE; +        eCode = SUCCESS; +    } else if (sModel.find("LE910C1-NS") == 0) { +    	sType = VALUE_TYPE_LTE; +    	eCode = SUCCESS; +    } else if (sModel.find("LE910C1-AP") == 0) { +    	sType = VALUE_TYPE_LTE; +    	eCode = SUCCESS; +    } else if (sModel.find("ME910C1-NA") == 0) { +        sType = VALUE_TYPE_LTE; +        eCode = SUCCESS; +    } else if (sModel.find("ME910C1-NV") == 0) { +        sType = VALUE_TYPE_LTE; +        eCode = SUCCESS; +    } else if (sModel.find("ME910C1-WW") == 0) { +        sType = VALUE_TYPE_LTE; +        eCode = SUCCESS; +    } else if (sModel.find("GE910") == 0) { +        sType = VALUE_TYPE_GSM; +        eCode = SUCCESS; +    } else if (sModel.find("CE910") == 0) { +        sType = VALUE_TYPE_CDMA; +        eCode = SUCCESS; +    } else if (sModel.find("DE910") == 0) { +        sType = VALUE_TYPE_CDMA; +        eCode = SUCCESS; +    } else if (sModel.find("EG95") == 0) { +        sType = VALUE_TYPE_LTE; +        eCode = SUCCESS; +    } else { +        sType = VALUE_TYPE_GSM; +        eCode = ERROR; +        printError("RADIO| Could not identify type from model. [%s].  Assuming [%s]", sModel.c_str(), sType.c_str()); +    } +    return eCode; +} + +std::string MTS::IO::ICellularRadio::sendCommand(MTS::AutoPtr<MTS::IO::Connection>& apIo, const std::string& sCmd, +                                       const std::vector<std::string>& vBail, int32_t timeoutMillis, const char& ESC) { +    IsNeedMoreData isNeedMoreData = [&vBail](const std::string&, const std::string& allData)->bool { +        for(size_t i = 0; i < vBail.size(); i++) { +            const std::string& sBail = vBail[i]; +            if(sBail.size() > 0) { +                if(allData.find(sBail) != std::string::npos) { +                    //Return when bail string is found +                    printTrace("RADIO| Found bail string [%s]", sBail.c_str()); +                    return false; +                } +            } +        } +        return true; +    }; + +    return sendCommand(apIo, sCmd, isNeedMoreData, timeoutMillis, ESC); +} + +std::string MTS::IO::ICellularRadio::sendCommand(MTS::AutoPtr<MTS::IO::Connection>& apIo, const std::string& sCmd, +                                       IsNeedMoreData& isNeedMoreData, int32_t timeoutMillis, const char& ESC) { +    if(MTS::Logger::getPrintLevel() >= MTS::Logger::PrintLevel::TRACE_LEVEL) { +        printTrace("RADIO| Sending command [%s]", sCmd.c_str()); +    } +    if(apIo.isNull()) { +        printError("RADIO| IO is not set in sendCommand"); +        return ""; +    } + +    int32_t iResult; +    if(ESC == 0x00) { +        iResult = apIo->write(sCmd.data(), sCmd.size()); +    } else { +        std::string sNewCmd(sCmd); +        sNewCmd.push_back(ESC); +        iResult = apIo->write(sNewCmd.data(), sNewCmd.size()); +    } + +    if(iResult == -1) { +        printError("RADIO| Failed to send command to radio"); +        return ""; +    } + +    bool done = false; +    const uint32_t capacity = 1024; +    char buffer[capacity]; +    std::string sResult; +    Timer timer; +    timer.start(); +    do { +        int32_t iterationTimeout = 100; +        int bytesRead = apIo->read((char*)buffer, capacity, iterationTimeout); +        if(bytesRead == -1) { +            printError("RADIO| Failed to read from radio"); +            break; +        } + +        std::string sIteration((char*)buffer, bytesRead); +        sResult += sIteration; + +        if(isNeedMoreData && !isNeedMoreData(sIteration, sResult)) { +            printTrace("RADIO| No more data needed"); +            return sResult; +        } +        if(timeoutMillis >= 0) { +            done = (timer.getMillis() >= (uint64_t)timeoutMillis); +        } else { +            //Do not stop looping until bail string is found +        } +    } while(!done); + +    //Timed out +    return sResult; +} + +MTS::IO::ICellularRadio::CODE MTS::IO::ICellularRadio::test(MTS::AutoPtr<MTS::IO::Connection>& apIo, uint32_t timeoutSeconds) { +    printTrace("RADIO| Basic Test"); +    uint32_t count = 0; +    std::string sCmd("AT"); +    do { +        std::string sResult = sendCommand(apIo, sCmd); +        if (sResult.find(RSP_OK) == std::string::npos) { +            printTrace("RADIO| Waiting for basic radio communication [%s] ...", sResult.c_str()); +        } else { +            break; +        } +        count++; +    } while (count < timeoutSeconds); + +    if(count == timeoutSeconds) { +        printWarning("RADIO| Basic radio communication FAILED"); +        return NO_RESPONSE; +    } +    return SUCCESS; +} + +std::string MTS::IO::ICellularRadio::extractModelFromResult(const std::string& sResult) { +    std::string sModel(VALUE_NOT_SUPPORTED); + +    if(sResult.find("HE910-D") != std::string::npos) { +        sModel = "HE910-D"; +    } else if(sResult.find("HE910-EUD") != std::string::npos) { +        sModel = "HE910-EUD"; +    } else if(sResult.find("LE910-JN1") != std::string::npos) { +        sModel = "LE910-JN1"; +    } else if(sResult.find("LE866A1-JS") != std::string::npos) { +        sModel = "LE866A1-JS"; +    } else if(sResult.find("LE910-NAG") != std::string::npos) { +        sModel = "LE910-NAG"; +    } else if(sResult.find("LE910C4-NF") != std::string::npos) { +        sModel = "LE910C4-NF"; +    } else if(sResult.find("LE910-NA1") != std::string::npos) { +        sModel = "LE910-NA1"; +    } else if(sResult.find("ME910C1-NA") != std::string::npos) { +        sModel = "ME910C1-NA"; +    } else if(sResult.find("ME910C1-NV") != std::string::npos) { +        sModel = "ME910C1-NV"; +    } else if(sResult.find("ME910C1-WW") != std::string::npos) { +        sModel = "ME910C1-WW"; +    } else if(sResult.find("LE910-SVG") != std::string::npos) { +        sModel = "LE910-SVG"; +    } else if(sResult.find("LE910-EUG") != std::string::npos) { +        sModel = "LE910-EUG"; +    } else if(sResult.find("LE910C4-EU") != std::string::npos) { +        sModel = "LE910C4-EU"; +    } else if(sResult.find("LE910-EU1") != std::string::npos) { +        sModel = "LE910-EU1"; +    } else if(sResult.find("LE910C1-NS") != std::string::npos) { +    	sModel = "LE910C1-NS"; +    } else if(sResult.find("LE910C1-AP") != std::string::npos) { +    	sModel = "LE910C1-AP"; +    } else if(sResult.find("GE910") != std::string::npos) { +        sModel = "GE910"; +    } else if(sResult.find("DE910-DUAL") != std::string::npos) { +        sModel = "DE910-DUAL"; +    } else if(sResult.find("CE910") != std::string::npos) { +        sModel = "CE910"; +    } else if(sResult.find("EG95") != std::string::npos) { +        sModel = "EG95"; +    } +    return sModel; +} + +std::string MTS::IO::ICellularRadio::getCodeAsString(CODE eCode) { +    switch(eCode) { +        case SUCCESS: +            return "SUCCESS"; +        case ERROR: +            return "ERROR"; +        case FAILURE: +            return "FAILURE"; +        case NO_RESPONSE: +            return "NO RESPONSE"; +        default: +            return "UNKNOWN"; +    } +} + diff --git a/src/MTS_IO_LE866Radio.cpp b/src/MTS_IO_LE866Radio.cpp index 2e92f67..85b8dc3 100644 --- a/src/MTS_IO_LE866Radio.cpp +++ b/src/MTS_IO_LE866Radio.cpp @@ -31,7 +31,7 @@  using namespace MTS::IO;  LE866Radio::LE866Radio(const std::string& sLE866Model, const std::string& sPort) -: CellularRadio(sLE866Model, sPort) +: TelitRadio(sLE866Model, sPort)  {  } diff --git a/src/MTS_IO_LE910C1APRadio.cpp b/src/MTS_IO_LE910C1APRadio.cpp index 3a560fa..dca5faa 100644 --- a/src/MTS_IO_LE910C1APRadio.cpp +++ b/src/MTS_IO_LE910C1APRadio.cpp @@ -30,7 +30,7 @@ LE910C1APRadio::LE910C1APRadio(const std::string& sPort)  } -CellularRadio::CODE LE910C1APRadio::getCarrier(std::string& sCarrier) { +ICellularRadio::CODE LE910C1APRadio::getCarrier(std::string& sCarrier) {      sCarrier = "Sprint";      return SUCCESS;  } diff --git a/src/MTS_IO_LE910C1NSRadio.cpp b/src/MTS_IO_LE910C1NSRadio.cpp index 6c403a0..907edd7 100644 --- a/src/MTS_IO_LE910C1NSRadio.cpp +++ b/src/MTS_IO_LE910C1NSRadio.cpp @@ -39,7 +39,7 @@ LE910C1NSRadio::LE910C1NSRadio(const std::string& sPort)  } -CellularRadio::CODE LE910C1NSRadio::getCarrier(std::string& sCarrier) { +ICellularRadio::CODE LE910C1NSRadio::getCarrier(std::string& sCarrier) {      sCarrier = "Sprint";      return SUCCESS;  } diff --git a/src/MTS_IO_LE910NA1Radio.cpp b/src/MTS_IO_LE910NA1Radio.cpp index 64583b4..c7341b0 100644 --- a/src/MTS_IO_LE910NA1Radio.cpp +++ b/src/MTS_IO_LE910NA1Radio.cpp @@ -38,8 +38,8 @@ LE910NA1Radio::LE910NA1Radio(const std::string& sPort)  } -CellularRadio::CODE LE910NA1Radio::setActiveFirmware(const Json::Value& jArgs) { -    CellularRadio::CODE rc; +ICellularRadio::CODE LE910NA1Radio::setActiveFirmware(const Json::Value& jArgs) { +    ICellularRadio::CODE rc;      //    Set command allows enabling a specific firmware image on products      //    embedding 2 different firmware images: @@ -82,9 +82,9 @@ CellularRadio::CODE LE910NA1Radio::setActiveFirmware(const Json::Value& jArgs) {      return sendBasicCommand(sCmd, 5000);  } -CellularRadio::CODE LE910NA1Radio::getActiveFirmware(std::string& sFwId) { +ICellularRadio::CODE LE910NA1Radio::getActiveFirmware(std::string& sFwId) {      std::string sCmd; -    CellularRadio::CODE rc; +    ICellularRadio::CODE rc;      //      // Read command reports the current active firmware image:      // AT#FWSWITCH? @@ -108,7 +108,7 @@ CellularRadio::CODE LE910NA1Radio::getActiveFirmware(std::string& sFwId) {      sCmd = "AT#FWSWITCH?";      std::string sResult = sendCommand(sCmd); -    size_t end = sResult.find(RSP_OK); +    size_t end = sResult.find(ICellularRadio::RSP_OK);      if (end == std::string::npos) {          printWarning("%s| Unable to get active image number from radio using command [%s]",                  getName().c_str(), diff --git a/src/MTS_IO_LE910Radio.cpp b/src/MTS_IO_LE910Radio.cpp index 76ccae2..ea905a8 100644 --- a/src/MTS_IO_LE910Radio.cpp +++ b/src/MTS_IO_LE910Radio.cpp @@ -33,12 +33,12 @@  using namespace MTS::IO;  LE910Radio::LE910Radio(const std::string& sLE910Model, const std::string& sPort) -: CellularRadio(sLE910Model, sPort) +: TelitRadio(sLE910Model, sPort)  {  } -CellularRadio::CODE LE910Radio::setRxDiversity(const Json::Value& jArgs) { +ICellularRadio::CODE LE910Radio::setRxDiversity(const Json::Value& jArgs) {  /* Command string for LAT1,LVW2,LEU1 radios:  "AT#RXDIV=" */  /* Setting needs to append ",1" to the 0/1 value */          if (jArgs["enabled"].asString() != "1" && jArgs["enabled"].asString() != "0") @@ -49,10 +49,10 @@ CellularRadio::CODE LE910Radio::setRxDiversity(const Json::Value& jArgs) {          sCmd += jArgs["enabled"].asString();          sCmd += ",1"; -        return CellularRadio::sendBasicCommand(sCmd); +        return sendBasicCommand(sCmd);  } -CellularRadio::CODE LE910Radio::getModemLocation(std::string& sLocation) { +ICellularRadio::CODE LE910Radio::getModemLocation(std::string& sLocation) {      const std::string& whitespace = " \t";      printTrace("LE910Radio getModemLocation");      std::string sCmd("AT$GPSACP"); diff --git a/src/MTS_IO_LE910SVGRadio.cpp b/src/MTS_IO_LE910SVGRadio.cpp index 692350d..a43165a 100644 --- a/src/MTS_IO_LE910SVGRadio.cpp +++ b/src/MTS_IO_LE910SVGRadio.cpp @@ -39,7 +39,7 @@ LE910SVGRadio::LE910SVGRadio(const std::string& sPort)  } -CellularRadio::CODE LE910SVGRadio::getCarrier(std::string& sCarrier) { +ICellularRadio::CODE LE910SVGRadio::getCarrier(std::string& sCarrier) {      sCarrier = "Verizon";      return SUCCESS;  } diff --git a/src/MTS_IO_ME910C1NVRadio.cpp b/src/MTS_IO_ME910C1NVRadio.cpp index e9a4874..0af5f24 100644 --- a/src/MTS_IO_ME910C1NVRadio.cpp +++ b/src/MTS_IO_ME910C1NVRadio.cpp @@ -53,13 +53,13 @@ ME910C1NVRadio::ME910C1NVRadio(const std::string& sPort)  } -CellularRadio::CODE ME910C1NVRadio::getCarrier(std::string& sCarrier) { +ICellularRadio::CODE ME910C1NVRadio::getCarrier(std::string& sCarrier) {      sCarrier = "Verizon";      return SUCCESS;  } -CellularRadio::CODE ME910C1NVRadio::doGetFirmwareNumbers(std::string &sFirmware, std::string &sFirmwareBuild) { -	CellularRadio::CODE rc = FAILURE; +ICellularRadio::CODE ME910C1NVRadio::doGetFirmwareNumbers(std::string &sFirmware, std::string &sFirmwareBuild) { +	ICellularRadio::CODE rc = FAILURE;  	rc = getFirmware(sFirmware);      if (rc != SUCCESS){ @@ -74,9 +74,9 @@ CellularRadio::CODE ME910C1NVRadio::doGetFirmwareNumbers(std::string &sFirmware,      return rc;  } -CellularRadio::CODE ME910C1NVRadio::doFumoReadConfig(const Json::Value& jArgs, Json::Value &jConfig) +ICellularRadio::CODE ME910C1NVRadio::doFumoReadConfig(const Json::Value& jArgs, Json::Value &jConfig)  { -    CellularRadio::CODE rc = INVALID_ARGS; +    ICellularRadio::CODE rc = INVALID_ARGS;      std::string sPath;      do @@ -196,9 +196,9 @@ CellularRadio::CODE ME910C1NVRadio::doFumoReadConfig(const Json::Value& jArgs, J      return rc;  } -CellularRadio::CODE ME910C1NVRadio::doFumoSetup(const Json::Value &jConfig, UpdateCb& stepCb) +ICellularRadio::CODE ME910C1NVRadio::doFumoSetup(const Json::Value &jConfig, UpdateCb& stepCb)  { -	CellularRadio::CODE rc = FAILURE; +	ICellularRadio::CODE rc = FAILURE;  	std::string sCmd;  	std::string sContextId = jConfig[KEY_FUMO_PDPID].asString(); @@ -215,7 +215,7 @@ CellularRadio::CODE ME910C1NVRadio::doFumoSetup(const Json::Value &jConfig, Upda  		// AT#SGACT=<cid>,<stat>[,<userId>,<pwd>]  		//  		sCmd = "AT#SGACT=" + sContextId + ",0"; -		rc = CellularRadio::sendBasicCommand(sCmd); +		rc = sendBasicCommand(sCmd);  		if (rc != SUCCESS) {  			if(stepCb) {  				stepCb(Json::Value("FUMO Error: Failed to deactivate PDP context")); @@ -244,7 +244,7 @@ CellularRadio::CODE ME910C1NVRadio::doFumoSetup(const Json::Value &jConfig, Upda  		if (!sApn.empty()) {  			sCmd += ",\"" + sApn + "\"";  		} -		rc = CellularRadio::sendBasicCommand(sCmd, 1000); +		rc = sendBasicCommand(sCmd, 1000);  		if (rc != SUCCESS) {  			if(stepCb) {  				stepCb(Json::Value("FUMO Error: Failed to setup PDP context")); @@ -267,7 +267,7 @@ CellularRadio::CODE ME910C1NVRadio::doFumoSetup(const Json::Value &jConfig, Upda  		//             less than max packet size (timeout value in hundreds of milliseconds).  		//  		sCmd = "AT#SCFG=1," + sContextId + ",300,90,600,50"; -		rc = CellularRadio::sendBasicCommand(sCmd); +		rc = sendBasicCommand(sCmd);  		if (rc != SUCCESS) {  			if(stepCb) {  				stepCb(Json::Value("FUMO Error: Failed to set connection configuration parameters")); @@ -279,7 +279,7 @@ CellularRadio::CODE ME910C1NVRadio::doFumoSetup(const Json::Value &jConfig, Upda  		// Activate PDP context  		//  		sCmd = "AT#SGACT=" + sContextId + ",1"; -		rc = CellularRadio::sendBasicCommand(sCmd, 60 * 1000); +		rc = sendBasicCommand(sCmd, 60 * 1000);  		if (rc != SUCCESS) {  			if(stepCb) {  				stepCb(Json::Value("FUMO Error: Failed to activate PDP context")); @@ -292,9 +292,9 @@ CellularRadio::CODE ME910C1NVRadio::doFumoSetup(const Json::Value &jConfig, Upda      return rc;  } -CellularRadio::CODE ME910C1NVRadio::doFumoFtp(const Json::Value &jConfig, UpdateCb& stepCb) +ICellularRadio::CODE ME910C1NVRadio::doFumoFtp(const Json::Value &jConfig, UpdateCb& stepCb)  { -	CellularRadio::CODE rc = FAILURE; +	ICellularRadio::CODE rc = FAILURE;  	std::string sCmd;  	std::string sResult; @@ -305,7 +305,7 @@ CellularRadio::CODE ME910C1NVRadio::doFumoFtp(const Json::Value &jConfig, Update      // AT#FTPTO= [<tout>]      // <tout> - time-out in 100 ms units      // -    rc = CellularRadio::sendBasicCommand("AT#FTPTO=2400"); +    rc = sendBasicCommand("AT#FTPTO=2400");      if (rc != SUCCESS) {          if(stepCb) {              stepCb(Json::Value("FUMO Error: Failed to setup connection timeout")); @@ -322,7 +322,7 @@ CellularRadio::CODE ME910C1NVRadio::doFumoFtp(const Json::Value &jConfig, Update      sCmd += "\"" + jConfig[KEY_FUMO_ADDRESS].asString() +  "\",";      sCmd += "\"" + jConfig[KEY_FUMO_USER].asString() +  "\",";      sCmd += "\"" + jConfig[KEY_FUMO_PASSWORD].asString() +  "\",1"; -    rc = CellularRadio::sendBasicCommand(sCmd, 60 * 1000); +    rc = sendBasicCommand(sCmd, 60 * 1000);      if (rc != SUCCESS) {          if(stepCb) {              stepCb(Json::Value("FUMO Error: Failed to open connection")); @@ -344,7 +344,7 @@ CellularRadio::CODE ME910C1NVRadio::doFumoFtp(const Json::Value &jConfig, Update  		//    0 - binary  		//    1 - ascii  		// -		rc = CellularRadio::sendBasicCommand("AT#FTPTYPE=0", 1000); +		rc = sendBasicCommand("AT#FTPTYPE=0", 1000);  		if (rc != SUCCESS) {  			if(stepCb) {  				stepCb(Json::Value("FUMO Error: failed to set file transfer type")); @@ -363,7 +363,7 @@ CellularRadio::CODE ME910C1NVRadio::doFumoFtp(const Json::Value &jConfig, Update  			sCmd += jConfig[KEY_FUMO_DIR].asString() + "/";  		}  		sCmd += "\""; -		rc = CellularRadio::sendBasicCommand(sCmd, 60 * 1000); +		rc = sendBasicCommand(sCmd, 60 * 1000);  		if (rc != SUCCESS) {  			if(stepCb) {  				stepCb(Json::Value("FUMO Error: failed to change working directory on the server")); @@ -380,7 +380,7 @@ CellularRadio::CODE ME910C1NVRadio::doFumoFtp(const Json::Value &jConfig, Update  		//  	    sCmd = "AT#FTPGETOTA=";  	    sCmd += "\"" + jConfig[KEY_FUMO_FILE].asString() + "\",1,1"; -	    CellularRadio::sendBasicCommand(sCmd); +	    sendBasicCommand(sCmd);  		//          // Noticed that after successful AT#FTPGETOTA the radio resets the connection. @@ -396,12 +396,12 @@ CellularRadio::CODE ME910C1NVRadio::doFumoFtp(const Json::Value &jConfig, Update  	    {  	    	MTS::Thread::sleep(5000); -	    	rc = CellularRadio::sendBasicCommand("AT"); +	    	rc = sendBasicCommand("AT");  	    	if (rc == SUCCESS) {  	    		break;  	    	} -	    	CellularRadio::resetConnection(1); +	    	resetConnection(1);  	    }  	    oTimer.stop(); @@ -419,7 +419,7 @@ CellularRadio::CODE ME910C1NVRadio::doFumoFtp(const Json::Value &jConfig, Update  	    printTrace("RADIO| AT#FTPMSG result [%s]", sResult.c_str()); -	    if (sResult.find(RSP_OK) == std::string::npos) { +	    if (sResult.find(ICellularRadio::RSP_OK) == std::string::npos) {  	    	rc = FAILURE;  			if(stepCb) {  				stepCb(Json::Value("FUMO Error: failed to download the firmware file")); @@ -450,7 +450,7 @@ CellularRadio::CODE ME910C1NVRadio::doFumoFtp(const Json::Value &jConfig, Update      //      // AT#FTPCLOSE      // -	CellularRadio::CODE rcclose = CellularRadio::sendBasicCommand("AT#FTPCLOSE", 60 * 1000); +	ICellularRadio::CODE rcclose = sendBasicCommand("AT#FTPCLOSE", 60 * 1000);  	if (rcclose != SUCCESS && rc == SUCCESS) {  		if(stepCb) {  			// Only one "FUMO Error" message should be sent @@ -468,9 +468,9 @@ CellularRadio::CODE ME910C1NVRadio::doFumoFtp(const Json::Value &jConfig, Update      return rc;  } -CellularRadio::CODE ME910C1NVRadio::doFumoCleanup(const Json::Value &jConfig, UpdateCb& stepCb) +ICellularRadio::CODE ME910C1NVRadio::doFumoCleanup(const Json::Value &jConfig, UpdateCb& stepCb)  { -	CellularRadio::CODE rc = FAILURE; +	ICellularRadio::CODE rc = FAILURE;  	std::string sCmd;  	std::string sContextId = jConfig[KEY_FUMO_PDPID].asString(); @@ -479,7 +479,7 @@ CellularRadio::CODE ME910C1NVRadio::doFumoCleanup(const Json::Value &jConfig, Up      // Deactivate PDP context      //  	sCmd = "AT#SGACT=" + sContextId + ",0"; -    rc = CellularRadio::sendBasicCommand(sCmd, 10000); +    rc = sendBasicCommand(sCmd, 10000);      if (rc != SUCCESS) {          if(stepCb) {              stepCb(Json::Value("FUMO Error: Failed to deactivate PDP context")); @@ -488,9 +488,9 @@ CellularRadio::CODE ME910C1NVRadio::doFumoCleanup(const Json::Value &jConfig, Up      return rc;  } -CellularRadio::CODE ME910C1NVRadio::doFumoApplyFirmware(const Json::Value &jConfig, UpdateCb& stepCb) +ICellularRadio::CODE ME910C1NVRadio::doFumoApplyFirmware(const Json::Value &jConfig, UpdateCb& stepCb)  { -	CellularRadio::CODE rc = FAILURE; +	ICellularRadio::CODE rc = FAILURE;  	if (jConfig.isMember(KEY_FUMO_DRYRUN)) {  		if(stepCb) { @@ -499,7 +499,7 @@ CellularRadio::CODE ME910C1NVRadio::doFumoApplyFirmware(const Json::Value &jConf  		return SUCCESS;  	} -	rc = CellularRadio::sendBasicCommand("AT#OTAUP=0", 10000); +	rc = sendBasicCommand("AT#OTAUP=0", 10000);      if (rc != SUCCESS) {      	if(stepCb) {      		stepCb(Json::Value("FUMO Error: failed to apply the firmware")); @@ -514,11 +514,11 @@ CellularRadio::CODE ME910C1NVRadio::doFumoApplyFirmware(const Json::Value &jConf  	return rc;  } -CellularRadio::CODE ME910C1NVRadio::doFumoWaitNewFirmware(const Json::Value &jConfig, UpdateCb& stepCb) +ICellularRadio::CODE ME910C1NVRadio::doFumoWaitNewFirmware(const Json::Value &jConfig, UpdateCb& stepCb)  {      std::string sFirmware;      std::string sFirmwareBuild; -	CellularRadio::CODE rc = FAILURE; +	ICellularRadio::CODE rc = FAILURE;  	if (jConfig.isMember(KEY_FUMO_DRYRUN)) {  		if(stepCb) { @@ -539,7 +539,7 @@ CellularRadio::CODE ME910C1NVRadio::doFumoWaitNewFirmware(const Json::Value &jCo  		if (doGetFirmwareNumbers(sFirmware, sFirmwareBuild) != SUCCESS) {  			// The radio is probably unavailable -			CellularRadio::resetConnection(100); +			resetConnection(100);  			continue;  		} @@ -570,9 +570,9 @@ CellularRadio::CODE ME910C1NVRadio::doFumoWaitNewFirmware(const Json::Value &jCo  } -CellularRadio::CODE ME910C1NVRadio::doFumoPerform(const Json::Value &jConfig, UpdateCb& stepCb) +ICellularRadio::CODE ME910C1NVRadio::doFumoPerform(const Json::Value &jConfig, UpdateCb& stepCb)  { -	CellularRadio::CODE rc = FAILURE; +	ICellularRadio::CODE rc = FAILURE;  	UpdateCb dummyCb; @@ -606,10 +606,10 @@ CellularRadio::CODE ME910C1NVRadio::doFumoPerform(const Json::Value &jConfig, Up  	return rc;  } -CellularRadio::CODE ME910C1NVRadio::updateFumo(const Json::Value& jArgs, UpdateCb& stepCb) +ICellularRadio::CODE ME910C1NVRadio::updateFumo(const Json::Value& jArgs, UpdateCb& stepCb)  {  	Json::Value jConfig(Json::objectValue); -	CellularRadio::CODE rc = FAILURE; +	ICellularRadio::CODE rc = FAILURE;      rc = doFumoReadConfig(jArgs, jConfig);      if (rc != SUCCESS) { diff --git a/src/MTS_IO_ME910C1WWRadio.cpp b/src/MTS_IO_ME910C1WWRadio.cpp index d26749a..0469d5d 100644 --- a/src/MTS_IO_ME910C1WWRadio.cpp +++ b/src/MTS_IO_ME910C1WWRadio.cpp @@ -32,8 +32,8 @@ ME910C1WWRadio::ME910C1WWRadio(const std::string& sPort)  } -CellularRadio::CODE ME910C1WWRadio::setActiveFirmware(const Json::Value& jArgs) { -    CellularRadio::CODE rc; +ICellularRadio::CODE ME910C1WWRadio::setActiveFirmware(const Json::Value& jArgs) { +    ICellularRadio::CODE rc;      //    Set command allows enabling a specific firmware image on products      //    embedding 2 different firmware images: @@ -76,9 +76,9 @@ CellularRadio::CODE ME910C1WWRadio::setActiveFirmware(const Json::Value& jArgs)      return sendBasicCommand(sCmd, 5000);  } -CellularRadio::CODE ME910C1WWRadio::getActiveFirmware(std::string& sFwId) { +ICellularRadio::CODE ME910C1WWRadio::getActiveFirmware(std::string& sFwId) {      std::string sCmd; -    CellularRadio::CODE rc; +    ICellularRadio::CODE rc;      //      // Read command reports the current active firmware image:      // AT#FWSWITCH? @@ -101,7 +101,7 @@ CellularRadio::CODE ME910C1WWRadio::getActiveFirmware(std::string& sFwId) {      sCmd = "AT#FWSWITCH?";      std::string sResult = sendCommand(sCmd); -    size_t end = sResult.find(RSP_OK); +    size_t end = sResult.find(ICellularRadio::RSP_OK);      if (end == std::string::npos) {          printWarning("%s| Unable to get active image number from radio using command [%s]",                  getName().c_str(), diff --git a/src/MTS_IO_ME910Radio.cpp b/src/MTS_IO_ME910Radio.cpp index 42796e9..2b181d2 100644 --- a/src/MTS_IO_ME910Radio.cpp +++ b/src/MTS_IO_ME910Radio.cpp @@ -25,22 +25,22 @@  using namespace MTS::IO;  ME910Radio::ME910Radio(const std::string& sME910Model, const std::string& sPort) -: CellularRadio(sME910Model, sPort) +: TelitRadio(sME910Model, sPort)  {  } -CellularRadio::CODE ME910Radio::setRxDiversity(const Json::Value& jArgs) { +ICellularRadio::CODE ME910Radio::setRxDiversity(const Json::Value& jArgs) {          return FAILURE;  } -CellularRadio::CODE ME910Radio::getFirmwareBuild(std::string& sFirmwareBuild) { +ICellularRadio::CODE ME910Radio::getFirmwareBuild(std::string& sFirmwareBuild) {      std::string sCmd("AT#CFVR");      std::string sResult = sendCommand(sCmd); -    size_t end = sResult.find(RSP_OK); +    size_t end = sResult.find(ICellularRadio::RSP_OK);      if (end == std::string::npos) {          printWarning("%s| Unable to get firmware build number [%s]",                  getName().c_str(), diff --git a/src/MTS_IO_QuectelRadio.cpp b/src/MTS_IO_QuectelRadio.cpp new file mode 100644 index 0000000..f3227a5 --- /dev/null +++ b/src/MTS_IO_QuectelRadio.cpp @@ -0,0 +1,612 @@ +/* + * 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_QuectelRadio.h" + +#include <mts/MTS_Logger.h> +#include <mts/MTS_Thread.h> +#include <mts/MTS_Text.h> + +using namespace MTS::IO; + +QuectelRadio::QuectelRadio(const std::string& sName, const std::string& sRadioPort) +: CellularRadio (sName, sRadioPort) +{ +} + +bool QuectelRadio::resetRadio(uint32_t iTimeoutMillis) { +    printInfo("%s| Rebooting radio", getName().c_str()); +    if(sendBasicCommand("AT+CFUN=1,1") == SUCCESS) { +        if(iTimeoutMillis > 5000) { +            MTS::Thread::sleep(5000); +            iTimeoutMillis -= 5000; +        } +        return resetConnection(iTimeoutMillis); +    } + +    return false; +} + +ICellularRadio::CODE QuectelRadio::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("AT+GMM"); +    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 QuectelRadio::getIccid(std::string& sIccid) { +    printTrace("%s| Get ICCID", getName().c_str()); +    sIccid = ICellularRadio::VALUE_NOT_SUPPORTED; + +    // AT+QCCID execution can take up to 300ms according to the datasheet. Setting timeout to 500ms just for sure. +    std::string sCmd("AT+QCCID"); +    std::string sResult = sendCommand(sCmd, DEFAULT_BAIL_STRINGS, 500); + +    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("+QCCID:"); +    if(start != std::string::npos) { +        start += sizeof("+QCCID:"); +        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 QuectelRadio::getService(std::string& sService) { +    printTrace("%s| Get Service", getName().c_str()); +    sService = ICellularRadio::VALUE_NOT_SUPPORTED; +    std::string sCmd("AT+COPS?"); +    std::string sResult = 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(":") + 1; //Position right after "+COPS:" +    std::vector<std::string> vParts = MTS::Text::split(MTS::Text::trim(sResult.substr(start, end-start)), ','); + +    int32_t iAccessTechnology; + +    // +COPS: <mode>[,<format>[,<oper>][,<Act>]] +    if (vParts.size() < 4 || !MTS::Text::parse(iAccessTechnology, vParts[3])) { +        printWarning("%s| Unable to get Service from radio using command [%s]", getName().c_str(), sCmd.c_str()); +        return FAILURE; +    } + +    switch(iAccessTechnology) { +        case   0 : sService = "GPRS"  ; break;  // GSM +        case   2 : sService = "WCDMA" ; break;  // UTRAN +        case   3 : sService = "EGPRS" ; break;  // GSM W/EGPRS +        case   4 : sService = "HSDPA" ; break;  // UTRAN W/HSDPA +        case   5 : sService = "WCDMA" ; break;  // UTRAN W/HSUPA +        case   6 : sService = "HSDPA" ; break;  // UTRAN W/HSDPA and HSUPA +        case   7 : sService = "LTE"   ; break;  // E-UTRAN +        case 100 : sService = "CDMA"  ; break;  // CDMA + +        default: sService = ICellularRadio::VALUE_UNKNOWN; break; +    } + +    printDebug("%s| Service ID: [%d][%s]", getName().c_str(), iAccessTechnology, sService.c_str()); + +    return SUCCESS; +} + +ICellularRadio::CODE QuectelRadio::getNetwork(std::string& sNetwork) { +    /* +     * TODO: Refactor using MccMncTable once it'll be corrected. +     * +     * The proper way to determine the current network is to do that +     * by MCC and MNC fetched from the `getNetworkStatus` and `AT+QENG` command. +     * By using MCC and MNC from `AT+QENG` we can fetch the name of the network +     * reported by a currently connected base station even if the SIM card is +     * not installed or if we are currently working is a roaming mode. +     * +     * Until MccMncTable implementation is not fixed, we are using the name +     * of a currently selected operator (AT+COPS). +     */ +    printTrace("%s| Get Network", getName().c_str()); +    sNetwork = ICellularRadio::VALUE_NOT_SUPPORTED; +    std::string sCmd("AT+COPS?"); +    std::string sResult = sendCommand(sCmd); +    size_t end = sResult.find(ICellularRadio::RSP_OK); + +    if (end == std::string::npos) { +        printWarning("%s| Unable to get network name from radio using command [%s]", getName().c_str(), sCmd.c_str()); +        return FAILURE; +    } + +    // +COPS: <mode>[, <format>, <oper>,<AcT>] +    // +COPS: vParts[0],vParts[1],vParts[2],vParts[3] +    size_t start = sResult.find(":") + 1; //Position right after "+COPS:" +    std::vector<std::string> vParts = MTS::Text::split(MTS::Text::trim(sResult.substr(start)), ","); + +    if(vParts.size() > 3) { +        const std::string sValue = vParts[2]; + +        // +COPS: 0,0,"CHN-UNICOM UNICOM",7 +        //             ^start    ^end +        // +COPS: 0,0,"AT&T",7 +        //             ^st ^end +        size_t start = sValue.find("\"") + 1; +        size_t end = sValue.find_first_of(" \"", start); +        sNetwork = sValue.substr(start, end-start); +    } else { +        sNetwork = "";  // Not connected to any network +    } + +    return SUCCESS; +} + +/*  AT+QENG="servingcell" - Query the information of serving cells + +    (GSM network) +    +QENG:"servingscell",<state>,"GSM",<mcc>,<mnc>,<lac>,<cellid>,<bsic>,<arfcn>,<band>,<rxlev>,<txp>,<rla>,<drx>,<c1>,<c2>,<gprs>,<tch>,<ts>,<ta>,<maio>,<hsn>,<rxlevsub>,<rxlevfull>,<rxqualsub>,<rxqualfull>,<voicecodec> + +    (WCDMA network) +    +QENG:"servingcell",<state>,"WCDMA",<mcc>,<mnc>,<lac>,<cellid>,<uarfcn>,<psc>,<rac>,<rscp>,<ecio>,<phych>,<sf>,<slot>,<speech_code>,<comMod> + +    (LTE Network) +    +QENG:"servingcell",<state>,"LTE",<is_tdd>,<mcc>,<mnc>,<cellid>,<pcid>,<earfcn>,<freq_band_ind>,<ul_bandwidth>,<dl_bandwidth>,<tac>,<rsrp>,<rsrq>,<rssi>,<sinr>,<srxlev> + +    The following modes are NOT currently handled: +    - TD-SCDMA mode; +    - CDMA mode; +    - HDR mode; +    - SRLTE mode. + +    In the case of TD-SCDMA mode: +    +QENG:"servingscell",<state>,"TDSCDMA",<mcc>,<mnc>,<lac>,<cellid>,<pfreq>,<rssi>,<rscp>,<ecio> + +    In the case of CDMA mode or CDMA+HDR mode: +    +QENG:"servingscell",<state>,"CDMA",<mcc>,<mnc>,<lac>,<cellid>,<bcch>,<rxpwr>,<ecio>,<txpwr> +    [+QENG:"servingscell",<state>,"HDR",<mcc>,<mnc>,<lac>,<cellid>,<bcch>,<rxpwr>,<ecio>,<txpwr>] + +    In the case of SRLTE mode: +    +QENG:"servingscell",<state>,"CDMA",<mcc>,<mnc>,<lac>,<cellid>,<bcch>,<rxpwr>,<ecio>,<txpwr> +    +QENG:"servingcell",<state>,"LTE",<is_tdd>,<mcc>,<mnc>,<cellid>,<pcid>,<earfcn>,<freq_band_ind>,<ul_bandwidth>,<dl_bandwidth>,<tac>,<rsrp>,<rsrq>,<rssi>,<sinr><srxlev> +*/ +CellularRadio::CODE QuectelRadio::getNetworkStatus(Json::Value& jData) { +    const std::string RAT_GSM = "GSM"; +    const std::string RAT_WCDMA = "WCDMA"; +    const std::string RAT_LTE = "LTE"; + +    int32_t iValue; +    ACTIVEBAND abnd; +    SERVICEDOMAIN sd; +    std::string sValue; +    std::string sRat;  // Radio Access Technology which is currently used + +    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+QENG fails below +    getCommonNetworkStats(jData); + +    // IMSI is not provided by AT+QENG. Fetch it separately to keep the same interface +    if (getImsi(sValue) == SUCCESS) { +        jData[ICellularRadio::KEY_IMSI] = sValue; +    } + +    // Network Name is not explicitly provided by AT+QENG. Fetch it separately to keep the same interface +    // TODO: Replace with lookup by MCC and MNC once MccMncTable is fixed. +    if (getNetwork(sValue) == SUCCESS) { +        jData[ICellularRadio::KEY_NETWORK] = sValue; +    } + +    std::string sCmd; +    std::string sResult; + +    sCmd = "AT+QENG=\"servingcell\""; +    sResult = sendCommand(sCmd, DEFAULT_BAIL_STRINGS, 200); +    if (sResult.find("+QENG: \"servingcell\"") == std::string::npos) { +        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 "+QENG:" +    size_t end = sResult.rfind(ICellularRadio::RSP_OK); +    std::vector<std::string> vParts = MTS::Text::split(MTS::Text::trim(sResult.substr(start, end-start)), ","); +    Json::Value jDebug; +    Json::Value jQuectelDebug; + +    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 { +        // UE state and Access technology, Quectel-specific information +        jQuectelDebug["state"] = vParts[1]; + +        sRat = MTS::Text::trim(vParts[2], '"'); +        jQuectelDebug["rat"] = sRat; +    } + +    // +QENG:"servingscell",<state>,"GSM",<mcc>,<mnc>,<lac>,<cellid>,<bsic>,<arfcn>,<band>,<rxlev>,<txp>,<rla>,<drx>,<c1>,<c2>,<gprs>,<tch>,<ts>,<ta>,<maio>,<hsn>,<rxlevsub>,<rxlevfull>,<rxqualsub>,<rxqualfull>,<voicecodec> +    // +QENG:           [0],    [1],  [2],  [3],  [4],  [5],     [6],   [7],    [8],   [9],   [10], [11], [12], [13],[14],[15],  [16], [17],[18],[19],  [20], [21],      [22],       [23],       [24],        [25],        [26] +    if (sRat == RAT_GSM) { +        //Parse as GSM Network Format +        jData[ICellularRadio::KEY_MCC] = vParts[3]; +        jData[ICellularRadio::KEY_MNC] = vParts[4]; +        jData[ICellularRadio::KEY_LAC] = vParts[5]; +        jData[ICellularRadio::KEY_CID] = vParts[6]; +        jQuectelDebug["bsic"] = vParts[7]; +        jData[ICellularRadio::KEY_CHANNEL] = vParts[8]; + +        if (convertToActiveBand(vParts[9], abnd) == SUCCESS && convertActiveBandToString(abnd, sValue) == SUCCESS) { +            jData[ICellularRadio::KEY_ABND] = sValue; +        } + +        jData[ICellularRadio::KEY_RSSIDBM] = vParts[10];  // Values already negative. No need to substract 111 as stated in a datasheet +        jData[ICellularRadio::KEY_TXPWR] = vParts[11]; +        jQuectelDebug["rla"] = vParts[12]; +        jQuectelDebug["drx"] = vParts[13]; +        jQuectelDebug["c1"] = vParts[14]; +        jQuectelDebug["c2"] = vParts[15]; +        jQuectelDebug["gprs"] = vParts[16]; +        jQuectelDebug["tch"] = vParts[17]; +        jQuectelDebug["ts"] = vParts[18]; +        jQuectelDebug["ta"] = vParts[19]; +        jQuectelDebug["maio"] = vParts[20]; +        jQuectelDebug["hsn"] = vParts[21]; +        jQuectelDebug["rxlevsub"] = vParts[22]; +        jQuectelDebug["rxlevfull"] = vParts[23]; +        jQuectelDebug["rxqualsub"] = vParts[24]; +        jQuectelDebug["rxqualfull"] = vParts[25]; +        jQuectelDebug["voicecodec"] = vParts[26]; + +        // Service Domain is not provided by AT+QENG. Fetch it separately to keep the same interface +        if (getServiceDomain(sd) == SUCCESS && convertServiceDomainToString(sd, sValue) == SUCCESS) { +            jData[ICellularRadio::KEY_SD] = sValue; +        } + +        // The following fields can NOT be fetched for Quectel in GSM mode: RAC, MM, RR, NOM + +        jData["quectelDebug"] = jQuectelDebug; +    } + +    // +QENG:"servingcell",<state>,"WCDMA",<mcc>,<mnc>,<lac>,<cellid>,<uarfcn>,<psc>,<rac>,<rscp>,<ecio>,<phych>,<sf>,<slot>,<speech_code>,<comMod> +    // +QENG:          [0],    [1],    [2],  [3],  [4],  [5],     [6],     [7],  [8],  [9],  [10],  [11],   [12],[13],  [14],         [15],    [16] +    else if(sRat == RAT_WCDMA) { +        //Parse as WCDMA Network Format +        jData[ICellularRadio::KEY_MCC] = vParts[3]; +        jData[ICellularRadio::KEY_MNC] = vParts[4]; +        jData[ICellularRadio::KEY_LAC] = vParts[5]; +        jData[ICellularRadio::KEY_CID] = vParts[6]; +        jData[ICellularRadio::KEY_CHANNEL] = vParts[7]; +        jDebug[ICellularRadio::KEY_PSC] = vParts[8]; +        jData[ICellularRadio::KEY_RAC] = vParts[9]; +        jDebug[ICellularRadio::KEY_RSCP] = vParts[10]; +        jDebug[ICellularRadio::KEY_ECIO] = vParts[11]; +        jQuectelDebug["phych"] = vParts[12]; +        jQuectelDebug["sf"] = vParts[13]; +        jQuectelDebug["slot"] = vParts[14]; +        jQuectelDebug["speechCode"] = vParts[15]; +        jQuectelDebug["comMod"] = vParts[16]; + +        // The following fields can NOT be fetched for Quectel in WCDMA mode: TXPWR, DRX, MM, RR, NOM, BLER + +        // RSSI is not provided by AT+QENG in WCDMA mode. It was filled above by the getCommonNetworkStats + +        // Service Domain is not provided by AT+QENG. Fetch it separately to keep the same interface +        if (getServiceDomain(sd) == SUCCESS && convertServiceDomainToString(sd, sValue) == SUCCESS) { +            jDebug[ICellularRadio::KEY_SD] = sValue; +        } + +        // BLER is not provided by AT+QENG. Set to constant +        jDebug[ICellularRadio::KEY_BLER] = "000"; + +        // Get the radio band given the channel (UARFCN) +        RadioBandMap radioBandMap(vParts[7], ICellularRadio::VALUE_TYPE_CDMA); +        jData[ICellularRadio::KEY_ABND] = radioBandMap.getRadioBandName(); + +        jData["quectelDebug"] = jQuectelDebug; +        jData[ICellularRadio::KEY_DEBUG] = jDebug; +    } + +    // +QENG:"servingcell",<state>,"LTE",<is_tdd>,<mcc>,<mnc>,<cellid>,<pcid>,<earfcn>,<freq_band_ind>,<ul_bandwidth>,<dl_bandwidth>,<tac>,<rsrp>,<rsrq>,<rssi>,<sinr>,<srxlev> +    // +QENG:          [0],    [1],  [2],     [3],  [4],  [5],     [6],   [7],     [8],            [9],          [10],          [11], [12],  [13],  [14],  [15],   [16],   [17] +    else if(sRat == RAT_LTE) { +        //Parse as LTE Network Format +        jQuectelDebug["isTdd"] = vParts[3]; +        jData[ICellularRadio::KEY_MCC] = vParts[4]; +        jData[ICellularRadio::KEY_MNC] = vParts[5]; +        jData[ICellularRadio::KEY_CID] = vParts[6]; +        jQuectelDebug["pcid"] = vParts[7]; +        jData[ICellularRadio::KEY_CHANNEL] = vParts[8]; +        jQuectelDebug["freqBandInd"] = vParts[9]; +        jQuectelDebug["ulBandwidth"] = vParts[10]; +        jQuectelDebug["dlBandwidth"] = vParts[11]; +        jData["tac"] = vParts[12]; +        jDebug["rsrp"] = vParts[13]; +        jDebug["rsrq"] = vParts[14]; +        jDebug[ICellularRadio::KEY_RSSIDBM] = vParts[15]; +        jQuectelDebug["sinr"] = vParts[16]; +        jQuectelDebug["srxlev"] = vParts[17]; + +        // Get the radio band given the channel (EARFCN) +        RadioBandMap radioBandMap(vParts[8], ICellularRadio::VALUE_TYPE_LTE); +        jData[ICellularRadio::KEY_ABND] = radioBandMap.getRadioBandName(); + +        // Service Domain is not provided by AT+QENG. Fetch it separately to keep the same interface +        if (getServiceDomain(sd) == SUCCESS && convertServiceDomainToString(sd, sValue) == SUCCESS) { +            jDebug[ICellularRadio::KEY_SD] = sValue; +        } + +        // LAC is not provided by AT+QENG in WCDMA mode. Use another command instead +        jData[ICellularRadio::KEY_LAC] = queryLteLac(); + +        jData["quectelDebug"] = jQuectelDebug; +        jData[ICellularRadio::KEY_DEBUG] = jDebug; +    } + +    printTrace("%s| Network Status:\n%s\n", getName().c_str(), jData.toStyledString().c_str()); +    return SUCCESS; +} + +ICellularRadio::CODE QuectelRadio::convertSignalStrengthTodBm(const int32_t& iRssi, int32_t& iDbm) { +    int dbmSteps, minValue, maxValue, rssiOffset; +    int rawDbm; + +    if(iRssi >= 0 && iRssi < 99) { +        // normal scaling +        dbmSteps   =  2; +        minValue   = -113; +        maxValue   = -51; +        rssiOffset =  0; +    } else if(iRssi >= 100 && iRssi < 199) { +        // TD-SCDMA scaling +        dbmSteps   =  1; +        minValue   = -116; +        maxValue   = -25; +        rssiOffset =  100; +    } else { +        return FAILURE;  // invalid, not known or not detectable +    } + +    rawDbm = minValue + ((iRssi - rssiOffset) * dbmSteps); +    iDbm = std::min(maxValue, rawDbm); + +    return SUCCESS; +} + +ICellularRadio::CODE QuectelRadio::convertdBmToSignalStrength(const int32_t& iDBm, int32_t& iRssi) { +    //Quectel Conversion FOR NORMAL SCALING +    const int dbmSteps   =  2; +    const int minValue   = -113; +    const int rssiOffset =  0; + +    if (iDBm < -113) { +        iRssi = 0; +    } else if (iDBm > -51) { +        iRssi = 31; +    } else { +        iRssi = ((iDBm - minValue) / dbmSteps) + rssiOffset; +    } + +    return SUCCESS; +} + +ICellularRadio::CODE QuectelRadio::setMdn(const Json::Value& jArgs) { +    printTrace("%s| Set MDN", getName().c_str()); +    return NOT_APPLICABLE; +} + +ICellularRadio::CODE QuectelRadio::getServiceDomain(ICellularRadio::SERVICEDOMAIN& sd) { +    printTrace("%s| Get Service Domain", getName().c_str()); + +    std::string sCmd("AT+QCFG=\"servicedomain\""); +    std::string sResult = sendCommand(sCmd); +    size_t end = sResult.find(ICellularRadio::RSP_OK); + +    if (end == std::string::npos) { +        printWarning("%s| Unable to get service domain using command [%s]", getName().c_str(), sCmd.c_str()); +        return FAILURE; +    } + +    // +QCFG: "servicedomain",<service> +    size_t start = sResult.find(",") + 1;  // Position right after comma +    std::string sServiceDomain = MTS::Text::trim(sResult.substr(start, end-start)); +    int iValue = -1; + +    if (!MTS::Text::parse(iValue, sServiceDomain)) { +        printWarning("%s| Failed to parse service domain from command output [%s]", getName().c_str(), sCmd.c_str()); +        return FAILURE; +    } + +    switch (iValue) { +        case 0: sd = SERVICEDOMAIN::CS_ONLY; break; +        case 1: sd = SERVICEDOMAIN::PS_ONLY; break; +        case 2: sd = SERVICEDOMAIN::CSPS; break; + +        default: return FAILURE;  // Unknown +    } + +    return SUCCESS; +} + +ICellularRadio::CODE QuectelRadio::getIsSimInserted(bool& bData) { +    printTrace("%s| Get SIM insertion status", getName().c_str()); + +    // AT+QSIMSTAT? execution can take up to 300ms according to the datasheet. Setting timeout to 500ms just for sure. +    std::string sCmd("AT+QSIMSTAT?"); +    std::string sResult = sendCommand(sCmd, DEFAULT_BAIL_STRINGS, 500); + +    const std::string sPrefix = "+QSIMSTAT: "; +    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+QSIMSTAT? returned unexpected response: [%s][%s]", getName().c_str(), sCmd.c_str(), sResult.c_str()); +        return FAILURE; +    } + +    // +QSIMSTAT: <enable>,<inserted_status> +    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") {  // Inserted +        bData = true; +    } else {   // Removed or Unknown, before (U)SIM initialization +        bData = false; +    } + +    return SUCCESS; +} + +ICellularRadio::CODE QuectelRadio::getSimLockAttempts(int& iAttemptsPin, int& iAttemptsPuk) { +    printTrace("%s| Get SIM unlock attempts left", getName().c_str()); + +    // AT+QPINC execution can take more time that expected. Set timeout to 2s just to be sure. +    std::string sCmd("AT+QPINC=\"SC\""); +    std::string sResult = sendCommand(sCmd, DEFAULT_BAIL_STRINGS, 2000); + +    const std::string sPrefix = "+QPINC: \"SC\","; +    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+QPINC returned unexpected response: [%s][%s]", getName().c_str(), sCmd.c_str(), sResult.c_str()); +        return FAILURE; +    } + +    // +QPINC: <facility>,<pincounter>,<pukcounter> +    //         [x]       ,[0]         ,[1] +    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 unlock attempts left from response [%s]", getName().c_str(), sResult.c_str()); +        return FAILURE; +    } + +    if (!MTS::Text::parse(iAttemptsPin, vParts[0])) { +        printWarning("%s| Unable to parse SIM PIM unlock attempts from response [%s]", getName().c_str(), sResult.c_str()); +        return FAILURE; +    } + +    if (!MTS::Text::parse(iAttemptsPuk, vParts[1])) { +        printWarning("%s| Unable to parse SIM PUK unlock attempts from response [%s]", getName().c_str(), sResult.c_str()); +        return FAILURE; +    } + +    return SUCCESS; +} + +ICellularRadio::CODE QuectelRadio::convertToActiveBand(const std::string& sQuectelBand, ICellularRadio::ACTIVEBAND& band) { +    int iQuectelBand = -1; + +    if (!MTS::Text::parse(iQuectelBand, sQuectelBand)) { +         return FAILURE;  // probably "-", other band +    } + +    switch (iQuectelBand) { +        case 0: band = ACTIVEBAND::DCS_1800; break; +        case 1: band = ACTIVEBAND::PCS_1900; break; + +        default: return FAILURE;  // actually, this case should never happen +    } + +    return SUCCESS; +} + +ICellularRadio::CODE QuectelRadio::getRadioNetworkMode(RADIO_NETWORK_MODE &mode) +{ +    // AT+QCFG="nwscanmode" execution can take up to 300ms according to the datasheet. Setting timeout to 500ms just for sure. +    std::string sCmd("AT+QCFG=\"nwscanmode\""); +    std::string cmdResult = sendCommand(sCmd, DEFAULT_BAIL_STRINGS, 500); + +    if (cmdResult.find(ICellularRadio::RSP_OK) == std::string::npos) { +        printDebug("%s| AT+QCFG? returned unexpected response: [%s][%s]", getName().c_str(), sCmd.c_str(), cmdResult.c_str()); +        return FAILURE; +    } +    switch (stoi(MTS::Text::split(cmdResult, ',')[1])) { +    case 1: mode = ICellularRadio::RADIO_NETWORK_MODE_GSM_ONLY; break; +    case 5: mode = ICellularRadio::RADIO_NETWORK_MODE_UMTS_ONLY; break; +    case 0: mode = ICellularRadio::RADIO_NETWORK_MODE_AUTO; break; +    default: mode = ICellularRadio::RADIO_NETWORK_MODE_UNKNOWN; break; +    } +    return SUCCESS; +} + +ICellularRadio::CODE QuectelRadio::setRadioNetworkMode(RADIO_NETWORK_MODE mode) +{ +    std::string value; +    switch (mode) { +    case ICellularRadio::RADIO_NETWORK_MODE_GSM_ONLY: value = "1"; break; +    case ICellularRadio::RADIO_NETWORK_MODE_UMTS_ONLY: value = "5"; break; +    case ICellularRadio::RADIO_NETWORK_MODE_AUTO: value = "0"; break; +    default: return FAILURE; +    } +    std::string sCmd("AT+QCFG=\"nwscanmode\","); +    sCmd += value; + +    // AT+QCFG="nwscanmode" execution can take up to 300ms according to the datasheet. Setting timeout to 500ms just for sure. +    std::string cmdResult = sendCommand(sCmd, DEFAULT_BAIL_STRINGS, 500); + +    if (cmdResult.find(ICellularRadio::RSP_OK) == std::string::npos) { +        printDebug("%s| AT+QCFG? returned unexpected response: [%s][%s]", getName().c_str(), sCmd.c_str(), cmdResult.c_str()); +        return FAILURE; +    } +    return SUCCESS; +} 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; +} | 
