~aleteoryx/muditaos

e1918179530e87b040b8c52f525ff3b66b4e26ba — SP2FET 5 years ago f7a742d
[EGD-5480] Bluetooth scan refactor

There was a need for Bluetooth scan code refactor. Here it is
M module-apps/application-settings-new/windows/AddDeviceWindow.cpp => module-apps/application-settings-new/windows/AddDeviceWindow.cpp +1 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "AddDeviceWindow.hpp"

M module-apps/application-settings-new/windows/AllDevicesWindow.cpp => module-apps/application-settings-new/windows/AllDevicesWindow.cpp +3 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "AllDevicesWindow.hpp"


@@ 28,6 28,8 @@ namespace gui
    void AllDevicesWindow::onBeforeShow(ShowMode mode, SwitchData *data)
    {
        clearOptions();
        application->bus.sendUnicast(std::make_shared<BluetoothMessage>(BluetoothMessage::Request::StopScan),
                                     "ServiceBluetooth");
        if (const auto newData = dynamic_cast<BondedDevicesData *>(data); newData != nullptr) {
            addOptions(allDevicesOptionsList(newData->getDevices()));
        }

M module-bluetooth/Bluetooth/BluetoothWorker.cpp => module-bluetooth/Bluetooth/BluetoothWorker.cpp +7 -7
@@ 48,7 48,7 @@ namespace
        [[nodiscard]] auto operator()()
        {
            bluetooth::KeyStorage::settings = settings;
            bluetooth::GAP::register_scan();
            bluetooth::GAP::registerScan();

            auto settingsName = std::get<std::string>(settings->getValue(bluetooth::Settings::DeviceName));
            if (settingsName.empty()) {


@@ 58,8 58,6 @@ namespace
                settingsName = name;
            }
            bluetooth::set_name(settingsName);
            bluetooth::GAP::set_visibility(
                std::visit(bluetooth::BoolVisitor{}, settings->getValue(bluetooth::Settings::Visibility)));

            settings->onLinkKeyAdded = onLinkKeyAdded;
            return bluetooth::Error::Success;


@@ 76,8 74,9 @@ namespace
                                  std::shared_ptr<bluetooth::Profile> currentProfile,
                                  DeviceRegistration::OnLinkKeyAddedCallback &&onLinkKeyAddedCallback)
    {
        auto driver         = std::make_unique<bluetooth::Driver>(loop->getRunLoopInstance());
        auto commandHandler = std::make_unique<bluetooth::CommandHandler>(service, settings, std::move(currentProfile));
        auto driver = std::make_shared<bluetooth::Driver>(loop->getRunLoopInstance(), service);
        auto commandHandler =
            std::make_unique<bluetooth::CommandHandler>(service, settings, std::move(currentProfile), driver);
        return std::make_unique<bluetooth::StatefulController>(
            std::move(driver),
            std::move(commandHandler),


@@ 109,7 108,8 @@ void BluetoothWorker::registerQueues()

void BluetoothWorker::onLinkKeyAdded(const std::string &deviceAddress)
{
    for (auto &device : bluetooth::GAP::devices) {
    auto devices = bluetooth::GAP::getDevicesList();
    for (auto &device : devices) {
        if (bd_addr_to_str(device.address) == deviceAddress) {
            pairedDevices.emplace_back(device);
            settings->setValue(bluetooth::Settings::BondedDevices, SettingsSerializer::toString(pairedDevices));


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

void BluetoothWorker::setDeviceAddress(bd_addr_t addr)
{
    bluetooth::GAP::do_pairing(addr);

    currentProfile->setDeviceAddress(addr);
}


M module-bluetooth/Bluetooth/BluetoothWorker.hpp => module-bluetooth/Bluetooth/BluetoothWorker.hpp +0 -1
@@ 13,7 13,6 @@
#include <vector>
#include "service-bluetooth/SettingsHolder.hpp"
#include "glucode/BluetoothRunLoop.hpp"
#include "interface/BluetoothDriver.hpp"
#include "WorkerController.hpp"
struct HCI;


M module-bluetooth/Bluetooth/BtCommand.hpp => module-bluetooth/Bluetooth/BtCommand.hpp +2 -14
@@ 1,31 1,19 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// 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 <FreeRTOS.h>
#include <task.h>

#include "BluetoothWorker.hpp"
#include "Error.hpp"
#include <functional>
#include <btstack_run_loop.h>
#include <string>

namespace bluetooth
{

    auto set_name(std::string &name) -> Error;
    namespace GAP
    {
        extern std::vector<Devicei> devices;
        /// THIS have to be called prior to Bt system start!
        auto register_scan() -> Error;
        auto scan() -> Error;
        void stop_scan();
        auto set_visibility(bool visibility) -> Error;
        auto do_pairing(uint8_t *addr) -> bool;

        void setOwnerService(sys::Service *service);
    }; // namespace GAP
    namespace PAN
    {
        auto bnep_start() -> Error;

M module-bluetooth/Bluetooth/CommandHandler.cpp => module-bluetooth/Bluetooth/CommandHandler.cpp +12 -8
@@ 3,8 3,10 @@

#include "CommandHandler.hpp"

#include "BtCommand.hpp"
#include <utility>

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

namespace bluetooth
{


@@ 18,8 20,10 @@ namespace bluetooth

    CommandHandler::CommandHandler(sys::Service *service,
                                   std::shared_ptr<bluetooth::SettingsHolder> settings,
                                   std::shared_ptr<bluetooth::Profile> currentProfile)
        : service{service}, settings{std::move(settings)}, currentProfile{std::move(currentProfile)}
                                   std::shared_ptr<bluetooth::Profile> currentProfile,
                                   std::shared_ptr<bluetooth::Driver> driver)
        : service{service}, settings{std::move(settings)}, currentProfile{std::move(currentProfile)}, driver{std::move(
                                                                                                          driver)}
    {}

    Error::Code CommandHandler::handle(Command command)


@@ 49,8 53,8 @@ namespace bluetooth

    Error::Code CommandHandler::scan()
    {
        bluetooth::GAP::setOwnerService(service);
        if (const auto ret = bluetooth::GAP::scan(); ret.err != bluetooth::Error::Success) {

        if (const auto ret = driver->scan(); ret.err != bluetooth::Error::Success) {
            LOG_ERROR("Cant start scan!: %s %" PRIu32 "", toString(ret.err).c_str(), ret.lib_code);
            return ret.err;
        }


@@ 62,7 66,7 @@ namespace bluetooth

    Error::Code CommandHandler::stopScan()
    {
        bluetooth::GAP::stop_scan();
        driver->stopScan();
        return Error::Success;
    }



@@ 78,9 82,9 @@ namespace bluetooth

    Error::Code CommandHandler::setVisibility(bool visibility)
    {
        const auto status = bluetooth::GAP::set_visibility(visibility);
        driver->setVisibility(visibility);
        settings->setValue(bluetooth::Settings::Visibility, static_cast<int>(visibility));
        return status.err;
        return Error::Success;
    }

    Error::Code CommandHandler::establishAudioConnection()

M module-bluetooth/Bluetooth/CommandHandler.hpp => module-bluetooth/Bluetooth/CommandHandler.hpp +4 -1
@@ 5,6 5,7 @@

#include "Error.hpp"
#include "interface/profiles/Profile.hpp"
#include "interface/BluetoothDriver.hpp"

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


@@ 39,7 40,8 @@ namespace bluetooth
      public:
        explicit CommandHandler(sys::Service *service,
                                std::shared_ptr<bluetooth::SettingsHolder> settings,
                                std::shared_ptr<bluetooth::Profile> currentProfile);
                                std::shared_ptr<bluetooth::Profile> currentProfile,
                                std::shared_ptr<bluetooth::Driver> driver);

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



@@ 54,5 56,6 @@ namespace bluetooth
        sys::Service *service;
        std::shared_ptr<bluetooth::SettingsHolder> settings;
        std::shared_ptr<bluetooth::Profile> currentProfile;
        std::shared_ptr<Driver> driver;
    };
} // namespace bluetooth

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

#pragma once


@@ 35,7 35,7 @@ struct Devicei : public Device
    Devicei(std::string name = "") : Device(std::move(name))
    {}
    ~Devicei() override = default;
    void address_set(bd_addr_t *addr)
    void setAddress(bd_addr_t *addr)
    {
        memcpy(&address, addr, sizeof address);
    }

M module-bluetooth/Bluetooth/WorkerController.cpp => module-bluetooth/Bluetooth/WorkerController.cpp +1 -0
@@ 7,6 7,7 @@
#include "interface/profiles/Profile.hpp"

#include <module-utils/log/log.hpp>
#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>


M module-bluetooth/Bluetooth/interface/BluetoothDriver.cpp => module-bluetooth/Bluetooth/interface/BluetoothDriver.cpp +18 -1
@@ 53,7 53,8 @@ namespace bluetooth
    }
#endif

    Driver::Driver(const btstack_run_loop *runLoop) : runLoop{runLoop}
    Driver::Driver(const btstack_run_loop *runLoop, sys::Service *ownerService)
        : runLoop{runLoop}, gap{std::make_unique<bluetooth::GAP>(ownerService)}
    {}

    auto Driver::init() -> Error::Code


@@ 187,4 188,20 @@ namespace bluetooth
        hci_close();
        return ret != 0 ? Error::LibraryError : Error::Success;
    }
    auto Driver::scan() -> Error
    {
        return gap->scan();
    }
    void Driver::stopScan()
    {
        gap->stopScan();
    }
    void Driver::setVisibility(bool visibility)
    {
        gap->setVisibility(visibility);
    }
    auto Driver::pair(uint8_t *addr, std::uint8_t protectionLevel) -> bool
    {
        return gap->pair(addr, protectionLevel);
    }
} // namespace bluetooth

M module-bluetooth/Bluetooth/interface/BluetoothDriver.hpp => module-bluetooth/Bluetooth/interface/BluetoothDriver.hpp +7 -1
@@ 5,6 5,7 @@

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

namespace bluetooth


@@ 27,6 28,7 @@ namespace bluetooth
        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


@@ 36,11 38,15 @@ namespace bluetooth
#endif

      public:
        explicit Driver(const btstack_run_loop *runLoop);
        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/profiles/GAP.cpp => module-bluetooth/Bluetooth/interface/profiles/GAP/GAP.cpp +197 -193
@@ 1,71 1,37 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "BluetoothWorker.hpp"
#include "Device.hpp"
#include <Bluetooth/Device.hpp>
#include <Bluetooth/Error.hpp>
#include "GAP.hpp"

#include <log/log.hpp>
#include <service-bluetooth/BluetoothMessage.hpp>
#include <vector>
#include <BtCommand.hpp>

extern "C"
{
#include "btstack.h"
#include "hci.h"
};

btstack_packet_callback_registration_t cb_handler;

std::vector<Devicei> bluetooth::GAP::devices;
static auto start_scan() -> int;
static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);

static auto getDeviceIndexForAddress(std::vector<Devicei> &devs, bd_addr_t addr) -> int
namespace bluetooth
{
    int j;
    for (j = 0; j < devs.size(); j++) {
        if (bd_addr_cmp(addr, devs[j].address) == 0) {
            return j;
        }
    }
    return -1;
}
    sys::Service *GAP::ownerService = nullptr;
    std::vector<Devicei> GAP::devices;
    btstack_packet_callback_registration_t GAP::cb_handler;
    ScanState GAP::state;

enum STATE
{
    INIT,
    ACTIVE,
    DONE
};
enum STATE state = INIT;

namespace bluetooth::GAP
{

    static sys::Service *ownerService = nullptr;

    void setOwnerService(sys::Service *service)
    {
        ownerService = service;
    }

    auto register_scan() -> Error
    auto GAP::registerScan() -> Error
    {
        LOG_INFO("GAP register scan!");
        /// -> this have to be called prior to power on!
        hci_set_inquiry_mode(INQUIRY_MODE_RSSI_AND_EIR);
        cb_handler.callback = &packet_handler;
        cb_handler.callback = &packetHandler;
        hci_add_event_handler(&cb_handler);
        return Error();
    }

    auto scan() -> Error
    auto GAP::scan() -> Error
    {
        LOG_INFO("Start scan if active: %d: %d", hci_get_state(), state);
        if (hci_get_state() == HCI_STATE_WORKING) {
            if (int ret = start_scan(); ret != 0) {
            if (auto ret = startScan(); ret != 0) {
                LOG_ERROR("Start scan error!: 0x%X", ret);
                return Error(Error::LibraryError, ret);
            }


@@ 76,192 42,230 @@ namespace bluetooth::GAP
        return Error();
    }

    void stop_scan()
    void GAP::stopScan()
    {
        gap_inquiry_force_stop();
        devices.clear();
        LOG_INFO("Scan stopped!");
    }

    auto set_visibility(bool visibility) -> Error
    void GAP::setVisibility(bool visibility)
    {
        gap_discoverable_control(static_cast<uint8_t>(visibility));
        gap_discoverable_control(static_cast<std::uint8_t>(visibility));
        LOG_INFO("Visibility: %s", visibility ? "true" : "false");
        return Error();
    }

    auto do_pairing(uint8_t *addr) -> bool
    auto GAP::pair(std::uint8_t *addr, std::uint8_t protectionLevel) -> bool
    {
        if (hci_get_state() == HCI_STATE_WORKING) {
            gap_dedicated_bonding(addr, 0);
            return true;
            return gap_dedicated_bonding(addr, protectionLevel) == 0;
        }
        return false;
    }

} // namespace bluetooth::GAP

#define INQUIRY_INTERVAL 5
static auto start_scan() -> int
{
    LOG_INFO("Starting inquiry scan..");
    return gap_inquiry_start(INQUIRY_INTERVAL);
}
    auto getDeviceIndexForAddress(const std::vector<Devicei> &devs, bd_addr_t addr) -> int
    {
        auto result = std::find_if(std::begin(devs), std::end(devs), [addr](const Devicei &device) {
            return bd_addr_cmp(addr, device.address) == 0;
        });

static auto has_more_remote_name_requests() -> int
{
    for (int i = 0; i < bluetooth::GAP::devices.size(); i++) {
        if (bluetooth::GAP::devices[i].state == REMOTE_NAME_REQUEST) {
            return 1;
        if (result == std::end(devs)) {
            return -1;
        }
    }
    return 0;
}

static void do_next_remote_name_request()
{

    for (auto &device : bluetooth::GAP::devices) {
        // remote name request
        if (device.state == REMOTE_NAME_REQUEST) {
            device.state = REMOTE_NAME_INQUIRED;
            LOG_INFO("Get remote name of %s...", bd_addr_to_str(device.address));
            gap_remote_name_request(device.address, device.pageScanRepetitionMode, device.clockOffset | 0x8000);
            return;
        }
        return std::distance(std::begin(devs), result);
    }
}

static void continue_remote_names()
{
    if (has_more_remote_name_requests() != 0) {
        do_next_remote_name_request();
        return;
    void GAP::sendDevices()
    {
        auto msg = std::make_shared<BluetoothScanResultMessage>(devices);
        ownerService->bus.sendUnicast(msg, "ApplicationSettings");
        ownerService->bus.sendUnicast(std::move(msg), "ApplicationSettingsNew");
    }
    start_scan();
}

static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
{
    UNUSED(channel);
    UNUSED(size);
    auto GAP::startScan() -> int
    {
        LOG_INFO("Starting inquiry scan..");
        return gap_inquiry_start(inquiryIntervalSeconds);
    }

    bd_addr_t addr;
    int i;
    int index;
    auto GAP::remoteNameToFetch() -> bool
    {
        auto result = std::find_if(std::begin(devices), std::end(devices), [](Devicei &device) {
            return device.state == REMOTE_NAME_REQUEST;
        });

    if (packet_type != HCI_EVENT_PACKET) {
        return;
        return result != std::end(devices);
    }

    uint8_t event = hci_event_packet_get_type(packet);
    void GAP::fetchRemoteName()
    {
        for (auto &device : bluetooth::GAP::devices) {
            if (device.state == REMOTE_NAME_REQUEST) {
                device.state = REMOTE_NAME_INQUIRED;
                LOG_INFO("Get remote name of %s...", bd_addr_to_str(device.address));
                gap_remote_name_request(device.address, device.pageScanRepetitionMode, device.clockOffset | 0x8000);
                return;
            }
        }
    }

    switch (state) {
        /* @text In INIT, an inquiry  scan is started, and the application transits to
         * ACTIVE state.
         */
    case INIT:
        switch (event) {
        case BTSTACK_EVENT_STATE:
            if (btstack_event_state_get_state(packet) == HCI_STATE_WORKING) {
                state = ACTIVE;
    void GAP::continueScanning()
    {
        if (remoteNameToFetch()) {
            fetchRemoteName();
            return;
        }
        startScan();
    }
    auto GAP::updateDeviceName(std::uint8_t *packet, bd_addr_t &addr) -> bool
    {
        reverse_bd_addr(&packet[3], addr);
        auto index = getDeviceIndexForAddress(devices, addr);
        if (index >= 0) {
            if (packet[2] == 0) {
                LOG_INFO("Name: '%s'", &packet[9]);
                devices[index].state = REMOTE_NAME_FETCHED;
                devices[index].name  = std::string{reinterpret_cast<const char *>(&packet[9])};
                return true;
            }
            else {
                LOG_INFO("Failed to get name: page timeout");
            }
            break;
        default:
            break;
        }
        break;
        return false;
    }

        /* @text In ACTIVE, the following events are processed:
         *  - GAP Inquiry result event: BTstack provides a unified inquiry result that contain
         *    Class of Device (CoD), page scan mode, clock offset. RSSI and name (from EIR) are optional.
         *  - Inquiry complete event: the remote name is requested for devices without a fetched
         *    name. The state of a remote name can be one of the following:
         *    REMOTE_NAME_REQUEST, REMOTE_NAME_INQUIRED, or REMOTE_NAME_FETCHED.
         *  - Remote name request complete event: the remote name is stored in the table and the
         *    state is updated to REMOTE_NAME_FETCHED. The query of remote names is continued.
         */
    case ACTIVE:
        switch (event) {
    void GAP::addNewDevice(std::uint8_t *packet, bd_addr_t &addr)
    {
        Devicei device;
        device.setAddress(&addr);
        device.pageScanRepetitionMode = gap_event_inquiry_result_get_page_scan_repetition_mode(packet);
        device.clockOffset            = gap_event_inquiry_result_get_clock_offset(packet);

        case GAP_EVENT_INQUIRY_RESULT: {
            gap_event_inquiry_result_get_bd_addr(packet, addr);
            index = getDeviceIndexForAddress(bluetooth::GAP::devices, addr);
            if (index >= 0) {
                break; // already in our list
            }
        LOG_INFO("Device found: %s ", bd_addr_to_str(addr));
        LOG_INFO("with COD: 0x%06x, ", static_cast<unsigned int>(gap_event_inquiry_result_get_class_of_device(packet)));
        LOG_INFO("pageScan %d, ", device.pageScanRepetitionMode);
        LOG_INFO("clock offset 0x%04x", device.clockOffset);
        if (gap_event_inquiry_result_get_rssi_available(packet) != 0u) {
            LOG_INFO(", rssi %d dBm", static_cast<int8_t>(gap_event_inquiry_result_get_rssi(packet)));
        }
        if (gap_event_inquiry_result_get_name_available(packet) != 0u) {
            auto name   = gap_event_inquiry_result_get_name(packet);
            device.name = std::string{reinterpret_cast<const char *>(name)};

            Devicei dev;
            dev.address_set(&addr);
            dev.pageScanRepetitionMode = gap_event_inquiry_result_get_page_scan_repetition_mode(packet);
            dev.clockOffset            = gap_event_inquiry_result_get_clock_offset(packet);
            // print info
            LOG_INFO("Device found: %s ", bd_addr_to_str(addr));
            LOG_INFO("with COD: 0x%06x, ", (unsigned int)gap_event_inquiry_result_get_class_of_device(packet));
            LOG_INFO("pageScan %d, ", dev.pageScanRepetitionMode);
            LOG_INFO("clock offset 0x%04x", dev.clockOffset);
            if (gap_event_inquiry_result_get_rssi_available(packet) != 0u) {
                LOG_INFO(", rssi %d dBm", (int8_t)gap_event_inquiry_result_get_rssi(packet));
            }
            if (gap_event_inquiry_result_get_name_available(packet) != 0u) {
                char name_buffer[240];
                int name_len = gap_event_inquiry_result_get_name_len(packet);
                memcpy(name_buffer, gap_event_inquiry_result_get_name(packet), name_len);
                name_buffer[name_len] = 0;
                LOG_INFO(", name '%s'", name_buffer);
                dev.name  = std::string{name_buffer};
                dev.state = REMOTE_NAME_FETCHED;
            }
            else {
                dev.state = REMOTE_NAME_REQUEST;
            LOG_INFO(", name '%s'", device.name.c_str());
            device.state = REMOTE_NAME_FETCHED;
        }
        else {
            device.state = REMOTE_NAME_REQUEST;
            device.name  = std::string{};
        }

        devices.emplace_back(std::move(device));
    }

    void GAP::processInquiryResult(std::uint8_t *packet, bd_addr_t &addr)
    {
        gap_event_inquiry_result_get_bd_addr(packet, addr);
        auto index = getDeviceIndexForAddress(devices, addr);
        if (index >= 0) {
            return; // already in our list
        }
        addNewDevice(packet, addr);
        sendDevices();
    }
    void GAP::processInquiryComplete()
    {
        for (auto &device : devices) {
            // retry remote name request
            if (device.state == REMOTE_NAME_INQUIRED) {
                device.state = REMOTE_NAME_REQUEST;
            }
            bluetooth::GAP::devices.push_back(dev);
            auto msg = std::make_shared<BluetoothScanResultMessage>(bluetooth::GAP::devices);
            bluetooth::GAP::ownerService->bus.sendUnicast(msg, "ApplicationSettings");
            bluetooth::GAP::ownerService->bus.sendUnicast(msg, "ApplicationSettingsNew");
        } break;
        }
        continueScanning();
    }
    void GAP::processNameRequestComplete(std::uint8_t *packet, bd_addr_t &addr)
    {
        if (updateDeviceName(packet, addr)) {
            sendDevices();
        }
        continueScanning();
    }
    void GAP::processDedicatedBondingCompleted(std::uint8_t *packet)
    {
        auto result = packet[2];
        auto msg    = std::make_shared<BluetoothPairResultMessage>(result == 0u);
        ownerService->bus.sendUnicast(msg, "ApplicationSettings");
        ownerService->bus.sendUnicast(std::move(msg), "ApplicationSettingsNew");
    }
    /* @text In ACTIVE, the following events are processed:
     *  - GAP Inquiry result event: BTstack provides a unified inquiry result that contain
     *    Class of Device (CoD), page scan mode, clock offset. RSSI and name (from EIR) are optional.
     *  - Inquiry complete event: the remote name is requested for devices without a fetched
     *    name. The state of a remote name can be one of the following:
     *    REMOTE_NAME_REQUEST, REMOTE_NAME_INQUIRED, or REMOTE_NAME_FETCHED.
     *  - Remote name request complete event: the remote name is stored in the table and the
     *    state is updated to REMOTE_NAME_FETCHED. The query of remote names is continued.
     */
    void GAP::activeStateHandler(std::uint8_t eventType, std::uint8_t *packet, bd_addr_t &addr)
    {
        switch (eventType) {

        case GAP_EVENT_INQUIRY_RESULT:
            processInquiryResult(packet, addr);
            break;

        case GAP_EVENT_INQUIRY_COMPLETE:
            for (i = 0; i < bluetooth::GAP::devices.size(); i++) {
                // retry remote name request
                if (bluetooth::GAP::devices[i].state == REMOTE_NAME_INQUIRED)
                    bluetooth::GAP::devices[i].state = REMOTE_NAME_REQUEST;
            }
            continue_remote_names();
            processInquiryComplete();
            break;

        case HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE: {
            reverse_bd_addr(&packet[3], addr);
            index = getDeviceIndexForAddress(bluetooth::GAP::devices, addr);
            if (index >= 0) {
                if (packet[2] == 0) {
                    LOG_INFO("Name: '%s'", &packet[9]);
                    bluetooth::GAP::devices[index].state = REMOTE_NAME_FETCHED;
                    bluetooth::GAP::devices[index].name  = reinterpret_cast<char *>(&packet[9]);
                }
                else {
                    LOG_INFO("Failed to get name: page timeout");
                }
            }
            if (index + 1 == bluetooth::GAP::devices.size()) {
                LOG_INFO("Scanned all");
                state = DONE;
                gap_inquiry_stop();
                break;
            }
            continue_remote_names();
        } break;
        case GAP_EVENT_DEDICATED_BONDING_COMPLETED: {
            auto result = packet[2];
            auto msg    = std::make_shared<BluetoothPairResultMessage>(result == 0u);
            bluetooth::GAP::ownerService->bus.sendUnicast(msg, "ApplicationSettings");
            bluetooth::GAP::ownerService->bus.sendUnicast(msg, "ApplicationSettingsNew");
        } break;
        case HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE:
            processNameRequestComplete(packet, addr);
            break;
        case GAP_EVENT_DEDICATED_BONDING_COMPLETED:
            processDedicatedBondingCompleted(packet);
            break;
        default:
            break;
        }
        break;
    }
    void GAP::initStateHandler(std::uint8_t eventType, std::uint8_t *packet)
    {
        if (eventType == BTSTACK_EVENT_STATE) {
            if (btstack_event_state_get_state(packet) == HCI_STATE_WORKING) {
                state = ScanState::active;
            }
        }
    }
    void GAP::packetHandler(std::uint8_t packet_type, std::uint16_t channel, std::uint8_t *packet, std::uint16_t size)
    {
        bd_addr_t addr;

        if (packet_type != HCI_EVENT_PACKET) {
            return;
        }

    default:
        break;
        const auto eventType = hci_event_packet_get_type(packet);
        switch (state) {
        case ScanState::init:
            initStateHandler(eventType, packet);
            break;
        case ScanState::active:
            activeStateHandler(eventType, packet, addr);
            break;
        default:
            break;
        }
    }
    GAP::GAP(sys::Service *owner)
    {
        ownerService = owner;
        state        = ScanState::init;
    }
}
    auto GAP::getDevicesList() -> const std::vector<Devicei> &
    {
        return devices;
    }

} // namespace bluetooth

A module-bluetooth/Bluetooth/interface/profiles/GAP/GAP.hpp => module-bluetooth/Bluetooth/interface/profiles/GAP/GAP.hpp +56 -0
@@ 0,0 1,56 @@
// 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 <vector>
#include <Bluetooth/Device.hpp>
#include <Bluetooth/Error.hpp>
#include <Service/Service.hpp>
extern "C"
{
#include "btstack_defines.h"
}
namespace bluetooth
{
    enum ScanState
    {
        init,
        active,
        done
    };
    class GAP
    {
        static std::vector<Devicei> devices;
        static sys::Service *ownerService;
        static btstack_packet_callback_registration_t cb_handler;
        static constexpr auto inquiryIntervalSeconds = 5;
        static ScanState state;
        static void sendDevices();
        static auto startScan() -> int;
        static auto remoteNameToFetch() -> bool;
        static void fetchRemoteName();
        static void continueScanning();
        static auto updateDeviceName(std::uint8_t *packet, bd_addr_t &addr) -> bool;
        static void addNewDevice(std::uint8_t *packet, bd_addr_t &addr);
        static void activeStateHandler(std::uint8_t eventType, std::uint8_t *packet, bd_addr_t &addr);
        static void packetHandler(std::uint8_t packet_type,
                                  std::uint16_t channel,
                                  std::uint8_t *packet,
                                  std::uint16_t size);
        static void processInquiryResult(std::uint8_t *packet, bd_addr_t &addr);
        static void processInquiryComplete();
        static void processNameRequestComplete(std::uint8_t *packet, bd_addr_t &addr);
        static void processDedicatedBondingCompleted(std::uint8_t *packet);
        static void initStateHandler(std::uint8_t eventType, std::uint8_t *packet);

      public:
        /// THIS have to be called prior to Bt system start!
        static auto registerScan() -> Error;
        auto scan() -> Error;
        void stopScan();
        void setVisibility(bool visibility);
        auto pair(uint8_t *addr, std::uint8_t protectionLevel = 0) -> bool;
        static auto getDevicesList() -> const std::vector<Devicei> &;
        explicit GAP(sys::Service *owner);
    };
} // namespace bluetooth

M module-bluetooth/CMakeLists.txt => module-bluetooth/CMakeLists.txt +1 -0
@@ 11,6 11,7 @@ set(SOURCES
    ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/glucode/BluetoothRunLoop.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/interface/BluetoothDriver.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
    ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/interface/profiles/A2DP/AVRCP.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/interface/profiles/A2DP/AVDTP.cpp

M module-bluetooth/lib/btstack.cmake => module-bluetooth/lib/btstack.cmake +0 -1
@@ 140,7 140,6 @@ list(APPEND TARGET_LIBRARIES_INCLUDES
    ${BT_STACK_ROOT}/platform/lwip
    )
set(BOARD_DIR_SOURCES
    ${BT_INT}/GAP.cpp
    ${BT_INT}/PAN.cpp

    ${BT_GLU}/bluetooth_init_cc2564C_1.0.c

M module-bsp/board/rt1051/common/macros.h => module-bsp/board/rt1051/common/macros.h +0 -2
@@ 10,8 10,6 @@
#define _STRINGIFY(s) #s
#define STRINGIFY(s)  _STRINGIFY(s)

#define UNUSED(x) ((void)(x))

#define ALIGN_(n) __attribute__((aligned(n)))

#define CACHEABLE_SECTION_SDRAM(var) __attribute__((section(".sdram"))) var