summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSerhii Kostiuk <serhii.o.kostiuk@globallogic.com>2021-05-28 15:18:47 +0300
committerSerhii Kostiuk <serhii.o.kostiuk@globallogic.com>2021-05-29 12:44:04 +0300
commit51484668683c5e10bda111c08a300af1834a59d2 (patch)
tree036272b226f64e02f8ab3084458ead1492f1c45c /src
parent3589be0c1b394c33abac98c2de98a5c56d595eb3 (diff)
downloadlibmts-io-51484668683c5e10bda111c08a300af1834a59d2.tar.gz
libmts-io-51484668683c5e10bda111c08a300af1834a59d2.tar.bz2
libmts-io-51484668683c5e10bda111c08a300af1834a59d2.zip
[GP-1111] mPower R. Apr 2021: +CEMODE shall be set to CEMODE=2
Added an ability to read the PLMN ID (MCC/MNC combination) of the home carrier from the SIM. SIM PLMN ID is a part of the IMSI that contains identifier of the home network. PLMN ID in turn consists of 3-digit MCC (country code) and 2-or-3-digit MNC (network code). The length of the MNC is stored in the SIM Elementary File called "Administrative Data" (EFad for short). The purpose of the new functions is to extract PLMN ID from the SIM if this information is available.
Diffstat (limited to 'src')
-rw-r--r--src/MTS_IO_CdmaRadio.cpp10
-rw-r--r--src/MTS_IO_CellularRadio.cpp174
-rw-r--r--src/MTS_IO_ICellularRadio.cpp1
3 files changed, 185 insertions, 0 deletions
diff --git a/src/MTS_IO_CdmaRadio.cpp b/src/MTS_IO_CdmaRadio.cpp
index f84fd34..de02055 100644
--- a/src/MTS_IO_CdmaRadio.cpp
+++ b/src/MTS_IO_CdmaRadio.cpp
@@ -1290,6 +1290,16 @@ ICellularRadio::CODE CdmaRadio::getNetworkStatus(Json::Value& jData) {
return SUCCESS;
}
+ICellularRadio::CODE CdmaRadio::getSimMccMnc(std::string&) {
+ printTrace("%s| Get MCC/MNC of the home network from the SIM: not applicable", getName().c_str());
+ return NOT_APPLICABLE;
+}
+
+ICellularRadio::CODE CdmaRadio::getSimMccMnc(std::string&, std::string&) {
+ printTrace("%s| Get MCC/MNC of the home network from the SIM: not applicable", getName().c_str());
+ return NOT_APPLICABLE;
+}
+
std::string CdmaRadio::getMeidLastSix() {
std::string sMeid;
if(getMeid(sMeid) != SUCCESS || sMeid.size() != 14) {
diff --git a/src/MTS_IO_CellularRadio.cpp b/src/MTS_IO_CellularRadio.cpp
index c2fcfad..5b6521f 100644
--- a/src/MTS_IO_CellularRadio.cpp
+++ b/src/MTS_IO_CellularRadio.cpp
@@ -977,6 +977,180 @@ ICellularRadio::CODE CellularRadio::getSimCarrierCode(const std::string& sIccid,
return SUCCESS; // no error cases for now
}
+ICellularRadio::CODE CellularRadio::simAccessReadBinary(uint16_t iFileId, uint8_t iP1, uint8_t iP2, uint8_t iLe, std::string& sResult) {
+ printTrace("%s| Read binary from the SIM Elementary File", m_sName.c_str());
+
+ // +CRSM=176,<fileid>,<P1>,<P2>,<P3/Le>[,<data>[,<pathid>]]
+ std::string sCmd = "AT+CRSM=176,";
+ sCmd += MTS::Text::format(iFileId);
+ sCmd += ',';
+ sCmd += MTS::Text::format(iP1);
+ sCmd += ',';
+ sCmd += MTS::Text::format(iP2);
+ sCmd += ',';
+ sCmd += MTS::Text::format(iLe);
+
+ std::string sRawResponse = sendCommand(sCmd, DEFAULT_BAIL_STRINGS, 3000);
+ printTrace("%s| Raw response from the radio: [%s]", m_sName.c_str(), sRawResponse.c_str());
+
+ if (sRawResponse.empty()) {
+ printError("%s| No response from the radio in 3 seconds.", m_sName.c_str());
+ return CODE::NO_RESPONSE;
+ }
+
+ if (sRawResponse.rfind(RSP_ERROR) != std::string::npos) {
+ printError("%s| Failed to read from the SIM Elementary File: [%s]", m_sName.c_str(), sRawResponse.c_str());
+ return CODE::ERROR;
+ }
+
+ // Trim the output to remove excess whitespaces and line separators.
+ sRawResponse = MTS::Text::trim(sRawResponse);
+
+ // The response should start with "+CRSM: ".
+ const std::string sResponsePrefix = "+CRSM: ";
+ if (sRawResponse.rfind(sResponsePrefix, 0) != 0) {
+ printError("%s| Unexpected response from the radio: [%s]", m_sName.c_str(), sRawResponse.c_str());
+ return CODE::FAILURE;
+ }
+
+ // Select eveything between the prefix and the next line.
+ auto eolPos = sRawResponse.find(CR, sResponsePrefix.size());
+ sRawResponse = sRawResponse.substr(sResponsePrefix.size(), eolPos - sResponsePrefix.size());
+
+ // Split the output by commas. Example: 144,0,"00FFFF02"
+ auto vOutput = MTS::Text::split(sRawResponse, ',', 3);
+ if (vOutput.size() < 3) {
+ printError("%s| Unexpected response from the radio: [%s]", m_sName.c_str(), sRawResponse.c_str());
+ return CODE::FAILURE;
+ }
+
+ // Two unquoted integers
+ const std::string& sSw1 = vOutput[0];
+ const std::string& sSw2 = vOutput[1];
+
+ // Check if the SIM indicates any errors
+ if (sSw1 != "144" || sSw2 != "0") {
+ printError("%s| Unexpected response from the SIM: [%s]", m_sName.c_str(), sRawResponse.c_str());
+ return CODE::FAILURE;
+ }
+
+ // Quectel radios quote the third element of the output. Remove the quoting.
+ const std::string& sResponse = MTS::Text::trim(vOutput[2], '"');
+
+ sResult = sResponse;
+ return CODE::SUCCESS;
+}
+
+ICellularRadio::CODE CellularRadio::getSimMncLength(uint8_t& iLength) {
+ printTrace("%s| Get SIM MNC length", m_sName.c_str());
+
+ const int iEfadId = 0x6FAD;
+ const uint8_t iOffsetHigh = 0;
+ const uint8_t iOffsetLow = 0;
+ const uint8_t iNumBytes = 0;
+
+ CODE rc;
+ std::string sEFadContent;
+
+ rc = simAccessReadBinary(iEfadId, iOffsetLow, iOffsetHigh, iNumBytes, sEFadContent);
+ if (rc != CODE::SUCCESS) {
+ printError("%s| Failed to determine the SIM MNC length", m_sName.c_str());
+ return rc;
+ }
+
+ // length of MNC in the IMSI is stored in byte 4 of EFad (indexing from 1)
+ const uint8_t iMncLengthEfadIdx = 4;
+ const uint8_t iCharsPerByte = 2;
+ const uint8_t iMinEFadLength = iMncLengthEfadIdx * iCharsPerByte;
+
+ if (sEFadContent.size() < iMinEFadLength) {
+ printError("%s| SIM EFad does not contain an MNC length byte: [%s]", m_sName.c_str(), sEFadContent.c_str());
+ return CODE::FAILURE;
+ }
+
+ // read byte 4 of EFad (indexing from 1) with the MNC length
+ const size_t iMncStartPosition = (iMncLengthEfadIdx - 1) * iCharsPerByte;
+ const std::string sMncLength = sEFadContent.substr(iMncStartPosition, iCharsPerByte);
+ uint8_t iMncLength;
+
+ // parse hex to unsigned byte
+ if (!MTS::Text::parseHex(iMncLength, sMncLength)) {
+ printError("%s| Unexpected SIM EFad content: [%s]", m_sName.c_str(), sEFadContent.c_str());
+ return CODE::FAILURE;
+ }
+
+ // Only the lower 4 bits are used for MNC length, others are reserved for future use.
+ iMncLength &= 0x0F;
+
+ // Done
+ iLength = iMncLength;
+ printDebug("%s| Got MNC length of [%u]", m_sName.c_str(), iLength);
+
+ return CODE::SUCCESS;
+}
+
+ICellularRadio::CODE CellularRadio::getSimMccMnc(std::string& sMccMnc) {
+ printTrace("%s| Get MCC/MNC of the home network from the SIM", m_sName.c_str());
+
+ CODE rc;
+ std::string sImsi;
+ uint8_t iMncLength;
+
+ do {
+ rc = getImsi(sImsi);
+ if (rc != CODE::SUCCESS) {
+ printError("%s| Failed to get SIM IMSI", m_sName.c_str());
+ break;
+ }
+
+ if (sImsi.size() < 5) {
+ printError("%s| Unexpected IMSI value: [%s]", m_sName.c_str(), sImsi.c_str());
+ rc = CODE::FAILURE;
+ break;
+ }
+
+ rc = getSimMncLength(iMncLength);
+ if (rc != CODE::SUCCESS) {
+ printError("%s| Failed to determine the MNC length", m_sName.c_str());
+ break;
+ }
+
+ // MNC shall be 2 or 3 characters long
+ if (iMncLength < 2 || iMncLength > 3) {
+ printError("%s| Unexpected MNC length: [%u]", m_sName.c_str(), iMncLength);
+ rc = CODE::FAILURE;
+ break;
+ }
+
+ // PLMN code shall be 5 or 6 characters long
+ const size_t mncLength = 3;
+ const size_t plmnCodeLength = mncLength + iMncLength;
+
+ sMccMnc = sImsi.substr(0, plmnCodeLength);
+
+ // Done
+ printDebug("%s| Got MCC/MNC of the home network from the SIM: [%s]", m_sName.c_str(), sMccMnc.c_str());
+ rc = CODE::SUCCESS;
+ } while (false);
+
+ return rc;
+}
+
+ICellularRadio::CODE CellularRadio::getSimMccMnc(std::string& sMcc, std::string& sMnc) {
+ CODE rc;
+ std::string sPlmnCode;
+
+ rc = getSimMccMnc(sPlmnCode);
+
+ if (rc == CODE::SUCCESS) {
+ // PLMN code consists of MCC (first 3 digits) and MNC (second 2 or 3 digits)
+ sMcc = sPlmnCode.substr(0, 3);
+ sMnc = sPlmnCode.substr(3);
+ }
+
+ return rc;
+}
+
ICellularRadio::CODE CellularRadio::validateMsl(const Json::Value&) {
printTrace("%s| Validate MSL", m_sName.c_str());
diff --git a/src/MTS_IO_ICellularRadio.cpp b/src/MTS_IO_ICellularRadio.cpp
index 0483dc8..042faf1 100644
--- a/src/MTS_IO_ICellularRadio.cpp
+++ b/src/MTS_IO_ICellularRadio.cpp
@@ -52,6 +52,7 @@ const char *MTS::IO::ICellularRadio::KEY_ICCID = "iccid"; //!< Integrated
const char *MTS::IO::ICellularRadio::KEY_MSL = "msl"; //!< Master Subsidy Lock
const char *MTS::IO::ICellularRadio::KEY_SUPPORTED_CELL_MODES = "supportedCellularModes"; //!< Comma-separated list of all supported cellular modes (2g,3g,4g)
const char *MTS::IO::ICellularRadio::KEY_SIM_CARRIER_CODE = "simCarrierCode"; //!< Unique carrier identifier based on the SIM card information.
+const char *MTS::IO::ICellularRadio::KEY_SIM_MCC_MNC = "simMccMnc"; //!< MCC/MNC of the home network from the SIM.
//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