~aleteoryx/muditaos

22b4afef28738182b68af4cac474f60d1de72068 — Hubert Chrzaniuk 5 years ago 82924c7
[EGD-4414] Add support for call barring MMI (#1057)

 * cover MMI requests with following codes:
   33,331,332,35,351,330,333,353
 * moved logic of building command string
   to base class
M changelog.md => changelog.md +2 -2
@@ 4,8 4,8 @@

### Added

* `[gui][desktop]` Added SIM PIN basic flow implementation.
* `[cellular]` Added CLIR, CLIP, COLP, and call-waiting MMI support.
* `[gui][desktop]` Added SIM PIN basic flow implementation
* `[cellular]` Added CLIR, CLIP, COLP, call waiting, call barring MMIs support

### Fixed


M module-services/service-cellular/CMakeLists.txt => module-services/service-cellular/CMakeLists.txt +1 -1
@@ 22,7 22,7 @@ set(SOURCES
    requests/ClirRequest.cpp
    requests/ColpRequest.cpp
    requests/CallWaitingRequest.cpp
)
    requests/CallBarringRequest.cpp)


add_library(${PROJECT_NAME} STATIC ${SOURCES})

A module-services/service-cellular/requests/CallBarringRequest.cpp => module-services/service-cellular/requests/CallBarringRequest.cpp +76 -0
@@ 0,0 1,76 @@
// 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/CallBarringRequest.hpp"

namespace cellular
{

    std::unique_ptr<SupplementaryServicesRequest> CallBarringRequest::create(const std::string &serviceCode,
                                                                             const std::string &data,
                                                                             GroupMatch matchGroups)
    {
        for (auto &it : barringServiceToFacility) {
            if (it.first == serviceCode) {
                return std::make_unique<CallBarringRequest>(std::string(it.second), data, matchGroups);
            }
        }

        return nullptr;
    }

    auto CallBarringRequest::command() -> std::string
    {
        std::vector<commandBuilderFunc> commandParts = {
            [this]() { return getCommandFacility(); },
            [this]() { return getCommandMode(); },
            [this]() { return getCommandPassword(); },
            [this]() { return getCommandClass(); },
        };

        return buildCommand(at::AT::CLCK, commandParts);
    }

    auto CallBarringRequest::getCommandFacility() const -> std::string
    {
        return "\"" + facility + "\"";
    }

    auto CallBarringRequest::getCommandMode() const -> std::string
    {
        return utils::to_string(magic_enum::enum_integer(procedureType));
    }

    auto CallBarringRequest::getCommandPassword() const -> std::string
    {
        return password.empty() ? std::string() : "\"" + password + "\"";
    }

    auto CallBarringRequest::getCommandClass() const -> std::string
    {
        if (basicServiceGroup.empty()) {
            return std::string();
        }

        return getCommandInformationClass(basicServiceGroup).value_or(std::string());
    }

    void CallBarringRequest::handle(RequestHandler &h, at::Result &result)
    {
        h.handle(*this, result);
    }

    auto CallBarringRequest::isValid() const noexcept -> bool
    {
        if (!getCommandInformationClass(basicServiceGroup).has_value()) {
            return false;
        }
        return procedureType != ProcedureType::Registration && procedureType != ProcedureType::Erasure;
    }

} // namespace cellular

