M changelog.md => changelog.md +1 -0
@@ 30,6 30,7 @@
* `[audio]` Added support for Bluetooth audio profiles
* `[filesystem]` Added support for standard file IO library.
* [`[messages]`] Added fetching text messages at phone startup.
+* `[cellular]` Support for MMI Call Forwarding call
## Changed
M module-cellular/at/Commands.hpp => module-cellular/at/Commands.hpp +12 -1
@@ 135,6 135,12 @@ namespace at
CFUN_DISABLE_TRANSMITTING, /// Disable the ME from both transmitting and receiving RF signals
LIST_MESSAGES, /// List all messages from message storage
GET_IMEI,
+ CCFC, /// Supplementary Services - Call Forwarding Number and Conditions Control
+ CCWA, /// Supplementary Services - Call Waiting Control
+ CHLD, /// Supplementary Services - Call Related Supplementary Services
+ CLIR, /// Supplementary Services - Calling Line Identification Restriction
+ COLP, /// Supplementary Services - Connected Line Identification Presentation
+ CSSN, /// Supplementary Services - Supplementary Service Notifications
};
// below timeouts are defined in Quectel_EC25&EC21_AT_Commands_Manual_V1.3.pdf
@@ 215,7 221,12 @@ namespace at
{AT::ENABLE_NETWORK_REGISTRATION_URC, {"AT+CREG=2"}},
{AT::SET_SMS_TEXT_MODE_UCS2, {"AT+CSMP=17,167,0,8"}},
{AT::LIST_MESSAGES, {"AT+CMGL=\"ALL\"", default_doc_timeout}},
- {AT::GET_IMEI, {"AT+GSN", default_doc_timeout}}};
+ {AT::GET_IMEI, {"AT+GSN", default_doc_timeout}},
+ {AT::CCFC, {"AT+CCFC=", default_doc_timeout}},
+ {AT::CCWA, {"AT+CCWA=\"", default_doc_timeout}},
+ {AT::CHLD, {"AT+CHLD=\"", default_doc_timeout}},
+ {AT::COLP, {"AT+COLP=\"", default_doc_timeout}},
+ {AT::CSSN, {"AT+CSSN=\"", default_doc_timeout}}};
if (fact.count(at)) {
return fact.at(at);
M module-services/service-cellular/CMakeLists.txt => module-services/service-cellular/CMakeLists.txt +15 -5
@@ 1,4 1,4 @@
-project(service-cellular)
+project(service-cellular)
message( "${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}" )
set(SOURCES
@@ 7,10 7,17 @@ set(SOURCES
CellularUrcHandler.cpp
ServiceCellular.cpp
SignalStrength.cpp
- CallRequest.cpp
SimCard.cpp
- CallRequestFactory.cpp
- CellularCallRequestHandler.cpp
+ RequestFactory.cpp
+ CellularRequestHandler.cpp
+ requests/Request.cpp
+ requests/CallRequest.cpp
+ requests/SupplementaryServicesRequest.cpp
+ requests/CallForwardingRequest.cpp
+ requests/PasswordRegistrationRequest.cpp
+ requests/PinChangeRequest.cpp
+ requests/ImeiRequest.cpp
+ requests/UssdRequest.cpp
)
add_library(${PROJECT_NAME} STATIC ${SOURCES})
@@ 28,4 35,7 @@ target_link_libraries(${PROJECT_NAME}
module-bsp
module-cellular
)
-
+
+if (${ENABLE_TESTS})
+ add_subdirectory(tests)
+endif ()
D module-services/service-cellular/CallRequestFactory.cpp => module-services/service-cellular/CallRequestFactory.cpp +0 -41
@@ 1,41 0,0 @@
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
-// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
-
-#include "service-cellular/CallRequestFactory.hpp"
-
-#include <re2/re2.h>
-
-#include <at/Commands.hpp>
-#include <log/log.hpp>
-
-namespace call_request
-{
- constexpr inline auto IMEIRegex = "(\\*#06#)";
- constexpr inline auto USSDRegex = "^[\\*].*[\\#]$";
-
- Factory::Factory(const std::string &data) : request(data)
- {
- registerRequest(IMEIRegex, IMEIRequest::create);
-
- /*It have to be last check due to 3GPP TS 22.030*/
- registerRequest(USSDRegex, USSDRequest::create);
- }
-
- void Factory::registerRequest(std::string regex, CreateCallback callback)
- {
- requestMap.insert(std::make_pair(regex, callback));
- }
-
- std::unique_ptr<IRequest> Factory::create()
- {
- for (const auto &element : requestMap) {
- re2::StringPiece input(request);
- re2::RE2 reg(element.first);
- if (re2::RE2::FullMatch(input, reg)) {
- return element.second(request);
- }
- }
- return std::make_unique<CallRequest>(request);
- }
-
-} // namespace call_request
R module-services/service-cellular/CellularCallRequestHandler.cpp => module-services/service-cellular/CellularRequestHandler.cpp +39 -5
@@ 1,15 1,22 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
-#include "service-cellular/CellularCallRequestHandler.hpp"
-#include "service-cellular/CallRequestFactory.hpp"
+#include "service-cellular/CellularRequestHandler.hpp"
+#include "service-cellular/RequestFactory.hpp"
#include "service-cellular/ServiceCellular.hpp"
#include "Service/Bus.hpp"
#include "Service/Message.hpp"
#include "Service/Timer.hpp"
-void CellularCallRequestHandler::handle(IMEIRequest &request, at::Result &result)
+#include "service-cellular/requests/CallRequest.hpp"
+#include "service-cellular/requests/SupplementaryServicesRequest.hpp"
+#include "service-cellular/requests/PasswordRegistrationRequest.hpp"
+#include "service-cellular/requests/PinChangeRequest.hpp"
+#include "service-cellular/requests/ImeiRequest.hpp"
+#include "service-cellular/requests/UssdRequest.hpp"
+
+void CellularRequestHandler::handle(ImeiRequest &request, at::Result &result)
{
if (!request.checkModemResponse(result)) {
request.setHandled(false);
@@ 18,7 25,7 @@ void CellularCallRequestHandler::handle(IMEIRequest &request, at::Result &result
request.setHandled(true);
}
-void CellularCallRequestHandler::handle(USSDRequest &request, at::Result &result)
+void CellularRequestHandler::handle(UssdRequest &request, at::Result &result)
{
if (!request.checkModemResponse(result)) {
request.setHandled(false);
@@ 29,7 36,7 @@ void CellularCallRequestHandler::handle(USSDRequest &request, at::Result &result
request.setHandled(true);
}
-void CellularCallRequestHandler::handle(CallRequest &request, at::Result &result)
+void CellularRequestHandler::handle(CallRequest &request, at::Result &result)
{
if (!request.checkModemResponse(result)) {
request.setHandled(false);
@@ 44,3 51,30 @@ void CellularCallRequestHandler::handle(CallRequest &request, at::Result &result
&cellular);
request.setHandled(true);
}
+
+void CellularRequestHandler::handle(SupplementaryServicesRequest &request, at::Result &result)
+{
+ if (!request.checkModemResponse(result)) {
+ request.setHandled(false);
+ return;
+ }
+ request.setHandled(true);
+}
+
+void CellularRequestHandler::handle(PasswordRegistrationRequest &request, at::Result &result)
+{
+ if (!request.checkModemResponse(result)) {
+ request.setHandled(false);
+ return;
+ }
+ request.setHandled(true);
+}
+
+void CellularRequestHandler::handle(PinChangeRequest &request, at::Result &result)
+{
+ if (!request.checkModemResponse(result)) {
+ request.setHandled(false);
+ return;
+ }
+ request.setHandled(true);
+}
A module-services/service-cellular/RequestFactory.cpp => module-services/service-cellular/RequestFactory.cpp +83 -0
@@ 0,0 1,83 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include "service-cellular/RequestFactory.hpp"
+
+#include <re2/re2.h>
+
+#include <at/Commands.hpp>
+#include <log/log.hpp>
+
+#include "service-cellular/requests/CallRequest.hpp"
+#include "service-cellular/requests/SupplementaryServicesRequest.hpp"
+#include "service-cellular/requests/PasswordRegistrationRequest.hpp"
+#include "service-cellular/requests/PinChangeRequest.hpp"
+#include "service-cellular/requests/ImeiRequest.hpp"
+#include "service-cellular/requests/UssdRequest.hpp"
+
+namespace cellular
+{
+ RequestFactory::RequestFactory(const std::string &data) : request(data)
+ {
+ registerRequest(ImeiRegex, ImeiRequest::create);
+ registerRequest(PasswordRegistrationRegex, PasswordRegistrationRequest::create);
+ registerRequest(PinChangeRegex, PinChangeRequest::create);
+ registerRequest(SupplementaryServicesRegex, SupplementaryServicesRequest::create);
+ /*It have to be last check due to 3GPP TS 22.030*/
+ registerRequest(UssdRegex, UssdRequest::create);
+ }
+
+ void RequestFactory::registerRequest(std::string regex, CreateCallback callback)
+ {
+ requestMap.emplace_back(std::make_pair(regex, callback));
+ }
+
+ std::unique_ptr<IRequest> RequestFactory::create()
+ {
+ std::string groupA, groupB, groupC, groupD, groupE, groupF;
+ GroupMatch matchPack = {groupA, groupB, groupC, groupD, groupE, groupF};
+
+ std::vector<std::string> results;
+
+ for (const auto &element : requestMap) {
+ auto const &requestCreateCallback = element.second;
+ re2::StringPiece input(request);
+ re2::RE2 reg(element.first);
+
+ std::vector<RE2::Arg> reArguments;
+ std::vector<RE2::Arg *> reArgumentPtrs;
+
+ std::size_t numberOfGroups = reg.NumberOfCapturingGroups();
+
+ if (numberOfGroups > matchPack.size()) {
+ LOG_ERROR("Internal error, GroupMatch has to be redefined.");
+ break;
+ }
+
+ reArguments.resize(numberOfGroups);
+ reArgumentPtrs.resize(numberOfGroups);
+ results.resize(numberOfGroups);
+
+ for (std::size_t i = 0; i < numberOfGroups; ++i) {
+ /// Bind RE arguments to strings from vector.
+ reArguments[i] = &matchPack[i].get();
+ /// Assign pointers to arguments.
+ reArgumentPtrs[i] = &reArguments[i];
+ }
+
+ if (re2::RE2::FullMatchN(input, reg, reArgumentPtrs.data(), numberOfGroups)) {
+ try {
+ if (auto req = requestCreateCallback(request, matchPack)) {
+ return req;
+ }
+ }
+ catch (const std::runtime_error &except) {
+ LOG_ERROR("Failed to create MMI request. Error message:\n%s", except.what());
+ }
+ break;
+ }
+ }
+ return std::make_unique<CallRequest>(request);
+ }
+
+} // namespace cellular
M module-services/service-cellular/ServiceCellular.cpp => module-services/service-cellular/ServiceCellular.cpp +5 -4
@@ 9,9 9,10 @@
#include "service-cellular/SignalStrength.hpp"
#include "service-cellular/State.hpp"
#include "service-cellular/USSD.hpp"
+
#include "SimCard.hpp"
-#include "service-cellular/CallRequestFactory.hpp"
-#include "service-cellular/CellularCallRequestHandler.hpp"
+#include "service-cellular/RequestFactory.hpp"
+#include "service-cellular/CellularRequestHandler.hpp"
#include <Audio/AudioCommon.hpp>
#include <BaseInterface.hpp>
@@ 728,8 729,8 @@ sys::MessagePointer ServiceCellular::DataReceivedHandler(sys::DataMessage *msgl,
break;
}
- call_request::Factory factory(msg->number.getEntered());
- CellularCallRequestHandler handler(*this);
+ cellular::RequestFactory factory(msg->number.getEntered());
+ CellularRequestHandler handler(*this);
auto request = factory.create();
auto result = channel->cmd(request->command());
A module-services/service-cellular/requests/CallForwardingRequest.cpp => module-services/service-cellular/requests/CallForwardingRequest.cpp +107 -0
@@ 0,0 1,107 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include <string>
+
+#include <at/Commands.hpp>
+#include <Utils.hpp>
+
+#include "service-cellular/requests/CallForwardingRequest.hpp"
+
+namespace
+{
+ // according to EC25&EC21_AT_Commands_Manual_V1.3
+ const std::map<std::string, std::string> reasonCodes = {{
+ {"21", "0"}, // Unconditional
+ {"67", "1"}, // MobileBusy
+ {"61", "2"}, // NoReply
+ {"62", "3"}, // NotReachable
+ {"002", "4"}, // AllCallForwarding
+ {"004", "5"}, // AllConditionalCallForwarding
+ }};
+} // namespace
+
+namespace cellular
+{
+
+ std::unique_ptr<SupplementaryServicesRequest> CallForwardingRequest::create(const std::string &serviceCode,
+ const std::string &data,
+ GroupMatch matchGroups)
+ {
+ if (auto it = reasonCodes.find(serviceCode); it != reasonCodes.end()) {
+ return std::make_unique<CallForwardingRequest>(it->second, data, matchGroups);
+ }
+
+ return nullptr;
+ }
+
+ auto CallForwardingRequest::command() -> std::string
+ {
+ std::array<std::function<std::string()>, 2> commandParts = {
+ [this]() { return this->getCommandMode(); },
+ [this]() { return this->getCommandNumber(); },
+ };
+
+ std::string cmd(at::factory(at::AT::CCFC) + this->getCommandReason());
+ for (auto &cmdPart : commandParts) {
+ auto partStr = cmdPart();
+ if (partStr.empty()) {
+ break;
+ }
+ cmd.append("," + partStr);
+ }
+
+ return cmd;
+ }
+
+ auto CallForwardingRequest::getCommandReason() const -> std::string
+ {
+ return forwardReason;
+ }
+
+ auto CallForwardingRequest::getCommandMode() const -> std::string
+ {
+ return utils::to_string(magic_enum::enum_integer(procedureType));
+ }
+
+ auto CallForwardingRequest::getCommandNumber() const -> std::string
+ {
+ return phoneNumber.empty() ? std::string() : "\"" + phoneNumber + "\"";
+ }
+
+ auto CallForwardingRequest::getCommandType() const -> std::string
+ {
+ // according to EC25&EC21_AT_Commands_Manual_V1.3
+ if (auto pos = phoneNumber.find("+"); pos != std::string::npos) {
+ return addressFormatTypeDefault;
+ }
+ else {
+ return addressFormatTypeInternational;
+ }
+ }
+
+ auto CallForwardingRequest::getCommandClass() const -> std::string
+ {
+ return getCommandInformationClass(basicServiceGroup);
+ }
+
+ auto CallForwardingRequest::getCommandSubAddr() const -> std::string
+ {
+ return subaddrDefault;
+ }
+
+ auto CallForwardingRequest::getCommandSatype() const -> std::string
+ {
+ return std::string();
+ }
+
+ auto CallForwardingRequest::getCommandTime() const -> std::string
+ {
+ return noReplyConditionTimer;
+ }
+
+ void CallForwardingRequest::handle(RequestHandler &h, at::Result &result)
+ {
+ h.handle(*this, result);
+ }
+} // namespace cellular
A module-services/service-cellular/requests/CallRequest.cpp => module-services/service-cellular/requests/CallRequest.cpp +23 -0
@@ 0,0 1,23 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include <string>
+#include <memory>
+
+#include <at/Result.hpp>
+#include <at/Commands.hpp>
+
+#include "service-cellular/requests/CallRequest.hpp"
+
+namespace cellular
+{
+ std::string CallRequest::command()
+ {
+ return std::string(at::factory(at::AT::ATD) + request + ";");
+ }
+
+ void CallRequest::handle(RequestHandler &h, at::Result &result)
+ {
+ h.handle(*this, result);
+ }
+}; // namespace cellular
A module-services/service-cellular/requests/ImeiRequest.cpp => module-services/service-cellular/requests/ImeiRequest.cpp +29 -0
@@ 0,0 1,29 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include <string>
+#include <memory>
+
+#include <at/Result.hpp>
+#include <at/Commands.hpp>
+
+#include "service-cellular/requests/ImeiRequest.hpp"
+
+namespace cellular
+{
+ std::string ImeiRequest::command()
+ {
+ return std::string(at::factory(at::AT::GET_IMEI));
+ }
+
+ void ImeiRequest::handle(RequestHandler &h, at::Result &result)
+ {
+ h.handle(*this, result);
+ }
+
+ std::unique_ptr<ImeiRequest> ImeiRequest::create(const std::string &data, GroupMatch)
+ {
+ return std::make_unique<ImeiRequest>(data);
+ }
+
+}; // namespace cellular
A module-services/service-cellular/requests/PasswordRegistrationRequest.cpp => module-services/service-cellular/requests/PasswordRegistrationRequest.cpp +86 -0
@@ 0,0 1,86 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include <string>
+
+#include <at/Commands.hpp>
+#include <Utils.hpp>
+
+#include "service-cellular/requests/PasswordRegistrationRequest.hpp"
+
+namespace
+{
+ // according to EC25&EC21_AT_Commands_Manual_V1.3
+ const std::map<std::string, std::string> barringServiceToFacilityMap = {{
+ {"33", "AO"}, // BAOC (Bar All Outgoing Calls)
+ {"331", "OI"}, // BOIC (Bar Outgoing International Calls)
+ {"332", "OX"}, // BOIC-exHC (Bar Outgoing International Calls except to home country)
+ {"35", "AI"}, // BAIC (Bar All Incoming Calls)
+ {"351", "IR"}, // BIC-Roam (Bar Incoming Calls when Roaming outside the home country)
+ {"330", "AB"}, // All barring services
+ {"333", "AG"}, // All outgoing barring services
+ {"353", "AC"}, // All incoming barring services
+ {"", "AB"}, // All incoming barring services (According to 3GPP TS 22.030 V16.0.0 )
+ }};
+} // namespace
+
+namespace
+{
+ constexpr inline std::string_view changeNetworkPasswordServiceCode = "03";
+}
+
+namespace cellular
+{
+
+ std::unique_ptr<PasswordRegistrationRequest> PasswordRegistrationRequest::create(const std::string &data,
+ GroupMatch matchGroups)
+ {
+ return std::make_unique<PasswordRegistrationRequest>(data, matchGroups);
+ }
+
+ auto PasswordRegistrationRequest::command() -> std::string
+ {
+ std::array<std::function<std::string()>, 3> commandParts = {
+ [this]() { return this->getCommandFacility(); },
+ [this]() { return "," + this->getOldPassword(); },
+ [this]() { return "," + this->getNewPassword(); },
+ };
+
+ std::string cmd(at::factory(at::AT::CPWD));
+ for (auto &cmdPart : commandParts) {
+ cmd.append(cmdPart());
+ }
+
+ return cmd;
+ }
+
+ auto PasswordRegistrationRequest::getCommandFacility() const noexcept -> std::string
+ {
+ if (auto it = barringServiceToFacilityMap.find(requestBarringService);
+ it != barringServiceToFacilityMap.end()) {
+ return "\"" + it->second + "\"";
+ }
+ return std::string();
+ }
+
+ auto PasswordRegistrationRequest::getOldPassword() const noexcept -> std::string
+ {
+ return "\"" + requestOldPassword + "\"";
+ }
+
+ auto PasswordRegistrationRequest::getNewPassword() const noexcept -> std::string
+ {
+ return "\"" + requestNewPassword + "\"";
+ }
+
+ void PasswordRegistrationRequest::handle(RequestHandler &h, at::Result &result)
+ {
+ h.handle(*this, result);
+ }
+
+ auto PasswordRegistrationRequest::isValid() const noexcept -> bool
+ {
+ return requestNewPassword == requestNewPasswordRepeat && !requestNewPasswordRepeat.empty() &&
+ !requestNewPassword.empty() && !requestOldPassword.empty();
+ }
+} // namespace cellular
A module-services/service-cellular/requests/PinChangeRequest.cpp => module-services/service-cellular/requests/PinChangeRequest.cpp +92 -0
@@ 0,0 1,92 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include <string>
+
+#include <at/Commands.hpp>
+#include <Utils.hpp>
+
+#include "service-cellular/requests/PinChangeRequest.hpp"
+
+namespace
+{
+ //(according to 3GPP TS 22.030 V16.0.0):
+ const std::map<std::string, cellular::PinChangeRequest::PassChangeType> serviceCodeToChangeType = {{
+ {"04", cellular::PinChangeRequest::PassChangeType::ChangePin},
+ {"042", cellular::PinChangeRequest::PassChangeType::ChangePin2},
+ {"05", cellular::PinChangeRequest::PassChangeType::ChangePinByPuk},
+ }};
+
+ constexpr inline std::string_view changeNetworkPasswordServiceCode = "03";
+} // namespace
+
+namespace cellular
+{
+
+ PinChangeRequest::PinChangeRequest(const std::string &data, GroupMatch matchGroups)
+ : Request(data), requestOldPinOrPuk(matchGroups[magic_enum::enum_integer(PinChangeRegexGroups::OldPassword)]),
+ requestNewPin(matchGroups[magic_enum::enum_integer(PinChangeRegexGroups::NewPassword)]),
+ requestNewPinRepeat(matchGroups[magic_enum::enum_integer(PinChangeRegexGroups::NewPasswordRepeat)])
+ {
+ auto &serviceCode = matchGroups[magic_enum::enum_integer(PinChangeRegexGroups::ServiceCode)];
+ if (auto it = serviceCodeToChangeType.find(serviceCode); it == serviceCodeToChangeType.end()) {
+ throw std::runtime_error(std::string(__FUNCTION__) + ": input service code not supported");
+ }
+ else {
+ passChangeType = it->second;
+ }
+ }
+
+ std::unique_ptr<PinChangeRequest> PinChangeRequest::create(const std::string &data, GroupMatch matchGroups)
+ {
+ return std::make_unique<PinChangeRequest>(data, matchGroups);
+ }
+
+ auto PinChangeRequest::command() -> std::string
+ {
+ std::array<std::function<std::string()>, 2> commandParts = {
+ [this]() { return this->getOldPinOrPuk(); },
+ [this]() { return "," + this->getNewPin(); },
+ };
+
+ std::string cmd;
+ switch (passChangeType) {
+ case PassChangeType::ChangePin:
+ cmd.append(at::factory(at::AT::CPWD) + "\"SC\",");
+ break;
+ case PassChangeType::ChangePin2:
+ cmd.append(at::factory(at::AT::CPWD) + "\"P2\",");
+ break;
+ case PassChangeType::ChangePinByPuk:
+ cmd.append(at::factory(at::AT::CPIN));
+ break;
+ };
+
+ for (auto &cmdPart : commandParts) {
+ cmd.append(cmdPart());
+ }
+
+ return cmd;
+ }
+
+ auto PinChangeRequest::getOldPinOrPuk() const noexcept -> std::string
+ {
+ return "\"" + requestOldPinOrPuk + "\"";
+ }
+
+ auto PinChangeRequest::getNewPin() const noexcept -> std::string
+ {
+ return "\"" + requestNewPin + "\"";
+ }
+
+ void PinChangeRequest::handle(RequestHandler &h, at::Result &result)
+ {
+ h.handle(*this, result);
+ }
+
+ auto PinChangeRequest::isValid() const noexcept -> bool
+ {
+ return requestNewPin == requestNewPinRepeat && !requestNewPin.empty() && !requestNewPinRepeat.empty() &&
+ !requestOldPinOrPuk.empty();
+ }
+} // namespace cellular
R module-services/service-cellular/CallRequest.cpp => module-services/service-cellular/requests/Request.cpp +6 -43
@@ 1,18 1,16 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
-#include <functional>
#include <string>
#include <memory>
-#include "service-cellular/CallRequest.hpp"
#include <at/Result.hpp>
#include <at/Commands.hpp>
-namespace call_request
-{
+#include "service-cellular/requests/Request.hpp"
- Request::Request(const std::string &data) : request(data){};
+namespace cellular
+{
void Request::setHandled(bool handled)
{
isRequestHandled = handled;
@@ 25,43 23,8 @@ namespace call_request
{
return result.code == at::Result::Code::OK;
}
-
- std::string IMEIRequest::command()
- {
- return std::string(at::factory(at::AT::GET_IMEI));
- }
- void IMEIRequest::handle(CallRequestHandler &h, at::Result &result)
- {
- h.handle(*this, result);
- }
-
- std::unique_ptr<IMEIRequest> IMEIRequest::create(const std::string &data)
- {
- return std::make_unique<IMEIRequest>(data);
- }
-
- std::string USSDRequest::command()
- {
- return std::string(at::factory(at::AT::CUSD_SEND) + request + ",15");
- }
-
- std::unique_ptr<USSDRequest> USSDRequest::create(const std::string &data)
- {
- return std::make_unique<USSDRequest>(data);
- }
-
- void USSDRequest::handle(CallRequestHandler &h, at::Result &result)
- {
- h.handle(*this, result);
- }
-
- std::string CallRequest::command()
- {
- return std::string(at::factory(at::AT::ATD) + request + ";");
- }
-
- void CallRequest::handle(CallRequestHandler &h, at::Result &result)
+ bool Request::isValid() const noexcept
{
- h.handle(*this, result);
+ return true;
}
-}; // namespace call_request
+}; // namespace cellular
A module-services/service-cellular/requests/SupplementaryServicesRequest.cpp => module-services/service-cellular/requests/SupplementaryServicesRequest.cpp +80 -0
@@ 0,0 1,80 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include <string>
+#include <memory>
+
+#include <at/Commands.hpp>
+
+#include "service-cellular/requests/SupplementaryServicesRequest.hpp"
+#include "service-cellular/requests/CallForwardingRequest.hpp"
+#include "service-cellular/requests/PasswordRegistrationRequest.hpp"
+
+namespace
+{
+ const std::map<std::string, cellular::SupplementaryServicesRequest::ProcedureType> procedureTypeMap = {
+ {"*", cellular::SupplementaryServicesRequest::ProcedureType::Activation},
+ {"#", cellular::SupplementaryServicesRequest::ProcedureType::Deactivation},
+ {"*#", cellular::SupplementaryServicesRequest::ProcedureType::Interrogation},
+ {"**", cellular::SupplementaryServicesRequest::ProcedureType::Registration},
+ {"##", cellular::SupplementaryServicesRequest::ProcedureType::Erasure},
+ };
+}
+
+namespace cellular
+{
+ SupplementaryServicesRequest::SupplementaryServicesRequest(const std::string &data, GroupMatch matchGroups)
+ : Request(data),
+ serviceCode(matchGroups[magic_enum::enum_integer(SupplementaryServicesRegexGroups::ServiceCode)]),
+ supplementaryInfoA(matchGroups[magic_enum::enum_integer(SupplementaryServicesRegexGroups::SupInfoA)]),
+ supplementaryInfoB(matchGroups[magic_enum::enum_integer(SupplementaryServicesRegexGroups::SupInfoB)]),
+ supplementaryInfoC(matchGroups[magic_enum::enum_integer(SupplementaryServicesRegexGroups::SupInfoC)])
+ {
+ static_assert(magic_enum::enum_count<SupplementaryServicesRegexGroups>() <= maxGroupsInRequest);
+
+ auto &procedureTypeString =
+ matchGroups[magic_enum::enum_integer(SupplementaryServicesRegexGroups::ProcedureType)];
+
+ auto pType = procedureTypeMap.find(procedureTypeString);
+ if (pType == procedureTypeMap.end()) {
+
+ throw std::runtime_error(std::string(__FUNCTION__) + ": procedure type not covered by constructor.");
+ }
+ procedureType = pType->second;
+ }
+
+ auto SupplementaryServicesRequest::create(const std::string &data, GroupMatch matchGroups)
+ -> std::unique_ptr<SupplementaryServicesRequest>
+ {
+ std::string serviceCode = matchGroups[magic_enum::enum_integer(SupplementaryServicesRegexGroups::ServiceCode)];
+
+ auto factoryList = {
+ CallForwardingRequest::create,
+ };
+
+ for (auto &createCb : factoryList) {
+ if (auto req = createCb(serviceCode, data, matchGroups)) {
+ return req;
+ }
+ }
+
+ return nullptr;
+ }
+
+ auto SupplementaryServicesRequest::getCommandInformationClass(const std::string &basicServiceGroup) const
+ -> std::string
+ {
+ // according to EC25&EC21_AT_Commands_Manual_V1.3
+ if (basicServiceGroup == basicServiceVoice) {
+ return atInformationClassVoice;
+ }
+ else if (basicServiceGroup == basicServiceVoiceFax) {
+ return atInformationClassFax;
+ }
+ else if (basicServiceGroup == basicServiceVoiceData) {
+ return atInformationClassData;
+ }
+ return atInformationClassAllButSms;
+ }
+
+}; // namespace cellular
A module-services/service-cellular/requests/UssdRequest.cpp => module-services/service-cellular/requests/UssdRequest.cpp +28 -0
@@ 0,0 1,28 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include <string>
+#include <memory>
+
+#include <at/Result.hpp>
+#include <at/Commands.hpp>
+
+#include "service-cellular/requests/UssdRequest.hpp"
+
+namespace cellular
+{
+ std::string UssdRequest::command()
+ {
+ return std::string(at::factory(at::AT::CUSD_SEND) + request + ",15");
+ }
+
+ std::unique_ptr<UssdRequest> UssdRequest::create(const std::string &data, GroupMatch)
+ {
+ return std::make_unique<UssdRequest>(data);
+ }
+
+ void UssdRequest::handle(RequestHandler &h, at::Result &result)
+ {
+ h.handle(*this, result);
+ }
+}; // namespace cellular
D module-services/service-cellular/service-cellular/CallRequest.hpp => module-services/service-cellular/service-cellular/CallRequest.hpp +0 -66
@@ 1,66 0,0 @@
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
-// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
-
-#pragma once
-
-#include <at/Result.hpp>
-#include "CallRequestHandler.hpp"
-
-namespace call_request
-{
- class IRequest
- {
- public:
- virtual std::string command() = 0;
- virtual void handle(CallRequestHandler &h, at::Result &result) = 0;
- virtual void setHandled(bool handled) = 0;
- virtual bool isHandled() const noexcept = 0;
- virtual bool checkModemResponse(const at::Result &result) = 0;
- virtual ~IRequest(){};
- };
-
- class Request : public IRequest
- {
- public:
- Request(const std::string &data);
- void setHandled(bool handled) final;
- bool isHandled() const noexcept final;
- bool checkModemResponse(const at::Result &result);
-
- protected:
- bool isRequestHandled = false;
- std::string request;
- };
-
- class IMEIRequest : public Request
- {
- public:
- IMEIRequest(const std::string &data) : Request(data){};
- std::string command() final;
- static std::unique_ptr<IMEIRequest> create(const std::string &data);
- void handle(CallRequestHandler &h, at::Result &result) final;
- };
-
- class USSDRequest : public Request
- {
- public:
- USSDRequest(const std::string &data) : Request(data){};
- std::string command() final;
-
- static std::unique_ptr<USSDRequest> create(const std::string &data);
- void handle(CallRequestHandler &h, at::Result &result) final;
- };
-
- class CallRequest : public Request
- {
- public:
- CallRequest(const std::string &data) : Request(data){};
- std::string command() final;
- std::string getNumber() const
- {
- return request;
- }
- static std::unique_ptr<CallRequest> create(const std::string &data);
- void handle(CallRequestHandler &h, at::Result &result) final;
- };
-}; // namespace call_request
D module-services/service-cellular/service-cellular/CallRequestHandler.hpp => module-services/service-cellular/service-cellular/CallRequestHandler.hpp +0 -21
@@ 1,21 0,0 @@
-// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
-// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
-
-#pragma once
-
-#include <at/Result.hpp>
-
-namespace call_request
-{
- class IMEIRequest;
- class USSDRequest;
- class CallRequest;
-
- class CallRequestHandler
- {
- public:
- virtual void handle(IMEIRequest &request, at::Result &result) = 0;
- virtual void handle(USSDRequest &request, at::Result &result) = 0;
- virtual void handle(CallRequest &request, at::Result &result) = 0;
- };
-} // namespace call_request
R module-services/service-cellular/service-cellular/CellularCallRequestHandler.hpp => module-services/service-cellular/service-cellular/CellularRequestHandler.hpp +9 -6
@@ 3,20 3,23 @@
#pragma once
-#include "CallRequestHandler.hpp"
+#include "RequestHandler.hpp"
#include "service-cellular/ServiceCellular.hpp"
-using namespace call_request;
+using namespace cellular;
-class CellularCallRequestHandler : public CallRequestHandler
+class CellularRequestHandler : public RequestHandler
{
public:
- CellularCallRequestHandler(ServiceCellular &serviceCellular) : cellular(serviceCellular)
+ CellularRequestHandler(ServiceCellular &serviceCellular) : cellular(serviceCellular)
{}
- void handle(IMEIRequest &request, at::Result &result) final;
- void handle(USSDRequest &request, at::Result &result) final;
+ void handle(ImeiRequest &request, at::Result &result) final;
+ void handle(UssdRequest &request, at::Result &result) final;
void handle(CallRequest &request, at::Result &result) final;
+ void handle(PasswordRegistrationRequest &request, at::Result &result) final;
+ void handle(SupplementaryServicesRequest &request, at::Result &result) final;
+ void handle(PinChangeRequest &request, at::Result &result) final;
private:
ServiceCellular &cellular;
R module-services/service-cellular/service-cellular/CallRequestFactory.hpp => module-services/service-cellular/service-cellular/RequestFactory.hpp +7 -7
@@ 8,21 8,21 @@
#include <map>
#include <functional>
-#include "CallRequest.hpp"
+#include "requests/CallRequest.hpp"
-namespace call_request
+namespace cellular
{
- using CreateCallback = std::function<std::unique_ptr<IRequest>(const std::string &)>;
+ using CreateCallback = std::function<std::unique_ptr<IRequest>(const std::string &, GroupMatch)>;
- class Factory
+ class RequestFactory
{
public:
- Factory(const std::string &data);
+ RequestFactory(const std::string &data);
std::unique_ptr<IRequest> create();
private:
std::string request;
- std::map<std::string, CreateCallback> requestMap;
+ std::vector<std::pair<std::string, CreateCallback>> requestMap;
void registerRequest(std::string regex, CreateCallback);
};
-} // namespace call_request
+} // namespace cellular
A module-services/service-cellular/service-cellular/RequestHandler.hpp => module-services/service-cellular/service-cellular/RequestHandler.hpp +27 -0
@@ 0,0 1,27 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include <at/Result.hpp>
+
+namespace cellular
+{
+ class ImeiRequest;
+ class UssdRequest;
+ class CallRequest;
+ class SupplementaryServicesRequest;
+ class PasswordRegistrationRequest;
+ class PinChangeRequest;
+
+ class RequestHandler
+ {
+ public:
+ virtual void handle(ImeiRequest &request, at::Result &result) = 0;
+ virtual void handle(UssdRequest &request, at::Result &result) = 0;
+ virtual void handle(CallRequest &request, at::Result &result) = 0;
+ virtual void handle(PasswordRegistrationRequest &request, at::Result &result) = 0;
+ virtual void handle(PinChangeRequest &request, at::Result &result) = 0;
+ virtual void handle(SupplementaryServicesRequest &request, at::Result &result) = 0;
+ };
+} // namespace cellular
M module-services/service-cellular/service-cellular/ServiceCellular.hpp => module-services/service-cellular/service-cellular/ServiceCellular.hpp +1 -1
@@ 253,6 253,6 @@ class ServiceCellular : public sys::Service
bool handleSimState(at::SimState state, const std::string message);
friend class CellularUrcHandler;
- friend class CellularCallRequestHandler;
friend class SimCard;
+ friend class CellularRequestHandler;
};
A module-services/service-cellular/service-cellular/requests/CallForwardingRequest.hpp => module-services/service-cellular/service-cellular/requests/CallForwardingRequest.hpp +44 -0
@@ 0,0 1,44 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include "SupplementaryServicesRequest.hpp"
+
+namespace cellular
+{
+ class CallForwardingRequest : public SupplementaryServicesRequest
+ {
+ public:
+ CallForwardingRequest(const std::string &forwardReason, const std::string &data, GroupMatch matchGroups)
+ : SupplementaryServicesRequest(data, matchGroups), forwardReason(forwardReason)
+ {}
+
+ static std::unique_ptr<SupplementaryServicesRequest> create(const std::string &serviceCode,
+ const std::string &data,
+ GroupMatch matchGroups);
+
+ auto command() -> std::string final;
+ void handle(RequestHandler &h, at::Result &result) final;
+
+ private:
+ static constexpr auto addressFormatTypeInternational = "145";
+ static constexpr auto addressFormatTypeDefault = "129";
+ static constexpr auto subaddrDefault = "128";
+
+ std::string forwardReason;
+ std::string &phoneNumber = supplementaryInfoA;
+ std::string &basicServiceGroup = supplementaryInfoB;
+ std::string &noReplyConditionTimer = supplementaryInfoB;
+
+ // command decomposition according to EC25&EC21_AT_Commands_Manual_V1.3
+ auto getCommandReason() const -> std::string;
+ auto getCommandMode() const -> std::string;
+ auto getCommandNumber() const -> std::string;
+ auto getCommandType() const -> std::string;
+ auto getCommandClass() const -> std::string;
+ auto getCommandSubAddr() const -> std::string;
+ auto getCommandSatype() const -> std::string;
+ auto getCommandTime() const -> std::string;
+ };
+}; // namespace cellular
A module-services/service-cellular/service-cellular/requests/CallRequest.hpp => module-services/service-cellular/service-cellular/requests/CallRequest.hpp +25 -0
@@ 0,0 1,25 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include <at/Result.hpp>
+
+#include "service-cellular/RequestHandler.hpp"
+#include "service-cellular/requests/Request.hpp"
+
+namespace cellular
+{
+ class CallRequest : public Request
+ {
+ public:
+ CallRequest(const std::string &data) : Request(data){};
+ std::string command() final;
+ std::string getNumber() const
+ {
+ return request;
+ }
+ static std::unique_ptr<CallRequest> create(const std::string &data, GroupMatch);
+ void handle(RequestHandler &h, at::Result &result) final;
+ };
+}; // namespace cellular
A module-services/service-cellular/service-cellular/requests/ImeiRequest.hpp => module-services/service-cellular/service-cellular/requests/ImeiRequest.hpp +24 -0
@@ 0,0 1,24 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include <at/Result.hpp>
+
+#include "service-cellular/RequestHandler.hpp"
+#include "service-cellular/requests/Request.hpp"
+
+namespace cellular
+{
+ constexpr inline auto ImeiRegex = "(\\*#06#)";
+
+ class ImeiRequest : public Request
+ {
+ public:
+ ImeiRequest(const std::string &data) : Request(data){};
+ std::string command() final;
+
+ static std::unique_ptr<ImeiRequest> create(const std::string &data, GroupMatch);
+ void handle(RequestHandler &h, at::Result &result) final;
+ };
+} // namespace cellular
A module-services/service-cellular/service-cellular/requests/PasswordRegistrationRequest.hpp => module-services/service-cellular/service-cellular/requests/PasswordRegistrationRequest.hpp +57 -0
@@ 0,0 1,57 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include "SupplementaryServicesRequest.hpp"
+
+namespace cellular
+{
+ constexpr inline auto PasswordRegistrationRegex =
+ R"(^(\*\*|\*)(03)(?:\*(30|31|330|331|33|332|333|35|351|353|))(?:\*([0-9]*))(?:\*([0-9]*))(?:\*([0-9]*))\#$)";
+
+ /**
+ * (according to 3GPP TS 22.030 V16.0.0):
+ */
+ enum class PasswordRegistrationRegexGroups
+ {
+ ProcedureType, //! (\*\*|\*)
+ //! * (activation/registration),
+ //! ** (registration),
+ ServiceCode, //! (03)
+ BarringServiceCode, //! (?:\*(30|31|330|331|33|332|333|35|351|353|))
+ OldPassword, //! (?:\*([0-9]*)
+ NewPassword, //! (?:\*([0-9]*)
+ NewPasswordRepeat //! (?:\*([0-9]*)
+ };
+
+ class PasswordRegistrationRequest : public Request
+ {
+ public:
+ PasswordRegistrationRequest(const std::string &data, GroupMatch matchGroups)
+ : Request(data),
+ requestBarringService(
+ matchGroups[magic_enum::enum_integer(PasswordRegistrationRegexGroups::BarringServiceCode)]),
+ requestOldPassword(matchGroups[magic_enum::enum_integer(PasswordRegistrationRegexGroups::OldPassword)]),
+ requestNewPassword(matchGroups[magic_enum::enum_integer(PasswordRegistrationRegexGroups::NewPassword)]),
+ requestNewPasswordRepeat(
+ matchGroups[magic_enum::enum_integer(PasswordRegistrationRegexGroups::NewPasswordRepeat)])
+ {}
+
+ static std::unique_ptr<PasswordRegistrationRequest> create(const std::string &data, GroupMatch matchGroups);
+
+ auto command() -> std::string final;
+ void handle(RequestHandler &h, at::Result &result) final;
+ auto isValid() const noexcept -> bool final;
+
+ auto getCommandFacility() const noexcept -> std::string;
+ auto getOldPassword() const noexcept -> std::string;
+ auto getNewPassword() const noexcept -> std::string;
+
+ private:
+ std::string requestBarringService;
+ std::string requestOldPassword;
+ std::string requestNewPassword;
+ std::string requestNewPasswordRepeat;
+ };
+}; // namespace cellular
A module-services/service-cellular/service-cellular/requests/PinChangeRequest.hpp => module-services/service-cellular/service-cellular/requests/PinChangeRequest.hpp +50 -0
@@ 0,0 1,50 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include "SupplementaryServicesRequest.hpp"
+
+namespace cellular
+{
+ constexpr inline auto PinChangeRegex = R"(^(\*\*)(04|042|05)(?:\*([0-9]*))(?:\*([0-9]*))(?:\*([0-9]*))\#$)";
+
+ // (according to 3GPP TS 22.030 V16.0.0):
+ enum class PinChangeRegexGroups
+ {
+ ProcedureType, //! (\*\*)
+ //! ** (registration),
+ ServiceCode, //! (04|042|05)
+ OldPassword, //! (?:\*([0-9]*))
+ NewPassword, //! (?:\*([0-9]*))
+ NewPasswordRepeat //! (?:\*([0-9]*))
+ };
+
+ class PinChangeRequest : public Request
+ {
+ public:
+ enum class PassChangeType
+ {
+ ChangePin,
+ ChangePin2,
+ ChangePinByPuk,
+ };
+
+ PinChangeRequest(const std::string &data, GroupMatch matchGroups);
+
+ static std::unique_ptr<PinChangeRequest> create(const std::string &data, GroupMatch matchGroups);
+
+ auto command() -> std::string final;
+ void handle(RequestHandler &h, at::Result &result) final;
+ auto isValid() const noexcept -> bool final;
+
+ auto getOldPinOrPuk() const noexcept -> std::string;
+ auto getNewPin() const noexcept -> std::string;
+
+ private:
+ PassChangeType passChangeType;
+ std::string requestOldPinOrPuk;
+ std::string requestNewPin;
+ std::string requestNewPinRepeat;
+ };
+}; // namespace cellular
A module-services/service-cellular/service-cellular/requests/Request.hpp => module-services/service-cellular/service-cellular/requests/Request.hpp +40 -0
@@ 0,0 1,40 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include <at/Result.hpp>
+#include "service-cellular/RequestHandler.hpp"
+
+namespace cellular
+{
+ constexpr inline auto maxGroupsInRequest = 6;
+ using GroupMatch = std::array<std::reference_wrapper<std::string>, maxGroupsInRequest>;
+
+ class IRequest
+ {
+ public:
+ virtual std::string command() = 0;
+ virtual void handle(RequestHandler &h, at::Result &result) = 0;
+ virtual void setHandled(bool handled) = 0;
+ virtual bool isHandled() const noexcept = 0;
+ virtual bool checkModemResponse(const at::Result &result) = 0;
+ virtual bool isValid() const noexcept = 0;
+ virtual ~IRequest(){};
+ };
+
+ class Request : public IRequest
+ {
+ public:
+ Request(const std::string &data) : request(data){};
+
+ void setHandled(bool handled) final;
+ bool isHandled() const noexcept final;
+ bool checkModemResponse(const at::Result &result) final;
+ bool isValid() const noexcept override;
+
+ protected:
+ bool isRequestHandled = false;
+ std::string request;
+ };
+}; // namespace cellular
A module-services/service-cellular/service-cellular/requests/SupplementaryServicesRequest.hpp => module-services/service-cellular/service-cellular/requests/SupplementaryServicesRequest.hpp +65 -0
@@ 0,0 1,65 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include <at/Result.hpp>
+#include "service-cellular/requests/CallRequest.hpp"
+
+namespace cellular
+{
+ constexpr inline auto SupplementaryServicesRegex =
+ R"(^(\*|\*\*|\*\#|\#|\#\#)(\d{2,3})(?:\*([^\*\#]*))?(?:\*([^\*\#]*))?(?:\*([^\*\#]*))?\#)";
+
+ /**
+ * (according to 3GPP TS 22.030 V16.0.0):
+ */
+ enum class SupplementaryServicesRegexGroups
+ {
+ ProcedureType, //! (\*|\*\*|\*\#|\#|\#\#)
+ //! * (activation/registration),
+ //! # (deactivation),
+ //! *# (interrogation),
+ //! ** (registration),
+ //! ## (erasure)
+ ServiceCode, //! (\d{2,3})
+ SupInfoA, //! (?:\*([^\*\#]+)) - Supplementary Information A (optional)
+ SupInfoB, //! (?:\*([^\*\#]+)) - Supplementary Information B (optional)
+ SupInfoC //! (?:\*([^\*\#]+)) - Supplementary Information C (optional)
+ };
+
+ class SupplementaryServicesRequest : public Request
+ {
+ public:
+ static std::unique_ptr<SupplementaryServicesRequest> create(const std::string &data, GroupMatch matchGroups);
+ SupplementaryServicesRequest(const std::string &data, GroupMatch matchGroups);
+
+ enum class ProcedureType
+ {
+ Deactivation,
+ Activation,
+ Interrogation,
+ Registration,
+ Erasure
+ };
+
+ protected:
+ std::string request;
+ std::string serviceCode;
+ std::string supplementaryInfoA;
+ std::string supplementaryInfoB;
+ std::string supplementaryInfoC;
+ ProcedureType procedureType;
+
+ static constexpr inline auto atInformationClassVoice = "1";
+ static constexpr inline auto atInformationClassData = "2";
+ static constexpr inline auto atInformationClassFax = "4";
+ static constexpr inline auto atInformationClassAllButSms = "7";
+
+ static constexpr inline auto basicServiceVoice = "11";
+ static constexpr inline auto basicServiceVoiceData = "25";
+ static constexpr inline auto basicServiceVoiceFax = "13";
+
+ auto getCommandInformationClass(const std::string &basicServiceGroup) const -> std::string;
+ };
+}; // namespace cellular
A module-services/service-cellular/service-cellular/requests/UssdRequest.hpp => module-services/service-cellular/service-cellular/requests/UssdRequest.hpp +24 -0
@@ 0,0 1,24 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include <at/Result.hpp>
+
+#include "service-cellular/RequestHandler.hpp"
+#include "service-cellular/requests/Request.hpp"
+
+namespace cellular
+{
+ constexpr inline auto UssdRegex = "^[\\*].*[\\#]$";
+
+ class UssdRequest : public Request
+ {
+ public:
+ UssdRequest(const std::string &data) : Request(data){};
+ std::string command() final;
+
+ static std::unique_ptr<UssdRequest> create(const std::string &data, GroupMatch);
+ void handle(RequestHandler &h, at::Result &result) final;
+ };
+} // namespace cellular
A module-services/service-cellular/tests/CMakeLists.txt => module-services/service-cellular/tests/CMakeLists.txt +11 -0
@@ 0,0 1,11 @@
+cmake_minimum_required(VERSION 3.12)
+
+add_catch2_executable(
+ NAME
+ cellular-mmi
+ SRCS
+ unittest_mmi.cpp
+ LIBS
+ module-cellular
+)
+
A module-services/service-cellular/tests/unittest_mmi.cpp => module-services/service-cellular/tests/unittest_mmi.cpp +141 -0
@@ 0,0 1,141 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#define CATCH_CONFIG_MAIN
+
+#include <catch2/catch.hpp>
+#include <service-cellular/RequestFactory.hpp>
+#include <service-cellular/requests/CallForwardingRequest.hpp>
+#include <service-cellular/requests/PasswordRegistrationRequest.hpp>
+#include <service-cellular/requests/PinChangeRequest.hpp>
+#include <service-cellular/requests/ImeiRequest.hpp>
+#include <service-cellular/requests/UssdRequest.hpp>
+
+using namespace cellular;
+
+TEST_CASE("MMI requests")
+{
+ struct TestCase
+ {
+ const std::string requestString;
+ const std::string expectedCommandString;
+ const std::type_info &expectedType;
+ const bool expectedValid = true;
+ };
+
+ std::vector<TestCase> testCases = {
+ /// IMEIRequest
+ {R"(*#06#)", R"(AT+GSN)", typeid(ImeiRequest)},
+
+ /// CallForwardingRequest
+ // all diversions
+ {R"(##002#)", R"(AT+CCFC=4,4)", typeid(CallForwardingRequest)},
+ // all conditional redirections
+ {R"(**004*666555444#)", R"(AT+CCFC=5,3,"666555444")", typeid(CallForwardingRequest)},
+ {R"(##004#)", R"(AT+CCFC=5,4)", typeid(CallForwardingRequest)},
+ // unconditional divert
+ {R"(**21*666555444#)", R"(AT+CCFC=0,3,"666555444")", typeid(CallForwardingRequest)},
+ {R"(*21#)", R"(AT+CCFC=0,1)", typeid(CallForwardingRequest)},
+ {R"(#21#)", R"(AT+CCFC=0,0)", typeid(CallForwardingRequest)},
+ {R"(##21#)", R"(AT+CCFC=0,4)", typeid(CallForwardingRequest)},
+ {R"(*#21#)", R"(AT+CCFC=0,2)", typeid(CallForwardingRequest)},
+ // divert when not answered
+ {R"(**61*666555444#)", R"(AT+CCFC=2,3,"666555444")", typeid(CallForwardingRequest)},
+ {R"(*61#)", R"(AT+CCFC=2,1)", typeid(CallForwardingRequest)},
+ {R"(#61#)", R"(AT+CCFC=2,0)", typeid(CallForwardingRequest)},
+ {R"(##61#)", R"(AT+CCFC=2,4)", typeid(CallForwardingRequest)},
+ {R"(*#61#)", R"(AT+CCFC=2,2)", typeid(CallForwardingRequest)},
+ // divert when off or not
+ {R"(**62*666555444#)", R"(AT+CCFC=3,3,"666555444")", typeid(CallForwardingRequest)},
+ {R"(*62#)", R"(AT+CCFC=3,1)", typeid(CallForwardingRequest)},
+ {R"(#62#)", R"(AT+CCFC=3,0)", typeid(CallForwardingRequest)},
+ {R"(##62#)", R"(AT+CCFC=3,4)", typeid(CallForwardingRequest)},
+ {R"(*#62#)", R"(AT+CCFC=3,2)", typeid(CallForwardingRequest)},
+ // divert when busy or pressing reject
+ {R"(**67*666555444#)", R"(AT+CCFC=1,3,"666555444")", typeid(CallForwardingRequest)},
+ {R"(*67#)", R"(AT+CCFC=1,1)", typeid(CallForwardingRequest)},
+ {R"(#67#)", R"(AT+CCFC=1,0)", typeid(CallForwardingRequest)},
+ {R"(##67#)", R"(AT+CCFC=1,4)", typeid(CallForwardingRequest)},
+ {R"(*#67#)", R"(AT+CCFC=1,2)", typeid(CallForwardingRequest)},
+ // alternative register and on
+ {R"(*21*666555444#)", R"(AT+CCFC=0,1,"666555444")", typeid(CallForwardingRequest)},
+
+ /// PasswordRegistrationRequest
+ // total incoming and outgoing service barring (empty string)
+ {R"(**03**23*111*111#)", R"(AT+CPWD="AB","23","111")", typeid(PasswordRegistrationRequest)},
+ // outgoing call barring
+ {R"(**03*33*1234*4321*4321#)", R"(AT+CPWD="AO","1234","4321")", typeid(PasswordRegistrationRequest)},
+ // outgoing international call barring
+ {R"(**03*331*1234*4321*4321#)", R"(AT+CPWD="OI","1234","4321")", typeid(PasswordRegistrationRequest)},
+ // outgoing international call barring, excluding to home
+ {R"(**03*332*1234*4321*4321#)", R"(AT+CPWD="OX","1234","4321")", typeid(PasswordRegistrationRequest)},
+ // incoming call barring
+ {R"(**03*35*1234*4321*4321#)", R"(AT+CPWD="AI","1234","4321")", typeid(PasswordRegistrationRequest)},
+ // incoming call barring, when international roaming
+ {R"(**03*351*1234*4321*4321#)", R"(AT+CPWD="IR","1234","4321")", typeid(PasswordRegistrationRequest)},
+ // total incoming and outgoing service barring
+ {R"(**03*330*1234*4321*4321#)", R"(AT+CPWD="AB","1234","4321")", typeid(PasswordRegistrationRequest)},
+ // total outgoing service barring
+ {R"(**03*333*1234*4321*4321#)", R"(AT+CPWD="AG","1234","4321")", typeid(PasswordRegistrationRequest)},
+ // total incoming service barring
+ {R"(**03*353*1234*4321*4321#)", R"(AT+CPWD="AC","1234","4321")", typeid(PasswordRegistrationRequest)},
+ // alternative procedure type *
+ {R"(*03*353*1234*4321*4321#)", R"(AT+CPWD="AC","1234","4321")", typeid(PasswordRegistrationRequest)},
+ // bad procedure type * fallback to UUSD
+ {R"(*#03*353*1234*4321*4321#)", R"(AT+CUSD=1,*#03*353*1234*4321*4321#,15)", typeid(UssdRequest)},
+ // bad procedure type ##
+ {R"(##03*353*1234*4321*4321#)", std::string(), typeid(CallRequest)},
+ // bad procedure type #
+ {R"(#03*353*1234*4321*4321#)", std::string(), typeid(CallRequest)},
+ // no password
+ {R"(**03*353***#)", std::string(), typeid(PasswordRegistrationRequest), false},
+ // no password
+ {R"(**03*353*24**#)", std::string(), typeid(PasswordRegistrationRequest), false},
+ // no password
+ {R"(**03*353**34*#)", std::string(), typeid(PasswordRegistrationRequest), false},
+ // no password
+ {R"(**03*353***34#)", std::string(), typeid(PasswordRegistrationRequest), false},
+ // password does not match
+ {R"(**03*353*56*46*74#)", std::string(), typeid(PasswordRegistrationRequest), false},
+
+ /// PinChangeRequest
+ // Change PIN
+ {R"(**04*0000*1111*1111#)", R"(AT+CPWD="SC","0000","1111")", typeid(PinChangeRequest)},
+ // Change PIN2
+ {R"(**042*0000*1111*1111#)", R"(AT+CPWD="P2","0000","1111")", typeid(PinChangeRequest)},
+ // Change PIN by PUK
+ {R"(**05*0000*1111*1111#)", R"(AT+CPIN="0000","1111")", typeid(PinChangeRequest)},
+ // Change PIN by PUK more than 4
+ {R"(**042*00002*11113*11113#)", R"(AT+CPWD="P2","00002","11113")", typeid(PinChangeRequest)},
+ // bad procedure type *
+ {R"(*042*00002*11112*11112#)", std::string(), typeid(CallRequest)},
+ // bad procedure type ##
+ {R"(##042*00002*11112*11112#)", std::string(), typeid(CallRequest)},
+ // bad procedure type #
+ {R"(#042*00002*11112*11112#)", std::string(), typeid(CallRequest)},
+ // bad procedure type *#
+ {R"(*#042*00002*11112*11112#)", std::string(), typeid(CallRequest)},
+ // no password
+ {R"(**042*00002**#)", std::string(), typeid(PinChangeRequest), false},
+ // no password
+ {R"(**042***11112#)", std::string(), typeid(PinChangeRequest), false},
+ // no password
+ {R"(**042**11112*#)", std::string(), typeid(PinChangeRequest), false},
+ // no password
+ {R"(**042**11112*#)", std::string(), typeid(PinChangeRequest), false},
+ // password does not match
+ {R"(**042*0000*1111*2222#)", std::string(), typeid(PinChangeRequest), false},
+ };
+
+ for (auto &testCase : testCases) {
+ RequestFactory requestFactory(testCase.requestString);
+ auto request = requestFactory.create();
+ auto requestCommand = request->command();
+ INFO("Failed on testcase: " << testCase.requestString);
+ REQUIRE(typeid(*request.get()).name() == testCase.expectedType.name());
+ REQUIRE(request->isValid() == testCase.expectedValid);
+ if (typeid(*request.get()).name() != typeid(CallRequest).name() && request->isValid()) {
+ REQUIRE(requestCommand == testCase.expectedCommandString);
+ }
+ }
+}