~aleteoryx/muditaos

5c7b518136c2fe576e76f803b1615af4f6c191e8 — SP2FET 5 years ago dbdcaf3
[EGD-5700] Fix Bluetooth pairing

To be able to proper propagate the pair message there was a need
for Command wrapper (to be able to send command and parameter in
one piece)
M module-bluetooth/Bluetooth/BluetoothWorker.cpp => module-bluetooth/Bluetooth/BluetoothWorker.cpp +4 -4
@@ 5,6 5,7 @@
#include "BluetoothWorker.hpp"
#include "BtCommand.hpp"
#include "log/log.hpp"
#include "interface/BluetoothDriverImpl.hpp"
#include "interface/profiles/A2DP/A2DP.hpp"
#include "interface/profiles/HSP/HSP.hpp"
#include "BtKeysStorage.hpp"


@@ 138,13 139,13 @@ auto BluetoothWorker::run() -> bool

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

    switch (command) {
    switch (command.getType()) {
    case bluetooth::Command::PowerOn:
        controller->turnOn();
        break;


@@ 249,7 250,6 @@ auto BluetoothWorker::handleMessage(uint32_t queueID) -> bool

void BluetoothWorker::setDeviceAddress(bd_addr_t addr)
{

    currentProfile->setDeviceAddress(addr);
}


M module-bluetooth/Bluetooth/CommandHandler.cpp => module-bluetooth/Bluetooth/CommandHandler.cpp +41 -11
@@ 5,10 5,18 @@

#include <utility>
#include <service-bluetooth/ServiceBluetooth.hpp>
#include <service-bluetooth/SettingsHolder.hpp>

#include <Service/Service.hpp>

#include "Device.hpp"
#include "BtCommand.hpp"

extern "C"
{
#include <module-bluetooth/lib/btstack/src/btstack_util.h>
}

namespace bluetooth
{
    namespace


@@ 22,31 30,35 @@ namespace bluetooth
    CommandHandler::CommandHandler(sys::Service *service,
                                   std::shared_ptr<bluetooth::SettingsHolder> settings,
                                   std::shared_ptr<bluetooth::Profile> currentProfile,
                                   std::shared_ptr<bluetooth::Driver> driver)
                                   std::shared_ptr<bluetooth::AbstractDriver> driver)
        : service{service}, settings{std::move(settings)}, currentProfile{std::move(currentProfile)}, driver{std::move(
                                                                                                          driver)}
    {}

    Error::Code CommandHandler::handle(Command command)
    {
        switch (command) {
        case bluetooth::PowerOn:
        switch (command.getType()) {
        case bluetooth::Command::PowerOn:
            return Error::Success;
        case bluetooth::StartScan:
        case bluetooth::Command::StartScan:
            return scan();
        case bluetooth::StopScan:
        case bluetooth::Command::StopScan:
            return stopScan();
        case bluetooth::StartPan:
        case bluetooth::Command::StartPan:
            return startPan();
        case bluetooth::VisibilityOn:
        case bluetooth::Command::Pair:
            return pair(command.getArgument().value());
        case bluetooth::Command::VisibilityOn:
            return setVisibility(true);
        case bluetooth::VisibilityOff:
        case bluetooth::Command::VisibilityOff:
            return setVisibility(false);
        case bluetooth::ConnectAudio:
        case bluetooth::Command::ConnectAudio:
            return establishAudioConnection();
        case bluetooth::DisconnectAudio:
        case bluetooth::Command::DisconnectAudio:
            return disconnectAudioConnection();
        case bluetooth::PowerOff:
        case bluetooth::Command::PowerOff:
            return Error::Success;
        case bluetooth::Command::None:
            return Error::Success;
        }
        return Error::LibraryError;


@@ 106,4 118,22 @@ namespace bluetooth
        currentProfile->disconnect();
        return Error::Success;
    }
    Error::Code CommandHandler::pair(CommandArgument arg)
    {
        try {
            auto addrString = std::get<std::string>(arg);
            bd_addr_t addr;
            if (sscanf_bd_addr(addrString.c_str(), addr) != 0) {
                LOG_INFO("Pairing with %s", addrString.c_str());
                driver->pair(addr);
            }
            else {
                return Error::SystemError;
            }
        }
        catch (const std::bad_variant_access &) {
            return Error::SystemError;
        }
        return Error::Success;
    }
} // namespace bluetooth

M module-bluetooth/Bluetooth/CommandHandler.hpp => module-bluetooth/Bluetooth/CommandHandler.hpp +44 -15
@@ 7,24 7,52 @@
#include "interface/profiles/Profile.hpp"
#include "interface/BluetoothDriver.hpp"

#include <service-bluetooth/SettingsHolder.hpp>
#include <Service/Service.hpp>

#include <cstdint>

namespace sys
{
    class Service;
}

namespace bluetooth
{
    enum Command : std::uint8_t
    class SettingsHolder;
    using CommandArgument = std::variant<std::string, bool, int>;
    class Command
    {
        StartScan,
        StopScan,
        StartPan,
        VisibilityOn,
        VisibilityOff,
        ConnectAudio,
        DisconnectAudio,
        PowerOn,
        PowerOff,
      public:
        enum Type : std::uint8_t
        {
            StartScan,
            StopScan,
            StartPan,
            VisibilityOn,
            VisibilityOff,
            ConnectAudio,
            DisconnectAudio,
            PowerOn,
            PowerOff,
            Pair,
            None,
        };

        Command(Command::Type type, std::optional<CommandArgument> arg = std::nullopt)
            : argument(std::move(arg)), type(type)
        {}

        auto getType() const noexcept -> Command::Type
        {
            return type;
        }

        auto getArgument() const -> std::optional<CommandArgument>
        {
            return argument;
        }

      private:
        std::optional<CommandArgument> argument;
        Type type;
    };

    class AbstractCommandHandler


@@ 41,7 69,7 @@ namespace bluetooth
        explicit CommandHandler(sys::Service *service,
                                std::shared_ptr<bluetooth::SettingsHolder> settings,
                                std::shared_ptr<bluetooth::Profile> currentProfile,
                                std::shared_ptr<bluetooth::Driver> driver);
                                std::shared_ptr<bluetooth::AbstractDriver> driver);

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



@@ 52,10 80,11 @@ namespace bluetooth
        Error::Code setVisibility(bool visibility);
        Error::Code establishAudioConnection();
        Error::Code disconnectAudioConnection();
        Error::Code pair(CommandArgument arg);

        sys::Service *service;
        std::shared_ptr<bluetooth::SettingsHolder> settings;
        std::shared_ptr<bluetooth::Profile> currentProfile;
        std::shared_ptr<Driver> driver;
        std::shared_ptr<AbstractDriver> driver;
    };
} // namespace bluetooth

