~aleteoryx/muditaos

31db992c5ce75517c72fed5a4f7d8b051635894a — Bartosz Cichocki 3 years ago 619685d
[MOS-264] Add handling of signal strength and operator name in HFP

To be able to display signal strength, operator name and
rest of status indicators in Bluetooth's HFP profile, some
refactor has been done.
40 files changed, 595 insertions(+), 171 deletions(-)

M module-bluetooth/Bluetooth/BluetoothWorker.cpp
M module-bluetooth/Bluetooth/CommandHandler.cpp
M module-bluetooth/Bluetooth/CommandHandler.hpp
M module-bluetooth/Bluetooth/WorkerController.cpp
M module-bluetooth/Bluetooth/WorkerController.hpp
A module-bluetooth/Bluetooth/command/Command.cpp
A module-bluetooth/Bluetooth/command/Command.hpp
A module-bluetooth/Bluetooth/command/CommandData.hpp
A module-bluetooth/Bluetooth/command/DeviceData.cpp
A module-bluetooth/Bluetooth/command/DeviceData.hpp
A module-bluetooth/Bluetooth/command/OperatorName.hpp
A module-bluetooth/Bluetooth/command/OperatorNameData.cpp
A module-bluetooth/Bluetooth/command/OperatorNameData.hpp
A module-bluetooth/Bluetooth/command/PhoneNumberData.cpp
A module-bluetooth/Bluetooth/command/PhoneNumberData.hpp
A module-bluetooth/Bluetooth/command/SignalStrengthData.cpp
A module-bluetooth/Bluetooth/command/SignalStrengthData.hpp
M module-bluetooth/Bluetooth/interface/profiles/A2DP/A2DP.cpp
M module-bluetooth/Bluetooth/interface/profiles/A2DP/A2DP.hpp
M module-bluetooth/Bluetooth/interface/profiles/HFP/HFP.cpp
M module-bluetooth/Bluetooth/interface/profiles/HFP/HFP.hpp
M module-bluetooth/Bluetooth/interface/profiles/HFP/HFPImpl.hpp
M module-bluetooth/Bluetooth/interface/profiles/HSP/HSP.cpp
M module-bluetooth/Bluetooth/interface/profiles/HSP/HSP.hpp
M module-bluetooth/Bluetooth/interface/profiles/Profile.hpp
M module-bluetooth/Bluetooth/interface/profiles/ProfileManager.cpp
M module-bluetooth/Bluetooth/interface/profiles/ProfileManager.hpp
M module-bluetooth/CMakeLists.txt
M module-bluetooth/lib/btstack
M module-bluetooth/tests/CMakeLists.txt
M module-bluetooth/tests/tests-StatefulController.cpp
A module-bluetooth/tests/tests-command.cpp
M module-services/service-bluetooth/ServiceBluetooth.cpp
M module-services/service-bluetooth/service-bluetooth/ServiceBluetooth.hpp
A module-services/service-bluetooth/service-bluetooth/messages/RequestStatusIndicatorData.hpp
M module-services/service-cellular/CellularUrcHandler.cpp
M module-services/service-cellular/ServiceCellular.cpp
M module-services/service-cellular/service-cellular/CellularMessage.hpp
M module-services/service-cellular/service-cellular/CellularServiceAPI.hpp
M module-services/service-cellular/service-cellular/ServiceCellular.hpp
M module-bluetooth/Bluetooth/BluetoothWorker.cpp => module-bluetooth/Bluetooth/BluetoothWorker.cpp +13 -8
@@ 10,6 10,7 @@
#include "interface/profiles/HSP/HSP.hpp"
#include "audio/BluetoothAudioDevice.hpp"
#include "BtKeysStorage.hpp"
#include "command/DeviceData.hpp"

#if DEBUG_BLUETOOTH_HCI_COMS == 1
#define logHciComs(...) LOG_DEBUG(__VA_ARGS__)


