From 67a991ff3d772d2f81cb9907e1a710a88436f7c7 Mon Sep 17 00:00:00 2001 From: "mykola.salomatin" Date: Thu, 15 Apr 2021 17:52:10 +0300 Subject: [MTX-3998] mPower R. Apr 2021: +CEMODE shall be set to CEMODE=2 - Quectel - GP-1111 Added CEMODE switching support for Quectel radios --- include/mts/MTS_IO_ICellularRadio.h | 10 ++- include/mts/MTS_IO_QuectelRadio.h | 12 +++ src/MTS_IO_ICellularRadio.cpp | 14 ++++ src/MTS_IO_QuectelRadio.cpp | 153 ++++++++++++++++++++++++++++++++++++ 4 files changed, 185 insertions(+), 4 deletions(-) diff --git a/include/mts/MTS_IO_ICellularRadio.h b/include/mts/MTS_IO_ICellularRadio.h index e8ae891..c35e903 100644 --- a/include/mts/MTS_IO_ICellularRadio.h +++ b/include/mts/MTS_IO_ICellularRadio.h @@ -70,10 +70,12 @@ namespace MTS { enum UE_MODES_OF_OPERATION : uint8_t { UNKNOWN_MODE = 0, // current mode of operation is not available - PS_MODE1, // only EPS (LTE) services are allowed, the usage is “voice centric” - PS_MODE2, // only EPS (LTE) services are allowed, the usage is “data centric” - CS_PS_MODE1, // both EPS and non-EPS services are allowed, the usage is “voice centric” - CS_PS_MODE2 // both EPS and non-EPS services are allowed, the usage is “data centric” + PS_MODE1, // only EPS (LTE) services are allowed, the usage is "voice centric" + PS_MODE2, // only EPS (LTE) services are allowed, the usage is "data centric" + CS_PS_MODE1, // both EPS and non-EPS services are allowed, the usage is "voice centric" + CS_PS_MODE2, // both EPS and non-EPS services are allowed, the usage is "data centric" + CS_MODE1, // only non-EPS services are allowed, the usage is "voice centric" + CS_MODE2 // only non-EPS services are allowed, the usage is "data centric" }; static CODE convertModelToType(const std::string& sModel, std::string& sType); diff --git a/include/mts/MTS_IO_QuectelRadio.h b/include/mts/MTS_IO_QuectelRadio.h index 9713f48..04c0ef9 100644 --- a/include/mts/MTS_IO_QuectelRadio.h +++ b/include/mts/MTS_IO_QuectelRadio.h @@ -51,7 +51,16 @@ namespace MTS { CODE fumoLocalCleanup() override; CODE fumoLocalApply(UpdateCb& stepCb) override; + CODE setUeModeOfOperation(UE_MODES_OF_OPERATION mode) override; + CODE getUeModeOfOperation(UE_MODES_OF_OPERATION& mode) override; + protected: + enum class UE_USAGE_SETTING : uint8_t { + UNKNOWN_MODE = 0, // Unknown mode + MODE_1, // Voice centric mode + MODE_2 // Data centric mode + }; + QuectelRadio(const std::string& sName, const std::string& sRadioPort); CODE getIsSimInserted(bool& bData) override; @@ -64,6 +73,9 @@ namespace MTS { virtual CODE removeFile(const std::string& sTargetFilename); virtual CODE checkFile(bool& bFilePresent, const std::string& sTargetFilename); + virtual CODE getUeUsageSetting(UE_USAGE_SETTING& us); + virtual CODE convertToUeUsageSetting(const std::string& sSetting, UE_USAGE_SETTING& us); + private: // private variable to save old firmware versions during FOTA std::string m_sQuectelFirmware; diff --git a/src/MTS_IO_ICellularRadio.cpp b/src/MTS_IO_ICellularRadio.cpp index 9f63408..1fbad0c 100644 --- a/src/MTS_IO_ICellularRadio.cpp +++ b/src/MTS_IO_ICellularRadio.cpp @@ -532,6 +532,14 @@ MTS::IO::ICellularRadio::CODE MTS::IO::ICellularRadio::convertUeModeToString(MTS string = "csps_2"; rc = CODE::SUCCESS; break; + case ICellularRadio::UE_MODES_OF_OPERATION::CS_MODE1: + string = "cs_1"; + rc = CODE::SUCCESS; + break; + case ICellularRadio::UE_MODES_OF_OPERATION::CS_MODE2: + string = "cs_2"; + rc = CODE::SUCCESS; + break; default: string = MTS::IO::ICellularRadio::VALUE_UNKNOWN; rc = CODE::FAILURE; @@ -555,6 +563,12 @@ MTS::IO::ICellularRadio::CODE MTS::IO::ICellularRadio::convertStringToUeMode(con } else if (sMode == "csps_2") { mode = ICellularRadio::UE_MODES_OF_OPERATION::CS_PS_MODE2; rc = CODE::SUCCESS; + } else if (sMode == "cs_1") { + mode = ICellularRadio::UE_MODES_OF_OPERATION::CS_MODE1; + rc = CODE::SUCCESS; + } else if (sMode == "cs_2") { + mode = ICellularRadio::UE_MODES_OF_OPERATION::CS_MODE2; + rc = CODE::SUCCESS; } else { mode = ICellularRadio::UNKNOWN_MODE; rc = CODE::FAILURE; diff --git a/src/MTS_IO_QuectelRadio.cpp b/src/MTS_IO_QuectelRadio.cpp index aeb06ab..4f20627 100644 --- a/src/MTS_IO_QuectelRadio.cpp +++ b/src/MTS_IO_QuectelRadio.cpp @@ -1221,3 +1221,156 @@ ICellularRadio::CODE QuectelRadio::abortFileUpload() { sleep(1); return sendBasicCommand(CMD_ABORT_UPLOAD, 2000, 0x00); } + +ICellularRadio::CODE QuectelRadio::setUeModeOfOperation(UE_MODES_OF_OPERATION mode) { + std::string sDomain, sPreference; + + switch (mode) { + case UE_MODES_OF_OPERATION::CS_MODE1: + sDomain = "0"; + sPreference = "00"; + break; + case UE_MODES_OF_OPERATION::CS_MODE2: + sDomain = "0"; + sPreference = "01"; + break; + case UE_MODES_OF_OPERATION::PS_MODE1: + sDomain = "1"; + sPreference = "00"; + break; + case UE_MODES_OF_OPERATION::PS_MODE2: + sDomain = "1"; + sPreference = "01"; + break; + case UE_MODES_OF_OPERATION::CS_PS_MODE1: + sDomain = "2"; + sPreference = "00"; + break; + case UE_MODES_OF_OPERATION::CS_PS_MODE2: + sDomain = "2"; + sPreference = "01"; + break; + default: + printTrace("Set UE Mode Of Operation: invalid argument"); + return INVALID_ARGS; + } + + CODE rc; + const int dTimeout = 1000; // ms + std::string sCommand = "AT+QNVFW=\"/nv/item_files/modem/mmode/ue_usage_setting\"," + sPreference; + + rc = sendBasicCommand(sCommand, dTimeout); + if (rc != SUCCESS) { + printError("Voice/data preference configuration failed with code [%d]", rc); + return rc; + } + + sCommand = "AT+QCFG=\"servicedomain\"," + sDomain + ",0"; + + rc = sendBasicCommand(sCommand, dTimeout); + if (rc != SUCCESS) { + printError("Service domain configuration failed with code [%d]", rc); + return rc; + } + + return SUCCESS; +} + +ICellularRadio::CODE QuectelRadio::getUeUsageSetting(UE_USAGE_SETTING& us) { + printTrace("%s| Get UE Usage Setting", getName().c_str()); + + std::string sCmd("AT+QNVFR=\"/nv/item_files/modem/mmode/ue_usage_setting\""); + std::string sResult = sendCommand(sCmd); + size_t end = sResult.find(ICellularRadio::RSP_OK); + + if (end == std::string::npos) { + printError("%s| Unable to get UE Usage Setting [%s]", getName().c_str(), sResult.c_str()); + return FAILURE; + } + + // +QNVFR: + const std::string sLabel = "+QNVFR: "; + size_t start = sResult.find(sLabel); + if (start == std::string::npos) { + printError("%s| Failed to parse UE Usage Setting from output [%s]", getName().c_str(), sResult.c_str()); + return FAILURE; + } + + start += sLabel.length(); + const std::string sPreference = MTS::Text::trim(sResult.substr(start, end - start)); + + if (convertToUeUsageSetting(sPreference, us) != SUCCESS) { + printError("%s| Unable to convert [%s] to UE Usage Setting", getName().c_str(), sPreference.c_str()); + return FAILURE; + } + + return SUCCESS; +} + +ICellularRadio::CODE QuectelRadio::convertToUeUsageSetting(const std::string& sSetting, UE_USAGE_SETTING& us) { + if (sSetting == "00") { + us = UE_USAGE_SETTING::MODE_1; + return SUCCESS; + } + + if (sSetting == "01") { + us = UE_USAGE_SETTING::MODE_2; + return SUCCESS; + } + + us = UE_USAGE_SETTING::UNKNOWN_MODE; + return FAILURE; +} + +ICellularRadio::CODE QuectelRadio::getUeModeOfOperation(UE_MODES_OF_OPERATION& mode) { + printTrace("%s| Get UE Mode Of Operation", getName().c_str()); + + SERVICEDOMAIN sd; + UE_USAGE_SETTING us; + + if (getServiceDomain(sd) != SUCCESS) { + return FAILURE; + } + + printTrace("%s| Retrieved servicedomain [%d]", getName().c_str(), sd); + + if (getUeUsageSetting(us) != SUCCESS) { + return FAILURE; + } + + printTrace("%s| Retrieved ue_usage_setting [%d]", getName().c_str(), us); + + if (sd == SERVICEDOMAIN::CS_ONLY && us == UE_USAGE_SETTING::MODE_1) { + mode = UE_MODES_OF_OPERATION::CS_MODE1; + return SUCCESS; + } + + if (sd == SERVICEDOMAIN::CS_ONLY && us == UE_USAGE_SETTING::MODE_2) { + mode = UE_MODES_OF_OPERATION::CS_MODE2; + return SUCCESS; + } + + if (sd == SERVICEDOMAIN::PS_ONLY && us == UE_USAGE_SETTING::MODE_1) { + mode = UE_MODES_OF_OPERATION::PS_MODE1; + return SUCCESS; + } + + if (sd == SERVICEDOMAIN::PS_ONLY && us == UE_USAGE_SETTING::MODE_2) { + mode = UE_MODES_OF_OPERATION::PS_MODE2; + return SUCCESS; + } + + if (sd == SERVICEDOMAIN::CSPS && us == UE_USAGE_SETTING::MODE_1) { + mode = UE_MODES_OF_OPERATION::CS_PS_MODE1; + return SUCCESS; + } + + if (sd == SERVICEDOMAIN::CSPS && us == UE_USAGE_SETTING::MODE_2) { + mode = UE_MODES_OF_OPERATION::CS_PS_MODE2; + return SUCCESS; + } + + printError("%s| Unknown combination of servicedomain [%d] and ue_usage_setting [%d]", getName().c_str(), sd, us); + mode = UE_MODES_OF_OPERATION::UNKNOWN_MODE; + return FAILURE; +} -- cgit v1.2.3