M module-cellular/at/response.cpp => module-cellular/at/response.cpp +45 -1
@@ 51,6 51,7 @@ namespace at
return parts;
}
+ constexpr std::string_view AT_COPS = "+COPS:";
bool parseCOPS(const at::Result &resp, std::vector<cops::Operator> &ret)
{
/// +COPS: (list of supported <stat>,long alphanumeric <oper>,
@@ 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: <mode>[,<format>[,<oper>][,<Act>]]
+ /// 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<cops::AccessTechnology>(utils::getNumericValue<int>(opParams[3]));
+ [[fallthrough]];
+ case 3: {
+ ret.setFormat(static_cast<cops::NameFormat>(utils::getNumericValue<int>(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<cops::NameFormat>(utils::getNumericValue<int>(opParams[1])));
+ [[fallthrough]];
+ case 1:
+ ret.setMode(static_cast<cops::CopsMode>(utils::getNumericValue<int>(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
M module-cellular/at/response.hpp => module-cellular/at/response.hpp +51 -1
@@ 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<cops::Operator> 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<cops::Operator> &ret);
using ResponseTokens = std::vector<std::vector<std::string>>;
+ /**
+ * @brief parse for AT+COPS? from quectel
+ *
+ */
+ bool parseCOPS(const at::Result &resp, cops::CurrentOperatorInfo &ret);
+
std::vector<std::string> tokenize(std::string &response, std::string separator = ",");
/**
M module-cellular/test/unittest_response.cpp => module-cellular/test/unittest_response.cpp +55 -0
@@ 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);
+ }
}
M module-services/service-cellular/CellularServiceAPI.cpp => module-services/service-cellular/CellularServiceAPI.cpp +6 -0
@@ 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<CellularGetCurrentOperatorMessage> msg = std::make_shared<CellularGetCurrentOperatorMessage>();
+ sys::Bus::SendUnicast(msg, ServiceCellular::serviceName, serv);
+}
+
void CellularServiceAPI::StartOperatorsScan(sys::Service *serv, bool fullInfo)
{
std::shared_ptr<CellularStartOperatorsScanMessage> msg =
M module-services/service-cellular/NetworkSettings.cpp => module-services/service-cellular/NetworkSettings.cpp +16 -0
@@ 5,6 5,22 @@
#include <unordered_map>
+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<std::string> NetworkSettings::scanOperators(bool fullInfoList)
{
std::vector<std::string> operatorNames;
M module-services/service-cellular/NetworkSettings.hpp => module-services/service-cellular/NetworkSettings.hpp +1 -0
@@ 26,6 26,7 @@ class NetworkSettings
std::vector<std::string> 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:
M module-services/service-cellular/ServiceCellular.cpp => module-services/service-cellular/ServiceCellular.cpp +13 -0
@@ 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<CellularGetCurrentOperatorMessage *>(request);
+ return handleCellularGetCurrentOperator(msg);
+ });
+
auto msg = static_cast<CellularGetAPNMessage *>(request);
return handleCellularGetAPNMessage(msg);
});
@@ 2043,6 2048,14 @@ bool ServiceCellular::handle_apn_conf_procedure()
return true;
}
+std::shared_ptr<CellularGetCurrentOperatorResponse> ServiceCellular::handleCellularGetCurrentOperator(
+ CellularGetCurrentOperatorMessage *msg)
+{
+ LOG_INFO("CellularGetCurrentOperator handled");
+ NetworkSettings networkSettings(*this);
+ return std::make_shared<CellularGetCurrentOperatorResponse>(networkSettings.getCurrentOperator());
+}
+
std::shared_ptr<CellularGetAPNResponse> ServiceCellular::handleCellularGetAPNMessage(CellularGetAPNMessage *msg)
{
std::vector<std::shared_ptr<packet_data::APN::Config>> apns;
M module-services/service-cellular/service-cellular/CellularMessage.hpp => module-services/service-cellular/service-cellular/CellularMessage.hpp +22 -1
@@ 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;
M module-services/service-cellular/service-cellular/CellularServiceAPI.hpp => module-services/service-cellular/service-cellular/CellularServiceAPI.hpp +6 -0
@@ 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.
M module-services/service-cellular/service-cellular/ServiceCellular.hpp => module-services/service-cellular/service-cellular/ServiceCellular.hpp +3 -0
@@ 269,8 269,11 @@ class ServiceCellular : public sys::Service
std::shared_ptr<cellular::RawCommandRespAsync> handleCellularStartOperatorsScan(
CellularStartOperatorsScanMessage *msg);
+
std::shared_ptr<CellularSetOperatorAutoSelectResponse> handleCellularSetOperatorAutoSelect(
CellularSetOperatorAutoSelectMessage *msg);
+ std::shared_ptr<CellularGetCurrentOperatorResponse> handleCellularGetCurrentOperator(
+ CellularGetCurrentOperatorMessage *msg);
std::shared_ptr<CellularGetAPNResponse> handleCellularGetAPNMessage(CellularGetAPNMessage *msg);
std::shared_ptr<CellularSetAPNResponse> handleCellularSetAPNMessage(CellularSetAPNMessage *msg);
std::shared_ptr<CellularSetOperatorResponse> handleCellularSetOperator(CellularSetOperatorMessage *msg);