diff options
| author | Serhii Kostiuk <serhii.o.kostiuk@globallogic.com> | 2022-12-16 17:04:08 +0200 | 
|---|---|---|
| committer | Serhii Kostiuk <serhii.o.kostiuk@globallogic.com> | 2022-12-19 13:32:47 +0200 | 
| commit | 4b448e3c5daf34062861d0261c5a2253638b8100 (patch) | |
| tree | f3ba4159fc60dc385b1019dca521dad1b9763fdd | |
| parent | c04f0c7224311c2b9828e653ed4014e1ccf7a82f (diff) | |
| download | libmts-io-4b448e3c5daf34062861d0261c5a2253638b8100.tar.gz libmts-io-4b448e3c5daf34062861d0261c5a2253638b8100.tar.bz2 libmts-io-4b448e3c5daf34062861d0261c5a2253638b8100.zip | |
[GP-1195] Cellular debugging - add a query
Define the set of debugging AT commands and a function to execute such
commands. The function executes the commands one-by-one end returns raw command
outputs. To be used by radio-query --diagnostics.
| -rw-r--r-- | include/mts/MTS_IO_CellularRadio.h | 11 | ||||
| -rw-r--r-- | include/mts/MTS_IO_ICellularRadio.h | 21 | ||||
| -rw-r--r-- | include/mts/MTS_IO_LE910Radio.h | 2 | ||||
| -rw-r--r-- | include/mts/MTS_IO_QuectelRadio.h | 2 | ||||
| -rw-r--r-- | include/mts/MTS_IO_TelitRadio.h | 2 | ||||
| -rw-r--r-- | src/MTS_IO_CellularRadio.cpp | 63 | ||||
| -rw-r--r-- | src/MTS_IO_LE910Radio.cpp | 65 | ||||
| -rw-r--r-- | src/MTS_IO_QuectelRadio.cpp | 46 | ||||
| -rw-r--r-- | src/MTS_IO_TelitRadio.cpp | 32 | 
9 files changed, 242 insertions, 2 deletions
| diff --git a/include/mts/MTS_IO_CellularRadio.h b/include/mts/MTS_IO_CellularRadio.h index 60659dc..e985c21 100644 --- a/include/mts/MTS_IO_CellularRadio.h +++ b/include/mts/MTS_IO_CellularRadio.h @@ -148,6 +148,8 @@ namespace MTS {                  CODE getPdpContexts(Json::Value& jData) override;                  CODE setPdpContext(const std::string& sId, const Json::Value& jConfig) override; +                CODE getDiagnostics(std::string& sReport) override; +              protected:                  CellularRadio(const std::string& sName, const std::string& sRadioPort); @@ -267,6 +269,15 @@ namespace MTS {                  virtual CODE sendData(const char* pData, size_t nBytes);                  virtual CODE sendBasicQuery(const std::string& sCmd, const std::string& sLabel, std::string& sResult, int32_t timeoutMillis = 100, const char& ESC = ICellularRadio::CR); +                /** +                 * @brief getDiagCommands - returns the list of Cellular Diagnostics commands for this radio. +                 * +                 * @param bIsSimReady - set to "true" if the SIM card is inserted and NOT locked by PIN or PUK. +                 * +                 * @return the list of AT commands (strings). +                 */ +                virtual const std::vector<std::string>& getDiagCommands(bool bIsSimReady = true) = 0; +                  class RadioBandMap : public MTS::NonCopyable {                      public:                          RadioBandMap() diff --git a/include/mts/MTS_IO_ICellularRadio.h b/include/mts/MTS_IO_ICellularRadio.h index 91ab782..0523236 100644 --- a/include/mts/MTS_IO_ICellularRadio.h +++ b/include/mts/MTS_IO_ICellularRadio.h @@ -697,6 +697,27 @@ namespace MTS {                  */                  virtual CODE setPdpContext(const std::string& sId, const Json::Value& jConfig) = 0; +                /** +                 * @brief Execute the diagnostics AT commands and capture their output +                 * +                 * NOTE: The list of diagnostic AT commands is radio-specific and changes +                 * depending on the radio model (code). +                 * +                 * NOTE: The method stops its execution if the radio repeatedly ignores +                 * the commands (returns no execution result for several of them). This +                 * is required to limit the maximum execution time of the function and +                 * prevent the process from occupying the radio for too long. In case +                 * of timeout, the report will contain the output of all commands that +                 * it managed to execute before the failure. +                 * +                 * @param sDiagReport - the AT commands execution report. +                 * +                 * @return CODE::SUCCESS when fetched successfully, +                 *         CODE::NO_RESPONSE when the radio ignored several of the AT commands, +                 *         CODE::FAILURE otherwise. +                 */ +                virtual CODE getDiagnostics(std::string& sDiagReport) = 0; +          };      }  } diff --git a/include/mts/MTS_IO_LE910Radio.h b/include/mts/MTS_IO_LE910Radio.h index 2ba423d..6700ee3 100644 --- a/include/mts/MTS_IO_LE910Radio.h +++ b/include/mts/MTS_IO_LE910Radio.h @@ -50,6 +50,8 @@ namespace MTS {              protected: +                const std::vector<std::string>& getDiagCommands(bool bIsSimReady = true) override; +              private: diff --git a/include/mts/MTS_IO_QuectelRadio.h b/include/mts/MTS_IO_QuectelRadio.h index bd312b8..4315cb3 100644 --- a/include/mts/MTS_IO_QuectelRadio.h +++ b/include/mts/MTS_IO_QuectelRadio.h @@ -85,6 +85,8 @@ namespace MTS {                  CODE setRxDiversity(const Json::Value& jArgs) override; +                const std::vector<std::string>& getDiagCommands(bool bIsSimReady = true) override; +              private:                  // private variable to save old firmware versions during FOTA                  std::string m_sQuectelFirmware; diff --git a/include/mts/MTS_IO_TelitRadio.h b/include/mts/MTS_IO_TelitRadio.h index a06da54..d198969 100644 --- a/include/mts/MTS_IO_TelitRadio.h +++ b/include/mts/MTS_IO_TelitRadio.h @@ -73,6 +73,8 @@ namespace MTS {                  virtual CODE fumoWriteGroupsABD(int fd, UpdateCb& stepCb);                  //virtual CODE fumoWriteGroupC(int fd, UpdateCb& stepCb); +                const std::vector<std::string>& getDiagCommands(bool bIsSimReady = true) override; +                  static bool isContainsSignChar(const std::string& str);              private: diff --git a/src/MTS_IO_CellularRadio.cpp b/src/MTS_IO_CellularRadio.cpp index 3de96ce..069d5fa 100644 --- a/src/MTS_IO_CellularRadio.cpp +++ b/src/MTS_IO_CellularRadio.cpp @@ -1868,4 +1868,65 @@ ICellularRadio::CODE CellularRadio::setPdpContext(const std::string& sId, const      rc = sendBasicCommand(sCommand, dTimeout);      return rc; -}
\ No newline at end of file +} + +ICellularRadio::CODE CellularRadio::getDiagnostics(std::string& sReport) { +    // Clear the original content before using the string as a buffer. +    sReport.clear(); + +    // Determine whether the SIM card is locked to select the appropriate +    // list of commands for this radio. +    std::string sSimLockStatus; +    CODE iSimLockRet = getSimLockStatus(sSimLockStatus); + +    // Re-use the SIM status detection logic from TelitRadio::getNetworkStatus. +    // The SIM should be inserted and NOT locked. +    bool bIsSimReady = (iSimLockRet == CODE::SUCCESS +                        && sSimLockStatus != "SIM PIN" +                        && sSimLockStatus != "SIM PUK"); + +    // Determine the list of diagnostic commands required for this radio. +    const auto& vCommands = getDiagCommands(bIsSimReady); + +    // For all commands - set the maximum timeout to 2 seconds. +    const int iMaxTimeout = 2000; + +    // Allow the radio to ignore up to 2 consecutive queries before giving up. +    int iMaxNoResponseCount = 2; +    int iNoResponseCount = 0; + +    // Execute each of the commands, add their output to the report. +    for (const auto& sCmd : vCommands) { +        // First line - the command to execute. +        sReport.append(sCmd); +        sReport.push_back(ICellularRadio::CR); +        sReport.push_back(ICellularRadio::NL); + +        // Execute the command. +        std::string sResult = sendCommand(sCmd, ICellularRadio::DEFAULT_BAIL_STRINGS, iMaxTimeout); + +        // Count the number of commands ignored by the radio. +        // Normally, the radio should not ignore any of the commands, +        // but radios have their own bugs. +        if (sResult.empty()) { +            printWarning("%s| Failed to execute the [%s] command - no response from the radio in [%d] ms", getName().c_str(), sCmd.c_str(), iMaxTimeout); +            sResult = "<NO RESPONSE FROM THE RADIO>\r\n"; +            ++iNoResponseCount; +        } else { +            iNoResponseCount = 0; +        } + +        // If the radio ignored too many commands - probably it is stuck and will not +        // return to operation on its own. There is no point in waiting any longer. +        if (iNoResponseCount >= iMaxNoResponseCount) { +            printError("%s| Failed to execute the diagnostic commands - the radio has stopped responding", getName().c_str()); +            return CODE::NO_RESPONSE; +        } + +        // Append the command output to the report. +        sReport.append(sResult); +    } + +    // All commands returned a non-empty output. +    return CODE::SUCCESS; +} diff --git a/src/MTS_IO_LE910Radio.cpp b/src/MTS_IO_LE910Radio.cpp index ba03c5e..2f1debb 100644 --- a/src/MTS_IO_LE910Radio.cpp +++ b/src/MTS_IO_LE910Radio.cpp @@ -165,3 +165,68 @@ ICellularRadio::CODE LE910Radio::getUeModeOfOperation(ICellularRadio::UE_MODES_O      return rc;  } +const std::vector<std::string>& LE910Radio::getDiagCommands(bool bIsSimReady) { +    // Declare as static to initialize only when used, but cache the results. +    const static std::vector<std::string> vCommands { +        // Radio model and firmware: +        "AT+CGMI", "AT+CGMM", "AT+CGMR", "AT#SWPKGV", "AT#CFVR", + +        // Current operator profile on the radio side: +        "AT#FWSWITCH?", "AT+CGSN", + +        // SIM card information: +        "AT#SIMDET?", "AT#CCID", "AT+CPIN?", "AT#PCT", + +        // Operating mode of the radio: +        "AT+CFUN?", + +        // Low-level network settings: +        "AT+WS46?", "AT#RXDIV", "AT#CALLDISA?", "AT+CEMODE?", + +        // Data connection configuration: +        "AT+CGDCONT?", "AT#PDPAUTH?", + +        // Registration and connection to the tower: +        "AT+CIND?", "AT+CSQ", "AT+COPS?", "AT+CREG?", "AT+CGREG?", "AT+CEREG?", +        "AT#RFSTS", "AT#PSNT?", "AT#MONI", + +        // Data connection status: +        "AT+CGACT?", "AT+CGCONTRDP=1", "AT+CGCONTRDP=2", "AT+CGCONTRDP=3" +    }; + +    const static std::vector<std::string> vSimLockedCommands { +        // Radio model and firmware: +        "AT+CGMI", "AT+CGMM", "AT+CGMR", "AT#SWPKGV", "AT#CFVR", + +        // Current operator profile on the radio side: +        "AT#FWSWITCH?", "AT+CGSN", + +        // SIM card information: +        "AT#SIMDET?", "AT#CCID", "AT+CPIN?", "AT#PCT", + +        // Operating mode of the radio: +        "AT+CFUN?", + +        // Low-level network settings: +        "AT+WS46?", "AT#RXDIV", "AT#CALLDISA?", "AT+CEMODE?", + +        // Data connection configuration: +        "AT+CGDCONT?", "AT#PDPAUTH?", + +        // Registration and connection to the tower. +        // The same set of commands, but AT#RFSTS is replaced with a dummy command. +        "AT+CIND?", "AT+CSQ", "AT+COPS?", "AT+CREG?", "AT+CGREG?", "AT+CEREG?", +        "AT#RFSTS_IGNORED", "AT#PSNT?", "AT#MONI", + +        // Data connection status: +        "AT+CGACT?", "AT+CGCONTRDP=1", "AT+CGCONTRDP=2", "AT+CGCONTRDP=3" +    }; + +    // Ignore AT#RFSTS on LE910 radios (mostly legacy ones like LAT1 and LEU1) if +    // the SIM card is locked by PIN or PUK. Telit Support Portal Case #5069697. +    if (bIsSimReady) { +        return vCommands; +    } else { +        return vSimLockedCommands; +    } +} diff --git a/src/MTS_IO_QuectelRadio.cpp b/src/MTS_IO_QuectelRadio.cpp index ae6200e..3a5924c 100644 --- a/src/MTS_IO_QuectelRadio.cpp +++ b/src/MTS_IO_QuectelRadio.cpp @@ -1627,4 +1627,48 @@ ICellularRadio::CODE QuectelRadio::setRxDiversity(const Json::Value& jArgs) {      }      return SUCCESS; -}
\ No newline at end of file +} + +const std::vector<std::string>& QuectelRadio::getDiagCommands(bool) { +    // Declare as static to initialize only when used, but cache the results. +    const static std::vector<std::string> vCommands { +        // Radio model and firmware: +        "AT+CGMI", "AT+CGMM", "AT+CGMR", "AT+QGMR", + +        // Current operator profile on the radio side: +        "AT+QMBNCFG=\"SELECT\"", "AT+CGSN", + +        // SIM card information: +        "AT+QSIMSTAT?", "AT+QCCID", "AT+CPIN?", "AT+QPINC=\"SC\"", + +        // Operating mode of the radio: +        "AT+CFUN?", + +        // Cellular Mode (RAT selection): +        "AT+QCFG=\"nwscanseq\"", "AT+QCFG=\"nwscanmode\"", + +        // Cellular Diversity configuration: +        "AT+QCFG=\"divctl\",\"lte\"", "AT+QCFG=\"divctl\",\"wcdma\"", "AT+QCFG=\"diversity\"", + +        // Voice call support (AT&T, T-Mobile): +        "AT+QNVFR=\"/nv/item_files/ims/IMS_enable\"", +        "AT+QNVFR=\"/nv/item_files/modem/mmode/sms_only\"", +        "AT+QNVR=5280,0", + +        // UE Mode of Operation (CEMODE; AT&T): +        "AT+QCFG=\"servicedomain\"", +        "AT+QNVFR=\"/nv/item_files/modem/mmode/ue_usage_setting\"", + +        // Data connection configuration: +        "AT+CGDCONT?", "AT+QICSGP=1", "AT+QICSGP=2", "AT+QICSGP=3", + +        // Registration and connection to the tower: +        "AT+CIND?", "AT+CSQ", "AT+COPS?", "AT+CREG?", "AT+CGREG?", "AT+CEREG?", +        "AT+QENG=\"servingcell\"", + +        // Data connection status: +        "AT+CGACT?", "AT+CGCONTRDP=1", "AT+CGCONTRDP=2", "AT+CGCONTRDP=3" +    }; + +    return vCommands; +} diff --git a/src/MTS_IO_TelitRadio.cpp b/src/MTS_IO_TelitRadio.cpp index 2a07939..4a0a8b2 100644 --- a/src/MTS_IO_TelitRadio.cpp +++ b/src/MTS_IO_TelitRadio.cpp @@ -1179,3 +1179,35 @@ bool MTS::IO::TelitRadio::isContainsSignChar(const std::string& str) {      return true;  } + +const std::vector<std::string>& TelitRadio::getDiagCommands(bool) { +    // Declare as static to initialize only when used, but cache the results. +    const static std::vector<std::string> vCommands { +        // Radio model and firmware: +        "AT+CGMI", "AT+CGMM", "AT+CGMR", "AT#SWPKGV", "AT#CFVR", + +        // Current operator profile on the radio side: +        "AT#FWSWITCH?", "AT+CGSN", + +        // SIM card information: +        "AT#SIMDET?", "AT#CCID", "AT+CPIN?", "AT#PCT", + +        // Operating mode of the radio: +        "AT+CFUN?", + +        // Low-level network settings: +        "AT+WS46?", "AT#RXDIV", "AT#CALLDISA?", "AT+CEMODE?", + +        // Data connection configuration: +        "AT+CGDCONT?", "AT#PDPAUTH?", + +        // Registration and connection to the tower: +        "AT+CIND?", "AT+CSQ", "AT+COPS?", "AT+CREG?", "AT+CGREG?", "AT+CEREG?", +        "AT#RFSTS", "AT#PSNT?", "AT#MONI", + +        // Data connection status: +        "AT+CGACT?", "AT+CGCONTRDP=1", "AT+CGCONTRDP=2", "AT+CGCONTRDP=3" +    }; + +    return vCommands; +} | 