M module-bluetooth/Bluetooth/WorkerController.cpp => module-bluetooth/Bluetooth/WorkerController.cpp +2 -1
@@ 10,6 10,7 @@
#define BOOST_SML_CFG_DISABLE_MIN_SIZE // GCC10 fix
#include <module-utils/sml/include/boost/sml.hpp>
#include <module-utils/magic_enum/include/magic_enum.hpp>
#include <stdexcept>

namespace bluetooth
{


@@ 177,7 178,7 @@ namespace bluetooth

    void StatefulController::processCommand(Command command)
    {
        LOG_INFO("Process command: %s", magic_enum::enum_name(command).data());
        LOG_INFO("Process command: %s", magic_enum::enum_name(command.getType()).data());
        pimpl->sm.process_event(ProcessCommand{command});
    }
} // namespace bluetooth

M module-bluetooth/Bluetooth/interface/BluetoothDriver.hpp => module-bluetooth/Bluetooth/interface/BluetoothDriver.hpp +4 -30
@@ 3,9 3,7 @@

#pragma once

#include <btstack.h>
#include <functional>
#include "GAP/GAP.hpp"
#include "Error.hpp"

namespace bluetooth


@@ 19,34 17,10 @@ namespace bluetooth
        [[nodiscard]] virtual auto init() -> Error::Code                     = 0;
        [[nodiscard]] virtual auto run() -> Error::Code                      = 0;
        [[nodiscard]] virtual auto stop() -> Error::Code                     = 0;
        [[nodiscard]] virtual auto scan() -> Error                                               = 0;
        virtual void stopScan()                                                                  = 0;
        virtual void setVisibility(bool visibility)                                              = 0;
        [[nodiscard]] virtual auto pair(uint8_t *addr, std::uint8_t protectionLevel = 0) -> bool = 0;
        virtual void registerErrorCallback(const ErrorCallback &newCallback) = 0;
    };

    class Driver : public AbstractDriver
    {
      private:
        static hci_transport_config_uart_t config;
        const btstack_run_loop *runLoop;
        btstack_packet_callback_registration_t hci_event_callback_registration;
        std::unique_ptr<bluetooth::GAP> gap;
        static void hci_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
        static void local_version_information_handler(uint8_t *packet);
#ifdef TARGET_RT1051
        [[maybe_unused]] auto runLoopInitTarget(const btstack_run_loop *runLoop) -> const btstack_uart_block_t *;
#else
        [[maybe_unused]] auto runLoopInitLinux(const btstack_run_loop *runLoop) -> const btstack_uart_block_t *;
#endif

      public:
        Driver(const btstack_run_loop *runLoop, sys::Service *ownerService);

        [[nodiscard]] auto init() -> Error::Code override;
        [[nodiscard]] auto run() -> Error::Code override;
        [[nodiscard]] auto stop() -> Error::Code override;
        void registerErrorCallback(const ErrorCallback &newCallback) override;
        auto scan() -> Error;
        void stopScan();
        void setVisibility(bool visibility);
        auto pair(uint8_t *addr, std::uint8_t protectionLevel = 0) -> bool;
    };
} // namespace bluetooth