@@ 95,7 96,7 @@ BluetoothWorker::BluetoothWorker(sys::Service *service)
{
    init({
        {queues::io, sizeof(bluetooth::Message), queues::queueLength},
        {queues::cmd, sizeof(bluetooth::Command), queues::queueLength},
        {queues::cmd, sizeof(bluetooth::Command::CommandPack), queues::queueLength},
        {queues::btstack, sizeof(bool), queues::triggerQueueLength},
    });
    registerQueues();


@@ 140,11 141,12 @@ auto BluetoothWorker::run() -> bool

auto BluetoothWorker::handleCommand(QueueHandle_t queue) -> bool
{
    bluetooth::Command command(bluetooth::Command::None);
    if (xQueueReceive(queue, static_cast<void *>(&command), 0) != pdTRUE) {
    bluetooth::Command::CommandPack pack{};
    if (xQueueReceive(queue, static_cast<void *>(&pack), 0) != pdTRUE) {
        LOG_ERROR("Queue receive failure!");
        return false;
    }
    auto command = bluetooth::Command(std::move(pack));

    switch (command.getType()) {
    case bluetooth::Command::PowerOn:


@@ 154,11 156,12 @@ auto BluetoothWorker::handleCommand(QueueHandle_t queue) -> bool
    case bluetooth::Command::PowerOff:
        controller->turnOff();
        break;
    case bluetooth::Command::Unpair:
    case bluetooth::Command::Unpair: {
        controller->processCommand(command);
        removeFromBoundDevices(command.getDevice().address);
        handleUnpairDisconnect(command.getDevice());
        break;
        auto device = std::get<Devicei>(command.getData());
        removeFromBoundDevices(device.address);
        handleUnpairDisconnect(device);
    } break;
    case bluetooth::Command::None:
        break;
    default:


@@ 294,7 297,9 @@ auto BluetoothWorker::isAddressConnected(const uint8_t *addr) -> bool
void BluetoothWorker::handleUnpairDisconnect(const Devicei &device)
{
    if (isAddressConnected(device.address)) {
        auto disconnectCmd = bluetooth::Command(bluetooth::Command::DisconnectAudio, device);
        auto commandData   = std::make_unique<bluetooth::DeviceData>(device);
        auto disconnectCmd = bluetooth::Command(
            bluetooth::Command::CommandPack{bluetooth::Command::DisconnectAudio, std::move(commandData)});
        controller->processCommand(disconnectCmd);
    }
}

M module-bluetooth/Bluetooth/CommandHandler.cpp => module-bluetooth/Bluetooth/CommandHandler.cpp +23 -15
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "CommandHandler.hpp"


@@ 39,7 39,7 @@ namespace bluetooth
        this->driver->registerPowerOnCallback([profilePtr = this->profileManager]() { profilePtr->init(); });
    }

    Error::Code CommandHandler::handle(Command command)
    Error::Code CommandHandler::handle(Command &command)
    {
        switch (command.getType()) {
        case bluetooth::Command::PowerOn:


@@ 51,15 51,15 @@ namespace bluetooth
        case bluetooth::Command::StopScan:
            return stopScan();
        case bluetooth::Command::Pair:
            return pair(command.getDevice());
            return pair(command.getData());
        case bluetooth::Command::Unpair:
            return unpair(command.getDevice());
            return unpair(command.getData());
        case bluetooth::Command::VisibilityOn:
            return setVisibility(true);
        case bluetooth::Command::VisibilityOff:
            return setVisibility(false);
        case bluetooth::Command::ConnectAudio:
            return establishAudioConnection(command.getDevice());
            return establishAudioConnection(command.getData());
        case bluetooth::Command::DisconnectAudio:
            return disconnectAudioConnection();
        case bluetooth::Command::PowerOff:


@@ 77,7 77,11 @@ namespace bluetooth
        case Command::CallAnswered:
            return profileManager->callAnswered();
        case Command::IncomingCallNumber:
            return profileManager->setIncomingCallNumber(command.getNumberString());
            return profileManager->setIncomingCallNumber(command.getData());
        case Command::SignalStrengthData:
            return profileManager->setSignalStrengthData(command.getData());
        case Command::OperatorNameData:
            return profileManager->setOperatorNameData(command.getData());
        case Command::StartStream:
            profileManager->start();
            return Error::Success;


@@ 115,8 119,9 @@ namespace bluetooth
        return Error::Success;
    }

    Error::Code CommandHandler::establishAudioConnection(const Devicei &device)
    Error::Code CommandHandler::establishAudioConnection(const DataVariant &data)
    {
        auto device = std::get<Devicei>(data);
        LOG_INFO("Connecting audio");
        profileManager->connect(device);
        return Error::Success;


@@ 128,12 133,13 @@ namespace bluetooth
        profileManager->disconnect();
        return Error::Success;
    }
    Error::Code CommandHandler::pair(const Devicei &device)
    Error::Code CommandHandler::pair(const DataVariant &data)
    {
        auto device = std::get<Devicei>(data);
        LOG_INFO("Pairing...");
        const auto error_code = driver->pair(device) ? Error::Success : Error::LibraryError;
        LOG_INFO("Pairing result: %s", magic_enum::enum_name(error_code).data());
        return error_code;
        const auto errorCode = driver->pair(device) ? Error::Success : Error::LibraryError;
        LOG_INFO("Pairing result: %s", magic_enum::enum_name(errorCode).data());
        return errorCode;
    }
    Error::Code CommandHandler::switchAudioProfile()
    {


@@ 149,12 155,13 @@ namespace bluetooth
        profileManager->switchProfile(profile);
        return Error::Success;
    }
    Error::Code CommandHandler::unpair(const Devicei &device)
    Error::Code CommandHandler::unpair(const DataVariant &data)
    {
        auto device = std::get<Devicei>(data);
        LOG_INFO("Unpairing...");
        const auto error_code = driver->unpair(device) ? Error::Success : Error::LibraryError;
        LOG_INFO("Unpairing result: %s", magic_enum::enum_name(error_code).data());
        return error_code;
        const auto errorCode = driver->unpair(device) ? Error::Success : Error::LibraryError;
        LOG_INFO("Unpairing result: %s", magic_enum::enum_name(errorCode).data());
        return errorCode;
    }

    Error::Code CommandHandler::availableDevices()


@@ 164,4 171,5 @@ namespace bluetooth

        return Error::Success;
    }

} // namespace bluetooth

M module-bluetooth/Bluetooth/CommandHandler.hpp => module-bluetooth/Bluetooth/CommandHandler.hpp +8 -75
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 9,6 9,8 @@

#include <cstdint>
#include <PhoneNumber.hpp>
#include <command/Command.hpp>
#include <utility>

namespace sys
{


@@ 19,82 21,13 @@ namespace sys
namespace bluetooth
{
    class SettingsHolder;
    class Command
    {
      public:
        enum Type
        {
            StartScan,
            StopScan,
            getDevicesAvailable,
            VisibilityOn,
            VisibilityOff,
            ConnectAudio,
            DisconnectAudio,
            PowerOn,
            PowerOff,
            Pair,
            Unpair,
            StartRinging,
            StopRinging,
            StartRouting,
            StartStream,
            StopStream,
            SwitchProfile,
            CallAnswered,
            IncomingCallNumber,
            None,
        };
        Command(Command::Type type, std::optional<Devicei> dev) : type(type)
        {
            if (dev.has_value()) {
                device = dev.value();
            }
        }
        Command(Command::Type type, std::optional<utils::PhoneNumber::View> num) : type(type)
        {
            if (num.has_value()) {
                numberStringPtr  = new std::string();
                *numberStringPtr = num->getEntered();
            }
        }
        explicit Command(Command::Type type) : type(type)
        {}
        auto getType() const noexcept -> Command::Type
        {
            return type;
        }

        auto getDevice() const noexcept -> Devicei
        {
            return device;
        }

        auto getNumberString() noexcept -> std::string
        {
            if (numberStringPtr != nullptr) {
                return *numberStringPtr;
            }
            return std::string();
        }

        void destroy()
        {
            delete numberStringPtr;
        }

      private:
        Devicei device{};
        std::string *numberStringPtr = nullptr;
        Type type;
    };

    class AbstractCommandHandler
    {
      public:
        virtual ~AbstractCommandHandler() noexcept = default;

        virtual auto handle(Command command) -> Error::Code = 0;
        virtual auto handle(Command &command) -> Error::Code = 0;
    };

    class CommandHandler : public AbstractCommandHandler


@@ 105,16 38,16 @@ namespace bluetooth
                                std::shared_ptr<bluetooth::ProfileManager> profileManager,
                                std::shared_ptr<bluetooth::AbstractDriver> driver);

        auto handle(Command command) -> Error::Code override;
        auto handle(Command &command) -> Error::Code override;

      private:
        Error::Code scan();
        Error::Code stopScan();
        Error::Code setVisibility(bool visibility);
        Error::Code establishAudioConnection(const Devicei &device);
        Error::Code establishAudioConnection(const DataVariant &data);
        Error::Code disconnectAudioConnection();
        Error::Code pair(const Devicei &device);
        Error::Code unpair(const Devicei &device);
        Error::Code pair(const DataVariant &data);
        Error::Code unpair(const DataVariant &data);
        Error::Code availableDevices();
        Error::Code switchAudioProfile();
        sys::Service *service;

M module-bluetooth/Bluetooth/WorkerController.cpp => module-bluetooth/Bluetooth/WorkerController.cpp +12 -6
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "WorkerController.hpp"


@@ 26,7 26,7 @@ namespace bluetooth
        {};
        struct ProcessCommand
        {
            Command command;
            Command &command;
        };

        class InitializationError : public std::runtime_error


@@ 176,10 176,16 @@ namespace bluetooth
        return pimpl->sm.is(X);
    }

    void StatefulController::processCommand(Command command)
    void StatefulController::processCommand(Command &command)
    {
        LOG_INFO("Process command: %s", magic_enum::enum_name(command.getType()).data());
        pimpl->sm.process_event(ProcessCommand{command});
        command.destroy();
        try {
            LOG_INFO("Process command: %s", magic_enum::enum_name(command.getType()).data());
            pimpl->sm.process_event(ProcessCommand{command});
            LOG_DEBUG("Command processed");
        }
        catch (std::bad_variant_access &e) {
            LOG_ERROR(
                "Failed to parse command %s, error: %s", magic_enum::enum_name(command.getType()).data(), e.what());
        }
    }
} // namespace bluetooth

M module-bluetooth/Bluetooth/WorkerController.hpp => module-bluetooth/Bluetooth/WorkerController.hpp +3 -3
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 24,7 24,7 @@ namespace bluetooth
        virtual auto isOn() const -> bool         = 0;
        virtual auto isTerminated() const -> bool = 0;

        virtual void processCommand(Command command) = 0;
        virtual void processCommand(Command &command) = 0;
    };

    class StatefulController : public AbstractController


@@ 41,7 41,7 @@ namespace bluetooth
        [[nodiscard]] auto isOn() const -> bool override;
        [[nodiscard]] auto isTerminated() const -> bool override;

        void processCommand(Command command) override;
        void processCommand(Command &command) override;

      private:
        class Impl;

A module-bluetooth/Bluetooth/command/Command.cpp => module-bluetooth/Bluetooth/command/Command.cpp +26 -0
@@ 0,0 1,26 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "Command.hpp"
#include <log/log.hpp>

namespace bluetooth
{

    Command::Command(CommandPack &&pack) : pack(std::move(pack))
    {}

    auto Command::getType() const noexcept -> Command::Type
    {
        return pack.commandType;
    }

