From 42d384984b2f760bc8f7a69c7ea3464c73f4d892 Mon Sep 17 00:00:00 2001 From: Serhii Kostiuk Date: Tue, 2 Jun 2020 17:19:03 +0300 Subject: [GP-651] LNA7: Allow to start the OMA DM procedure when it is required This commits adds support for the Quectel-specific OMA DM commands. This allows to trigger OMA DM procedure om Verizon to fetch the corrent APN values and other settings from the network. Expected radio output on success: ``` +QODM: "DME",0,DM Start +QODM: "DME",0,DM End ``` Other +QODM URC codes are also possible according to information from Quectel forum: https://forums.quectel.com/t/what-is-the-meaning-of-qodm-fumo-report-failed/2444/5. But only "DM Start" and "DM End" responses are expected, supported and treated as correct in the libmts-io. --- src/MTS_IO_CellularRadio.cpp | 6 ++++ src/MTS_IO_QuectelRadio.cpp | 72 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) (limited to 'src') diff --git a/src/MTS_IO_CellularRadio.cpp b/src/MTS_IO_CellularRadio.cpp index 50fdf5c..648894f 100644 --- a/src/MTS_IO_CellularRadio.cpp +++ b/src/MTS_IO_CellularRadio.cpp @@ -1020,6 +1020,12 @@ ICellularRadio::CODE CellularRadio::activate(const Json::Value&, UpdateCb&) { return NOT_APPLICABLE; } +ICellularRadio::CODE CellularRadio::startOmaDm(ICellularRadio::UpdateCb&) { + printTrace("%s| Start OMA DM procedure: not applicable", m_sName.c_str()); + + return NOT_APPLICABLE; +} + ICellularRadio::CODE CellularRadio::setActiveFirmware(const Json::Value&) { printTrace("%s| Set Active Firmware Image Number: not applicable", m_sName.c_str()); diff --git a/src/MTS_IO_QuectelRadio.cpp b/src/MTS_IO_QuectelRadio.cpp index c4bdc56..b750bd6 100644 --- a/src/MTS_IO_QuectelRadio.cpp +++ b/src/MTS_IO_QuectelRadio.cpp @@ -436,6 +436,78 @@ ICellularRadio::CODE QuectelRadio::setMdn(const Json::Value& jArgs) { return NOT_APPLICABLE; } +ICellularRadio::CODE QuectelRadio::startOmaDm(ICellularRadio::UpdateCb& stepCb) { + printTrace("%s| Start OMA DM procedure", getName().c_str()); + + const int32_t iTimeoutOk = 3 * 1000; // 3 seconds + const int32_t iTimeoutStart = 5 * 1000; // 5 seconds + const int32_t iTimeoutEnd = 1 * 60 * 1000; // 1 minute + + const std::string sOdmStarted = "DM Start"; + const std::string sOdmFinished = "DM End"; + + const std::vector vOdmStartedStrings{ sOdmStarted }; + const std::vector vOdmFinishedStrings{ sOdmFinished }; + + CODE eCode; + + do { + + // Send command and expect "OK" in iTimeoutOk milliseconds + eCode = sendBasicCommand("AT+QODM=\"DME\",2,\"UI\"", iTimeoutOk); + if (eCode != SUCCESS) { + printError("%s| OMA DM procedure can not be started", getName().c_str()); + if (stepCb) { + stepCb(Json::Value("OMA DM Error: OMA DM can not be started")); + } + break; + } + + // Wait for the "Start" response + std::string sResponse = sendCommand("", vOdmStartedStrings, iTimeoutStart, 0x00); + printDebug("%s| Radio returned: [%s]", getName().c_str(), sResponse.c_str()); + + if (sResponse.find(sOdmStarted) == std::string::npos) { + printError("%s| OMA DM procedure failed due to timeout", getName().c_str()); + if (stepCb) { + stepCb(Json::Value("OMA DM Error: OMA DM failed due to timeout")); + } + eCode = FAILURE; + break; + } + + // Got "DM Started" message from the radio + printTrace("%s| OMA DM started", getName().c_str()); + if (stepCb) { + stepCb(Json::Value("OMA DM Info: OMA DM started")); + } + + // Wait for the "End" response + sResponse = sendCommand("", vOdmFinishedStrings, iTimeoutEnd, 0x00); + printDebug("%s| Radio returned: [%s]", getName().c_str(), sResponse.c_str()); + + if (sResponse.find(sOdmFinished) == std::string::npos) { + printError("%s| OMA DM procedure failed due to timeout", getName().c_str()); + if (stepCb) { + stepCb(Json::Value("OMA DM Error: OMA DM failed due to timeout")); + } + eCode = FAILURE; + break; + } + + // Got "DM End" message from the radio + printTrace("%s| OMA DM finished", getName().c_str()); + if (stepCb) { + stepCb(Json::Value("OMA DM Info: OMA DM finished")); + } + + eCode = SUCCESS; + + } while (false); + + return eCode; +} + ICellularRadio::CODE QuectelRadio::getServiceDomain(ICellularRadio::SERVICEDOMAIN& sd) { printTrace("%s| Get Service Domain", getName().c_str()); -- cgit v1.2.3 From 406cce9d517465698bd6f60c788b01c0e9f8e32e Mon Sep 17 00:00:00 2001 From: Serhii Kostiuk Date: Wed, 3 Jun 2020 11:16:37 +0300 Subject: [GP-651] LNA7: Allow to start the OMA DM procedure when it is required Fixed AT+QODM parameters. AT+QODM parameters are case-sensitive. --- src/MTS_IO_QuectelRadio.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/MTS_IO_QuectelRadio.cpp b/src/MTS_IO_QuectelRadio.cpp index b750bd6..5d29be7 100644 --- a/src/MTS_IO_QuectelRadio.cpp +++ b/src/MTS_IO_QuectelRadio.cpp @@ -454,7 +454,7 @@ ICellularRadio::CODE QuectelRadio::startOmaDm(ICellularRadio::UpdateCb& stepCb) do { // Send command and expect "OK" in iTimeoutOk milliseconds - eCode = sendBasicCommand("AT+QODM=\"DME\",2,\"UI\"", iTimeoutOk); + eCode = sendBasicCommand("AT+QODM=\"dme\",2,\"ui\"", iTimeoutOk); if (eCode != SUCCESS) { printError("%s| OMA DM procedure can not be started", getName().c_str()); if (stepCb) { -- cgit v1.2.3 From 73a5dc4711da4d21a7f650aec4534ecb3691ca15 Mon Sep 17 00:00:00 2001 From: Serhii Kostiuk Date: Fri, 5 Jun 2020 12:18:58 +0300 Subject: [GP-651] LNA7: Allow to start the OMA DM procedure when it is required Fixes after a code review: - increased timeout from 60 to 160 seconds for "Abnormal" cases; - added hanlding for the "DME Abnormal" URC; - added "kill OMA DM" logic for the timeout case. --- src/MTS_IO_QuectelRadio.cpp | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/MTS_IO_QuectelRadio.cpp b/src/MTS_IO_QuectelRadio.cpp index 5d29be7..360d988 100644 --- a/src/MTS_IO_QuectelRadio.cpp +++ b/src/MTS_IO_QuectelRadio.cpp @@ -439,22 +439,29 @@ ICellularRadio::CODE QuectelRadio::setMdn(const Json::Value& jArgs) { ICellularRadio::CODE QuectelRadio::startOmaDm(ICellularRadio::UpdateCb& stepCb) { printTrace("%s| Start OMA DM procedure", getName().c_str()); + // TODO: All the timeout values below are empirically defined. + // Feel free to update them if you get any verified information. const int32_t iTimeoutOk = 3 * 1000; // 3 seconds const int32_t iTimeoutStart = 5 * 1000; // 5 seconds - const int32_t iTimeoutEnd = 1 * 60 * 1000; // 1 minute + const int32_t iTimeoutEnd = 160 * 1000; // 2 minutes 40 seconds + const int32_t iTimeoutAbort = 3 * 1000; // 3 seconds + + const std::string sCmdOdmStart = "AT+QODM=\"dme\",2,\"ui\""; + const std::string sCmdOdmAbort = "AT+QODM=\"dme\",2,\"kill\""; const std::string sOdmStarted = "DM Start"; const std::string sOdmFinished = "DM End"; + const std::string sOdmAbnormal = "DME Abnormal"; const std::vector vOdmStartedStrings{ sOdmStarted }; - const std::vector vOdmFinishedStrings{ sOdmFinished }; + const std::vector vOdmFinishedStrings{ sOdmFinished, sOdmAbnormal }; CODE eCode; do { // Send command and expect "OK" in iTimeoutOk milliseconds - eCode = sendBasicCommand("AT+QODM=\"dme\",2,\"ui\"", iTimeoutOk); + eCode = sendBasicCommand(sCmdOdmStart, iTimeoutOk); if (eCode != SUCCESS) { printError("%s| OMA DM procedure can not be started", getName().c_str()); if (stepCb) { @@ -467,6 +474,7 @@ ICellularRadio::CODE QuectelRadio::startOmaDm(ICellularRadio::UpdateCb& stepCb) std::string sResponse = sendCommand("", vOdmStartedStrings, iTimeoutStart, 0x00); printDebug("%s| Radio returned: [%s]", getName().c_str(), sResponse.c_str()); + // Received something unexpected or nothing at all? if (sResponse.find(sOdmStarted) == std::string::npos) { printError("%s| OMA DM procedure failed due to timeout", getName().c_str()); if (stepCb) { @@ -482,15 +490,27 @@ ICellularRadio::CODE QuectelRadio::startOmaDm(ICellularRadio::UpdateCb& stepCb) stepCb(Json::Value("OMA DM Info: OMA DM started")); } - // Wait for the "End" response + // Wait for the "End" or "Abnormal" response sResponse = sendCommand("", vOdmFinishedStrings, iTimeoutEnd, 0x00); printDebug("%s| Radio returned: [%s]", getName().c_str(), sResponse.c_str()); + // Received "Abnormal"? + if (sResponse.find(sOdmAbnormal) != std::string::npos) { + printError("%s| OMA DM procedure failed due to internal error: [%s]", getName().c_str(), sResponse.c_str()); + if (stepCb) { + stepCb(Json::Value("OMA DM Error: OMA DM failed due to internal error: [%s]", sOdmAbnormal.c_str())); + } + eCode = FAILURE; + break; + } + + // Received something unexpected or nothing at all? if (sResponse.find(sOdmFinished) == std::string::npos) { printError("%s| OMA DM procedure failed due to timeout", getName().c_str()); if (stepCb) { stepCb(Json::Value("OMA DM Error: OMA DM failed due to timeout")); } + sendBasicCommand(sCmdOdmAbort, iTimeoutAbort); // abort the procedure eCode = FAILURE; break; } -- cgit v1.2.3 From c9b6389ac4e53315e7d543091c821ea4b9771ed3 Mon Sep 17 00:00:00 2001 From: Serhii Kostiuk Date: Fri, 5 Jun 2020 13:55:04 +0300 Subject: [GP-651] LNA7: Allow to start the OMA DM procedure when it is required Fixed totally invalid string formatting for the stepCb argument. The previous implementation caused Json::Value to select the following constructor: ```Value(const char* begin, const char* end); ///< Copy all, incl zeroes.``` Which, of course, resulted in OOM violations. Oops. --- src/MTS_IO_QuectelRadio.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/MTS_IO_QuectelRadio.cpp b/src/MTS_IO_QuectelRadio.cpp index 360d988..4498919 100644 --- a/src/MTS_IO_QuectelRadio.cpp +++ b/src/MTS_IO_QuectelRadio.cpp @@ -498,7 +498,7 @@ ICellularRadio::CODE QuectelRadio::startOmaDm(ICellularRadio::UpdateCb& stepCb) if (sResponse.find(sOdmAbnormal) != std::string::npos) { printError("%s| OMA DM procedure failed due to internal error: [%s]", getName().c_str(), sResponse.c_str()); if (stepCb) { - stepCb(Json::Value("OMA DM Error: OMA DM failed due to internal error: [%s]", sOdmAbnormal.c_str())); + stepCb(Json::Value("OMA DM Error: OMA DM failed due to internal error")); } eCode = FAILURE; break; -- cgit v1.2.3 From 7634bcfed0ea186175e9f59672a38d2a86fbf025 Mon Sep 17 00:00:00 2001 From: Serhii Kostiuk Date: Tue, 16 Jun 2020 11:50:20 +0300 Subject: GP-654: Add SIM card-based carrier detection This commit adds implementation of the SIM-based carrier detection. The goal for this implementation is to replace various places in the firmware that previously relied on the ICCID-based carrier detection, provide some layer of abstraction and forward compatibility for such places. It is particularly useful for fwSwitch radios with AUTO firmware selection capability. --- src/MTS_IO_CellularRadio.cpp | 43 +++++++++++++++++++++++++++++++++++++++++++ src/MTS_IO_ICellularRadio.cpp | 4 ++++ 2 files changed, 47 insertions(+) (limited to 'src') diff --git a/src/MTS_IO_CellularRadio.cpp b/src/MTS_IO_CellularRadio.cpp index 648894f..bef15e9 100644 --- a/src/MTS_IO_CellularRadio.cpp +++ b/src/MTS_IO_CellularRadio.cpp @@ -912,6 +912,49 @@ ICellularRadio::CODE CellularRadio::unlockSimCard(const Json::Value& jArgs) { return SUCCESS; } +ICellularRadio::CODE CellularRadio::getMtsSimCarrierCode(std::string& sCarrierCode) { + std::string sIccid; + CODE rc; + + printTrace("%s| Get MTS carrier code from the SIM card installed", m_sName.c_str()); + + rc = getIccid(sIccid); + if (rc != SUCCESS) { + printError("%s| Unable to determine SIM carrier: Failed to fetch SIM identifier", m_sName.c_str()); + return rc; + } + + printTrace("%s| Fetched ICCID: [%s]", m_sName.c_str(), sIccid.c_str()); + + rc = getMtsSimCarrierCode(sIccid, sCarrierCode); + if (rc != SUCCESS) { + printError("%s| Unable to determine SIM carrier: Unable to extract carrier from the SIM identifier", m_sName.c_str()); + return rc; + } + + printTrace("%s| Detected MTS carrier code: [%s]", m_sName.c_str(), sCarrierCode.c_str()); + return rc; +} + +ICellularRadio::CODE CellularRadio::getMtsSimCarrierCode(const std::string& sIccid, std::string& sCarrierCode) { + const char* ICCID_PREFIX_VZW = "891480"; + const char* ICCID_PREFIX_ATT = "8901410"; + + if (sIccid.find(ICCID_PREFIX_VZW) == 0) { + printTrace("%s| Verizon SIM detected", m_sName.c_str()); + sCarrierCode = VALUE_MTS_CARRIER_CODE_VERIZON; + } else if (sIccid.find(ICCID_PREFIX_ATT) == 0) { + printTrace("%s| AT&T SIM detected", m_sName.c_str()); + sCarrierCode = VALUE_MTS_CARRIER_CODE_ATT; + } else { + // All other carriers for which ICCID prefixes are not defined + printWarning("%s| Carrier is unknown for this SIM ID: [%s]", m_sName.c_str(), sIccid.c_str()); + sCarrierCode = VALUE_UNKNOWN; + } + + return SUCCESS; // no error cases for now +} + 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 53c8faa..e83ce80 100644 --- a/src/MTS_IO_ICellularRadio.cpp +++ b/src/MTS_IO_ICellularRadio.cpp @@ -50,6 +50,7 @@ const char *MTS::IO::ICellularRadio::KEY_MDN = "mdn"; //!< Mobile Dir const char *MTS::IO::ICellularRadio::KEY_ICCID = "iccid"; //!< Integrated Circuit Card Identifier 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_MTS_SIM_CARRIER_CODE = "mtsSimCarrierCode"; //!< MTS-specific carrier code fetched from the SIM card //Dynamic Data const char *MTS::IO::ICellularRadio::KEY_ROAMING = "roaming"; //!< Indicates whether or not using Home Network @@ -112,6 +113,9 @@ 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 char *MTS::IO::ICellularRadio::VALUE_MTS_CARRIER_CODE_VERIZON = "vz"; +const char *MTS::IO::ICellularRadio::VALUE_MTS_CARRIER_CODE_ATT = "att"; + const std::vector MTS::IO::ICellularRadio::DEFAULT_BAIL_STRINGS = { MTS::IO::ICellularRadio::RSP_OK, MTS::IO::ICellularRadio::RSP_ERROR }; MTS::IO::ICellularRadio::~ICellularRadio() -- cgit v1.2.3 From 747b898f36c4764475e61f20847ba4bbb3a81404 Mon Sep 17 00:00:00 2001 From: Serhii Kostiuk Date: Tue, 16 Jun 2020 15:37:02 +0300 Subject: [GP-654] Add SIM card-based carrier detection Changes after a code review: - renamed "MTS Carrier Code" to the "Carrier Code"; - fixed descriptions for the new field and methods. --- src/MTS_IO_CellularRadio.cpp | 14 +++++++------- src/MTS_IO_ICellularRadio.cpp | 7 +++---- 2 files changed, 10 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/MTS_IO_CellularRadio.cpp b/src/MTS_IO_CellularRadio.cpp index bef15e9..b18478e 100644 --- a/src/MTS_IO_CellularRadio.cpp +++ b/src/MTS_IO_CellularRadio.cpp @@ -912,11 +912,11 @@ ICellularRadio::CODE CellularRadio::unlockSimCard(const Json::Value& jArgs) { return SUCCESS; } -ICellularRadio::CODE CellularRadio::getMtsSimCarrierCode(std::string& sCarrierCode) { +ICellularRadio::CODE CellularRadio::getSimCarrierCode(std::string& sCarrierCode) { std::string sIccid; CODE rc; - printTrace("%s| Get MTS carrier code from the SIM card installed", m_sName.c_str()); + printTrace("%s| Get carrier code from the SIM card installed", m_sName.c_str()); rc = getIccid(sIccid); if (rc != SUCCESS) { @@ -926,26 +926,26 @@ ICellularRadio::CODE CellularRadio::getMtsSimCarrierCode(std::string& sCarrierCo printTrace("%s| Fetched ICCID: [%s]", m_sName.c_str(), sIccid.c_str()); - rc = getMtsSimCarrierCode(sIccid, sCarrierCode); + rc = getSimCarrierCode(sIccid, sCarrierCode); if (rc != SUCCESS) { printError("%s| Unable to determine SIM carrier: Unable to extract carrier from the SIM identifier", m_sName.c_str()); return rc; } - printTrace("%s| Detected MTS carrier code: [%s]", m_sName.c_str(), sCarrierCode.c_str()); + printTrace("%s| Detected carrier code: [%s]", m_sName.c_str(), sCarrierCode.c_str()); return rc; } -ICellularRadio::CODE CellularRadio::getMtsSimCarrierCode(const std::string& sIccid, std::string& sCarrierCode) { +ICellularRadio::CODE CellularRadio::getSimCarrierCode(const std::string& sIccid, std::string& sCarrierCode) { const char* ICCID_PREFIX_VZW = "891480"; const char* ICCID_PREFIX_ATT = "8901410"; if (sIccid.find(ICCID_PREFIX_VZW) == 0) { printTrace("%s| Verizon SIM detected", m_sName.c_str()); - sCarrierCode = VALUE_MTS_CARRIER_CODE_VERIZON; + sCarrierCode = VALUE_CARRIER_CODE_VERIZON; } else if (sIccid.find(ICCID_PREFIX_ATT) == 0) { printTrace("%s| AT&T SIM detected", m_sName.c_str()); - sCarrierCode = VALUE_MTS_CARRIER_CODE_ATT; + sCarrierCode = VALUE_CARRIER_CODE_ATT; } else { // All other carriers for which ICCID prefixes are not defined printWarning("%s| Carrier is unknown for this SIM ID: [%s]", m_sName.c_str(), sIccid.c_str()); diff --git a/src/MTS_IO_ICellularRadio.cpp b/src/MTS_IO_ICellularRadio.cpp index e83ce80..12d7916 100644 --- a/src/MTS_IO_ICellularRadio.cpp +++ b/src/MTS_IO_ICellularRadio.cpp @@ -50,8 +50,7 @@ const char *MTS::IO::ICellularRadio::KEY_MDN = "mdn"; //!< Mobile Dir const char *MTS::IO::ICellularRadio::KEY_ICCID = "iccid"; //!< Integrated Circuit Card Identifier 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_MTS_SIM_CARRIER_CODE = "mtsSimCarrierCode"; //!< MTS-specific carrier code fetched from the SIM card - +const char *MTS::IO::ICellularRadio::KEY_SIM_CARRIER_CODE = "simCarrierCode"; //!< Unique carrier identifier based on the SIM card information. //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 @@ -113,8 +112,8 @@ 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 char *MTS::IO::ICellularRadio::VALUE_MTS_CARRIER_CODE_VERIZON = "vz"; -const char *MTS::IO::ICellularRadio::VALUE_MTS_CARRIER_CODE_ATT = "att"; +const char *MTS::IO::ICellularRadio::VALUE_CARRIER_CODE_VERIZON = "vz"; +const char *MTS::IO::ICellularRadio::VALUE_CARRIER_CODE_ATT = "att"; const std::vector MTS::IO::ICellularRadio::DEFAULT_BAIL_STRINGS = { MTS::IO::ICellularRadio::RSP_OK, MTS::IO::ICellularRadio::RSP_ERROR }; -- cgit v1.2.3