R module-bluetooth/Bluetooth/interface/BluetoothDriver.cpp => module-bluetooth/Bluetooth/interface/BluetoothDriverImpl.cpp +1 -1
@@ 1,7 1,7 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "BluetoothDriver.hpp"
#include "BluetoothDriverImpl.hpp"

extern "C"
{

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

#pragma once

#include "BluetoothDriver.hpp"

extern "C"
{
#include <btstack.h>
}
#include "GAP/GAP.hpp"

namespace bluetooth
{
    class Driver : public AbstractDriver
    {
      private:
        static hci_transport_config_uart_t config;
        const btstack_run_loop *runLoop;
        btstack_packet_callback_registration_t hci_event_callback_registration;
        std::unique_ptr<bluetooth::GAP> gap;
        static void hci_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
        static void local_version_information_handler(uint8_t *packet);
#ifdef TARGET_RT1051
        [[maybe_unused]] auto runLoopInitTarget(const btstack_run_loop *runLoop) -> const btstack_uart_block_t *;
#else
        [[maybe_unused]] auto runLoopInitLinux(const btstack_run_loop *runLoop) -> const btstack_uart_block_t *;
#endif

      public:
        Driver(const btstack_run_loop *runLoop, sys::Service *ownerService);

        [[nodiscard]] auto init() -> Error::Code override;
        [[nodiscard]] auto run() -> Error::Code override;
        [[nodiscard]] auto stop() -> Error::Code override;
        void registerErrorCallback(const ErrorCallback &newCallback) override;
        auto scan() -> Error override;
        void stopScan() override;
        void setVisibility(bool visibility) override;
        auto pair(uint8_t *addr, std::uint8_t protectionLevel = 0) -> bool override;
    };
} // namespace bluetooth

M module-bluetooth/CMakeLists.txt => module-bluetooth/CMakeLists.txt +1 -1
@@ 9,7 9,7 @@ set(SOURCES
    ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/WorkerController.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/CommandHandler.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/glucode/BluetoothRunLoop.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/interface/BluetoothDriver.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/interface/BluetoothDriverImpl.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/BtKeysStorage.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/interface/profiles/GAP/GAP.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/interface/profiles/A2DP/A2DP.cpp

M module-bluetooth/tests/tests-StatefulController.cpp => module-bluetooth/tests/tests-StatefulController.cpp +15 -6
@@ 4,9 4,6 @@
#include <catch2/catch.hpp>

#include "WorkerController.hpp"
#include "interface/BluetoothDriver.hpp"

#include <iostream>

using namespace bluetooth;



@@ 25,6 22,18 @@ class DriverMock : public AbstractDriver
    {
        return stopReturnCode;
    }
    Error scan() override
    {
        return Error::Success;
    }
    void stopScan() override
    {}
    void setVisibility(bool visibility) override
    {}
    bool pair(uint8_t *addr, std::uint8_t protectionLevel = 0) override
    {
        return true;
    }
    void registerErrorCallback(const ErrorCallback &) override
    {}



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

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



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

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

M module-services/service-bluetooth/ServiceBluetooth.cpp => module-services/service-bluetooth/ServiceBluetooth.cpp +21 -9
@@ 74,16 74,26 @@ sys::ReturnCodes ServiceBluetooth::InitHandler()
                enabledFromHarness = true;
                LOG_INFO("BT enabled from Harness");
            }
            sendWorkerCommand(bluetooth::Command::PowerOn);
            sendWorkerCommand(bluetooth::Command(bluetooth::Command::Type::PowerOn));
            break;
        case BluetoothStatus::State::Off:
            sendWorkerCommand(bluetooth::Command::PowerOff);
            sendWorkerCommand(bluetooth::Command(bluetooth::Command::Type::PowerOff));
            enabledFromHarness = false;
            break;
        default:
            break;
        }
        sendWorkerCommand(newBtStatus.visibility ? bluetooth::VisibilityOn : bluetooth::VisibilityOff);
        bluetooth::Command command(newBtStatus.visibility ? bluetooth::Command::Type::VisibilityOn
                                                          : bluetooth::Command::Type::VisibilityOff);
        sendWorkerCommand(command);
        return sys::MessageNone{};
    });

    connect(typeid(BluetoothPairMessage), [&](sys::Message *msg) {
        auto pairMsg = static_cast<BluetoothPairMessage *>(msg);
        auto addr    = pairMsg->addr;

        sendWorkerCommand(bluetooth::Command(bluetooth::Command::Type::Pair, addr));
        return sys::MessageNone{};
    });