M module-services/service-cellular/requests/CallForwardingRequest.cpp => module-services/service-cellular/requests/CallForwardingRequest.cpp +5 -16
@@ 37,24 37,13 @@ namespace cellular

    auto CallForwardingRequest::command() -> std::string
    {
        std::array<std::function<std::string()>, 3> commandParts = {
            [this]() { return this->getCommandReason(); },
            [this]() { return this->getCommandMode(); },
            [this]() { return this->getCommandNumber(); },
        std::vector<commandBuilderFunc> commandParts = {
            [this]() { return getCommandReason(); },
            [this]() { return getCommandMode(); },
            [this]() { return getCommandNumber(); },
        };

        std::string cmd(at::factory(at::AT::CCFC));
        bool formatFirst = true;
        for (auto &cmdPart : commandParts) {
            auto partStr = cmdPart();
            if (partStr.empty()) {
                continue;
            }
            cmd.append(formatFirst ? partStr : "," + partStr);
            formatFirst = false;
        }

        return cmd;
        return buildCommand(at::AT::CCFC, commandParts);
    }

    auto CallForwardingRequest::getCommandReason() const -> std::string

M module-services/service-cellular/requests/CallWaitingRequest.cpp => module-services/service-cellular/requests/CallWaitingRequest.cpp +5 -20
@@ 25,28 25,13 @@ namespace cellular

    auto CallWaitingRequest::command() -> std::string
    {
        if (!isValid()) {
            return std::string();
        }

        std::array<std::function<std::string()>, 3> commandParts = {
            [this]() { return this->getCommandPresentation(); },
            [this]() { return this->getCommandMode(); },
            [this]() { return this->getCommandClass(); },
        std::vector<commandBuilderFunc> commandParts = {
            [this]() { return getCommandPresentation(); },
            [this]() { return getCommandMode(); },
            [this]() { return getCommandClass(); },
        };

        std::string cmd(at::factory(at::AT::CCWA));
        bool formatFirst = true;
        for (auto &cmdPart : commandParts) {
            auto partStr = cmdPart();
            if (partStr.empty()) {
                continue;
            }
            cmd.append(formatFirst ? partStr : "," + partStr);
            formatFirst = false;
        }

        return cmd;
        return buildCommand(at::AT::CCWA, commandParts);
    }

    auto CallWaitingRequest::getCommandPresentation() const noexcept -> std::string

M module-services/service-cellular/requests/PasswordRegistrationRequest.cpp => module-services/service-cellular/requests/PasswordRegistrationRequest.cpp +14 -33
@@ 7,22 7,7 @@
#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
#include "service-cellular/requests/CallBarringRequest.hpp" // for barringServiceToFacility map

namespace
{


@@ 40,29 25,25 @@ namespace cellular

    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::vector<commandBuilderFunc> commandParts = {
            [this]() { return getCommandFacility(); },
            [this]() { return getOldPassword(); },
            [this]() { return getNewPassword(); },
        };

        if (!isValid()) {
            return std::string();
        }

        std::string cmd(at::factory(at::AT::CPWD));
        for (auto &cmdPart : commandParts) {
            cmd.append(cmdPart());
        }

        return cmd;
        return buildCommand(at::AT::CPWD, commandParts);
    }

    auto PasswordRegistrationRequest::getCommandFacility() const noexcept -> std::string
    {
        if (auto it = barringServiceToFacilityMap.find(requestBarringService);
            it != barringServiceToFacilityMap.end()) {
            return "\"" + it->second + "\"";
        if (requestBarringService.empty()) {
            return "\"" + std::string(CallBarringRequest::allBarringServicesFacilityString) +
                   "\""; //(According to 3GPP TS 22.030 V16.0.0 )
        }
        for (auto &it : CallBarringRequest::barringServiceToFacility) {
            if (it.first == requestBarringService) {
                return "\"" + std::string(it.second) + "\"";
            }
        }
        return std::string();
    }

M module-services/service-cellular/requests/Request.cpp => module-services/service-cellular/requests/Request.cpp +23 -0
@@ 15,16 15,39 @@ namespace cellular
    {
        isRequestHandled = handled;
    }

    bool Request::isHandled() const noexcept
    {
        return isRequestHandled;
    }

    bool Request::checkModemResponse(const at::Result &result)
    {
        return result.code == at::Result::Code::OK;
    }

    bool Request::isValid() const noexcept
    {
        return true;
    }

    std::string Request::buildCommand(at::AT atCommand, const std::vector<commandBuilderFunc> &builderFunctions) const
    {
        if (!isValid()) {
            return std::string();
        }

        std::string cmd(at::factory(atCommand));
        bool formatFirst = true;
        for (auto &cmdPart : builderFunctions) {
            auto partStr = cmdPart();
            if (partStr.empty()) {
                continue;
            }
            cmd.append(formatFirst ? partStr : "," + partStr);
            formatFirst = false;
        }

        return cmd;
    }
}; // namespace cellular

M module-services/service-cellular/requests/SupplementaryServicesRequest.cpp => module-services/service-cellular/requests/SupplementaryServicesRequest.cpp +2 -0
@@ 13,6 13,7 @@
#include "service-cellular/requests/ClirRequest.hpp"
#include "service-cellular/requests/ColpRequest.hpp"
#include "service-cellular/requests/CallWaitingRequest.hpp"
#include "service-cellular/requests/CallBarringRequest.hpp"

namespace
{


@@ 55,6 56,7 @@ namespace cellular
        auto factoryList = {
            CallForwardingRequest::create,
            CallWaitingRequest::create,
            CallBarringRequest::create,
            ClipRequest::create,
            ClirRequest::create,
            ColpRequest::create,

A module-services/service-cellular/service-cellular/requests/CallBarringRequest.hpp => module-services/service-cellular/service-cellular/requests/CallBarringRequest.hpp +49 -0
@@ 0,0 1,49 @@
// 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 CallBarringRequest : public SupplementaryServicesRequest
    {
      public:
        // according to EC25&EC21_AT_Commands_Manual_V1.3
        static constexpr auto allBarringServicesFacilityString                                                 = "AB";
        static constexpr std::array<std::pair<std::string_view, std::string_view>, 8> barringServiceToFacility = {{
            {"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", allBarringServicesFacilityString}, // All barring services
            {"333", "AG"},                             // All outgoing barring services
            {"353", "AC"},                             // All incoming barring services
        }};

        CallBarringRequest(const std::string &facility, const std::string &data, GroupMatch matchGroups)
            : SupplementaryServicesRequest(data, matchGroups), facility(facility)
        {}

        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;
        auto isValid() const noexcept -> bool;

      private:
        std::string facility;
        std::string &password          = supplementaryInfoA;
        std::string &basicServiceGroup = supplementaryInfoB;

        // command decomposition according to EC25&EC21_AT_Commands_Manual_V1.3
        auto getCommandFacility() const -> std::string;
        auto getCommandMode() const -> std::string;
        auto getCommandPassword() const -> std::string;
        auto getCommandClass() const -> std::string;
    };
}; // namespace cellular

M module-services/service-cellular/service-cellular/requests/Request.hpp => module-services/service-cellular/service-cellular/requests/Request.hpp +10 -0
@@ 4,6 4,7 @@
#pragma once

#include <at/Result.hpp>
#include <at/Commands.hpp>
#include "service-cellular/RequestHandler.hpp"

namespace cellular


@@ 34,6 35,15 @@ namespace cellular
        bool isValid() const noexcept override;

      protected:
        using commandBuilderFunc = std::function<std::string()>;
        /**
         * Helper command for building output command
         * @param atCommand
         * @param builderFunctions functions that build parts of the output command in order of execution
         * @return formatted command or empty string if input is invalid
         */
        auto buildCommand(at::AT atCommand, const std::vector<commandBuilderFunc> &builderFunctions) const
            -> std::string;
        bool isRequestHandled = false;
        std::string request;
    };

M module-services/service-cellular/tests/unittest_mmi.cpp => module-services/service-cellular/tests/unittest_mmi.cpp +112 -0
@@ 7,6 7,7 @@
#include <service-cellular/RequestFactory.hpp>
#include <service-cellular/requests/CallForwardingRequest.hpp>
#include <service-cellular/requests/CallWaitingRequest.hpp>
#include <service-cellular/requests/CallBarringRequest.hpp>
#include <service-cellular/requests/PasswordRegistrationRequest.hpp>
#include <service-cellular/requests/PinChangeRequest.hpp>
#include <service-cellular/requests/ImeiRequest.hpp>


@@ 71,6 72,117 @@ TEST_CASE("MMI requests")
        // bad procedure type
        {R"(**76#)", std::string(), typeid(ColpRequest), false},

        /// CallBarringRequest
        // BAOC (Bar All Outgoing Calls)
        {R"(*33#)", R"(AT+CLCK="AO",1)", typeid(CallBarringRequest)},                    // lock
        {R"(*33*1111#)", R"(AT+CLCK="AO",1,"1111")", typeid(CallBarringRequest)},        // lock with pass
        {R"(*33*1111*10#)", R"(AT+CLCK="AO",1,"1111",13)", typeid(CallBarringRequest)},  // lock with pass and BS
        {R"(#33#)", R"(AT+CLCK="AO",0)", typeid(CallBarringRequest)},                    // unlock
        {R"(#33*1111#)", R"(AT+CLCK="AO",0,"1111")", typeid(CallBarringRequest)},        // unlock with pass
        {R"(#33*1111*11#)", R"(AT+CLCK="AO",0,"1111",1)", typeid(CallBarringRequest)},   // unlock with pass and BS
        {R"(*#33#)", R"(AT+CLCK="AO",2)", typeid(CallBarringRequest)},                   // query
        {R"(*#33*1111#)", R"(AT+CLCK="AO",2,"1111")", typeid(CallBarringRequest)},       // query with pass
        {R"(*#33*1111*12#)", R"(AT+CLCK="AO",2,"1111",12)", typeid(CallBarringRequest)}, // query with pass and BS
        {R"(**33#)", std::string(), typeid(CallBarringRequest), false},                  // bad procedure - register
        {R"(##33#)", std::string(), typeid(CallBarringRequest), false},                  // bad procedure - erasure
        {R"(*#33*1111*17#)",
         std::string(),
         typeid(CallBarringRequest),
         false}, // unsupported BS - Voice Group Call Service
        {R"(*#33*1111*18#)",
         std::string(),
         typeid(CallBarringRequest),
         false}, // unsupported BS - Voice Broadcast Service
        {R"(*#33*1111*99#)",
         std::string(),
         typeid(CallBarringRequest),
         false}, // unsupported BS - All GPRS bearer services
        {R"(*#33*1111*45#)", std::string(), typeid(CallBarringRequest), false}, // unsupported BS - random
        /// BOIC (Bar Outgoing International Calls)
        {R"(*331#)", R"(AT+CLCK="OI",1)", typeid(CallBarringRequest)},                   // lock
        {R"(*331*2222#)", R"(AT+CLCK="OI",1,"2222")", typeid(CallBarringRequest)},       // lock with pass
        {R"(*331*2222*13#)", R"(AT+CLCK="OI",1,"2222",4)", typeid(CallBarringRequest)},  // lock with pass and BS
        {R"(#331#)", R"(AT+CLCK="OI",0)", typeid(CallBarringRequest)},                   // unlock
        {R"(#331*2222#)", R"(AT+CLCK="OI",0,"2222")", typeid(CallBarringRequest)},       // unlock with pass
        {R"(#331*2222*16#)", R"(AT+CLCK="OI",0,"2222",8)", typeid(CallBarringRequest)},  // unlock with pass and BS
        {R"(*#331#)", R"(AT+CLCK="OI",2)", typeid(CallBarringRequest)},                  // query
        {R"(*#331*2222#)", R"(AT+CLCK="OI",2,"2222")", typeid(CallBarringRequest)},      // query with pass
        {R"(*#331*2222*19#)", R"(AT+CLCK="OI",2,"2222",5)", typeid(CallBarringRequest)}, // query with pass and BS
        {R"(**331#)", std::string(), typeid(CallBarringRequest), false},                 // bad procedure - register
        {R"(##331#)", std::string(), typeid(CallBarringRequest), false},                 // bad procedure - erasure
        /// BOIC-exHC (Bar Outgoing International Calls except to home country)
        {R"(*332#)", R"(AT+CLCK="OX",1)", typeid(CallBarringRequest)},                    // lock
        {R"(*332*3333#)", R"(AT+CLCK="OX",1,"3333")", typeid(CallBarringRequest)},        // lock
        {R"(*332*2222*20#)", R"(AT+CLCK="OX",1,"2222",50)", typeid(CallBarringRequest)},  // lock with pass
        {R"(#332#)", R"(AT+CLCK="OX",0)", typeid(CallBarringRequest)},                    // unlock with pass and BS
        {R"(#332*3333#)", R"(AT+CLCK="OX",0,"3333")", typeid(CallBarringRequest)},        // unlock
        {R"(#332*2222*21#)", R"(AT+CLCK="OX",0,"2222",32)", typeid(CallBarringRequest)},  // unlock with pass
        {R"(*#332#)", R"(AT+CLCK="OX",2)", typeid(CallBarringRequest)},                   // query with pass and BS
        {R"(*#332*3333#)", R"(AT+CLCK="OX",2,"3333")", typeid(CallBarringRequest)},       // query with pass
        {R"(*#332*2222*22#)", R"(AT+CLCK="OX",2,"2222",16)", typeid(CallBarringRequest)}, // query with pass and BS
        {R"(**332#)", std::string(), typeid(CallBarringRequest), false},                  // bad procedure - register
        {R"(##332#)", std::string(), typeid(CallBarringRequest), false},                  // bad procedure - erasure
        /// BAIC (Bar All Incoming Calls)
        {R"(*35#)", R"(AT+CLCK="AI",1)", typeid(CallBarringRequest)},                    // lock
        {R"(*35*1234#)", R"(AT+CLCK="AI",1,"1234")", typeid(CallBarringRequest)},        // lock with pass
        {R"(*35*2222*24#)", R"(AT+CLCK="AI",1,"2222",16)", typeid(CallBarringRequest)},  // lock with pass and BS
        {R"(#35#)", R"(AT+CLCK="AI",0)", typeid(CallBarringRequest)},                    // unlock
        {R"(#35*1234#)", R"(AT+CLCK="AI",0,"1234")", typeid(CallBarringRequest)},        // unlock with pass
        {R"(#35*2222*25#)", R"(AT+CLCK="AI",0,"2222",32)", typeid(CallBarringRequest)},  // unlock with pass and BS
        {R"(*#35#)", R"(AT+CLCK="AI",2)", typeid(CallBarringRequest)},                   // query
        {R"(*#35*1234#)", R"(AT+CLCK="AI",2,"1234")", typeid(CallBarringRequest)},       // query with pass
        {R"(*#35*2222*26#)", R"(AT+CLCK="AI",2,"2222",17)", typeid(CallBarringRequest)}, // query with pass and BS
        {R"(**35#)", std::string(), typeid(CallBarringRequest), false},                  // bad procedure - register
        {R"(##35#)", std::string(), typeid(CallBarringRequest), false},                  // bad procedure - erasure
        /// BIC-Roam (Bar Incoming Calls when Roaming outside the home country)
        {R"(*351#)", R"(AT+CLCK="IR",1)", typeid(CallBarringRequest)},                    // lock
        {R"(*351*1234#)", R"(AT+CLCK="IR",1,"1234")", typeid(CallBarringRequest)},        // lock with pass
        {R"(*351*2222*10#)", R"(AT+CLCK="IR",1,"2222",13)", typeid(CallBarringRequest)},  // lock with pass and BS
        {R"(#351#)", R"(AT+CLCK="IR",0)", typeid(CallBarringRequest)},                    // unlock
        {R"(#351*1234#)", R"(AT+CLCK="IR",0,"1234")", typeid(CallBarringRequest)},        // unlock with pass
        {R"(#351*2222*11#)", R"(AT+CLCK="IR",0,"2222",1)", typeid(CallBarringRequest)},   // unlock with pass and BS
        {R"(*#351#)", R"(AT+CLCK="IR",2)", typeid(CallBarringRequest)},                   // query
        {R"(*#351*1234#)", R"(AT+CLCK="IR",2,"1234")", typeid(CallBarringRequest)},       // query with pass
        {R"(*#351*2222*12#)", R"(AT+CLCK="IR",2,"2222",12)", typeid(CallBarringRequest)}, // query with pass and BS
        {R"(**351#)", std::string(), typeid(CallBarringRequest), false},                  // bad procedure - register
        {R"(##351#)", std::string(), typeid(CallBarringRequest), false},                  // bad procedure - erasure
        /// All barring services
        {R"(*330#)", R"(AT+CLCK="AB",1)", typeid(CallBarringRequest)},                   // lock
        {R"(*330*1234#)", R"(AT+CLCK="AB",1,"1234")", typeid(CallBarringRequest)},       // lock with pass
        {R"(*330*2222*13#)", R"(AT+CLCK="AB",1,"2222",4)", typeid(CallBarringRequest)},  // lock with pass and BS
        {R"(#330#)", R"(AT+CLCK="AB",0)", typeid(CallBarringRequest)},                   // unlock
        {R"(#330*1234#)", R"(AT+CLCK="AB",0,"1234")", typeid(CallBarringRequest)},       // unlock with pass
        {R"(#330*2222*16#)", R"(AT+CLCK="AB",0,"2222",8)", typeid(CallBarringRequest)},  // unlock with pass and BS
        {R"(*#330#)", R"(AT+CLCK="AB",2)", typeid(CallBarringRequest)},                  // query
        {R"(*#330*1234#)", R"(AT+CLCK="AB",2,"1234")", typeid(CallBarringRequest)},      // query with pass
        {R"(*#330*2222*19#)", R"(AT+CLCK="AB",2,"2222",5)", typeid(CallBarringRequest)}, // query with pass and BS
        {R"(**330#)", std::string(), typeid(CallBarringRequest), false},                 // bad procedure - register
        {R"(##330#)", std::string(), typeid(CallBarringRequest), false},                 // bad procedure - erasure
        /// All outgoing barring services
        {R"(*333#)", R"(AT+CLCK="AG",1)", typeid(CallBarringRequest)},                    // lock
        {R"(*333*1234#)", R"(AT+CLCK="AG",1,"1234")", typeid(CallBarringRequest)},        // lock with pass
        {R"(*333*2222*20#)", R"(AT+CLCK="AG",1,"2222",50)", typeid(CallBarringRequest)},  // lock with pass and BS
        {R"(#333#)", R"(AT+CLCK="AG",0)", typeid(CallBarringRequest)},                    // unlock
        {R"(#333*1234#)", R"(AT+CLCK="AG",0,"1234")", typeid(CallBarringRequest)},        // unlock with pass
        {R"(#333*2222*21#)", R"(AT+CLCK="AG",0,"2222",32)", typeid(CallBarringRequest)},  // unlock with pass and BS
        {R"(*#333#)", R"(AT+CLCK="AG",2)", typeid(CallBarringRequest)},                   // query
        {R"(*#333*1234#)", R"(AT+CLCK="AG",2,"1234")", typeid(CallBarringRequest)},       // query with pass
        {R"(*#333*2222*22#)", R"(AT+CLCK="AG",2,"2222",16)", typeid(CallBarringRequest)}, // query with pass and BS
        {R"(**333#)", std::string(), typeid(CallBarringRequest), false},                  // bad procedure - register
        {R"(##333#)", std::string(), typeid(CallBarringRequest), false},                  // bad procedure - erasure
        /// All incoming barring services
        {R"(*353#)", R"(AT+CLCK="AC",1)", typeid(CallBarringRequest)},                    // lock
        {R"(*353*1234#)", R"(AT+CLCK="AC",1,"1234")", typeid(CallBarringRequest)},        // lock with pass
        {R"(*353*2222*24#)", R"(AT+CLCK="AC",1,"2222",16)", typeid(CallBarringRequest)},  // lock with pass and BS
        {R"(#353#)", R"(AT+CLCK="AC",0)", typeid(CallBarringRequest)},                    // unlock
        {R"(#353*1234#)", R"(AT+CLCK="AC",0,"1234")", typeid(CallBarringRequest)},        // unlock with pass
        {R"(#353*2222*25#)", R"(AT+CLCK="AC",0,"2222",32)", typeid(CallBarringRequest)},  // unlock with pass and BS
        {R"(*#353#)", R"(AT+CLCK="AC",2)", typeid(CallBarringRequest)},                   // query
        {R"(*#353*1234#)", R"(AT+CLCK="AC",2,"1234")", typeid(CallBarringRequest)},       // query with pass
        {R"(*#353*2222*10#)", R"(AT+CLCK="AC",2,"2222",13)", typeid(CallBarringRequest)}, // query with pass and BS
        {R"(**353#)", std::string(), typeid(CallBarringRequest), false},                  // bad procedure - register
        {R"(##353#)", std::string(), typeid(CallBarringRequest), false},                  // bad procedure - erasure

        /// CallWaitingRequest
        // enable all
        {R"(*43#)", R"(AT+CCWA=1,1)", typeid(CallWaitingRequest)},