    auto Command::getData() -> DataVariant
    {
        if (pack.data == nullptr) {
            LOG_ERROR("Terrible,terrible damage!");
            return DataVariant{};
        }
        return pack.data->getData();
    }
} // namespace bluetooth

A module-bluetooth/Bluetooth/command/Command.hpp => module-bluetooth/Bluetooth/command/Command.hpp +57 -0
@@ 0,0 1,57 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once
#include "CommandData.hpp"

namespace bluetooth
{

    class Command
    {
      public:
        enum Type
        {
            StartScan,
            StopScan,
            getDevicesAvailable,
            VisibilityOn,
            VisibilityOff,
            ConnectAudio,
            DisconnectAudio,
            PowerOn,
            PowerOff,
            Pair,
            Unpair,
            StartRinging,
            StopRinging,
            StartRouting,
            StartStream,
            StopStream,
            SwitchProfile,
            CallAnswered,
            IncomingCallNumber,
            SignalStrengthData,
            OperatorNameData,
            None,
        };

        struct CommandPack
        {
            Command::Type commandType         = Command::None;
            std::unique_ptr<CommandData> data = nullptr;
        };

        explicit Command(CommandPack &&);
        explicit Command(Command::Type type)
        {
            pack.commandType = type;
        }
        auto getType() const noexcept -> Command::Type;
        auto getData() -> DataVariant;

      private:
        CommandPack pack;
    };

} // namespace bluetooth

A module-bluetooth/Bluetooth/command/CommandData.hpp => module-bluetooth/Bluetooth/command/CommandData.hpp +22 -0
@@ 0,0 1,22 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once
#include <utility>
#include <variant>
#include <PhoneNumber.hpp>
#include "Device.hpp"
#include "EventStore.hpp"
#include "OperatorName.hpp"

namespace bluetooth
{
    using DataVariant = std::variant<OperatorName, Store::SignalStrength, Devicei, utils::PhoneNumber::View>;

    class CommandData
    {
      public:
        virtual auto getData() -> DataVariant = 0;
        virtual ~CommandData()                = default;
    };
} // namespace bluetooth

A module-bluetooth/Bluetooth/command/DeviceData.cpp => module-bluetooth/Bluetooth/command/DeviceData.cpp +16 -0
@@ 0,0 1,16 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "DeviceData.hpp"

namespace bluetooth
{
    DeviceData::DeviceData(const Devicei &device) : device(device)
    {}

    auto DeviceData::getData() -> DataVariant
    {
        return device;
    }

} // namespace bluetooth

A module-bluetooth/Bluetooth/command/DeviceData.hpp => module-bluetooth/Bluetooth/command/DeviceData.hpp +21 -0
@@ 0,0 1,21 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once
#include "CommandData.hpp"
#include "Device.hpp"

namespace bluetooth
{

    class DeviceData : public CommandData
    {
      public:
        explicit DeviceData(const Devicei &device);
        auto getData() -> DataVariant override;

      private:
        Devicei device;
    };

} // namespace bluetooth

A module-bluetooth/Bluetooth/command/OperatorName.hpp => module-bluetooth/Bluetooth/command/OperatorName.hpp +23 -0
@@ 0,0 1,23 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once
#include <string>
#include <string_view>
namespace bluetooth
{

    class OperatorName
    {
      public:
        explicit OperatorName(const std::string &name) : name(name){};
        OperatorName() = default;
        auto getName() const -> const std::string_view
        {
            return name;
        }

      private:
        std::string name{""};
    };
} // namespace bluetooth

A module-bluetooth/Bluetooth/command/OperatorNameData.cpp => module-bluetooth/Bluetooth/command/OperatorNameData.cpp +16 -0
@@ 0,0 1,16 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "OperatorNameData.hpp"

#include <utility>

namespace bluetooth
{
    OperatorNameData::OperatorNameData(OperatorName operatorName) : operatorName(std::move(operatorName))
    {}
    auto OperatorNameData::getData() -> DataVariant
    {
        return operatorName;
    }
} // namespace bluetooth

A module-bluetooth/Bluetooth/command/OperatorNameData.hpp => module-bluetooth/Bluetooth/command/OperatorNameData.hpp +20 -0
@@ 0,0 1,20 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once
#include "CommandData.hpp"

namespace bluetooth
{

    class OperatorNameData : public CommandData
    {
      public:
        explicit OperatorNameData(OperatorName operatorName);
        auto getData() -> DataVariant override;

      private:
        OperatorName operatorName;
    };

} // namespace bluetooth

A module-bluetooth/Bluetooth/command/PhoneNumberData.cpp => module-bluetooth/Bluetooth/command/PhoneNumberData.cpp +16 -0
@@ 0,0 1,16 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "PhoneNumberData.hpp"

namespace bluetooth
{
    PhoneNumberData::PhoneNumberData(const utils::PhoneNumber::View &view) : view(view)
    {}
    PhoneNumberData::PhoneNumberData(const utils::PhoneNumber &number) : view(number.getView())
    {}
    auto PhoneNumberData::getData() -> DataVariant
    {
        return view;
    }
} // namespace bluetooth

A module-bluetooth/Bluetooth/command/PhoneNumberData.hpp => module-bluetooth/Bluetooth/command/PhoneNumberData.hpp +21 -0
@@ 0,0 1,21 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once
#include "CommandData.hpp"

namespace bluetooth
{

    class PhoneNumberData : public CommandData
    {
      public:
        explicit PhoneNumberData(const utils::PhoneNumber::View &view);
        explicit PhoneNumberData(const utils::PhoneNumber &number);
        auto getData() -> DataVariant override;

      private:
        utils::PhoneNumber::View view;
    };

} // namespace bluetooth

A module-bluetooth/Bluetooth/command/SignalStrengthData.cpp => module-bluetooth/Bluetooth/command/SignalStrengthData.cpp +14 -0
@@ 0,0 1,14 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "SignalStrengthData.hpp"

namespace bluetooth
{
    SignalStrengthData::SignalStrengthData(const Store::SignalStrength &signalStrength) : signalStrength(signalStrength)
    {}
    auto SignalStrengthData::getData() -> DataVariant
    {
        return signalStrength;
    }
} // namespace bluetooth

A module-bluetooth/Bluetooth/command/SignalStrengthData.hpp => module-bluetooth/Bluetooth/command/SignalStrengthData.hpp +20 -0
@@ 0,0 1,20 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once
#include "CommandData.hpp"

namespace bluetooth
{

    class SignalStrengthData : public CommandData
    {
      public:
        explicit SignalStrengthData(const Store::SignalStrength &signalStrength);
        auto getData() -> DataVariant override;

      private:
        Store::SignalStrength signalStrength;
    };

} // namespace bluetooth

M module-bluetooth/Bluetooth/interface/profiles/A2DP/A2DP.cpp => module-bluetooth/Bluetooth/interface/profiles/A2DP/A2DP.cpp +10 -0
@@ 123,6 123,16 @@ namespace bluetooth
        LOG_INFO("Setting number in A2DP - ignoring");
        return Error::Success;
    }
    auto A2DP::setSignalStrength(int bars) const noexcept -> Error::Code
    {
        LOG_INFO("Setting signal bars in A2DP - ignoring");
        return Error::Success;
    }
    auto A2DP::setOperatorName(const std::string_view &name) const noexcept -> Error::Code
    {
        LOG_INFO("Setting operator name in A2DP - ignoring");
        return Error::Success;
    }

    const sys::Service *A2DP::A2DPImpl::ownerService;
    QueueHandle_t A2DP::A2DPImpl::sourceQueue = nullptr;