@@ 135,10 145,10 @@ sys::MessagePointer ServiceBluetooth::DataReceivedHandler(sys::DataMessage *msg,
            case BluetoothMessage::Start:
                break;
            case BluetoothMessage::Scan:
                sendWorkerCommand(bluetooth::StartScan);
                sendWorkerCommand(bluetooth::Command(bluetooth::Command::Type::StartScan));
                break;
            case BluetoothMessage::StopScan:
                sendWorkerCommand(bluetooth::StopScan);
                sendWorkerCommand(bluetooth::Command(bluetooth::Command::Type::StopScan));
                break;
            case BluetoothMessage::PAN: {
                /// TODO request lwip first...


@@ 151,20 161,22 @@ sys::MessagePointer ServiceBluetooth::DataReceivedHandler(sys::DataMessage *msg,
                //                    else {
                /// TODO request PPP
                LOG_INFO("Start PAN");
                sendWorkerCommand(bluetooth::StartPan);
                sendWorkerCommand(bluetooth::Command(bluetooth::Command::Type::StartPan));
                //                    }
            } break;
            case BluetoothMessage::Visible: {
                static bool visibility = true;
                sendWorkerCommand(visibility ? bluetooth::VisibilityOn : bluetooth::VisibilityOff);
                bluetooth::Command command(visibility ? bluetooth::Command::Type::VisibilityOn
                                                      : bluetooth::Command::Type::VisibilityOff);
                sendWorkerCommand(command);
                visibility = !visibility;
            } break;

            case BluetoothMessage::Play:
                sendWorkerCommand(bluetooth::ConnectAudio);
                sendWorkerCommand(bluetooth::Command(bluetooth::Command::Type::ConnectAudio));
                break;
            case BluetoothMessage::StopPlayback:
                sendWorkerCommand(bluetooth::DisconnectAudio);
                sendWorkerCommand(bluetooth::Command(bluetooth::Command::Type::DisconnectAudio));
                break;

            default:

M module-services/service-bluetooth/service-bluetooth/BluetoothMessage.cpp => module-services/service-bluetooth/service-bluetooth/BluetoothMessage.cpp +4 -0
@@ 7,8 7,12 @@ extern "C"
{
#include <module-bluetooth/lib/btstack/src/btstack_util.h>
}
#include <utility>

BluetoothAddrMessage::BluetoothAddrMessage(std::string addr) : sys::DataMessage(MessageType::BluetoothAddrResult)
{
    sscanf_bd_addr(addr.c_str(), this->addr);
}
BluetoothPairMessage::BluetoothPairMessage(std::string addr)
    : sys::DataMessage(MessageType::BluetoothPairResult), addr(std::move(addr))
{}

M module-services/service-bluetooth/service-bluetooth/BluetoothMessage.hpp => module-services/service-bluetooth/service-bluetooth/BluetoothMessage.hpp +8 -0
@@ 78,6 78,14 @@ class BluetoothAddrMessage : public sys::DataMessage
    ~BluetoothAddrMessage() override = default;
};

class BluetoothPairMessage : public sys::DataMessage
{
  public:
    std::string addr;
    explicit BluetoothPairMessage(std::string addr);
    ~BluetoothPairMessage() override = default;
};

class BluetoothAudioRegisterMessage : public sys::DataMessage
{
  public: