From 30d6ddbe471115dc4e6e2a8b159c7449df5e2e88 Mon Sep 17 00:00:00 2001 From: breichel Date: Wed, 23 Dec 2020 17:34:19 +0100 Subject: [PATCH] [EGD-4920] Add API to get current operator name Asynchronous API to get operator name, also possibility to easy extend solution for current operator technology and information about operator selection mode (automatic/hand). --- module-cellular/at/response.cpp | 46 +++++++++++++++- module-cellular/at/response.hpp | 52 +++++++++++++++++- module-cellular/test/unittest_response.cpp | 55 +++++++++++++++++++ .../service-cellular/CellularServiceAPI.cpp | 6 ++ .../service-cellular/NetworkSettings.cpp | 16 ++++++ .../service-cellular/NetworkSettings.hpp | 1 + .../service-cellular/ServiceCellular.cpp | 13 +++++ .../service-cellular/CellularMessage.hpp | 23 +++++++- .../service-cellular/CellularServiceAPI.hpp | 6 ++ .../service-cellular/ServiceCellular.hpp | 3 + 10 files changed, 218 insertions(+), 3 deletions(-) diff --git a/module-cellular/at/response.cpp b/module-cellular/at/response.cpp index 4d4d60c14ceb0760d11e2cd90775a9a3704d4f96..cbe2436fe8c970e9b9e25ce7b83991537194af46 100644 --- a/module-cellular/at/response.cpp +++ b/module-cellular/at/response.cpp @@ -51,6 +51,7 @@ namespace at return parts; } + constexpr std::string_view AT_COPS = "+COPS:"; bool parseCOPS(const at::Result &resp, std::vector &ret) { /// +COPS: (list of supported ,long alphanumeric , @@ -67,7 +68,6 @@ namespace at constexpr auto minOperatorParams = 4; constexpr auto maxOperatorParams = 5; - constexpr std::string_view AT_COPS = "+COPS:"; if (auto line = getResponseLineATCommand(resp, AT_COPS); line) { const auto &commandLine = *line; @@ -112,6 +112,50 @@ namespace at return false; } + + bool parseCOPS(const at::Result &resp, cops::CurrentOperatorInfo &ret) + { + /// ret as +COPS: [,[,][,]] + /// parameters could be 1,2,3,4 all optional in documentation ! + + constexpr auto minCOPSLength = 1; + + if (auto line = getResponseLineATCommand(resp, AT_COPS); line) { + const auto &commandLine = *line; + + if (commandLine.length() < minCOPSLength) { + return false; + } + + auto opParams = utils::split(commandLine, ","); + cops::Operator op; + + switch (opParams.size()) { + case 4: + op.technology = static_cast(utils::getNumericValue(opParams[3])); + [[fallthrough]]; + case 3: { + ret.setFormat(static_cast(utils::getNumericValue(opParams[1]))); + utils::findAndReplaceAll(opParams[2], at::response::StringDelimiter, ""); + op.setNameByFormat(ret.getFormat(), opParams[2]); + } + ret.setOperator(op); + [[fallthrough]]; + case 2: + ret.setFormat(static_cast(utils::getNumericValue(opParams[1]))); + [[fallthrough]]; + case 1: + ret.setMode(static_cast(utils::getNumericValue(opParams[0]))); + break; + default: + return false; + } + + return true; + } + return false; + } + bool parseQPINC(const at::Result &resp, qpinc::AttemptsCounters &ret) { /// parse only first result from QPINC diff --git a/module-cellular/at/response.hpp b/module-cellular/at/response.hpp index 0c00036ff563d254fa3eebccaf4921a6b0e7874a..3a9d2f9c930081a05994e0aca3a950b5c3ec9c9e 100644 --- a/module-cellular/at/response.hpp +++ b/module-cellular/at/response.hpp @@ -55,7 +55,6 @@ namespace at E_UTRAN = 7, CDMA = 100 }; - enum class NameFormat { Long = 0, @@ -100,10 +99,61 @@ namespace at } } }; + + class CurrentOperatorInfo + { + Operator op; + CopsMode mode = CopsMode::Automatic; + NameFormat format = NameFormat::Long; + bool operatorSet = false; + + public: + void setFormat(NameFormat format) + { + this->format = format; + } + NameFormat getFormat() const noexcept + { + return this->format; + } + void setMode(CopsMode mode) + { + this->mode = mode; + } + CopsMode getMode() const noexcept + { + return this->mode; + } + + void setOperator(Operator op) + { + this->operatorSet = true; + this->op = op; + } + std::optional getOperator() const + { + if (operatorSet) { + return op; + } + else { + return std::nullopt; + } + } + }; } // namespace cops + /** + * @brief parse for AT+COPS=? from quectel + * + */ bool parseCOPS(const at::Result &resp, std::vector &ret); using ResponseTokens = std::vector>; + /** + * @brief parse for AT+COPS? from quectel + * + */ + bool parseCOPS(const at::Result &resp, cops::CurrentOperatorInfo &ret); + std::vector tokenize(std::string &response, std::string separator = ","); /** diff --git a/module-cellular/test/unittest_response.cpp b/module-cellular/test/unittest_response.cpp index 403bdeb88ff6ffe4a09a720ea7021d17e77594d4..da48325d940419a5f1abcec56fb4fa38b5e6f78b 100644 --- a/module-cellular/test/unittest_response.cpp +++ b/module-cellular/test/unittest_response.cpp @@ -96,4 +96,59 @@ TEST_CASE("Response COPS") resp.response.push_back("+COPS: (2,\"PLAY\",\"PLAY\", 4)("); REQUIRE(at::response::parseCOPS(resp, ret) == false); } + + SECTION("OK COPS? - return operator") + { + at::Result resp; + resp.code = at::Result::Code::OK; + at::response::cops::CurrentOperatorInfo ret; + resp.response.push_back("+COPS: 0,0,\"PLAY\",2"); + resp.response.push_back("OK"); + REQUIRE(resp.code == at::Result::Code::OK); + REQUIRE(at::response::parseCOPS(resp, ret) == true); + REQUIRE(ret.getOperator()); + REQUIRE(ret.getMode() == at::response::cops::CopsMode::Automatic); + REQUIRE(ret.getFormat() == at::response::cops::NameFormat::Long); + auto op = *ret.getOperator(); + REQUIRE(op.longName == "PLAY"); + REQUIRE(op.technology == at::response::cops::AccessTechnology::UTRAN); + } + + SECTION("OK COPS? - return operator no act") + { + at::Result resp; + resp.code = at::Result::Code::OK; + at::response::cops::CurrentOperatorInfo ret; + resp.response.push_back("+COPS: 0,0,\"PLAY\""); + resp.response.push_back("OK"); + REQUIRE(resp.code == at::Result::Code::OK); + REQUIRE(at::response::parseCOPS(resp, ret) == true); + REQUIRE(ret.getOperator()); + REQUIRE(ret.getMode() == at::response::cops::CopsMode::Automatic); + REQUIRE(ret.getFormat() == at::response::cops::NameFormat::Long); + auto op = *ret.getOperator(); + REQUIRE(op.longName == "PLAY"); + } + + SECTION("OK COPS? - no operator") + { + at::Result resp; + resp.code = at::Result::Code::OK; + at::response::cops::CurrentOperatorInfo ret; + resp.response.push_back("+COPS: 0"); + resp.response.push_back("OK"); + REQUIRE(resp.code == at::Result::Code::OK); + REQUIRE(at::response::parseCOPS(resp, ret) == true); + REQUIRE(ret.getMode() == at::response::cops::CopsMode::Automatic); + } + SECTION("WRONG COPS? - to many") + { + at::Result resp; + resp.code = at::Result::Code::OK; + at::response::cops::CurrentOperatorInfo ret; + resp.response.push_back("+COPS: 0,0,\"PLAY\",2, 3"); + resp.response.push_back("OK"); + REQUIRE(resp.code == at::Result::Code::OK); + REQUIRE(at::response::parseCOPS(resp, ret) == false); + } } diff --git a/module-services/service-cellular/CellularServiceAPI.cpp b/module-services/service-cellular/CellularServiceAPI.cpp index 55d242936fb5fd196cc282b90d529bb031404a46..a9d830c617f6ca32683c4a91ab3ea85fb20b2cb7 100644 --- a/module-services/service-cellular/CellularServiceAPI.cpp +++ b/module-services/service-cellular/CellularServiceAPI.cpp @@ -112,6 +112,12 @@ void CellularServiceAPI::GetNetworkInfo(sys::Service *serv) sys::Bus::SendUnicast(msg, ServiceCellular::serviceName, serv); } +void CellularServiceAPI::GetCurrentOperator(sys::Service *serv) +{ + std::shared_ptr msg = std::make_shared(); + sys::Bus::SendUnicast(msg, ServiceCellular::serviceName, serv); +} + void CellularServiceAPI::StartOperatorsScan(sys::Service *serv, bool fullInfo) { std::shared_ptr msg = diff --git a/module-services/service-cellular/NetworkSettings.cpp b/module-services/service-cellular/NetworkSettings.cpp index 50f15840f64fc81d527f0d408c51053a879051b3..e0b2787becbff9f134467989cefc2afdcebc15b9 100644 --- a/module-services/service-cellular/NetworkSettings.cpp +++ b/module-services/service-cellular/NetworkSettings.cpp @@ -5,6 +5,22 @@ #include +std::string NetworkSettings::getCurrentOperator() const +{ + auto channel = cellularService.cmux->get(TS0710::Channel::Commands); + if (channel) { + at::Cmd buildCmd = at::factory(at::AT::COPS) + "?"; + auto resp = channel->cmd(buildCmd); + at::response::cops::CurrentOperatorInfo ret; + if ((resp.code == at::Result::Code::OK) && (at::response::parseCOPS(resp, ret))) { + if (auto _operator = ret.getOperator(); _operator) { + return _operator->getNameByFormat(ret.getFormat()); + } + } + } + + return {}; +} std::vector NetworkSettings::scanOperators(bool fullInfoList) { std::vector operatorNames; diff --git a/module-services/service-cellular/NetworkSettings.hpp b/module-services/service-cellular/NetworkSettings.hpp index 1142dcf53f5d23e75c804d160274d6b2bbe87360..061735789598884aec9970f8fc1e55d56937723d 100644 --- a/module-services/service-cellular/NetworkSettings.hpp +++ b/module-services/service-cellular/NetworkSettings.hpp @@ -26,6 +26,7 @@ class NetworkSettings std::vector scanOperators(bool fullInfoList = false); bool setOperatorAutoSelect(); + std::string getCurrentOperator() const; bool setOperator(at::response::cops::CopsMode mode, at::response::cops::NameFormat format, const std::string &name); private: diff --git a/module-services/service-cellular/ServiceCellular.cpp b/module-services/service-cellular/ServiceCellular.cpp index 9e7b498a0eeaab7177ca52cc3407fc0172318223..1de19d49cd844a1e010d3ae968662c25f7b9ac38 100644 --- a/module-services/service-cellular/ServiceCellular.cpp +++ b/module-services/service-cellular/ServiceCellular.cpp @@ -300,6 +300,11 @@ void ServiceCellular::registerMessageHandlers() }); connect(typeid(CellularGetAPNMessage), [&](sys::Message *request) -> sys::MessagePointer { + connect(typeid(CellularGetCurrentOperatorMessage), [&](sys::Message *request) -> sys::MessagePointer { + auto msg = static_cast(request); + return handleCellularGetCurrentOperator(msg); + }); + auto msg = static_cast(request); return handleCellularGetAPNMessage(msg); }); @@ -2043,6 +2048,14 @@ bool ServiceCellular::handle_apn_conf_procedure() return true; } +std::shared_ptr ServiceCellular::handleCellularGetCurrentOperator( + CellularGetCurrentOperatorMessage *msg) +{ + LOG_INFO("CellularGetCurrentOperator handled"); + NetworkSettings networkSettings(*this); + return std::make_shared(networkSettings.getCurrentOperator()); +} + std::shared_ptr ServiceCellular::handleCellularGetAPNMessage(CellularGetAPNMessage *msg) { std::vector> apns; diff --git a/module-services/service-cellular/service-cellular/CellularMessage.hpp b/module-services/service-cellular/service-cellular/CellularMessage.hpp index d7c39385e67ea2a7905a4c5d5819a1ab8aa1783c..5ba820cff4d4b891d9db75a22a28284783d1e869 100644 --- a/module-services/service-cellular/service-cellular/CellularMessage.hpp +++ b/module-services/service-cellular/service-cellular/CellularMessage.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved. +// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #pragma once @@ -88,6 +88,13 @@ class CellularNotificationMessage : public CellularMessage std::string data; }; +class CellularGetCurrentOperatorMessage : public CellularMessage +{ + public: + explicit CellularGetCurrentOperatorMessage() : CellularMessage(MessageType::CellularNotification) + {} +}; + class CellularSetOperatorAutoSelectMessage : public sys::Message { public: @@ -95,6 +102,20 @@ class CellularSetOperatorAutoSelectMessage : public sys::Message {} }; +class CellularGetCurrentOperatorResponse : public CellularMessage +{ + std::string currentOperatorName; + + public: + explicit CellularGetCurrentOperatorResponse(std::string currentOperatorName) + : CellularMessage(MessageType::CellularNotification), currentOperatorName(currentOperatorName) + {} + + std::string getCurrentOperatorName() const + { + return currentOperatorName; + } +}; class CellularSetOperatorMessage : public sys::Message { at::response::cops::CopsMode mode; diff --git a/module-services/service-cellular/service-cellular/CellularServiceAPI.hpp b/module-services/service-cellular/service-cellular/CellularServiceAPI.hpp index 06419b7cddbc292d2f34a6882711a5c35c579505..9a0fffba3e0ce6fec5698735ed67918808341168 100644 --- a/module-services/service-cellular/service-cellular/CellularServiceAPI.hpp +++ b/module-services/service-cellular/service-cellular/CellularServiceAPI.hpp @@ -43,6 +43,12 @@ namespace CellularServiceAPI * @param serv pointer to caller service. */ void GetNetworkInfo(sys::Service *serv); + + /* + * @brief Get current operator, result async in + * CellularGetCurrentOperatorResponse message + */ + void GetCurrentOperator(sys::Service *serv); /* * @brief It calls service-cellulat to perform operators scan * @param serv pointer to caller service. diff --git a/module-services/service-cellular/service-cellular/ServiceCellular.hpp b/module-services/service-cellular/service-cellular/ServiceCellular.hpp index 44ad9c4208eba975f098bc59258c54ed99dfbd94..d6f96a3532c5a3a4c293b022547160dec08dcd50 100644 --- a/module-services/service-cellular/service-cellular/ServiceCellular.hpp +++ b/module-services/service-cellular/service-cellular/ServiceCellular.hpp @@ -269,8 +269,11 @@ class ServiceCellular : public sys::Service std::shared_ptr handleCellularStartOperatorsScan( CellularStartOperatorsScanMessage *msg); + std::shared_ptr handleCellularSetOperatorAutoSelect( CellularSetOperatorAutoSelectMessage *msg); + std::shared_ptr handleCellularGetCurrentOperator( + CellularGetCurrentOperatorMessage *msg); std::shared_ptr handleCellularGetAPNMessage(CellularGetAPNMessage *msg); std::shared_ptr handleCellularSetAPNMessage(CellularSetAPNMessage *msg); std::shared_ptr handleCellularSetOperator(CellularSetOperatorMessage *msg);