M module-bluetooth/Bluetooth/interface/profiles/A2DP/A2DP.hpp => module-bluetooth/Bluetooth/interface/profiles/A2DP/A2DP.hpp +5 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 40,6 40,10 @@ namespace bluetooth
        [[nodiscard]] auto callAnswered() const noexcept -> Error::Code override;
        /// @return Success - ignoring in A2DP
        [[nodiscard]] auto setIncomingCallNumber(const std::string &num) const noexcept -> Error::Code override;
        /// @return Success - ignoring in A2DP
        [[nodiscard]] auto setSignalStrength(int bars) const noexcept -> Error::Code override;
        /// @return Success - ignoring in A2DP
        [[nodiscard]] auto setOperatorName(const std::string_view &name) const noexcept -> Error::Code override;

        void setAudioDevice(std::shared_ptr<bluetooth::BluetoothAudioDevice> audioDevice) override;


M module-bluetooth/Bluetooth/interface/profiles/HFP/HFP.cpp => module-bluetooth/Bluetooth/interface/profiles/HFP/HFP.cpp +29 -2
@@ 11,6 11,8 @@
#include <service-bluetooth/messages/AudioVolume.hpp>
#include <service-bluetooth/messages/Connect.hpp>
#include <service-bluetooth/messages/Disconnect.hpp>
#include <service-bluetooth/messages/RequestStatusIndicatorData.hpp>

#include <BluetoothWorker.hpp>
#include "SCO/ScoUtils.hpp"



@@ 99,9 101,19 @@ namespace bluetooth
    }
    auto HFP::setIncomingCallNumber(const std::string &num) const noexcept -> Error::Code
    {
        LOG_INFO("Setting number: %s", num.c_str());
        LOG_SENSITIVE(LOGDEBUG, "Setting number: %s", num.c_str());
        return pimpl->setIncomingCallNumber(num);
    }
    auto HFP::setSignalStrength(int bars) const noexcept -> Error::Code
    {
        LOG_DEBUG("Setting RSSI bars: %d/4", bars);
        return pimpl->setSignalStrength(bars);
    }
    auto HFP::setOperatorName(const std::string_view &name) const noexcept -> Error::Code
    {
        LOG_DEBUG("Setting operator name: %s", name.data());
        return pimpl->setOperatorName(name);
    }

    HFP::~HFP() = default;



@@ 125,7 137,7 @@ namespace bluetooth
        {2, "call", 0, 1, 0, 1, 1, 0},
        {3, "callsetup", 0, 3, 0, 1, 1, 0},
        {4, "battchg", 0, 5, 3, 0, 0, 0},
        {5, "signal", 0, 5, 5, 0, 1, 0},
        {5, "signal", 0, 4, 5, 0, 1, 0},
        {6, "roam", 0, 1, 0, 0, 1, 0},
        {7, "callheld", 0, 2, 0, 1, 1, 0}};
    [[maybe_unused]] int HFP::HFPImpl::call_hold_services_nr                      = 5;


@@ 241,6 253,9 @@ namespace bluetooth
                device.deviceState = DeviceState::ConnectedVoice;
                busProxy.sendUnicast(std::make_shared<message::bluetooth::ConnectResult>(device, true),
                                     service::name::bluetooth);
                // request cellular status indicators for HFP
                busProxy.sendUnicast(std::make_shared<message::bluetooth::RequestStatusIndicatorData>(),
                                     service::name::bluetooth);
            }
            dump_supported_codecs();
            break;


@@ 484,5 499,17 @@ namespace bluetooth
        hfp_ag_set_clip(129, num.c_str());
        return Error::Success;
    }
    auto HFP::HFPImpl::setSignalStrength(int bars) const noexcept -> Error::Code
    {
        hfp_ag_set_signal_strength(bars);
        return Error::Success;
    }

    auto HFP::HFPImpl::setOperatorName(const std::string_view &name) const noexcept -> Error::Code
    {
        auto result = hfp_ag_set_operator_name(HFP::HFPImpl::aclHandle, name.data());
        LOG_DEBUG("Operator set name result: %d", result);
        return Error::Success;
    }

} // namespace bluetooth

M module-bluetooth/Bluetooth/interface/profiles/HFP/HFP.hpp => module-bluetooth/Bluetooth/interface/profiles/HFP/HFP.hpp +5 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 46,6 46,10 @@ namespace bluetooth
        [[nodiscard]] auto initializeCall() const noexcept -> Error::Code override;
        [[nodiscard]] auto callAnswered() const noexcept -> Error::Code override;
        [[nodiscard]] auto setIncomingCallNumber(const std::string &num) const noexcept -> Error::Code override;
        /// @brief Sets the signal strength bars data
        /// @return Success
        [[nodiscard]] auto setSignalStrength(int bars) const noexcept -> Error::Code override;
        [[nodiscard]] auto setOperatorName(const std::string_view &name) const noexcept -> Error::Code override;

        void setAudioDevice(std::shared_ptr<bluetooth::BluetoothAudioDevice> audioDevice) override;


M module-bluetooth/Bluetooth/interface/profiles/HFP/HFPImpl.hpp => module-bluetooth/Bluetooth/interface/profiles/HFP/HFPImpl.hpp +3 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 30,6 30,8 @@ namespace bluetooth
        void setAudioDevice(std::shared_ptr<bluetooth::BluetoothAudioDevice> audioDevice);
        [[nodiscard]] auto callAnswered() const noexcept -> Error::Code;
        [[nodiscard]] auto setIncomingCallNumber(const std::string &num) const noexcept -> Error::Code;
        [[nodiscard]] auto setSignalStrength(int bars) const noexcept -> Error::Code;
        [[nodiscard]] auto setOperatorName(const std::string_view &name) const noexcept -> Error::Code;

      private:
        static void sendAudioEvent(audio::EventType event, audio::Event::DeviceState state);

M module-bluetooth/Bluetooth/interface/profiles/HSP/HSP.cpp => module-bluetooth/Bluetooth/interface/profiles/HSP/HSP.cpp +9 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <log/log.hpp>


