diff options
-rw-r--r-- | include/mts/MTS_IO_CellularRadio.h | 331 | ||||
-rw-r--r-- | include/mts/MTS_IO_ICellularRadio.h | 1 | ||||
-rw-r--r-- | include/mts/MTS_IO_QuectelRadio.h | 2 | ||||
-rw-r--r-- | include/mts/MTS_IO_SequansRadio.h | 2 | ||||
-rw-r--r-- | include/mts/MTS_IO_TelitRadio.h | 2 | ||||
-rw-r--r-- | src/MTS_IO_CellularRadio.cpp | 67 | ||||
-rw-r--r-- | src/MTS_IO_QuectelRadio.cpp | 23 | ||||
-rw-r--r-- | src/MTS_IO_SequansRadio.cpp | 5 | ||||
-rw-r--r-- | src/MTS_IO_TelitRadio.cpp | 23 |
9 files changed, 266 insertions, 190 deletions
diff --git a/include/mts/MTS_IO_CellularRadio.h b/include/mts/MTS_IO_CellularRadio.h index 991dc47..a2fa3f3 100644 --- a/include/mts/MTS_IO_CellularRadio.h +++ b/include/mts/MTS_IO_CellularRadio.h @@ -279,171 +279,172 @@ namespace MTS { */ virtual const std::vector<std::string>& getDiagCommands(bool bIsSimReady = true) = 0; - struct PdpContextInfo { - std::string sId; - std::string sIpMode; - std::string sApn; - std::string sAuthType; - std::string sUsername; - std::string sPassword; - }; - - virtual std::vector<std::string> getSupportedPdpContextAuthTypes() const = 0; - static CODE convertPdpContextAuthTypeToString(PDP_CONTEXT_AUTH_TYPE eAuthType, std::string& sAuthType); - static CODE convertStringToPdpContextAuthType(const std::string& sAuthType, PDP_CONTEXT_AUTH_TYPE& eAuthType); - - /** - * @brief checks if PDP context authentication is supported by the modem. - * - * @param isSupported - sets to "true" if PDP context authentication is supported, "false" otherwise. - * - * @return CODE::SUCCESS when the response from the radio is received - * CODE::NO_RESPONSE when the modem doesn't respond, - * CODE::FAILURE otherwise. - */ - virtual CODE isPdpContextAuthSupported(bool& isSupported) = 0; - - /** - * @brief Get the list of PDP contexts with the base info about them from the radio. - * - * @param jData - a JSON object to be filled with data. - * { - * "context_number : STRING": { - * "apn" : "apn_value: STRING", - * "ipMode" : "ip_mode_value: STRING", - * } - * } - * - * @return CODE::SUCCESS when fetched successfully, - * CODE::NO_RESPONSE when the modem doesn't respond, - * CODE::ERROR when the radio returns "ERROR", - * CODE::FAILURE otherwise (unexpected response). - */ - virtual CODE getPdpContextsBase(Json::Value& jData); - - /** - * @brief fills jData with the information about PDP context authentication - * - * @param jData - a JSON object that is pre-filled with the list of PDP contexts: - * { - * "context_number : STRING": { - * "apn" : "apn_value: STRING", - * "ipMode" : "ip_mode_value: STRING", - * } - * } - * On success the method will complement jData with the PDP context authentication fields: - * { - * "context_number : STRING": { - * "apn" : "apn_value: STRING", - * "authType" : "auth_type_value: STRING", - * "ipMode" : "ip_mode_value: STRING", - * "password" : "password_value (optional): STRING", - * "username" : "username_value (optional): STRING" - * } - * } - * - * @return CODE::SUCCESS when fetched successfully, - * CODE::NO_RESPONSE when the modem doesn't respond, - * CODE::ERROR when the radio returns "ERROR", - * CODE::FAILURE otherwise (unexpected response). - */ - virtual CODE fillPdpContextAuthFields(Json::Value& jData) = 0; - - /** - * @brief merges the current configuration of the PDP context with the one requested by user - * - * @param sId - ID of the PDP context to change. - * @param jCurrentContext - a JSON object filled with current configuration data - * { - * "apn" : "apn_value (optional): STRING", - * "authType" : "auth_type_value: STRING", - * "ipMode" : "ip_mode_value: STRING", - * "password" : "password_value (optional): STRING", - * "username" : "username_value (optional): STRING" - * } - * @param jChanges - a JSON object filled with new configuration data - * { - * "apn" : "apn_value (optional): STRING", - * "authType" : "auth_type_value (optional): STRING", - * "ipMode" : "ip_mode_value (optional): STRING", - * "password" : "password_value (optional): STRING", - * "username" : "username_value (optional): STRING" - * } - * @param jResult - a JSON object to be filled with merged data - * { - * "apn" : "apn_value (optional): STRING", - * "authType" : "auth_type_value (optional): STRING", - * "id" : "ctx_id (optional): STRING", - * "ipMode" : "ip_mode_value (optional): STRING", - * "password" : "password_value (optional): STRING", - * "username" : "username_value (optional): STRING" - * } - * @return CODE::SUCCESS. - */ - virtual CODE mergePdpContexts(const std::string& sId, const Json::Value& jCurrentContext, const Json::Value& jChanges, Json::Value& jResult); - - /** - * @brief fills a PdpContextInfo instance with the data from JSON - * @param jData - a JSON object that contains: - * { - * "apn" : "apn_value: STRING", - * "authType" : "auth_type_value: STRING", - * "id" : "ctx_id: STRING", - * "ipMode" : "ip_mode_value: STRING", - * "password" : "password_value: STRING", - * "username" : "username_value: STRING" - * } - * @param pdpContextResult - PdpContextInfo object to be filled with parameters. - * @return CODE::SUCCESS if validated successfully, - * CODE::INVALID_ARGS if validation failed. - */ - virtual CODE initPdpContextInfo(const Json::Value& jConfig, PdpContextInfo& pdpContextResult); - - /** - * @brief checks if PDP context authentication should be configured - * @param jData - a JSON object that contains: - * { - * "apn" : "apn_value (optional): STRING", - * "authType" : "auth_type_value: STRING", - * "ipMode" : "ip_mode_value: STRING", - * "password" : "password_value (optional): STRING", - * "username" : "username_value (optional): STRING" - * } - * @param bIsAuthEditRequired - sets to "false" if there are no authType, username, and password fields in the json, otherwise sets to "true". - * @return CODE::SUCCESS. - */ - static CODE isPdpContextAuthEditRequired(const Json::Value& jConfig, bool& bIsAuthEditRequired); - - /** - * @brief Sets the base PDP context parameters: IP Mode and APN - * @param pdpContext - The new PDP context configuration - * @return CODE::SUCCESS when set successfully, - * CODE::NO_RESPONSE when the modem doesn't respond, - * CODE::ERROR when the radio returns "ERROR", - * CODE::FAILURE otherwise (unexpected response). - */ - virtual CODE setPdpContextBase(const PdpContextInfo& pdpContext); - - /** - * @brief Sets the Cellular Authentication parameters for this PDP context: Authentication Type, Username and Password. - * NOTE: Some implementations (Quectel) override the current IP Mode and APN in addition to the authentication fields. - * @param pdpContext - The new PDP context configuration - * @return CODE::SUCCESS when set successfully, - * CODE::NO_RESPONSE when the modem doesn't respond, - * CODE::ERROR when the radio returns "ERROR", - * CODE::FAILURE otherwise (unexpected response). - */ - virtual CODE setPdpContextAuth(const PdpContextInfo& pdpContext) = 0; - - /** - * @brief Delete the PDP context by its ID. - * @param sId - PDP context ID - * @return CODE::SUCCESS when delete successfully, - * CODE::NO_RESPONSE when the modem doesn't respond, - * CODE::ERROR when the radio returns "ERROR", - * CODE::FAILURE otherwise (unexpected response). - */ - virtual CODE deletePdpContext(const std::string& sId); + virtual CODE setTimeFormat() = 0; + struct PdpContextInfo { + std::string sId; + std::string sIpMode; + std::string sApn; + std::string sAuthType; + std::string sUsername; + std::string sPassword; + }; + + virtual std::vector<std::string> getSupportedPdpContextAuthTypes() const = 0; + static CODE convertPdpContextAuthTypeToString(PDP_CONTEXT_AUTH_TYPE eAuthType, std::string& sAuthType); + static CODE convertStringToPdpContextAuthType(const std::string& sAuthType, PDP_CONTEXT_AUTH_TYPE& eAuthType); + + /** + * @brief checks if PDP context authentication is supported by the modem. + * + * @param isSupported - sets to "true" if PDP context authentication is supported, "false" otherwise. + * + * @return CODE::SUCCESS when the response from the radio is received + * CODE::NO_RESPONSE when the modem doesn't respond, + * CODE::FAILURE otherwise. + */ + virtual CODE isPdpContextAuthSupported(bool& isSupported) = 0; + + /** + * @brief Get the list of PDP contexts with the base info about them from the radio. + * + * @param jData - a JSON object to be filled with data. + * { + * "context_number : STRING": { + * "apn" : "apn_value: STRING", + * "ipMode" : "ip_mode_value: STRING", + * } + * } + * + * @return CODE::SUCCESS when fetched successfully, + * CODE::NO_RESPONSE when the modem doesn't respond, + * CODE::ERROR when the radio returns "ERROR", + * CODE::FAILURE otherwise (unexpected response). + */ + virtual CODE getPdpContextsBase(Json::Value& jData); + + /** + * @brief fills jData with the information about PDP context authentication + * + * @param jData - a JSON object that is pre-filled with the list of PDP contexts: + * { + * "context_number : STRING": { + * "apn" : "apn_value: STRING", + * "ipMode" : "ip_mode_value: STRING", + * } + * } + * On success the method will complement jData with the PDP context authentication fields: + * { + * "context_number : STRING": { + * "apn" : "apn_value: STRING", + * "authType" : "auth_type_value: STRING", + * "ipMode" : "ip_mode_value: STRING", + * "password" : "password_value (optional): STRING", + * "username" : "username_value (optional): STRING" + * } + * } + * + * @return CODE::SUCCESS when fetched successfully, + * CODE::NO_RESPONSE when the modem doesn't respond, + * CODE::ERROR when the radio returns "ERROR", + * CODE::FAILURE otherwise (unexpected response). + */ + virtual CODE fillPdpContextAuthFields(Json::Value& jData) = 0; + + /** + * @brief merges the current configuration of the PDP context with the one requested by user + * + * @param sId - ID of the PDP context to change. + * @param jCurrentContext - a JSON object filled with current configuration data + * { + * "apn" : "apn_value (optional): STRING", + * "authType" : "auth_type_value: STRING", + * "ipMode" : "ip_mode_value: STRING", + * "password" : "password_value (optional): STRING", + * "username" : "username_value (optional): STRING" + * } + * @param jChanges - a JSON object filled with new configuration data + * { + * "apn" : "apn_value (optional): STRING", + * "authType" : "auth_type_value (optional): STRING", + * "ipMode" : "ip_mode_value (optional): STRING", + * "password" : "password_value (optional): STRING", + * "username" : "username_value (optional): STRING" + * } + * @param jResult - a JSON object to be filled with merged data + * { + * "apn" : "apn_value (optional): STRING", + * "authType" : "auth_type_value (optional): STRING", + * "id" : "ctx_id (optional): STRING", + * "ipMode" : "ip_mode_value (optional): STRING", + * "password" : "password_value (optional): STRING", + * "username" : "username_value (optional): STRING" + * } + * @return CODE::SUCCESS. + */ + virtual CODE mergePdpContexts(const std::string& sId, const Json::Value& jCurrentContext, const Json::Value& jChanges, Json::Value& jResult); + + /** + * @brief fills a PdpContextInfo instance with the data from JSON + * @param jData - a JSON object that contains: + * { + * "apn" : "apn_value: STRING", + * "authType" : "auth_type_value: STRING", + * "id" : "ctx_id: STRING", + * "ipMode" : "ip_mode_value: STRING", + * "password" : "password_value: STRING", + * "username" : "username_value: STRING" + * } + * @param pdpContextResult - PdpContextInfo object to be filled with parameters. + * @return CODE::SUCCESS if validated successfully, + * CODE::INVALID_ARGS if validation failed. + */ + virtual CODE initPdpContextInfo(const Json::Value& jConfig, PdpContextInfo& pdpContextResult); + + /** + * @brief checks if PDP context authentication should be configured + * @param jData - a JSON object that contains: + * { + * "apn" : "apn_value (optional): STRING", + * "authType" : "auth_type_value: STRING", + * "ipMode" : "ip_mode_value: STRING", + * "password" : "password_value (optional): STRING", + * "username" : "username_value (optional): STRING" + * } + * @param bIsAuthEditRequired - sets to "false" if there are no authType, username, and password fields in the json, otherwise sets to "true". + * @return CODE::SUCCESS. + */ + static CODE isPdpContextAuthEditRequired(const Json::Value& jConfig, bool& bIsAuthEditRequired); + + /** + * @brief Sets the base PDP context parameters: IP Mode and APN + * @param pdpContext - The new PDP context configuration + * @return CODE::SUCCESS when set successfully, + * CODE::NO_RESPONSE when the modem doesn't respond, + * CODE::ERROR when the radio returns "ERROR", + * CODE::FAILURE otherwise (unexpected response). + */ + virtual CODE setPdpContextBase(const PdpContextInfo& pdpContext); + + /** + * @brief Sets the Cellular Authentication parameters for this PDP context: Authentication Type, Username and Password. + * NOTE: Some implementations (Quectel) override the current IP Mode and APN in addition to the authentication fields. + * @param pdpContext - The new PDP context configuration + * @return CODE::SUCCESS when set successfully, + * CODE::NO_RESPONSE when the modem doesn't respond, + * CODE::ERROR when the radio returns "ERROR", + * CODE::FAILURE otherwise (unexpected response). + */ + virtual CODE setPdpContextAuth(const PdpContextInfo& pdpContext) = 0; + + /** + * @brief Delete the PDP context by its ID. + * @param sId - PDP context ID + * @return CODE::SUCCESS when delete successfully, + * CODE::NO_RESPONSE when the modem doesn't respond, + * CODE::ERROR when the radio returns "ERROR", + * CODE::FAILURE otherwise (unexpected response). + */ + virtual CODE deletePdpContext(const std::string& sId); class RadioBandMap : public MTS::NonCopyable { public: diff --git a/include/mts/MTS_IO_ICellularRadio.h b/include/mts/MTS_IO_ICellularRadio.h index a698647..2a22a5a 100644 --- a/include/mts/MTS_IO_ICellularRadio.h +++ b/include/mts/MTS_IO_ICellularRadio.h @@ -748,7 +748,6 @@ namespace MTS { * CODE::FAILURE otherwise. */ virtual CODE getDiagnostics(std::string& sDiagReport) = 0; - }; } } diff --git a/include/mts/MTS_IO_QuectelRadio.h b/include/mts/MTS_IO_QuectelRadio.h index b3881cb..09bae1e 100644 --- a/include/mts/MTS_IO_QuectelRadio.h +++ b/include/mts/MTS_IO_QuectelRadio.h @@ -93,6 +93,8 @@ namespace MTS { const std::vector<std::string>& getDiagCommands(bool bIsSimReady = true) override; + CODE setTimeFormat() override; + private: // private variable to save old firmware versions during FOTA std::string m_sQuectelFirmware; diff --git a/include/mts/MTS_IO_SequansRadio.h b/include/mts/MTS_IO_SequansRadio.h index b5a3a38..8392227 100644 --- a/include/mts/MTS_IO_SequansRadio.h +++ b/include/mts/MTS_IO_SequansRadio.h @@ -63,6 +63,8 @@ namespace MTS { const std::vector<std::string>& getDiagCommands(bool bIsSimReady = true) override; + CODE setTimeFormat() override; + private: /* * @brief getSimLockAttemptsByType - get the number of remaining attempts to diff --git a/include/mts/MTS_IO_TelitRadio.h b/include/mts/MTS_IO_TelitRadio.h index dc02755..39b5e22 100644 --- a/include/mts/MTS_IO_TelitRadio.h +++ b/include/mts/MTS_IO_TelitRadio.h @@ -82,6 +82,8 @@ namespace MTS { static bool isContainsSignChar(const std::string& str); + CODE setTimeFormat() override; + private: virtual CODE getSimLockAttempts(int& iAttemptsPin, int& iAttemptsPuk, const std::string& sLockStatus); ICellularRadio::CODE wdsList(std::set<int> &wds); diff --git a/src/MTS_IO_CellularRadio.cpp b/src/MTS_IO_CellularRadio.cpp index 7200658..fb1d02b 100644 --- a/src/MTS_IO_CellularRadio.cpp +++ b/src/MTS_IO_CellularRadio.cpp @@ -578,61 +578,80 @@ ICellularRadio::CODE CellularRadio::getTime(std::string& sDate, std::string& sTi sDate = ""; sTime = ""; sTimeZone = ""; + CODE rc; + std::vector<std::string> vTimeParts; + std::string sSign = "+"; + + rc = setTimeFormat(); + if (rc != SUCCESS) { + printWarning("%s| Unable to set Time Parameters for radio [%s]", m_sName.c_str()); + return rc; + } std::string sCmd("AT+CCLK?"); 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; } size_t start = sResult.find("CCLK: "); - if(start != std::string::npos) { + if (start != std::string::npos) { start += sizeof("CCLK: "); std::string sValue = MTS::Text::trim(sResult.substr(start, end - start)); sValue = MTS::Text::strip(sValue, '"'); std::vector<std::string> vParts = MTS::Text::split(sValue, ','); - if(vParts.size() != 2) { + if (vParts.size() != 2) { printWarning("%s| Unable to parse Date from response [%s]", m_sName.c_str(), sResult.c_str()); return FAILURE; } - std::vector<std::string> vDateParts = MTS::Text::split(vParts[0], '/'); - if(vDateParts.size() != 3) { - printWarning("%s| Unable to parse Date from response [%s]", m_sName.c_str(), sResult.c_str()); + if (vDateParts.size() != 3) { + printWarning("%s| Unable to parse Date parts from response [%s]", m_sName.c_str(), sResult.c_str()); return FAILURE; } - //The Date format is YY/MM/DD -> Change to MM/DD/YY - sDate = vDateParts[1] + "/" + vDateParts[2] + "/" + vDateParts[0]; + // The format is YYYY-MM-DD + sDate = vDateParts[0] + "-" + vDateParts[1] + "-" + vDateParts[2]; - vParts = MTS::Text::split(vParts[1], '-'); - if(vParts.size() != 2) { - printWarning("%s| Unable to parse Time from response [%s]", m_sName.c_str(), sResult.c_str()); - return FAILURE; + sTime = (vParts[1]); + + //E.g. 20:39:34-16. Split time and zone with + or - sign. + size_t psign = sTime.find("+"); + size_t nsign = sTime.find("-"); + + if (psign != std::string::npos) { + vTimeParts = MTS::Text::split(vParts[1], '+'); + } else if (nsign != std::string::npos) { + vTimeParts = MTS::Text::split(vParts[1], '-'); + sSign = "-"; + } else { + sSign = ""; } - sTime = vParts[0]; - int32_t iZoneUnits; //the difference, expressed in quarters of an hour, between the local time and GMT - if(!MTS::Text::parse(iZoneUnits, MTS::Text::strip(vParts[1], '+'))) { - printWarning("%s| Unable to parse Time Zone from response [%s]", m_sName.c_str(), sResult.c_str()); + if (vTimeParts.size() != 2) { + printWarning("%s| Unable to parse Time Zone from response [%s], size %d", m_sName.c_str(), sResult.c_str(),vTimeParts.size()); return FAILURE; } + //Get local time + sTime = (vTimeParts[0]); + + int32_t iZoneUnits = 0; //the difference, expressed in quarters of an hour, between the local time and GMT + if (!MTS::Text::parse(iZoneUnits, vTimeParts[1])) { + printWarning("%s| Unable to parse Time Zone units from response [%s], size %d", m_sName.c_str(), sResult.c_str(),vTimeParts.size()); + return FAILURE; + } int32_t iZone = iZoneUnits/4; //Divide by 4 to get hours difference int32_t iZonePartial = (iZoneUnits % 4) * 15; //Remainder in minutes - std::string sPlusSign = "+"; - if(iZonePartial < 0) { - //Remove negative sign from partial and clear plus sign component - iZonePartial *= -1; - sPlusSign = ""; - } + std::stringstream ss; - ss << sPlusSign << iZone; - if(iZonePartial != 0) { + ss << sSign << iZone; + if (iZonePartial != 0) { ss << ":" << iZonePartial; } @@ -640,7 +659,7 @@ ICellularRadio::CODE CellularRadio::getTime(std::string& sDate, std::string& sTi return SUCCESS; } else { - printWarning("%s| Unable to get Time from radio using command [%s]", m_sName.c_str(), sCmd.c_str()); + printWarning("%s| Unable to parse Time from radio using command [%s]", m_sName.c_str(), sCmd.c_str()); } return FAILURE; diff --git a/src/MTS_IO_QuectelRadio.cpp b/src/MTS_IO_QuectelRadio.cpp index b01bbb1..b1ac6fa 100644 --- a/src/MTS_IO_QuectelRadio.cpp +++ b/src/MTS_IO_QuectelRadio.cpp @@ -1783,3 +1783,26 @@ const std::vector<std::string>& QuectelRadio::getDiagCommands(bool) { return vCommands; } + +ICellularRadio::CODE QuectelRadio::setTimeFormat() { + printTrace("%s| Set standard time format", getName().c_str()); + ICellularRadio::CODE rc; + // Set year format in YYYY first, in case it is in YY format to get accurate year + std::string sCmdCSDF("AT+CSDF=1,2"); + rc = sendBasicCommand(sCmdCSDF); + + if (rc != SUCCESS) { + printError("%s| Unable to set year format for radio using command [%s]", getName().c_str(), sCmdCSDF.c_str()); + return rc; + } + + // Set command enables the automatic time zone update + std::string sCmdCTZU("AT+CTZU=3"); + rc = sendBasicCommand(sCmdCTZU); + + if (rc != SUCCESS) { + printError("%s| Unable to set automatic time zone update for radio using command [%s]", getName().c_str(), sCmdCTZU.c_str()); + return rc; + } + return SUCCESS; +}
\ No newline at end of file diff --git a/src/MTS_IO_SequansRadio.cpp b/src/MTS_IO_SequansRadio.cpp index 380dd80..3a3585c 100644 --- a/src/MTS_IO_SequansRadio.cpp +++ b/src/MTS_IO_SequansRadio.cpp @@ -588,3 +588,8 @@ const std::vector<std::string>& SequansRadio::getDiagCommands(bool) { return vCommands; } + +ICellularRadio::CODE SequansRadio::setTimeFormat() { + // AT+CSDF does not work on CB610L. Also, since CB610L does not return the correct time anyway. + return NOT_APPLICABLE; +} diff --git a/src/MTS_IO_TelitRadio.cpp b/src/MTS_IO_TelitRadio.cpp index 00c1686..a706069 100644 --- a/src/MTS_IO_TelitRadio.cpp +++ b/src/MTS_IO_TelitRadio.cpp @@ -1315,3 +1315,26 @@ const std::vector<std::string>& TelitRadio::getDiagCommands(bool) { return vCommands; } + +ICellularRadio::CODE TelitRadio::setTimeFormat() { + printTrace("%s| Set standard time format", getName().c_str()); + ICellularRadio::CODE rc; + // Set year format in YYYY first, in case it is in YY format to get accurate year + std::string sCmdCSDF("AT+CSDF=1,2"); + rc = sendBasicCommand(sCmdCSDF); + + if (rc != SUCCESS) { + printError("%s| Unable to set year format for radio using command [%s]", getName().c_str(), sCmdCSDF.c_str()); + return rc; + } + + // Set command enables the automatic time zone update + std::string sCmdCTZU("AT+CTZU=1"); + rc = sendBasicCommand(sCmdCTZU); + + if (rc != SUCCESS) { + printError("%s| Unable to set automatic time zone update for radio using command [%s]", getName().c_str(), sCmdCTZU.c_str()); + return rc; + } + return SUCCESS; +} |