diff options
32 files changed, 878 insertions, 58 deletions
@@ -38,12 +38,14 @@ OBJS += \ src/MTS_IO_ME910Radio.o \ src/MTS_IO_LockFile.o \ src/MTS_IO_MccMncTable.o \ - src/MTS_IO_SerialConnection.o + src/MTS_IO_SerialConnection.o \ + src/MTS_IO_SequansRadio.o \ + src/MTS_IO_CB610LRadio.o CC := $(CXX) CXXFLAGS += -Wall -Werror -std=c++0x -fmessage-length=0 -fPIC -fvisibility=hidden -fvisibility-inlines-hidden CPPFLAGS += -I=/usr/include/jsoncpp -Iinclude -LDFLAGS += -s -shared -Wl,-soname,$(APPNAME).so.0 +LDFLAGS += -shared -Wl,-soname,$(APPNAME).so.0 .PHONY: all clean install diff --git a/data/MccMncTable.csv b/data/MccMncTable.csv index e79ef10..4c6f986 100644 --- a/data/MccMncTable.csv +++ b/data/MccMncTable.csv @@ -718,6 +718,7 @@ "313","130","us","United States","1","AT&T Wireless Inc.","att-first" "313","140","us","United States","1","FirstNet","att-first" "313","210","us","United States","1","AT&T Wireless Inc.","att" +"315","010","us","United States","1","Generic CBRS","cbrs-generic" "316","010","us","United States","1","Sprint Spectrum", "316","011","us","United States","1","Southern Communications Services Inc.", "330","11","pr","Puerto Rico","1787","Puerto Rico Telephone Company Inc. (PRTC)", diff --git a/include/mts/MTS_IO_CB610LRadio.h b/include/mts/MTS_IO_CB610LRadio.h new file mode 100644 index 0000000..b802a2b --- /dev/null +++ b/include/mts/MTS_IO_CB610LRadio.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2023 by Multi-Tech Systems + * + * This file is part of libmts-io. + * + * libmts-io is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * libmts-io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libmts-io. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifndef MTS_IO_CB610LRADIO_H_ +#define MTS_IO_CB610LRADIO_H_ + +#include <mts/MTS_IO_SequansRadio.h> + +namespace MTS { + namespace IO { + + class CB610LRadio : public SequansRadio { + + public: + static const std::string MODEL_NAME; + + CB610LRadio(const std::string& sPort); + virtual ~CB610LRadio(); + + CODE setCellularMode(CELLULAR_MODES networks) override; + CODE getSupportedCellularModes(CELLULAR_MODES &networks) override; + + protected: + + private: + + }; + } +} + +#endif /* MTS_IO_CB610LRADIO_H_ */
\ No newline at end of file diff --git a/include/mts/MTS_IO_CE910Radio.h b/include/mts/MTS_IO_CE910Radio.h index 58642cb..8d3b912 100644 --- a/include/mts/MTS_IO_CE910Radio.h +++ b/include/mts/MTS_IO_CE910Radio.h @@ -43,6 +43,8 @@ namespace MTS { virtual ~CE910Radio(){}; CODE setRxDiversity(const Json::Value& jArgs); + virtual const std::vector<std::string> getRegistrationCommands() override; + protected: private: diff --git a/include/mts/MTS_IO_CellularRadio.h b/include/mts/MTS_IO_CellularRadio.h index e985c21..68c1394 100644 --- a/include/mts/MTS_IO_CellularRadio.h +++ b/include/mts/MTS_IO_CellularRadio.h @@ -262,7 +262,7 @@ namespace MTS { virtual std::string queryCGREGstring(); virtual void setCGREG(std::string value); - const std::vector<std::string> getRegistrationCommands(); + virtual const std::vector<std::string> getRegistrationCommands() = 0; REGISTRATION parseRegResponse(std::string sResult); CODE getRegistration(REGISTRATION& eRegistration, const std::string& sType); diff --git a/include/mts/MTS_IO_CellularRadioFactory.h b/include/mts/MTS_IO_CellularRadioFactory.h index 13f3993..127be65 100644 --- a/include/mts/MTS_IO_CellularRadioFactory.h +++ b/include/mts/MTS_IO_CellularRadioFactory.h @@ -56,6 +56,7 @@ namespace MTS { ICellularRadio* createLE866A1JS(const std::string& sPort = ICellularRadio::DEFAULT_RADIO_PORT) const; ICellularRadio* createEG95Radio(const std::string& sPort = ICellularRadio::DEFAULT_RADIO_PORT) const; ICellularRadio* createEG25Radio(const std::string& sPort = ICellularRadio::DEFAULT_RADIO_PORT) const; + ICellularRadio* createCB610LRadio(const std::string& sPort = ICellularRadio::DEFAULT_RADIO_PORT) const; protected: typedef MTS::IO::ICellularRadio* (CellularRadioFactory::*CREATEFUNCPTR)(const std::string& sPort) const; diff --git a/include/mts/MTS_IO_DE910Radio.h b/include/mts/MTS_IO_DE910Radio.h index 9f9b9ae..67964fc 100644 --- a/include/mts/MTS_IO_DE910Radio.h +++ b/include/mts/MTS_IO_DE910Radio.h @@ -41,7 +41,9 @@ namespace MTS { DE910Radio(const std::string& sPort); virtual ~DE910Radio(){}; - CODE setRxDiversity(const Json::Value& jArgs); + CODE setRxDiversity(const Json::Value& jArgs); + + const std::vector<std::string> getRegistrationCommands() override; protected: diff --git a/include/mts/MTS_IO_EG25Radio.h b/include/mts/MTS_IO_EG25Radio.h index e05fa7d..326b192 100644 --- a/include/mts/MTS_IO_EG25Radio.h +++ b/include/mts/MTS_IO_EG25Radio.h @@ -35,6 +35,8 @@ namespace MTS { EG25Radio(const std::string& sPort); virtual ~EG25Radio(); + const std::vector<std::string> getRegistrationCommands() override; + protected: private: diff --git a/include/mts/MTS_IO_EG95Radio.h b/include/mts/MTS_IO_EG95Radio.h index 6fb47c8..a238e94 100644 --- a/include/mts/MTS_IO_EG95Radio.h +++ b/include/mts/MTS_IO_EG95Radio.h @@ -35,6 +35,8 @@ namespace MTS { EG95Radio(const std::string& sPort); virtual ~EG95Radio(); + const std::vector<std::string> getRegistrationCommands() override; + protected: private: diff --git a/include/mts/MTS_IO_GE910Radio.h b/include/mts/MTS_IO_GE910Radio.h index 4904ea7..499933c 100644 --- a/include/mts/MTS_IO_GE910Radio.h +++ b/include/mts/MTS_IO_GE910Radio.h @@ -41,7 +41,8 @@ namespace MTS { GE910Radio(const std::string& sPort); virtual ~GE910Radio(){}; - CODE setRxDiversity(const Json::Value& jArgs); + CODE setRxDiversity(const Json::Value& jArgs); + const std::vector<std::string> getRegistrationCommands() override; protected: diff --git a/include/mts/MTS_IO_HE910Radio.h b/include/mts/MTS_IO_HE910Radio.h index c8700da..54ad5a3 100644 --- a/include/mts/MTS_IO_HE910Radio.h +++ b/include/mts/MTS_IO_HE910Radio.h @@ -39,10 +39,12 @@ namespace MTS { public: virtual ~HE910Radio(){}; - CODE setRxDiversity(const Json::Value& jArgs); + CODE setRxDiversity(const Json::Value& jArgs); + const std::vector<std::string> getRegistrationCommands() override; protected: HE910Radio(const std::string& sHE910Model, const std::string& sPort); + private: }; diff --git a/include/mts/MTS_IO_LE866Radio.h b/include/mts/MTS_IO_LE866Radio.h index 2775e4d..a127f63 100644 --- a/include/mts/MTS_IO_LE866Radio.h +++ b/include/mts/MTS_IO_LE866Radio.h @@ -48,6 +48,8 @@ namespace MTS { LE866Radio(const std::string& sLE866Model, const std::string& sPort); virtual ~LE866Radio(){}; + const std::vector<std::string> getRegistrationCommands() override; + protected: private: diff --git a/include/mts/MTS_IO_LE910Radio.h b/include/mts/MTS_IO_LE910Radio.h index 6700ee3..e509c95 100644 --- a/include/mts/MTS_IO_LE910Radio.h +++ b/include/mts/MTS_IO_LE910Radio.h @@ -48,6 +48,8 @@ namespace MTS { CODE setUeModeOfOperation(ICellularRadio::UE_MODES_OF_OPERATION mode) override; CODE getUeModeOfOperation(ICellularRadio::UE_MODES_OF_OPERATION& mode) override; + const std::vector<std::string> getRegistrationCommands() override; + protected: const std::vector<std::string>& getDiagCommands(bool bIsSimReady = true) override; diff --git a/include/mts/MTS_IO_ME910Radio.h b/include/mts/MTS_IO_ME910Radio.h index 93af86f..7c34009 100644 --- a/include/mts/MTS_IO_ME910Radio.h +++ b/include/mts/MTS_IO_ME910Radio.h @@ -36,6 +36,8 @@ namespace MTS { virtual CODE setRxDiversity(const Json::Value& jArgs); + const std::vector<std::string> getRegistrationCommands() override; + protected: private: diff --git a/include/mts/MTS_IO_SequansRadio.h b/include/mts/MTS_IO_SequansRadio.h new file mode 100644 index 0000000..11f2c91 --- /dev/null +++ b/include/mts/MTS_IO_SequansRadio.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2023 by Multi-Tech Systems + * + * This file is part of libmts-io. + * + * libmts-io is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * libmts-io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libmts-io. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifndef MTS_IO_SEQUANSRADIO +#define MTS_IO_SEQUANSRADIO + +#include <mts/MTS_IO_CellularRadio.h> + +namespace MTS { + namespace IO { + + class SequansRadio : public CellularRadio { + + public: + bool resetRadio(uint32_t iTimeoutMillis = 5000) override; + + CODE getVendorFirmware(std::string& sVendorFirmware) override; + CODE getModel(std::string& sModel) override; + CODE getIccid(std::string& sIccid) override; + CODE getService(std::string& sService) override; + CODE getNetwork(std::string& sNetwork) override; + CODE getNetworkStatus(Json::Value& jData) override; + + CODE convertSignalStrengthTodBm(const int32_t& iRssi, int32_t& iDBm) override; + CODE convertdBmToSignalStrength(const int32_t& dBm, int32_t& iRssi) override; + + CODE setMdn(const Json::Value& jArgs) override; + + CODE setUeModeOfOperation(ICellularRadio::UE_MODES_OF_OPERATION mode) override; + CODE getUeModeOfOperation(ICellularRadio::UE_MODES_OF_OPERATION& mode) override; + + CODE setRxDiversity(const Json::Value& jArgs) override; + + const std::vector<std::string> getRegistrationCommands() override; + + protected: + SequansRadio(const std::string& sName, const std::string& sRadioPort); + + CODE getIsSimInserted(bool& bData) override; + CODE getSimLockAttempts(int& iAttemptsPin, int& iAttemptsPuk) override; + + const std::vector<std::string>& getDiagCommands(bool bIsSimReady = true) override; + + private: + /* + * @brief getSimLockAttemptsByType - get the number of remaining attempts to + * enter the specified SIM password type + * + * @param sType - SIM password type, "SIM PIN", "SIM PUK", "SIM PIN2" or "SIM PUK2". + * @param iAttempts - the number of remaining attempts for this password type. + * @return CODE::SUCCESS when fetched successfully, + * CODE::NOT_APPLICABLE when the modem doesn't support this feature, + * CODE::NO_RESPONSE when the modem doesn't respond, + * CODE::ERROR when the radio returns "ERROR" (SIM card removed, etc), + * CODE::FAILURE otherwise (modem is inaccessible, etc). + */ + CODE getSimLockAttemptsByType(const std::string& sType, int& iAttempts); + CODE getNetworkStatusSQN(Json::Value& jData, Json::Value& jDebug); + CODE getNetworkStatusSignal(Json::Value& jData, Json::Value& jDebug); + CODE getNetworkStatusTxPower(Json::Value& jData, Json::Value& jDebug); + + }; + } +} + +#endif /* MTS_IO_SEQUANSRADIO */ diff --git a/src/MTS_IO_CB610LRadio.cpp b/src/MTS_IO_CB610LRadio.cpp new file mode 100644 index 0000000..7fbd884 --- /dev/null +++ b/src/MTS_IO_CB610LRadio.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2023 by Multi-Tech Systems + * + * This file is part of libmts-io. + * + * libmts-io is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * libmts-io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libmts-io. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include <mts/MTS_IO_CB610LRadio.h> + +#include <mts/MTS_Logger.h> +#include <mts/MTS_Thread.h> +#include <mts/MTS_Text.h> +#include <mts/MTS_Timer.h> + +using namespace MTS::IO; + +const std::string CB610LRadio::MODEL_NAME("CB610L"); + +CB610LRadio::CB610LRadio(const std::string& sPort) +: SequansRadio(MODEL_NAME, sPort) { + +} + +CB610LRadio::~CB610LRadio() { + +} + +ICellularRadio::CODE CB610LRadio::setCellularMode(CELLULAR_MODES networks) { + if (networks != CELLULAR_MODE_4G) { + printError("%s| The CB610L radios support only the 4G cellular mode", getName().c_str()); + return FAILURE; + } + std::string sCmd("AT+WS46=28"); + std::string cmdResult = sendCommand(sCmd); + if (cmdResult.find(ICellularRadio::RSP_OK) == std::string::npos) { + printError("%s| AT+WS46=28 returned unexpected response: [%s][%s]", getName().c_str(), sCmd.c_str(), cmdResult.c_str()); + return FAILURE; + } + return SUCCESS; +} + +ICellularRadio::CODE CB610LRadio::getSupportedCellularModes(CELLULAR_MODES &networks) { + networks = CELLULAR_MODE_4G; + return SUCCESS; +}
\ No newline at end of file diff --git a/src/MTS_IO_CE910Radio.cpp b/src/MTS_IO_CE910Radio.cpp index d1cad9b..f0ec560 100644 --- a/src/MTS_IO_CE910Radio.cpp +++ b/src/MTS_IO_CE910Radio.cpp @@ -41,5 +41,9 @@ CE910Radio::CE910Radio(const std::string& sPort) ICellularRadio::CODE CE910Radio::setRxDiversity(const Json::Value& jArgs) { /* Command string for CE radios: N/A */ - return FAILURE; + return NOT_APPLICABLE; +} + +const std::vector<std::string> CE910Radio::getRegistrationCommands() { + return { "CREG" }; } diff --git a/src/MTS_IO_CellularRadio.cpp b/src/MTS_IO_CellularRadio.cpp index 069d5fa..3ce97ec 100644 --- a/src/MTS_IO_CellularRadio.cpp +++ b/src/MTS_IO_CellularRadio.cpp @@ -64,27 +64,41 @@ namespace { // http://niviuk.free.fr/lte_band.php const nameRangeMap EULTRAband[] = { - {"EUTRAN BAND1", 0, 599}, {"EUTRAN BAND2", 600, 1199}, - {"EUTRAN BAND3", 1200, 1949}, {"EUTRAN BAND4", 1950, 2399}, - {"EUTRAN BAND5", 2400, 2649}, {"EUTRAN BAND6", 2650, 2749}, - {"EUTRAN BAND7", 2750, 3449}, {"EUTRAN BAND8", 3450, 3799}, - {"EUTRAN BAND9", 3800, 4149}, {"EUTRAN BAND10", 4150, 4749}, - {"EUTRAN BAND11", 4750, 4999}, {"EUTRAN BAND12", 5000, 5179}, - {"EUTRAN BAND13", 5180, 5279}, {"EUTRAN BAND14", 5280, 5379}, - {"EUTRAN BAND17", 5730, 5849}, {"EUTRAN BAND18", 5850, 5999}, - {"EUTRAN BAND19", 6000, 6149}, {"EUTRAN BAND20", 6150, 6449}, - {"EUTRAN BAND21", 6450, 6525}, {"EUTRAN BAND22", 6600, 7399}, - {"EUTRAN BAND23", 7500, 7699}, {"EUTRAN BAND24", 7700, 8039}, - {"EUTRAN BAND25", 8040, 8689}, {"EUTRAN BAND26", 8690, 9039}, - {"EUTRAN BAND27", 9040, 9209}, {"EUTRAN BAND28", 9210, 9659}, - {"EUTRAN BAND29", 9660, 9769}, {"EUTRAN BAND30", 9770, 9869}, - {"EUTRAN BAND31", 9870, 9919}, {"EUTRAN BAND32", 9920, 10359}, - {"EUTRAN BAND33", 36000, 36199}, {"EUTRAN BAND34", 36200, 36349}, - {"EUTRAN BAND35", 36350, 36949}, {"EUTRAN BAND36", 36950, 37549}, - {"EUTRAN BAND37", 37550, 37749}, {"EUTRAN BAND38", 37750, 38249}, - {"EUTRAN BAND39", 38250, 38649}, {"EUTRAN BAND40", 38650, 39649}, - {"EUTRAN BAND41", 39650, 41589}, {"EUTRAN BAND42", 41590, 43589}, - {"EUTRAN BAND43", 43590, 45589}, {"EUTRAN BAND44", 45590, 46589} + {"EUTRAN BAND1", 0, 599}, {"EUTRAN BAND2", 600, 1199}, + {"EUTRAN BAND3", 1200, 1949}, {"EUTRAN BAND4", 1950, 2399}, + {"EUTRAN BAND5", 2400, 2649}, {"EUTRAN BAND6", 2650, 2749}, + {"EUTRAN BAND7", 2750, 3449}, {"EUTRAN BAND8", 3450, 3799}, + {"EUTRAN BAND9", 3800, 4149}, {"EUTRAN BAND10", 4150, 4749}, + {"EUTRAN BAND11", 4750, 4999}, {"EUTRAN BAND12", 5000, 5179}, + {"EUTRAN BAND13", 5180, 5279}, {"EUTRAN BAND14", 5280, 5379}, + {"EUTRAN BAND17", 5730, 5849}, {"EUTRAN BAND18", 5850, 5999}, + {"EUTRAN BAND19", 6000, 6149}, {"EUTRAN BAND20", 6150, 6449}, + {"EUTRAN BAND21", 6450, 6525}, {"EUTRAN BAND22", 6600, 7399}, + {"EUTRAN BAND23", 7500, 7699}, {"EUTRAN BAND24", 7700, 8039}, + {"EUTRAN BAND25", 8040, 8689}, {"EUTRAN BAND26", 8690, 9039}, + {"EUTRAN BAND27", 9040, 9209}, {"EUTRAN BAND28", 9210, 9659}, + {"EUTRAN BAND29", 9660, 9769}, {"EUTRAN BAND30", 9770, 9869}, + {"EUTRAN BAND31", 9870, 9919}, {"EUTRAN BAND32", 9920, 10359}, + {"EUTRAN BAND33", 36000, 36199}, {"EUTRAN BAND34", 36200, 36349}, + {"EUTRAN BAND35", 36350, 36949}, {"EUTRAN BAND36", 36950, 37549}, + {"EUTRAN BAND37", 37550, 37749}, {"EUTRAN BAND38", 37750, 38249}, + {"EUTRAN BAND39", 38250, 38649}, {"EUTRAN BAND40", 38650, 39649}, + {"EUTRAN BAND41", 39650, 41589}, {"EUTRAN BAND42", 41590, 43589}, + {"EUTRAN BAND43", 43590, 45589}, {"EUTRAN BAND44", 45590, 46589}, + {"EUTRAN BAND45", 46590, 46789}, {"EUTRAN BAND46", 46790, 54539}, + {"EUTRAN BAND47", 54540, 55239}, {"EUTRAN BAND48", 55240, 56739}, + {"EUTRAN BAND49", 56740, 58239}, {"EUTRAN BAND50", 58240, 59089}, + {"EUTRAN BAND51", 59090, 59139}, {"EUTRAN BAND52", 59140, 60139}, + {"EUTRAN BAND53", 60140, 60254}, + {"EUTRAN BAND65", 65536, 66435}, {"EUTRAN BAND66", 66436, 67335}, + {"EUTRAN BAND67", 67336, 67535}, {"EUTRAN BAND68", 67536, 67835}, + {"EUTRAN BAND69", 67836, 68335}, {"EUTRAN BAND70", 68336, 68585}, + {"EUTRAN BAND71", 68586, 68935}, {"EUTRAN BAND72", 68936, 68985}, + {"EUTRAN BAND73", 68986, 69035}, {"EUTRAN BAND74", 69036, 69465}, + {"EUTRAN BAND75", 69466, 70315}, {"EUTRAN BAND76", 70316, 70365}, + {"EUTRAN BAND85", 70366, 70545}, + {"EUTRAN BAND87", 70546, 70595}, {"EUTRAN BAND88", 70596, 70645}, + {"EUTRAN BAND103", 70646, 70655} }; } @@ -225,7 +239,7 @@ ICellularRadio::CODE CellularRadio::getHardware(std::string& sHardware) { ICellularRadio::CODE CellularRadio::getManufacturer(std::string& sManufacturer) { printTrace("%s| Get Manufacturer", m_sName.c_str()); sManufacturer = ICellularRadio::VALUE_NOT_SUPPORTED; - std::string sCmd("AT+GMI"); + std::string sCmd("AT+CGMI"); std::string sResult = sendCommand(sCmd); size_t pos = sResult.find(ICellularRadio::RSP_OK); if (pos == std::string::npos) { @@ -309,6 +323,13 @@ ICellularRadio::CODE CellularRadio::getSimStatusSummary(Json::Value& jData) { do { retCode = getIsSimInserted(bIsSimInserted); + + // Some radio modems do not have separate commands for the SIM presence check + if (retCode == NOT_APPLICABLE) { + retCode = SUCCESS; + bIsSimInserted = true; + } + if (retCode != SUCCESS) { break; } @@ -841,17 +862,6 @@ void CellularRadio::initMipProfile(Json::Value& jData) { jData[ICellularRadio::KEY_MIP_MNHASS] = false; } -const std::vector<std::string> CellularRadio::getRegistrationCommands() { - std::string sType; - convertModelToType(getName(), sType); - - if (sType == VALUE_TYPE_LTE) { - return { "CREG", "CGREG", "CEREG" }; - } else { - return { "CREG", "CGREG" }; - } -} - ICellularRadio::REGISTRATION CellularRadio::parseRegResponse(std::string sResult) { size_t start = sResult.find(','); size_t stop = sResult.find(' ', start); diff --git a/src/MTS_IO_CellularRadioFactory.cpp b/src/MTS_IO_CellularRadioFactory.cpp index 1a2cee2..f545599 100644 --- a/src/MTS_IO_CellularRadioFactory.cpp +++ b/src/MTS_IO_CellularRadioFactory.cpp @@ -38,6 +38,7 @@ #include <mts/MTS_IO_DE910Radio.h> #include "mts/MTS_IO_EG95Radio.h" #include "mts/MTS_IO_EG25Radio.h" +#include "mts/MTS_IO_CB610LRadio.h" #include <mts/MTS_Logger.h> using namespace MTS::IO; @@ -62,6 +63,7 @@ CellularRadioFactory::CellularRadioFactory() { m_mCreationMap[LE866A1JSRadio::MODEL_NAME] = &CellularRadioFactory::createLE866A1JS; m_mCreationMap[EG95Radio::MODEL_NAME] = &CellularRadioFactory::createEG95Radio; m_mCreationMap[EG25Radio::MODEL_NAME] = &CellularRadioFactory::createEG25Radio; + m_mCreationMap[CB610LRadio::MODEL_NAME] = &CellularRadioFactory::createCB610LRadio; } ICellularRadio* CellularRadioFactory::create(const std::string& sModel, const std::string& sPort) { @@ -101,7 +103,7 @@ std::string CellularRadioFactory::identifyRadio(const std::string& sPort) { //Get model int count = 0; - std::string sCmd("AT+GMM"); + std::string sCmd("AT+CGMM"); std::string sResult; do { sResult = ICellularRadio::sendCommand(apIo, sCmd, ICellularRadio::DEFAULT_BAIL_STRINGS, 1000, ICellularRadio::CR); @@ -120,7 +122,7 @@ std::string CellularRadioFactory::identifyRadio(const std::string& sPort) { } std::string sModel = ICellularRadio::extractModelFromResult(sResult); - printDebug("RADIO| Extracted [%s] from AT+GMM query", sModel.c_str()); + printDebug("RADIO| Extracted [%s] from AT+CGMM query", sModel.c_str()); apIo->close(); return sModel; } @@ -200,3 +202,7 @@ ICellularRadio* CellularRadioFactory::createEG95Radio(const std::string& sPort) ICellularRadio* CellularRadioFactory::createEG25Radio(const std::string& sPort) const { return new EG25Radio(sPort); } + +ICellularRadio* CellularRadioFactory::createCB610LRadio(const std::string& sPort) const { + return new CB610LRadio(sPort); +}
\ No newline at end of file diff --git a/src/MTS_IO_DE910Radio.cpp b/src/MTS_IO_DE910Radio.cpp index 26668f1..d45515d 100644 --- a/src/MTS_IO_DE910Radio.cpp +++ b/src/MTS_IO_DE910Radio.cpp @@ -50,3 +50,7 @@ ICellularRadio::CODE DE910Radio::setRxDiversity(const Json::Value& jArgs) { return sendBasicCommand(sCmd); } + +const std::vector<std::string> DE910Radio::getRegistrationCommands() { + return { "CREG" }; +}
\ No newline at end of file diff --git a/src/MTS_IO_EG25Radio.cpp b/src/MTS_IO_EG25Radio.cpp index c6d1c34..effac4c 100644 --- a/src/MTS_IO_EG25Radio.cpp +++ b/src/MTS_IO_EG25Radio.cpp @@ -38,4 +38,8 @@ EG25Radio::~EG25Radio() { ICellularRadio::CODE EG25Radio::getSupportedCellularModes(CELLULAR_MODES &networks) { networks = static_cast<CELLULAR_MODES>(CELLULAR_MODE_2G | CELLULAR_MODE_3G | CELLULAR_MODE_4G); return SUCCESS; +} + +const std::vector<std::string> EG25Radio::getRegistrationCommands() { + return { "CREG", "CGREG", "CEREG" }; }
\ No newline at end of file diff --git a/src/MTS_IO_EG95Radio.cpp b/src/MTS_IO_EG95Radio.cpp index 83d6489..8dc79a3 100644 --- a/src/MTS_IO_EG95Radio.cpp +++ b/src/MTS_IO_EG95Radio.cpp @@ -52,4 +52,8 @@ ICellularRadio::CODE EG95Radio::getSupportedCellularModes(CELLULAR_MODES &networ } return SUCCESS; +} + +const std::vector<std::string> EG95Radio::getRegistrationCommands() { + return { "CREG", "CGREG", "CEREG" }; }
\ No newline at end of file diff --git a/src/MTS_IO_GE910Radio.cpp b/src/MTS_IO_GE910Radio.cpp index 61332b5..22a6482 100644 --- a/src/MTS_IO_GE910Radio.cpp +++ b/src/MTS_IO_GE910Radio.cpp @@ -41,5 +41,9 @@ GE910Radio::GE910Radio(const std::string& sPort) ICellularRadio::CODE GE910Radio::setRxDiversity(const Json::Value& jArgs) { /* Command string for GE radios: N/A */ - return FAILURE; + return NOT_APPLICABLE; } + +const std::vector<std::string> GE910Radio::getRegistrationCommands() { + return { "CREG", "CGREG" }; +}
\ No newline at end of file diff --git a/src/MTS_IO_HE910Radio.cpp b/src/MTS_IO_HE910Radio.cpp index 4c0a759..a1fddbd 100644 --- a/src/MTS_IO_HE910Radio.cpp +++ b/src/MTS_IO_HE910Radio.cpp @@ -48,3 +48,7 @@ ICellularRadio::CODE HE910Radio::setRxDiversity(const Json::Value& jArgs) { return sendBasicCommand(sCmd); } + +const std::vector<std::string> HE910Radio::getRegistrationCommands() { + return { "CREG", "CGREG" }; +} diff --git a/src/MTS_IO_ICellularRadio.cpp b/src/MTS_IO_ICellularRadio.cpp index 05af28d..e42713d 100644 --- a/src/MTS_IO_ICellularRadio.cpp +++ b/src/MTS_IO_ICellularRadio.cpp @@ -239,6 +239,9 @@ MTS::IO::ICellularRadio::CODE MTS::IO::ICellularRadio::convertModelToMtsShortCod eCode = ERROR; } } + } else if (sModel.find("CB610L") == 0) { + sCode = "L6G1"; + eCode = SUCCESS; } else { sCode = VALUE_NOT_SUPPORTED; printError("RADIO| Could not identify MTS short code from model. [%s]", sModel.c_str()); @@ -335,6 +338,9 @@ MTS::IO::ICellularRadio::CODE MTS::IO::ICellularRadio::convertModelToType(const } else if (sModel.find("EG25") == 0) { sType = VALUE_TYPE_LTE; eCode = SUCCESS; + } else if (sModel.find("CB610L") == 0) { + sType = VALUE_TYPE_LTE; + eCode = SUCCESS; } else { sType = VALUE_TYPE_GSM; eCode = ERROR; @@ -504,6 +510,8 @@ std::string MTS::IO::ICellularRadio::extractModelFromResult(const std::string& s sModel = "EG95"; } else if(sResult.find("EG25") != std::string::npos) { sModel = "EG25"; + } else if(sResult.find("CB610L") != std::string::npos) { + sModel = "CB610L"; } return sModel; } diff --git a/src/MTS_IO_LE866Radio.cpp b/src/MTS_IO_LE866Radio.cpp index 85b8dc3..f695707 100644 --- a/src/MTS_IO_LE866Radio.cpp +++ b/src/MTS_IO_LE866Radio.cpp @@ -36,4 +36,6 @@ LE866Radio::LE866Radio(const std::string& sLE866Model, const std::string& sPort) } - +const std::vector<std::string> LE866Radio::getRegistrationCommands() { + return { "CREG", "CGREG", "CEREG" }; +} diff --git a/src/MTS_IO_LE910Radio.cpp b/src/MTS_IO_LE910Radio.cpp index 2f1debb..3b2864b 100644 --- a/src/MTS_IO_LE910Radio.cpp +++ b/src/MTS_IO_LE910Radio.cpp @@ -64,7 +64,7 @@ ICellularRadio::CODE LE910Radio::getModemLocation(std::string& sLocation) { } printDebug("modem reply: [%s]", sResult.c_str()); size_t start = sResult.find(':'); - if (start==std::string::npos){ + if (start==std::string::npos) { start = 0; } else { start++; @@ -230,3 +230,7 @@ const std::vector<std::string>& LE910Radio::getDiagCommands(bool bIsSimReady) { return vSimLockedCommands; } } + +const std::vector<std::string> LE910Radio::getRegistrationCommands() { + return { "CREG", "CGREG", "CEREG" }; +} diff --git a/src/MTS_IO_ME910Radio.cpp b/src/MTS_IO_ME910Radio.cpp index ad3e7ec..1f4ff58 100644 --- a/src/MTS_IO_ME910Radio.cpp +++ b/src/MTS_IO_ME910Radio.cpp @@ -31,5 +31,9 @@ ME910Radio::ME910Radio(const std::string& sME910Model, const std::string& sPort) } ICellularRadio::CODE ME910Radio::setRxDiversity(const Json::Value& jArgs) { - return FAILURE; + return NOT_APPLICABLE; +} + +const std::vector<std::string> ME910Radio::getRegistrationCommands() { + return { "CREG", "CGREG", "CEREG" }; } diff --git a/src/MTS_IO_MccMncTable.cpp b/src/MTS_IO_MccMncTable.cpp index f1940be..6b45e77 100644 --- a/src/MTS_IO_MccMncTable.cpp +++ b/src/MTS_IO_MccMncTable.cpp @@ -21,7 +21,7 @@ /*! \file MTS_IO_MccMncTable.cpp \brief Auto-Generated MCC-MNC Lookup Table - \date 2023-01-06 + \date 2023-01-26 \author sgodinez An Auto-Generated MCC-MNC Lookup Table @@ -798,6 +798,7 @@ void MccMncTable::createTable() { m_mTable[787][304] = "us,United States,1,AT&T Wireless Inc.,att-first"; m_mTable[787][320] = "us,United States,1,FirstNet,att-first"; m_mTable[787][528] = "us,United States,1,AT&T Wireless Inc.,att"; + m_mTable[789][16] = "us,United States,1,Generic CBRS,cbrs-generic"; m_mTable[790][16] = "us,United States,1,Sprint Spectrum,"; m_mTable[790][17] = "us,United States,1,Southern Communications Services Inc.,"; m_mTable[816][287] = "pr,Puerto Rico,1787,Puerto Rico Telephone Company Inc. (PRTC),"; diff --git a/src/MTS_IO_QuectelRadio.cpp b/src/MTS_IO_QuectelRadio.cpp index 3a5924c..af7adde 100644 --- a/src/MTS_IO_QuectelRadio.cpp +++ b/src/MTS_IO_QuectelRadio.cpp @@ -288,7 +288,7 @@ CellularRadio::CODE QuectelRadio::getNetworkStatus(Json::Value& jData) { Json::Value jQuectelDebug; if (vParts.size() < 3) { - printDebug("%s| Network Status command reponse is an unknown format: [%s][%s]", getName().c_str(), sCmd.c_str(), sResult.c_str()); + printDebug("%s| Network Status command response is an unknown format: [%s][%s]", getName().c_str(), sCmd.c_str(), sResult.c_str()); printTrace("%s| Network Status:\n%s\n", getName().c_str(), jData.toStyledString().c_str()); return SUCCESS; //return SUCCESS because getCommonNetworkStats() succeeded at top of this function } else { @@ -410,7 +410,7 @@ CellularRadio::CODE QuectelRadio::getNetworkStatus(Json::Value& jData) { jDebug[ICellularRadio::KEY_SD] = sValue; } - // LAC is not provided by AT+QENG in WCDMA mode. Use another command instead + // LAC is not provided by AT+QENG in LTE mode. Use another command instead jData[ICellularRadio::KEY_LAC] = queryLteLac(); jData["quectelDebug"] = jQuectelDebug; @@ -842,7 +842,7 @@ ICellularRadio::CODE QuectelRadio::convertToActiveBand(const std::string& sQuect ICellularRadio::CODE QuectelRadio::setCellularMode(CELLULAR_MODES networks) { std::string prefNet; unsigned int prefOnly = 0, prefCount = 0; - for (int i = sizeof(networks)*CHAR_BIT-1; i>=0; --i){ + for (int i = sizeof(networks)*CHAR_BIT-1; i>=0; --i) { switch (1<<i & networks) { case ICellularRadio::CELLULAR_MODE_2G: prefNet += "01" ; prefOnly = 1; prefCount++; break; case ICellularRadio::CELLULAR_MODE_3G: prefNet += "0302"; prefOnly = 2; prefCount++; break; diff --git a/src/MTS_IO_SequansRadio.cpp b/src/MTS_IO_SequansRadio.cpp new file mode 100644 index 0000000..f3b32fb --- /dev/null +++ b/src/MTS_IO_SequansRadio.cpp @@ -0,0 +1,553 @@ +/* + * Copyright (C) 2023 by Multi-Tech Systems + * + * This file is part of libmts-io. + * + * libmts-io is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * libmts-io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libmts-io. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include <mts/MTS_IO_SequansRadio.h> + +#include <mts/MTS_Logger.h> +#include <mts/MTS_Thread.h> +#include <mts/MTS_Text.h> +#include <mts/MTS_Timer.h> + +using namespace MTS::IO; + +bool SequansRadio::resetRadio(uint32_t iTimeoutMillis) { + printInfo("%s| Rebooting radio", getName().c_str()); + if (sendBasicCommand("AT^RESET") == SUCCESS) { + if (iTimeoutMillis > 5000) { + MTS::Thread::sleep(5000); + iTimeoutMillis -= 5000; + } + return resetConnection(iTimeoutMillis); + } + + return false; +} + +ICellularRadio::CODE SequansRadio::getVendorFirmware(std::string& sVendorFirmware) { + return getFirmware(sVendorFirmware); +} + +ICellularRadio::CODE SequansRadio::getModel(std::string& sModel) { + printTrace("%s| Get Model", getName().c_str()); + //Always returns SUCCESS because the model should be m_sName + sModel = getName(); + std::string sCmd("AT+CGMM"); + std::string sResult = sendCommand(sCmd); + if (sResult.find("OK") == std::string::npos) { + printWarning("%s| Unable to get model from radio. Returning [%s]", getName().c_str(), getName().c_str()); + return SUCCESS; + } else { + sModel = extractModelFromResult(sResult); + if (sModel.size() == 0) { + printWarning("%s| Unable to get model from radio. Returning [%s]", getName().c_str(), getName().c_str()); + return SUCCESS; + } + } + + printDebug("%s| Extracted [%s] from [%s] query", getName().c_str(), sModel.c_str(), sCmd.c_str()); + if (sModel != getName()) { + printWarning("%s| Model identified [%s] does not match expected [%s]. Returning [%s]", + getName().c_str(), sModel.c_str(), getName().c_str(), sModel.c_str()); + } + + return SUCCESS; +} + +ICellularRadio::CODE SequansRadio::getIccid(std::string& sIccid) { + printTrace("%s| Get ICCID", getName().c_str()); + + const int iEFiccidId = 0x2FE2; + const uint8_t iOffsetHigh = 0; + const uint8_t iOffsetLow = 0; + const uint8_t iNumBytes = 10; + + CODE rc; + std::string sEFiccidContent; + + rc = simAccessReadBinary(iEFiccidId, iOffsetLow, iOffsetHigh, iNumBytes, sEFiccidContent); + if (rc != SUCCESS) { + printError("%s| Failed to determine the SIM ICCID", getName().c_str()); + return rc; + } + + int iEFiccidLen = sEFiccidContent.size(); + if (iEFiccidLen != 20) { + printError("%s| Invalid length of the raw ICCID value: expected [20], actual: [%d]", getName().c_str(), iEFiccidLen); + return FAILURE; + } + + // sEFiccidContent is a raw Binary-Coded Decimal string with swapped nibbles. + for (int i = 0; i < iEFiccidLen; i+=2) { + std::string sPart = sEFiccidContent.substr(i, 2); + std::swap(sPart[0], sPart[1]); + sIccid.append(sPart); + } + + printDebug("%s| Got ICCID [%s]", getName().c_str(), sIccid.c_str()); + + return SUCCESS; +} + +ICellularRadio::CODE SequansRadio::getService(std::string& sService) { + printTrace("%s| Get Service", getName().c_str()); + sService = ICellularRadio::VALUE_NOT_SUPPORTED; + std::string sCmd("AT+COPS?"); + std::string sPrefix("+COPS:"); + std::string sResult; + CODE rc; + + rc = sendBasicQuery(sCmd, sPrefix, sResult, 100); + if (SUCCESS != rc) { + printWarning("%s| Unable to get Service from radio using command [%s]", getName().c_str(), sCmd.c_str()); + return rc; + } + + std::vector<std::string> vParts = MTS::Text::split(sResult, ','); + int32_t iAccessTechnology; + + // +COPS: <mode>[,<format>[,<oper>][,<Act>]] + if (vParts.size() < 4 || !MTS::Text::parse(iAccessTechnology, vParts[3])) { + printWarning("%s| Unable to get Service from radio using command [%s]", getName().c_str(), sCmd.c_str()); + return FAILURE; + } + + switch(iAccessTechnology) { + case 0 : sService = "GPRS" ; break; // GSM + case 1 : sService = "GPRS" ; break; // GSM Compact + case 2 : sService = "WCDMA" ; break; // UTRAN + case 3 : sService = "EGPRS" ; break; // GSM W/EGPRS + case 4 : sService = "HSDPA" ; break; // UTRAN W/HSDPA + case 5 : sService = "WCDMA" ; break; // UTRAN W/HSUPA + case 6 : sService = "HSDPA" ; break; // UTRAN W/HSDPA and HSUPA + case 7 : sService = "LTE" ; break; // E-UTRAN + case 8 : sService = "EGPRS" ; break; // EC-GSM-IoT + case 9 : sService = "LTE" ; break; // E-UTRAN (NB-S1 mode) + + default: sService = ICellularRadio::VALUE_UNKNOWN; break; + } + + printDebug("%s| Service ID: [%d][%s]", getName().c_str(), iAccessTechnology, sService.c_str()); + + return SUCCESS; +} + +ICellularRadio::CODE SequansRadio::getNetwork(std::string& sNetwork) { + printTrace("%s| Get Network", getName().c_str()); + sNetwork = ICellularRadio::VALUE_NOT_SUPPORTED; + std::string sCmd("AT+COPS?"); + std::string sPrefix("+COPS:"); + std::string sResult; + CODE rc; + + rc = sendBasicQuery(sCmd, sPrefix, sResult, 100); + if (SUCCESS != rc) { + printWarning("%s| Unable to get network name from radio using command [%s]", getName().c_str(), sCmd.c_str()); + return rc; + } + std::vector<std::string> vParts = MTS::Text::split(sResult, ","); + + if (vParts.size() > 3) { + const std::string sValue = vParts[2]; + + // +COPS: 0,2,"315010",7 + // ^start ^end + size_t start = sValue.find("\"") + 1; + size_t end = sValue.find("\"", start); + sNetwork = sValue.substr(start, end-start); + } else { + sNetwork = ""; // Not connected to any network + } + + return SUCCESS; +} + +// AT+SQNQRCCI? -- This command queries and reports several information from camped cell. +// +SQNQRCCI: [<mcc>,<mnc>,<cellId>,<pci>,<tac>,<dlBw>,<specialSubframeConfig>,<subframeAssignment>,<dlEarfcn>,<dlTxMode>,<band>] +ICellularRadio::CODE SequansRadio::getNetworkStatusSQN(Json::Value& jData, Json::Value& jDebug) { + std::string sCmd; + std::string sResult; + std::string sPrefix; + std::vector<std::string> vParts; + CODE rc; + + sCmd = "AT+SQNQRCCI?"; + sPrefix = "+SQNQRCCI:"; + + rc = sendBasicQuery(sCmd, sPrefix, sResult, 200); + if (SUCCESS != rc) { + printDebug("%s| Network Status command returned unexpected response: [%s][%s]", getName().c_str(), sCmd.c_str(), sResult.c_str()); + printTrace("%s| Network Status:\n%s\n", getName().c_str(), jData.toStyledString().c_str()); + return rc; + } + + // <mcc>,<mnc>,<cellId>,<pci>,<tac>,<dlBw>,<specialSubframeConfig>,<subframeAssignment>,<dlEarfcn>,<dlTxMode>,<band> + // [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] + vParts = MTS::Text::split(sResult, ","); + + if (vParts.size() < 11) { + printDebug("%s| Network Status command reponse is an unknown format: [%s][%s]", getName().c_str(), sCmd.c_str(), sResult.c_str()); + printTrace("%s| Network Status:\n%s\n", getName().c_str(), jData.toStyledString().c_str()); + return FAILURE; + } + + jData[ICellularRadio::KEY_MCC] = vParts[0]; + jData[ICellularRadio::KEY_MNC] = vParts[1]; + jData[ICellularRadio::KEY_CID] = vParts[2]; + jData["tac"] = vParts[4]; + jData[ICellularRadio::KEY_CHANNEL] = vParts[8]; + jData[ICellularRadio::KEY_ABND] = "EUTRAN BAND" + vParts[10]; // concat string to convert to common format + + return SUCCESS; +} + +// AT+CESQ? -- Execution command returns received signal quality parameters. +// +CESQ: <rxlev>,<ber>,<rscp>,<ecno>,<rsrq>,<rsrp> +ICellularRadio::CODE SequansRadio::getNetworkStatusSignal(Json::Value& jData, Json::Value& jDebug) { + std::string sCmd; + std::string sResult; + std::string sPrefix; + std::vector<std::string> vParts; + CODE rc; + + sCmd = "AT+CESQ"; + sPrefix = "+CESQ:"; + + rc = sendBasicQuery(sCmd, sPrefix, sResult, 200); + if (SUCCESS != rc) { + printDebug("%s| Network Status command returned unexpected response: [%s][%s]", getName().c_str(), sCmd.c_str(), sResult.c_str()); + printTrace("%s| Network Status:\n%s\n", getName().c_str(), jData.toStyledString().c_str()); + return rc; + } + + // <rxlev>,<ber>,<rscp>,<ecno>,<rsrq>,<rsrp> + // [0] [1] [2] [3] [4] [5] + vParts = MTS::Text::split(sResult, ","); + + if (vParts.size() < 6) { + printDebug("%s| Network Status command response is an unknown format: [%s][%s]", getName().c_str(), sCmd.c_str(), sResult.c_str()); + printTrace("%s| Network Status:\n%s\n", getName().c_str(), jData.toStyledString().c_str()); + return FAILURE; + } + + int iValue; + if (MTS::Text::parse(iValue, vParts[5])) { + do { + if (255 == iValue) { + break; // invalid, not known or not detectable + } + if (iValue > 97 || iValue < 0) { + printDebug("%s| Network Status command returned unexpected value of RSRP: [%s][%d]", getName().c_str(), sCmd.c_str(), iValue); + printTrace("%s| Network Status:\n%s\n", getName().c_str(), jData.toStyledString().c_str()); + break; + } + // converting value to rsrp dBm according to documentation + jDebug["rsrp"] = std::to_string(iValue - 141); + } while (false); + } + + if (MTS::Text::parse(iValue, vParts[4])) { + do { + if (255 == iValue) { + break; // invalid, not known or not detectable + } + if (iValue > 34 || iValue < 0) { + printDebug("%s| Network Status command returned unexpected value of RSRQ: [%s][%d]", getName().c_str(), sCmd.c_str(), iValue); + printTrace("%s| Network Status:\n%s\n", getName().c_str(), jData.toStyledString().c_str()); + break; + } + // converting value to rsrq in dBm according to documentation + jDebug["rsrq"] = std::to_string((iValue-40.0)/2.0); + } while (false); + } + + return SUCCESS; +} + +// AT+SQNQRUP? -- This command queries and reports the uplink power of the current LTE network. +// +SQNQRUP: <txPower>,<maxTxPower> +ICellularRadio::CODE SequansRadio::getNetworkStatusTxPower(Json::Value& jData, Json::Value& jDebug) { + std::string sCmd; + std::string sResult; + std::string sPrefix; + std::vector<std::string> vParts; + int iValue; + CODE rc; + + sCmd = "AT+SQNQRUP?"; + sPrefix = "+SQNQRUP:"; + + // the key must be present + jDebug[ICellularRadio::KEY_TXPWR] = ""; + + rc = sendBasicQuery(sCmd, sPrefix, sResult, 200); + if (SUCCESS != rc) { + printDebug("%s| Network Status command returned unexpected response: [%s][%s]", getName().c_str(), sCmd.c_str(), sResult.c_str()); + printTrace("%s| Network Status:\n%s\n", getName().c_str(), jData.toStyledString().c_str()); + return rc; + } + // <txPower>,<maxTxPower> + // [0] [1] + vParts = MTS::Text::split(sResult, ","); + + if (vParts.size() < 2) { + printDebug("%s| Network Status command response is an unknown format: [%s][%s]", getName().c_str(), sCmd.c_str(), sResult.c_str()); + printTrace("%s| Network Status:\n%s\n", getName().c_str(), jData.toStyledString().c_str()); + return FAILURE; + } + + double fTxPow; + if (MTS::Text::parse(fTxPow, vParts[0])) { + do { + if (-21474836.0 == fTxPow) { + break; // invalid, not known or not detectable + } + if (fTxPow < -255 || fTxPow > 99) { + printDebug("%s| Network Status command returned unexpected value of txPower: [%s][%d]", getName().c_str(), sCmd.c_str(), iValue); + printTrace("%s| Network Status:\n%s\n", getName().c_str(), jData.toStyledString().c_str()); + break; + } + jDebug[ICellularRadio::KEY_TXPWR] = vParts[0]; + } while (false); + } + + return SUCCESS; +} + +ICellularRadio::CODE SequansRadio::getNetworkStatus(Json::Value& jData) { + printTrace("%s| Get Network Status", getName().c_str()); + + // NOTE: Only the LTE radios from Sequans are supported at the moment + + Json::Value jDebug; + std::string sResult; + + getCommonNetworkStats(jData); + getNetworkStatusSQN(jData, jDebug); + getNetworkStatusSignal(jData, jDebug); + getNetworkStatusTxPower(jData, jDebug); + + if (jData.isMember(ICellularRadio::KEY_RSSIDBM)) { + jDebug[ICellularRadio::KEY_RSSIDBM] = jData[ICellularRadio::KEY_RSSIDBM]; + } + + if (SUCCESS == getImsi(sResult)) { + jData[ICellularRadio::KEY_IMSI] = sResult; + } + + if (SUCCESS == getNetwork(sResult)) { + jData[ICellularRadio::KEY_NETWORK] = sResult; + } + + jDebug[ICellularRadio::KEY_SD] = "PS"; + + jData[ICellularRadio::KEY_DEBUG] = jDebug; + + printTrace("%s| Network Status:\n%s\n", getName().c_str(), jData.toStyledString().c_str()); + return SUCCESS; + +} + +ICellularRadio::CODE MTS::IO::SequansRadio::convertSignalStrengthTodBm(const int32_t &iRssi, int32_t &iDBm) { + const int dbmSteps = 2; + const int minValue = -113; + const int maxValue = -51; + const int rssiOffset = 0; + int rawDbm; + + if (iRssi < 0 || iRssi > 99) { + return FAILURE; // invalid, not known or not detectable + } + + rawDbm = minValue + ((iRssi - rssiOffset) * dbmSteps); + iDBm = std::min(maxValue, rawDbm); + + return SUCCESS; +} + +ICellularRadio::CODE SequansRadio::convertdBmToSignalStrength(const int32_t& iDBm, int32_t& iRssi) { + const int dbmSteps = 2; + const int minValue = -113; + const int rssiOffset = 0; + + if (iDBm < -113) { + iRssi = 0; + } else if (iDBm > -51) { + iRssi = 31; + } else { + iRssi = ((iDBm - minValue) / dbmSteps) + rssiOffset; + } + + return SUCCESS; +} + +ICellularRadio::CODE SequansRadio::setMdn(const Json::Value& jArgs) { + printTrace("%s| Set MDN", getName().c_str()); + return NOT_APPLICABLE; +} + +ICellularRadio::CODE SequansRadio::setUeModeOfOperation(ICellularRadio::UE_MODES_OF_OPERATION mode) { + printTrace("%s| Set UE Mode Of Operation", getName().c_str()); + + std::string sValue; + + switch (mode) { + case ICellularRadio::UE_MODES_OF_OPERATION::PS_MODE1: + sValue = "3"; + break; + case ICellularRadio::UE_MODES_OF_OPERATION::PS_MODE2: + sValue = "0"; + break; + case ICellularRadio::UE_MODES_OF_OPERATION::CS_PS_MODE1: + sValue = "1"; + break; + case ICellularRadio::UE_MODES_OF_OPERATION::CS_PS_MODE2: + sValue = "2"; + break; + default: + printError("%s| Set UE Mode Of Operation: invalid argument", getName().c_str()); + return INVALID_ARGS; + } + + const int dTimeout = 1000; // ms + const std::string sCmd = "AT+CEMODE=" + sValue; + + return sendBasicCommand(sCmd, dTimeout); +} + +ICellularRadio::CODE SequansRadio::getUeModeOfOperation(ICellularRadio::UE_MODES_OF_OPERATION& mode) { + printTrace("%s| Get UE Mode Of Operation", getName().c_str()); + + std::string sCmd = "AT+CEMODE?"; + std::string sPrefix = "+CEMODE:"; + std::string sResult; + + if (SUCCESS != sendBasicQuery(sCmd, sPrefix, sResult, 1000)) { + printError("%s| Unable to get UE Mode Of Operation from radio using command [%s]", getName().c_str(), sCmd.c_str()); + return FAILURE; + } + + uint8_t uiValue; + + if (!MTS::Text::parse(uiValue, sResult)) { + printError("%s| Unable to parse CEMODE from response [%s]", getName().c_str(), sResult.c_str()); + return FAILURE; + } + + CODE rc; + switch (uiValue) { + case 0: + mode = ICellularRadio::UE_MODES_OF_OPERATION::PS_MODE2; + rc = SUCCESS; + break; + case 1: + mode = ICellularRadio::UE_MODES_OF_OPERATION::CS_PS_MODE1; + rc = SUCCESS; + break; + case 2: + mode = ICellularRadio::UE_MODES_OF_OPERATION::CS_PS_MODE2; + rc = SUCCESS; + break; + case 3: + mode = ICellularRadio::UE_MODES_OF_OPERATION::PS_MODE1; + rc = SUCCESS; + break; + default: + printError("%s| Unable to parse CEMODE from response [%s]", getName().c_str(), sResult.c_str()); + mode = ICellularRadio::UE_MODES_OF_OPERATION::UNKNOWN_MODE; + rc = FAILURE; + break; + } + return rc; +} + +ICellularRadio::CODE SequansRadio::setRxDiversity(const Json::Value& jArgs) { + return NOT_APPLICABLE; +} + +const std::vector<std::string> SequansRadio::getRegistrationCommands() { + return { "CEREG" }; +} + +SequansRadio::SequansRadio(const std::string& sName, const std::string& sRadioPort) +: CellularRadio (sName, sRadioPort) +{ +} + +ICellularRadio::CODE SequansRadio::getIsSimInserted(bool& bData) { + printTrace("%s| Get SIM insertion status", getName().c_str()); + // there is no command to check SIM presence + return NOT_APPLICABLE; +} + +ICellularRadio::CODE SequansRadio::getSimLockAttempts(int& iAttemptsPin, int& iAttemptsPuk) { + printTrace("%s| Get SIM unlock attempts left", getName().c_str()); + CODE rc = FAILURE; + + rc = getSimLockAttemptsByType("SIM PIN", iAttemptsPin); + if (rc != SUCCESS) { + return rc; + } + + rc = getSimLockAttemptsByType("SIM PUK", iAttemptsPuk); + if (rc != SUCCESS) { + return rc; + } + + return SUCCESS; +} + +ICellularRadio::CODE SequansRadio::getSimLockAttemptsByType(const std::string& sArg, int& iAttempts) { + std::string sCmd("AT+CPINR"); + std::string sPrefix("+CPINR:"); + std::string sResult; + int iValue; + CODE rc = FAILURE; + + sCmd += "=\""; + sCmd += sArg; + sCmd += "\""; + + printDebug("%s| Sending SIM lock attempt query [%s]", getName().c_str(), sCmd.c_str()); + + rc = sendBasicQuery(sCmd, sPrefix, sResult, 500); + if (SUCCESS != rc) { + return rc; + } + + std::vector<std::string> vParts = MTS::Text::split(sResult, ','); + + if (vParts.size() < 3 || ! MTS::Text::parse(iValue, vParts[1])) { + printWarning("%s| Unable to parse SIM unlock attempts from response [%s]", getName().c_str(), sResult.c_str()); + return FAILURE; + } + + iAttempts = iValue; + return SUCCESS; +} + +const std::vector<std::string>& SequansRadio::getDiagCommands(bool) { + // TODO: Fill the list of commands in scope of the "L6G1 - Cellular Diagnostics" feature + + // Declare as static to initialize only when used, but cache the results. + const static std::vector<std::string> vCommands { + }; + + return vCommands; +} diff --git a/src/MTS_IO_TelitRadio.cpp b/src/MTS_IO_TelitRadio.cpp index 4a0a8b2..704f692 100644 --- a/src/MTS_IO_TelitRadio.cpp +++ b/src/MTS_IO_TelitRadio.cpp @@ -110,12 +110,12 @@ ICellularRadio::CODE TelitRadio::getVendorFirmware(std::string& sVendorFirmware) // Not Found. Then we will use "AT+CGMR" + "AT#CFVR" rc = getFirmware(sFirmware); - if (rc != SUCCESS){ + if (rc != SUCCESS) { break; } rc = getFirmwareBuild(sFirmwareBuild); - if (rc != SUCCESS){ + if (rc != SUCCESS) { break; } @@ -714,7 +714,7 @@ ICellularRadio::CODE TelitRadio::getSupportedCellularModes(CELLULAR_MODES &netwo networks = CELLULAR_MODE_NA; std::set<int> wds; - if ( TelitRadio::wdsList(wds) != SUCCESS ) { + if ( wdsList(wds) != SUCCESS ) { return FAILURE; } for(const auto &it : wds) { @@ -729,8 +729,7 @@ ICellularRadio::CODE TelitRadio::getSupportedCellularModes(CELLULAR_MODES &netwo return SUCCESS; } -ICellularRadio::CODE TelitRadio::wdsList(std::set<int> &wds) -{ +ICellularRadio::CODE TelitRadio::wdsList(std::set<int> &wds) { std::string sCmd("AT+WS46=?"); std::string cmdResult = sendCommand(sCmd); if (cmdResult.find("+WS46:") == std::string::npos) { @@ -745,8 +744,7 @@ ICellularRadio::CODE TelitRadio::wdsList(std::set<int> &wds) std::string s = MTS::Text::split(cmdResult, '(')[1]; s = MTS::Text::split(s, ')')[0]; std::vector<std::string>v = MTS::Text::split(s, ','); - for(const auto &it : v) - { + for(const auto &it : v) { if (it.find("-") != std::string::npos) { const std::vector<std::string> &r = MTS::Text::split(it, "-"); int begin, end; @@ -778,7 +776,7 @@ ICellularRadio::CODE TelitRadio::wdsList(std::set<int> &wds) ICellularRadio::CODE TelitRadio::setCellularMode(CELLULAR_MODES networks) { std::set<int> supportedWds; - if ( TelitRadio::wdsList(supportedWds) != SUCCESS ) { + if ( wdsList(supportedWds) != SUCCESS ) { return FAILURE; } |