@@ 381,6 381,14 @@ namespace bluetooth
    {
        return Error::Success;
    }
    auto HSP::setSignalStrength(int bars) const noexcept -> Error::Code
    {
        return Error::Success;
    }
    auto HSP::setOperatorName(const std::string_view &name) const noexcept -> Error::Code
    {
        return Error::Success;
    }

    void HSP::HSPImpl::setAudioDevice(std::shared_ptr<bluetooth::BluetoothAudioDevice> audioDevice)
    {

M module-bluetooth/Bluetooth/interface/profiles/HSP/HSP.hpp => module-bluetooth/Bluetooth/interface/profiles/HSP/HSP.hpp +5 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 44,6 44,10 @@ namespace bluetooth
        [[nodiscard]] auto initializeCall() const noexcept -> Error::Code override;
        [[nodiscard]] auto callAnswered() const noexcept -> Error::Code override;
        [[nodiscard]] auto setIncomingCallNumber(const std::string &num) const noexcept -> Error::Code override;
        /// @return Success - ignoring in HSP
        [[nodiscard]] auto setSignalStrength(int bars) const noexcept -> Error::Code override;
        /// @return Success - ignoring in HSP
        [[nodiscard]] auto setOperatorName(const std::string_view &name) const noexcept -> Error::Code override;

        void setAudioDevice(std::shared_ptr<bluetooth::BluetoothAudioDevice> audioDevice) override;


M module-bluetooth/Bluetooth/interface/profiles/Profile.hpp => module-bluetooth/Bluetooth/interface/profiles/Profile.hpp +7 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 39,6 39,12 @@ namespace bluetooth
        /// Sets the incoming call number
        /// @return Error code that determines, whether operation was successful or not
        [[nodiscard]] virtual auto setIncomingCallNumber(const std::string &num) const noexcept -> Error::Code = 0;
        /// Sets the signal strength bars data in HFP profile
        /// @return Error code that determines, whether operation was successful or not
        [[nodiscard]] virtual auto setSignalStrength(int bars) const noexcept -> Error::Code = 0;
        /// Sets the operator name in HFP profile
        /// @return Error code that determines, whether operation was successful or not
        [[nodiscard]] virtual auto setOperatorName(const std::string_view &name) const noexcept -> Error::Code = 0;

      protected:
        static void initSdp();

M module-bluetooth/Bluetooth/interface/profiles/ProfileManager.cpp => module-bluetooth/Bluetooth/interface/profiles/ProfileManager.cpp +22 -3
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <service-bluetooth/ServiceBluetooth.hpp>


@@ 119,10 119,29 @@ namespace bluetooth
    {
        return currentProfilePtr->callAnswered();
    }
    auto ProfileManager::setIncomingCallNumber(const std::string &num) -> Error::Code
    auto ProfileManager::setIncomingCallNumber(const DataVariant &data) -> Error::Code
    {
        auto number = std::get<utils::PhoneNumber::View>(data);
        if (currentProfilePtr) {
            return currentProfilePtr->setIncomingCallNumber(num);
            return currentProfilePtr->setIncomingCallNumber(number.getE164());
        }
        LOG_ERROR("No profile, returning!");
        return Error::NotReady;
    }
    auto ProfileManager::setSignalStrengthData(const DataVariant &data) -> Error::Code
    {
        auto signalData = std::get<Store::SignalStrength>(data);
        if (currentProfilePtr) {
            return currentProfilePtr->setSignalStrength(static_cast<int>(signalData.rssiBar));
        }
        LOG_ERROR("No profile, returning!");
        return Error::NotReady;
    }
    auto ProfileManager::setOperatorNameData(const DataVariant &data) -> Error::Code
    {
        auto operatorName = std::get<OperatorName>(data);
        if (currentProfilePtr) {
            return currentProfilePtr->setOperatorName(operatorName.getName());
        }
        LOG_ERROR("No profile, returning!");
        return Error::NotReady;

M module-bluetooth/Bluetooth/interface/profiles/ProfileManager.hpp => module-bluetooth/Bluetooth/interface/profiles/ProfileManager.hpp +6 -2
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 13,6 13,7 @@
#include "audio/BluetoothAudioDevice.hpp"

#include <memory>
#include <command/CommandData.hpp>

extern "C"
{


@@ 44,7 45,10 @@ namespace bluetooth
        auto stopRinging() -> Error::Code;
        auto initializeCall() -> Error::Code;
        auto callAnswered() -> Error::Code;
        auto setIncomingCallNumber(const std::string &num) -> Error::Code;
        auto setIncomingCallNumber(const DataVariant &data) -> Error::Code;
        auto setSignalStrengthData(const DataVariant &data) -> Error::Code;
        auto setOperatorNameData(const DataVariant &data) -> Error::Code;

        auto setAudioDevice(std::shared_ptr<BluetoothAudioDevice> device) -> Error::Code;

      private:

M module-bluetooth/CMakeLists.txt => module-bluetooth/CMakeLists.txt +7 -0
@@ 30,6 30,13 @@ set(SOURCES
    ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/interface/profiles/Profile.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/interface/profiles/ProfileManager.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/interface/profiles/PhoneInterface.cpp

    ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/command/Command.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/command/DeviceData.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/command/PhoneNumberData.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/command/SignalStrengthData.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/command/OperatorNameData.cpp

        )

include(lib/btstack.cmake)

M module-bluetooth/lib/btstack => module-bluetooth/lib/btstack +1 -1
@@ 1,1 1,1 @@
Subproject commit e20f13fc58a9c227c4f7bc4b1267a072ba2e5e30
Subproject commit edeaa6ceebef69dd66aff31f8ad3100c8c1f435f

M module-bluetooth/tests/CMakeLists.txt => module-bluetooth/tests/CMakeLists.txt +1 -0
@@ 5,6 5,7 @@ add_catch2_executable(
        tests-StatefulController.cpp
        tests-BluetoothDevicesModel.cpp
        tests-Devicei.cpp
        tests-command.cpp
    LIBS
        module-sys
        module-bluetooth

M module-bluetooth/tests/tests-StatefulController.cpp => module-bluetooth/tests/tests-StatefulController.cpp +8 -5
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <catch2/catch.hpp>


@@ 53,7 53,7 @@ auto InitializerMock = []() { return Error::Success; };
class HandlerMock : public AbstractCommandHandler
{
  public:
    Error::Code handle(Command command) override
    Error::Code handle(Command &command) override
    {
        return returnCode;
    }


@@ 167,7 167,8 @@ TEST_CASE("Given StatefulController when process command successfully then turne
    controller.turnOn();
    REQUIRE(controller.isOn());

    controller.processCommand(bluetooth::Command(Command::Type::PowerOn));
    auto command = bluetooth::Command(Command::Type::PowerOn);
    controller.processCommand(command);
    REQUIRE(controller.isOn());
}



@@ 180,7 181,9 @@ TEST_CASE("Given StatefulController when processing command failed then restarte
    controller.turnOn();
    REQUIRE(controller.isOn());

    controller.processCommand(bluetooth::Command(Command::Type::PowerOn));
    controller.processCommand(bluetooth::Command(Command::Type::PowerOn));
    auto command = bluetooth::Command(Command::Type::PowerOn);
    controller.processCommand(command);
    controller.processCommand(command);

    REQUIRE(controller.isOn());
}

A module-bluetooth/tests/tests-command.cpp => module-bluetooth/tests/tests-command.cpp +33 -0
@@ 0,0 1,33 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <catch2/catch.hpp>
#include "btstack_util.h"
#include <command/Command.hpp>
#include <command/DeviceData.hpp>
#include <command/PhoneNumberData.hpp>

using namespace bluetooth;

TEST_CASE("Command data handling test")
{
    utils::PhoneNumber number("123456789", utils::country::getIdByAlpha2Code("PL"));
    Command::CommandPack receivedPack;

    auto queueSimulator = [](bluetooth::Command::CommandPack *pack, bluetooth::Command::CommandPack *targetPack) {
        memcpy(targetPack, pack, sizeof(bluetooth::Command::CommandPack));
        pack->data.release();
    };

    {
        auto data = std::make_unique<PhoneNumberData>(number);
        Command::CommandPack pack;
        pack.commandType = Command::Type::PowerOn;
        pack.data        = std::move(data);
        queueSimulator(&pack, &receivedPack);
    }

    auto receivedCommand = bluetooth::Command(std::move(receivedPack));
    REQUIRE(number == std::get<utils::PhoneNumber::View>(receivedCommand.getData()));
    REQUIRE(receivedCommand.getType() == bluetooth::Command::PowerOn);
}

M module-services/service-bluetooth/ServiceBluetooth.cpp => module-services/service-bluetooth/ServiceBluetooth.cpp +78 -33
@@ 23,6 23,7 @@
#include "service-bluetooth/messages/Ring.hpp"
#include "service-bluetooth/BluetoothDevicesModel.hpp"
#include "service-bluetooth/messages/BluetoothModeChanged.hpp"
#include "service-bluetooth/messages/RequestStatusIndicatorData.hpp"

#include "system/messages/SentinelRegistrationMessage.hpp"



@@ 40,6 41,10 @@
#include <service-bluetooth/messages/Authenticate.hpp>
#include <GAP/GAP.hpp>
#include <service-cellular/CellularMessage.hpp>
#include <command/PhoneNumberData.hpp>
#include <command/DeviceData.hpp>
#include <command/SignalStrengthData.hpp>
#include <command/OperatorNameData.hpp>

namespace
{


@@ 70,6 75,7 @@ sys::ReturnCodes ServiceBluetooth::InitHandler()
    bluetooth::KeyStorage::settings = settingsHolder;

    bus.channels.push_back(sys::BusChannel::BluetoothNotifications);
    bus.channels.push_back(sys::BusChannel::ServiceCellularNotifications);

    worker = std::make_unique<BluetoothWorker>(this);
    worker->run();


@@ 107,8 113,11 @@ sys::ReturnCodes ServiceBluetooth::InitHandler()
    connectHandler<message::bluetooth::ResponseAuthenticatePin>();
    connectHandler<message::bluetooth::ResponseAuthenticatePasskey>();
    connectHandler<message::bluetooth::ResponseAuthenticatePairCancel>();
    connectHandler<message::bluetooth::RequestStatusIndicatorData>();
    connectHandler<CellularCallerIdMessage>();
    connectHandler<CellularCallActiveNotification>();
    connectHandler<CellularSignalStrengthUpdateNotification>();
    connectHandler<CellularCurrentOperatorNameNotification>();

    settingsHolder->onStateChange = [this]() {
        auto initialState = std::visit(bluetooth::IntVisitor(), settingsHolder->getValue(bluetooth::Settings::State));


@@ 130,8 139,8 @@ sys::ReturnCodes ServiceBluetooth::DeinitHandler()

void ServiceBluetooth::ProcessCloseReason(sys::CloseReason closeReason)
{
    sendWorkerCommand(bluetooth::Command(bluetooth::Command::Type::DisconnectAudio));
    sendWorkerCommand(bluetooth::Command(bluetooth::Command::Type::PowerOff));
    sendWorkerCommand(bluetooth::Command::Type::DisconnectAudio);
    sendWorkerCommand(bluetooth::Command::Type::PowerOff);
}

sys::MessagePointer ServiceBluetooth::DataReceivedHandler([[maybe_unused]] sys::DataMessage *msg,


@@ 145,9 154,15 @@ sys::ReturnCodes ServiceBluetooth::SwitchPowerModeHandler(const sys::ServicePowe
    LOG_ERROR("TODO");
    return sys::ReturnCodes::Success;
}
void ServiceBluetooth::sendWorkerCommand(bluetooth::Command command)

void ServiceBluetooth::sendWorkerCommand(bluetooth::Command::Type commandType,
                                         std::unique_ptr<bluetooth::CommandData> data)
{
    xQueueSend(workerQueue, &command, portMAX_DELAY);
    bluetooth::Command::CommandPack pack;
    pack.data        = std::move(data);
    pack.commandType = commandType;
    xQueueSend(workerQueue, &pack, portMAX_DELAY);
    pack.data.release();
}

auto ServiceBluetooth::handle(BluetoothAudioStartMessage *msg) -> std::shared_ptr<sys::Message>


@@ 188,7 203,7 @@ auto ServiceBluetooth::handle(message::bluetooth::SetStatus *msg) -> std::shared
    case BluetoothStatus::State::On:

        cpuSentinel->HoldMinimumFrequency(bsp::CpuFrequencyMHz::Level_3);
        sendWorkerCommand(bluetooth::Command(bluetooth::Command::Type::PowerOn));
        sendWorkerCommand(bluetooth::Command::Type::PowerOn);
        bus.sendMulticast(
            std::make_shared<sys::bluetooth::BluetoothModeChanged>(sys::bluetooth::BluetoothMode::Enabled),
            sys::BusChannel::BluetoothModeChanges);


@@ 207,9 222,8 @@ auto ServiceBluetooth::handle(message::bluetooth::SetStatus *msg) -> std::shared
    default:
        break;
    }
    bluetooth::Command command(newBtStatus.visibility ? bluetooth::Command::Type::VisibilityOn
                                                      : bluetooth::Command::Type::VisibilityOff);
    sendWorkerCommand(command);
    sendWorkerCommand(newBtStatus.visibility ? bluetooth::Command::Type::VisibilityOn
                                             : bluetooth::Command::Type::VisibilityOff);
    return sys::MessageNone{};
}



@@ 217,7 231,9 @@ auto ServiceBluetooth::handle(BluetoothPairMessage *msg) -> std::shared_ptr<sys:
{
    auto device = msg->getDevice();
    bluetoothDevicesModel->removeDevice(device);
    sendWorkerCommand(bluetooth::Command(bluetooth::Command::Type::Pair, device));
    auto commandData = std::make_unique<bluetooth::DeviceData>(device);

    sendWorkerCommand(bluetooth::Command::Type::Pair, std::move(commandData));

    device.deviceState = DeviceState::Pairing;
    bluetoothDevicesModel->insertDevice(device);


@@ 249,7 265,8 @@ auto ServiceBluetooth::handle(BluetoothPairResultMessage *msg) -> std::shared_pt

auto ServiceBluetooth::handle(message::bluetooth::Unpair *msg) -> std::shared_ptr<sys::Message>
{
    sendWorkerCommand(bluetooth::Command(bluetooth::Command::Type::Unpair, msg->getDevice()));
    auto commandData = std::make_unique<bluetooth::DeviceData>(msg->getDevice());
    sendWorkerCommand(bluetooth::Command::Type::Unpair, std::move(commandData));
    bluetoothDevicesModel->removeDevice(msg->getDevice());

    return sys::MessageNone{};


@@ 271,11 288,11 @@ auto ServiceBluetooth::handle(message::bluetooth::SetDeviceName *msg) -> std::sh
    auto newName = msg->getName();
    bluetooth::set_name(newName);
    settingsHolder->setValue(bluetooth::Settings::DeviceName, newName);
    sendWorkerCommand(bluetooth::Command(bluetooth::Command::Type::PowerOff));
    sendWorkerCommand(bluetooth::Command::Type::PowerOff);

    btRestartTimer =
        sys::TimerFactory::createSingleShotTimer(this, "btRestartTimer", btRestartDelay, [this](sys::Timer &_) {
            sendWorkerCommand(bluetooth::Command(bluetooth::Command::Type::PowerOn));
            sendWorkerCommand(bluetooth::Command::Type::PowerOn);
        });
    btRestartTimer.start();



@@ 285,7 302,8 @@ auto ServiceBluetooth::handle(message::bluetooth::SetDeviceName *msg) -> std::sh
auto ServiceBluetooth::handle(message::bluetooth::Connect *msg) -> std::shared_ptr<sys::Message>
{
    auto device = msg->getDevice();
    sendWorkerCommand(bluetooth::Command(bluetooth::Command::Type::ConnectAudio, device));
    auto commandData = std::make_unique<bluetooth::DeviceData>(msg->getDevice());
    sendWorkerCommand(bluetooth::Command::Type::ConnectAudio, std::move(commandData));

    bluetoothDevicesModel->setInternalDeviceState(device, DeviceState::Connecting);
    bluetoothDevicesModel->syncDevicesWithApp();


@@ 321,7 339,7 @@ auto ServiceBluetooth::handle(message::bluetooth::ConnectResult *msg) -> std::sh

auto ServiceBluetooth::handle([[maybe_unused]] message::bluetooth::Disconnect *msg) -> std::shared_ptr<sys::Message>
{
    sendWorkerCommand(bluetooth::Command(bluetooth::Command::Type::DisconnectAudio));
    sendWorkerCommand(bluetooth::Command::Type::DisconnectAudio);
    return sys::MessageNone{};
}



@@ 382,32 400,31 @@ auto ServiceBluetooth::handle(BluetoothMessage *msg) -> std::shared_ptr<sys::Mes
    case BluetoothMessage::Start:
        break;
    case BluetoothMessage::Scan:
        sendWorkerCommand(bluetooth::Command(bluetooth::Command::Type::StartScan));
        sendWorkerCommand(bluetooth::Command::Type::StartScan);
        break;
    case BluetoothMessage::StopScan:
        sendWorkerCommand(bluetooth::Command(bluetooth::Command::Type::StopScan));
        sendWorkerCommand(bluetooth::Command::Type::StopScan);
        break;
    case BluetoothMessage::getDevicesAvailable:
        sendWorkerCommand(bluetooth::Command(bluetooth::Command::Type::getDevicesAvailable));
        sendWorkerCommand(bluetooth::Command::Type::getDevicesAvailable);
        break;
    case BluetoothMessage::Visible: {
        auto visibility =
            not std::visit(bluetooth::BoolVisitor(), settingsHolder->getValue(bluetooth::Settings::Visibility));
        bluetooth::Command command(visibility ? bluetooth::Command::Type::VisibilityOn
                                              : bluetooth::Command::Type::VisibilityOff);
        sendWorkerCommand(command);
        sendWorkerCommand(visibility ? bluetooth::Command::Type::VisibilityOn
                                     : bluetooth::Command::Type::VisibilityOff);
    } break;
    case BluetoothMessage::Play:
        sendWorkerCommand(bluetooth::Command(bluetooth::Command::Type::StartStream));
        sendWorkerCommand(bluetooth::Command::Type::StartStream);
        break;
    case BluetoothMessage::SwitchProfile:
        sendWorkerCommand(bluetooth::Command(bluetooth::Command::Type::SwitchProfile));
        sendWorkerCommand(bluetooth::Command::Type::SwitchProfile);
        break;
    case BluetoothMessage::Disconnect:
        sendWorkerCommand(bluetooth::Command(bluetooth::Command::Type::DisconnectAudio));
        sendWorkerCommand(bluetooth::Command::Type::DisconnectAudio);
        break;
    case BluetoothMessage::Stop:
        sendWorkerCommand(bluetooth::Command(bluetooth::Command::Type::StopStream));
        sendWorkerCommand(bluetooth::Command::Type::StopStream);
        break;
    default:
        break;


@@ 418,14 435,15 @@ auto ServiceBluetooth::handle(BluetoothMessage *msg) -> std::shared_ptr<sys::Mes

auto ServiceBluetooth::handle(BluetoothAddrMessage *msg) -> std::shared_ptr<sys::Message>
{
    sendWorkerCommand(bluetooth::Command(bluetooth::Command::Type::ConnectAudio, msg->device));
    auto commandData = std::make_unique<bluetooth::DeviceData>(msg->device);
    sendWorkerCommand(bluetooth::Command::Type::ConnectAudio, std::move(commandData));
    return std::make_shared<sys::ResponseMessage>();
}

auto ServiceBluetooth::handle(sdesktop::developerMode::DeveloperModeRequest *msg) -> std::shared_ptr<sys::Message>
{
    if (typeid(*msg->event) == typeid(sdesktop::bluetooth::GetAvailableDevicesEvent)) {
        sendWorkerCommand(bluetooth::Command(bluetooth::Command::Type::getDevicesAvailable));
        sendWorkerCommand(bluetooth::Command::Type::getDevicesAvailable);
    }
    return sys::MessageNone{};
}


@@ 453,15 471,14 @@ auto ServiceBluetooth::handle(message::bluetooth::HFPVolume *msg) -> std::shared
auto ServiceBluetooth::handle(message::bluetooth::Ring *msg) -> std::shared_ptr<sys::Message>
{
    const auto enableRing = msg->enabled();
    sendWorkerCommand(bluetooth::Command(enableRing ? bluetooth::Command::Type::StartRinging
                                                    : bluetooth::Command::Type::StopRinging));
    sendWorkerCommand(enableRing ? bluetooth::Command::Type::StartRinging : bluetooth::Command::Type::StopRinging);

    return std::make_shared<sys::ResponseMessage>();
}

auto ServiceBluetooth::handle(message::bluetooth::StartAudioRouting *msg) -> std::shared_ptr<sys::Message>
{
    sendWorkerCommand(bluetooth::Command(bluetooth::Command::Type::StartRouting));
    sendWorkerCommand(bluetooth::Command::Type::StartRouting);
    return std::make_shared<sys::ResponseMessage>();
}



@@ 469,11 486,12 @@ auto ServiceBluetooth::handle(CellularCallerIdMessage *msg) -> std::shared_ptr<s
{
    auto number = msg->number;
    auto btOn   = std::visit(bluetooth::BoolVisitor(), settingsHolder->getValue(bluetooth::Settings::State));
    LOG_ERROR("Received caller ID msg! ");
    LOG_DEBUG("Received caller ID msg! ");

    if (btOn) {
        LOG_DEBUG("Sending to profile!");
        sendWorkerCommand(bluetooth::Command(bluetooth::Command::Type::IncomingCallNumber, number));
        auto commandData = std::make_unique<bluetooth::PhoneNumberData>(number);
        sendWorkerCommand(bluetooth::Command::Type::IncomingCallNumber, std::move(commandData));
    }

    return sys::MessageNone{};


@@ 481,7 499,25 @@ auto ServiceBluetooth::handle(CellularCallerIdMessage *msg) -> std::shared_ptr<s

auto ServiceBluetooth::handle(CellularCallActiveNotification *msg) -> std::shared_ptr<sys::Message>
{
    sendWorkerCommand(bluetooth::Command(bluetooth::Command::Type::CallAnswered));
    sendWorkerCommand(bluetooth::Command::Type::CallAnswered);
    return std::make_shared<sys::ResponseMessage>();
}

auto ServiceBluetooth::handle(CellularSignalStrengthUpdateNotification *msg) -> std::shared_ptr<sys::Message>
{
    auto signalStrength = Store::GSM::get()->getSignalStrength();
    LOG_INFO("Bluetooth: RSSI %d/5", static_cast<int>(signalStrength.rssiBar));
    auto commandData = std::make_unique<bluetooth::SignalStrengthData>(signalStrength);
    sendWorkerCommand(bluetooth::Command::Type::SignalStrengthData, std::move(commandData));
    return std::make_shared<sys::ResponseMessage>();
}

auto ServiceBluetooth::handle(CellularCurrentOperatorNameNotification *msg) -> std::shared_ptr<sys::Message>
{
    auto opName = msg->getCurrentOperatorName();
    LOG_INFO("Bluetooth: Operator name: %s", opName.c_str());
    auto commandData = std::make_unique<bluetooth::OperatorNameData>(bluetooth::OperatorName(opName));
    sendWorkerCommand(bluetooth::Command::Type::OperatorNameData, std::move(commandData));
    return std::make_shared<sys::ResponseMessage>();
}



@@ 509,8 545,17 @@ void ServiceBluetooth::resetTimeoutTimer()

void ServiceBluetooth::handleTurnOff()
{
    sendWorkerCommand(bluetooth::Command(bluetooth::Command::Type::PowerOff));
    sendWorkerCommand(bluetooth::Command::Type::PowerOff);
    cpuSentinel->ReleaseMinimumFrequency();
    bus.sendMulticast(std::make_shared<sys::bluetooth::BluetoothModeChanged>(sys::bluetooth::BluetoothMode::Disabled),
                      sys::BusChannel::BluetoothModeChanges);
}
auto ServiceBluetooth::handle(message::bluetooth::RequestStatusIndicatorData *msg) -> std::shared_ptr<sys::Message>
{
    bus.sendUnicast(std::make_shared<CellularRequestCurrentOperatorNameMessage>(), cellular::service::name);

    // just to execute proper handle method and sending it back to worker
    bus.sendUnicast(std::make_shared<CellularSignalStrengthUpdateNotification>(), service::name::bluetooth);

    return sys::MessageNone{};
}

M module-services/service-bluetooth/service-bluetooth/ServiceBluetooth.hpp => module-services/service-bluetooth/service-bluetooth/ServiceBluetooth.hpp +8 -1
@@ 55,10 55,13 @@ namespace message::bluetooth
    class Ring;
    class StartAudioRouting;
    class GetBluetoothDevicesModel;
    class RequestStatusIndicatorData;
} // namespace message::bluetooth

class CellularCallerIdMessage;
class CellularCallActiveNotification;
class CellularSignalStrengthUpdateNotification;
class CellularCurrentOperatorNameNotification;

class ServiceBluetooth : public sys::Service
{


@@ 72,7 75,8 @@ class ServiceBluetooth : public sys::Service
    sys::ReturnCodes DeinitHandler() override;
    void ProcessCloseReason(sys::CloseReason closeReason) override;
    virtual sys::ReturnCodes SwitchPowerModeHandler(const sys::ServicePowerMode mode) override;
    void sendWorkerCommand(bluetooth::Command command);
    void sendWorkerCommand(bluetooth::Command::Type commandType,
                           std::unique_ptr<bluetooth::CommandData> data = nullptr);
    void handleTurnOff();
    QueueHandle_t workerQueue = nullptr;
    std::shared_ptr<bluetooth::SettingsHolder> settingsHolder;


@@ 117,8 121,11 @@ class ServiceBluetooth : public sys::Service
    [[nodiscard]] auto handle(message::bluetooth::ResponseAuthenticatePin *msg) -> std::shared_ptr<sys::Message>;
    [[nodiscard]] auto handle(message::bluetooth::ResponseAuthenticatePasskey *msg) -> std::shared_ptr<sys::Message>;
    [[nodiscard]] auto handle(message::bluetooth::ResponseAuthenticatePairCancel *msg) -> std::shared_ptr<sys::Message>;
    [[nodiscard]] auto handle(message::bluetooth::RequestStatusIndicatorData *msg) -> std::shared_ptr<sys::Message>;
    [[nodiscard]] auto handle(CellularCallerIdMessage *msg) -> std::shared_ptr<sys::Message>;
    [[nodiscard]] auto handle(CellularCallActiveNotification *msg) -> std::shared_ptr<sys::Message>;
    [[nodiscard]] auto handle(CellularSignalStrengthUpdateNotification *msg) -> std::shared_ptr<sys::Message>;
    [[nodiscard]] auto handle(CellularCurrentOperatorNameNotification *msg) -> std::shared_ptr<sys::Message>;
};

namespace sys

A module-services/service-bluetooth/service-bluetooth/messages/RequestStatusIndicatorData.hpp => module-services/service-bluetooth/service-bluetooth/messages/RequestStatusIndicatorData.hpp +14 -0
@@ 0,0 1,14 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once
#include "service-bluetooth/BluetoothMessage.hpp"

namespace message::bluetooth
{
    class RequestStatusIndicatorData : public BluetoothMessage
    {
      public:
        RequestStatusIndicatorData() = default;
    };
} // namespace message::bluetooth

M module-services/service-cellular/CellularUrcHandler.cpp => module-services/service-cellular/CellularUrcHandler.cpp +2 -0
@@ 49,6 49,8 @@ void CellularUrcHandler::Handle(Creg &urc)
        }
        else {
            Store::GSM::get()->setNetworkOperatorName("");
            auto notification = std::make_shared<CellularCurrentOperatorNameNotification>("");
            cellularService.bus.sendMulticast(std::move(notification), sys::BusChannel::ServiceCellularNotifications);
        }

        Store::Network network{status, accessTechnology};

M module-services/service-cellular/ServiceCellular.cpp => module-services/service-cellular/ServiceCellular.cpp +5 -4
@@ 335,7 335,8 @@ void ServiceCellular::registerMessageHandlers()

    connect(typeid(CellularRequestCurrentOperatorNameMessage), [&](sys::Message *request) -> sys::MessagePointer {
        auto msg = static_cast<CellularRequestCurrentOperatorNameMessage *>(request);
        return handleCellularRequestCurrentOperatorName(msg);
        handleCellularRequestCurrentOperatorName(msg);
        return sys::MessageNone{};
    });

    connect(typeid(CellularGetAPNMessage), [&](sys::Message *request) -> sys::MessagePointer {


@@ 1653,14 1654,14 @@ bool ServiceCellular::handle_apn_conf_procedure()
    return true;
}

std::shared_ptr<CellularCurrentOperatorNameResponse> ServiceCellular::handleCellularRequestCurrentOperatorName(
    CellularRequestCurrentOperatorNameMessage *msg)
void ServiceCellular::handleCellularRequestCurrentOperatorName(CellularRequestCurrentOperatorNameMessage *msg)
{
    LOG_INFO("CellularRequestCurrentOperatorName handled");
    NetworkSettings networkSettings(*this);
    const auto currentNetworkOperatorName = networkSettings.getCurrentOperatorName();
    Store::GSM::get()->setNetworkOperatorName(currentNetworkOperatorName);
    return std::make_shared<CellularCurrentOperatorNameResponse>(currentNetworkOperatorName);
    auto notification = std::make_shared<CellularCurrentOperatorNameNotification>(currentNetworkOperatorName);
    this->bus.sendMulticast(std::move(notification), sys::BusChannel::ServiceCellularNotifications);
}

std::shared_ptr<CellularGetAPNResponse> ServiceCellular::handleCellularGetAPNMessage(CellularGetAPNMessage *msg)

M module-services/service-cellular/service-cellular/CellularMessage.hpp => module-services/service-cellular/service-cellular/CellularMessage.hpp +2 -2
@@ 171,12 171,12 @@ class CellularRequestCurrentOperatorNameMessage : public CellularMessage
class CellularSetOperatorAutoSelectMessage : public sys::DataMessage
{};

class CellularCurrentOperatorNameResponse : public CellularMessage
class CellularCurrentOperatorNameNotification : public CellularMessage
{
    std::string currentOperatorName;

  public:
    explicit CellularCurrentOperatorNameResponse(const std::string &currentOperatorName)
    explicit CellularCurrentOperatorNameNotification(const std::string &currentOperatorName)
        : CellularMessage(Type::Notification), currentOperatorName(currentOperatorName)
    {}


M module-services/service-cellular/service-cellular/CellularServiceAPI.hpp => module-services/service-cellular/service-cellular/CellularServiceAPI.hpp +3 -3
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 53,8 53,8 @@ namespace CellularServiceAPI
    void GetNetworkInfo(sys::Service *serv);

    /*
     * @brief Get current operator, result async in
     * CellularCurrentOperatorNameResponse message
     * @brief Get current operator, result in
     * CellularCurrentOperatorNameNotification message on notification channel
     */
    void RequestCurrentOperatorName(sys::Service *serv);
    /*

M module-services/service-cellular/service-cellular/ServiceCellular.hpp => module-services/service-cellular/service-cellular/ServiceCellular.hpp +1 -2
@@ 238,8 238,7 @@ class ServiceCellular : public sys::Service

    std::shared_ptr<CellularSetOperatorAutoSelectResponse> handleCellularSetOperatorAutoSelect(
        CellularSetOperatorAutoSelectMessage *msg);
    std::shared_ptr<CellularCurrentOperatorNameResponse> handleCellularRequestCurrentOperatorName(
        CellularRequestCurrentOperatorNameMessage *msg);
    void handleCellularRequestCurrentOperatorName(CellularRequestCurrentOperatorNameMessage *msg);
    std::shared_ptr<CellularGetAPNResponse> handleCellularGetAPNMessage(CellularGetAPNMessage *msg);
    std::shared_ptr<CellularSetAPNResponse> handleCellularSetAPNMessage(CellularSetAPNMessage *msg);
    std::shared_ptr<CellularNewAPNResponse> handleCellularNewAPNMessage(CellularNewAPNMessage *msg);