summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/mts/MTS_IO_CellularRadio.h38
-rw-r--r--include/mts/MTS_IO_ICellularRadio.h48
-rw-r--r--include/mts/MTS_IO_QuectelRadio.h3
-rw-r--r--include/mts/MTS_IO_TelitRadio.h4
-rw-r--r--src/MTS_IO_CellularRadio.cpp88
-rw-r--r--src/MTS_IO_ICellularRadio.cpp6
-rw-r--r--src/MTS_IO_QuectelRadio.cpp79
-rw-r--r--src/MTS_IO_TelitRadio.cpp91
8 files changed, 357 insertions, 0 deletions
diff --git a/include/mts/MTS_IO_CellularRadio.h b/include/mts/MTS_IO_CellularRadio.h
index 899ceeb..9866d73 100644
--- a/include/mts/MTS_IO_CellularRadio.h
+++ b/include/mts/MTS_IO_CellularRadio.h
@@ -61,6 +61,7 @@ namespace MTS {
CODE getMeid(std::string& sMeid) override;
CODE getImsi(std::string& sImsi) override;
CODE getSimStatus(std::string& sSimStatus) override;
+ CODE getSimStatusSummary(Json::Value& jData) override;
CODE getLac(std::string& sLac) override;
CODE getMdn(std::string& sMdn) override;
CODE getMsid(std::string& sMsid) override;
@@ -75,6 +76,9 @@ namespace MTS {
CODE getRegistration(REGISTRATION& eRegistration) override;
CODE convertRegistrationToString(REGISTRATION eRegistration, std::string& sRegistration) override;
+
+ CODE unlockSimCard(const Json::Value& jArgs) override;
+
CODE getMipProfile(Json::Value& jMipProfile) override;
CODE validateMsl(const Json::Value& jArgs) override;
CODE setMsid(const Json::Value& jArgs) override;
@@ -122,6 +126,40 @@ namespace MTS {
virtual void getCommonNetworkStats(Json::Value& jData);
+ /**
+ * @brief getIsSimInserted - returns if the SIM card is inserted / installed or not.
+ *
+ * @param bData - an object to be filled with the SIM card insertion status.
+ * `true` when SIM card is inserted / installed / present,
+ * `false` otherwise.
+ * @return CODE::SUCCESS when SIM insertion status is fetched successfully,
+ * CODE::NOT_APPLICABLE when the modem doesn't support this feature,
+ * CODE::ERROR otherwise (when modem is inaccessible or in other cases).
+ */
+ virtual CODE getIsSimInserted(bool& bData) = 0;
+
+ /**
+ * @brief getSimLockStatus - return the SIM lock status as defined by AT+CPIN? command.
+ * Returns "READY", "SIM PIN", "SIM PUK" or other SIM status.
+ *
+ * @param sData - an object to be filled with the SIM lock status
+ * @return CODE::SUCCESS when SIM status is fetched successfully,
+ * CODE::NOT_APPLICABLE when the modem doesn't support this feature,
+ * CODE::ERROR otherwise (SIM card removed, modem is inaccessible, etc).
+ */
+ virtual CODE getSimLockStatus(std::string& sData);
+
+ /**
+ * @brief getSimLockAttempts - get the number of SIM unlock attempts left.
+ *
+ * @param iAttemptsPin - the number of attempts left to enter a PIN code.
+ * @param iAttemptsPuk - the number of attempts left to enter a PUK code.
+ * @return CODE::SUCCESS when both numbers are fetched successfully,
+ * CODE::NOT_APPLICABLE when the modem doesn't support this feature,
+ * CODE::ERROR otherwise (SIM card removed, modem is inaccessible, etc).
+ */
+ virtual CODE getSimLockAttempts(int& iAttemptsPin, int& iAttemptsPuk) = 0;
+
void initMipProfile(Json::Value& jData);
bool splitAndAssign(const std::string& sLine, const std::string& sKey, Json::Value& jParent, const std::string& sJsonKey, Json::ValueType eType = Json::ValueType::stringValue);
diff --git a/include/mts/MTS_IO_ICellularRadio.h b/include/mts/MTS_IO_ICellularRadio.h
index 1b95a0d..2d47fcf 100644
--- a/include/mts/MTS_IO_ICellularRadio.h
+++ b/include/mts/MTS_IO_ICellularRadio.h
@@ -168,6 +168,12 @@ namespace MTS {
static const char *KEY_MIP_MNAAASS; //!< Mobile Node Authentication, Authorization, and Accounting Server Shared Secret
static const char *KEY_MIP_MNHASS; //!< Mobile Node Home Agent Shared Secret
+ //SIM Status Summary data
+ static const char *KEY_IS_SIM_INSERTED; //!< SIM card insertion indicator. True when a SIM card is inserted
+ static const char *KEY_IS_SIM_LOCKED; //!< SIM card lock status indicator. True when a SIM card is locked by PIN / PUK / other code
+ static const char *KEY_SIM_LOCK_STATUS; //!< SIM card lock status string. Either "READY", "SIM PIN", "SIM PUK" or other state
+ static const char *KEY_ATTEMPTS_PIN; //!< The number of attempts left to unlock the SIM card using PIN code
+ static const char *KEY_ATTEMPTS_PUK; //!< The number of attempts left to unlock the SIM card using PUK code
//Values - Type
static const char *VALUE_TYPE_LTE;
@@ -213,6 +219,29 @@ namespace MTS {
virtual CODE getMeid(std::string& sMeid) = 0;
virtual CODE getImsi(std::string& sImsi) = 0;
virtual CODE getSimStatus(std::string& sSimStatus) = 0;
+
+ /**
+ * @brief getSimStatusSummary - get summary on the SIM card status
+ * (if there is a SIM card inserted, is it locked, etc).
+ * See below for the full list of returned fields.
+ *
+ * - `isSimInserted` - bool, is the SIM card installed or not;
+ * - `isSimLocked` - bool, is the SIM card blocked with PIN/PUK or not (or is READY);
+ * - `lockStatus` - string, either "READY", "SIM PUK", "SIM PIN" or other status as
+ * returned by "AT+CPIN?" AT command;
+ * - `attemptsPin` - integer, the number of attempts lef to enter a PIN code;
+ * - `attemptsPuk` - integer, the number of attempts lef to enter a PUK code.
+ *
+ * **Only `isSimInserted` is always present.** All other fields are omitted if
+ * the SIM card is removed.
+ *
+ * @param jData - an object to be filled with data
+ * @return CODE::SUCCESS on success,
+ * CODE::NOT_APPLICABLE if not supported by this radio
+ * and CODE::ERROR otherwise
+ */
+ virtual CODE getSimStatusSummary(Json::Value& jData) = 0;
+
virtual CODE getIccid(std::string& sIccid) = 0;
virtual CODE getService(std::string& sService) = 0;
virtual CODE getLac(std::string& sLac) = 0;
@@ -235,6 +264,25 @@ namespace MTS {
virtual CODE getRadioMode(RADIOMODE &mode) = 0;
virtual CODE setRadioMode(RADIOMODE mode) = 0;
+ /**
+ * @brief unlockSimCard - unlock the SIM card using PIN code provided
+ *
+ * This command does not peform any checks on the number of attempts left.
+ * Use with caution, verify the SIM status manually before execution.
+ *
+ * @param jArgs - a JSON object with the following format:
+ *
+ * jArgs = {
+ * "pin" : "A correct PIN code to unlock the SIM card: STRING"
+ * }
+ *
+ * @return CODE::SUCCESS when SIM card was succeffully unlocked,
+ * CODE::INVALID_ARGS when passed arguments are invalid,
+ * CODE::ERROR otherwise (i.e. when modem is not responding,
+ * when SIM card is removed, when PIN code is not correct
+ * or on any other error).
+ */
+ virtual CODE unlockSimCard(const Json::Value& jArgs) = 0;
//! Gather details of the radio's Mobile IP Profile
/*!
diff --git a/include/mts/MTS_IO_QuectelRadio.h b/include/mts/MTS_IO_QuectelRadio.h
index 0ca7f3b..3e5886c 100644
--- a/include/mts/MTS_IO_QuectelRadio.h
+++ b/include/mts/MTS_IO_QuectelRadio.h
@@ -50,6 +50,9 @@ namespace MTS {
bool getCarrierFromFirmware(const std::string& sFirmware, std::string& sCarrier) override;
bool getHardwareVersionFromFirmware(const std::string& sFirmware, std::string& sHardware) override;
+ CODE getIsSimInserted(bool& bData) override;
+ CODE getSimLockAttempts(int& iAttemptsPin, int& iAttemptsPuk) override;
+
virtual CODE getServiceDomain(SERVICEDOMAIN& sd);
virtual CODE convertToActiveBand(const std::string& sQuectelBand, ACTIVEBAND& band);
diff --git a/include/mts/MTS_IO_TelitRadio.h b/include/mts/MTS_IO_TelitRadio.h
index 47d6cf6..08b144c 100644
--- a/include/mts/MTS_IO_TelitRadio.h
+++ b/include/mts/MTS_IO_TelitRadio.h
@@ -48,7 +48,11 @@ namespace MTS {
bool getCarrierFromFirmware(const std::string& sFirmware, std::string& sCarrier) override;
bool getHardwareVersionFromFirmware(const std::string& sFirmware, std::string& sHardware) override;
+ CODE getIsSimInserted(bool& bData) override;
+ CODE getSimLockAttempts(int& iAttemptsPin, int& iAttemptsPuk) override;
+
private:
+ virtual CODE getSimLockAttempts(int& iAttemptsPin, int& iAttemptsPuk, const std::string& sLockStatus);
};
}
diff --git a/src/MTS_IO_CellularRadio.cpp b/src/MTS_IO_CellularRadio.cpp
index dbb64a5..df1303c 100644
--- a/src/MTS_IO_CellularRadio.cpp
+++ b/src/MTS_IO_CellularRadio.cpp
@@ -285,6 +285,50 @@ CellularRadio::CODE CellularRadio::getSimStatus(std::string& sSimStatus) {
return FAILURE;
}
+CellularRadio::CODE CellularRadio::getSimStatusSummary(Json::Value& jData) {
+ bool bIsSimInserted = false;
+ bool bIsSimLocked = true;
+ int iAttemptsPin = 0;
+ int iAttemptsPuk = 0;
+ std::string sSimLockStatus;
+ CODE retCode;
+
+ do {
+ retCode = getIsSimInserted(bIsSimInserted);
+ if (retCode != SUCCESS) {
+ break;
+ }
+
+ if (!bIsSimInserted) {
+ // There is no left much to do. Return one field only.
+ jData[KEY_IS_SIM_INSERTED] = bIsSimInserted;
+ break;
+ }
+
+ // The following code assumes that the SIM card is inserted
+ retCode = getSimLockStatus(sSimLockStatus);
+ if (retCode != SUCCESS) {
+ break;
+ }
+
+ 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) {
Json::Value jData;
@@ -716,6 +760,31 @@ void CellularRadio::getCommonNetworkStats(Json::Value& jData) {
}
}
+CellularRadio::CODE CellularRadio::getSimLockStatus(std::string& sData)
+{
+ printTrace("%s| Get SIM lock status", m_sName.c_str());
+ std::string sCmd("AT+CPIN?");
+ std::string sResult = sendCommand(sCmd);
+
+ 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[ICellularRadio::KEY_MIP_ID] = 0;
jData[ICellularRadio::KEY_MIP_ENABLED] = false;
@@ -777,6 +846,25 @@ CellularRadio::CODE CellularRadio::convertRegistrationToString(REGISTRATION eReg
return eCode;
}
+CellularRadio::CODE CellularRadio::unlockSimCard(const Json::Value& jArgs) {
+ printTrace("%s| Unlock the SIM card using PIN code", m_sName.c_str());
+
+ if(!jArgs["pin"].isString()) {
+ return INVALID_ARGS;
+ }
+
+ std::string sCmd = "AT+CPIN=" + jArgs["pin"].asString();
+ std::string sResult = sendCommand(sCmd);
+
+ 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::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 7f216d0..4e7809e 100644
--- a/src/MTS_IO_ICellularRadio.cpp
+++ b/src/MTS_IO_ICellularRadio.cpp
@@ -94,6 +94,12 @@ 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";
diff --git a/src/MTS_IO_QuectelRadio.cpp b/src/MTS_IO_QuectelRadio.cpp
index 50185b3..8ac9bac 100644
--- a/src/MTS_IO_QuectelRadio.cpp
+++ b/src/MTS_IO_QuectelRadio.cpp
@@ -478,6 +478,85 @@ bool QuectelRadio::getHardwareVersionFromFirmware(const std::string& sFirmware,
return false;
}
+CellularRadio::CODE QuectelRadio::getIsSimInserted(bool& bData) {
+ printTrace("%s| Get SIM insertion status", getName().c_str());
+ std::string sCmd("AT+QSIMSTAT?");
+ std::string sResult = sendCommand(sCmd);
+
+ 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;
+}
+
+CellularRadio::CODE QuectelRadio::getSimLockAttempts(int& iAttemptsPin, int& iAttemptsPuk) {
+ printTrace("%s| Get SIM unlock attempts left", getName().c_str());
+ std::string sCmd("AT+QPINC=\"SC\"");
+ std::string sResult = sendCommand(sCmd);
+
+ 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;
+}
+
CellularRadio::CODE QuectelRadio::convertToActiveBand(const std::string& sQuectelBand, ICellularRadio::ACTIVEBAND& band) {
int iQuectelBand = -1;
diff --git a/src/MTS_IO_TelitRadio.cpp b/src/MTS_IO_TelitRadio.cpp
index 7b5b18b..2d0422d 100644
--- a/src/MTS_IO_TelitRadio.cpp
+++ b/src/MTS_IO_TelitRadio.cpp
@@ -573,3 +573,94 @@ ICellularRadio::CODE TelitRadio::setRadioMode(RADIOMODE mode)
}
return SUCCESS;
}
+
+CellularRadio::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;
+}
+
+CellularRadio::CODE TelitRadio::getSimLockAttempts(int& iAttemptsPin, int& iAttemptsPuk) {
+ std::string sLockStatus;
+ 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);
+}
+
+CellularRadio::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);
+ 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;
+}