~aleteoryx/muditaos

2de63da94351d16b4bd25ad45c5ad70cbc1bb6fa — Tomasz Langowski 4 years ago 0fd72b0
[EGD-5954] Add CoD verification for bluetooth conn

Implement selective profile connection based on Class of Device
M module-bluetooth/Bluetooth/Device.hpp => module-bluetooth/Bluetooth/Device.hpp +50 -0
@@ 24,12 24,62 @@ enum DEVICE_STATE
    REMOTE_NAME_FETCHED
};

namespace TYPE_OF_SERVICE
{
    inline constexpr uint32_t POSITIONING     = 0x00010000;
    inline constexpr uint32_t NETWORKING      = 0x00020000;
    inline constexpr uint32_t RENDERING       = 0x00040000;
    inline constexpr uint32_t CAPTURING       = 0x00080000;
    inline constexpr uint32_t OBJECT_TRANSFER = 0x00100000;
    inline constexpr uint32_t AUDIO           = 0x00200000;
    inline constexpr uint32_t TELEPHONY       = 0x00400000;
    inline constexpr uint32_t INFORMATION     = 0x00800000;

    ///> At least one of this class has to be supported by remote device in order to establish connection
    inline constexpr uint32_t REMOTE_SUPPORTED_SERVICES = (AUDIO | POSITIONING);

} // namespace TYPE_OF_SERVICE

static inline std::string getListOfSupportedServicesInString(uint32_t cod)
{
    std::string res = "|";
    if (cod & TYPE_OF_SERVICE::POSITIONING) {
        res += "POSITIONING|";
    }
    if (cod & TYPE_OF_SERVICE::NETWORKING) {
        res += "NETWORKING|";
    }
    if (cod & TYPE_OF_SERVICE::RENDERING) {
        res += "RENDERING|";
    }
    if (cod & TYPE_OF_SERVICE::CAPTURING) {
        res += "CAPTURING|";
    }
    if (cod & TYPE_OF_SERVICE::OBJECT_TRANSFER) {
        res += "OBJECT_TRANSFER|";
    }
    if (cod & TYPE_OF_SERVICE::AUDIO) {
        res += "AUDIO|";
    }
    if (cod & TYPE_OF_SERVICE::TELEPHONY) {
        res += "TELEPHONY|";
    }
    if (cod & TYPE_OF_SERVICE::INFORMATION) {
        res += "INFORMATION|";
    }
    if (res == std::string("|")) {
        res += "NONE|";
    }
    return res;
}

struct Devicei : public Device
{
  public:
    bd_addr_t address;
    uint8_t pageScanRepetitionMode;
    uint16_t clockOffset;
    uint32_t classOfDevice; ///> Class of Device/Service
    DEVICE_STATE state;

    Devicei(std::string name = "") : Device(std::move(name))

M module-bluetooth/Bluetooth/interface/profiles/GAP/GAP.cpp => module-bluetooth/Bluetooth/interface/profiles/GAP/GAP.cpp +19 -4
@@ 146,18 146,18 @@ namespace bluetooth
        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);

        device.classOfDevice          = gap_event_inquiry_result_get_class_of_device(packet);
        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("with COD: 0x%06x, ", static_cast<unsigned int>(device.classOfDevice));
        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)};

            LOG_INFO(", name '%s'", device.name.c_str());
            device.state = REMOTE_NAME_FETCHED;
        }


@@ 176,6 176,13 @@ namespace bluetooth
        if (index >= 0) {
            return; // already in our list
        }
        uint32_t classOfDevice = gap_event_inquiry_result_get_class_of_device(packet);
        ///> Device has to support services: AUDIO for HFP and HSP profiles, and RENDERING for SNK of A2DP profile
        if (!(classOfDevice & TYPE_OF_SERVICE::REMOTE_SUPPORTED_SERVICES)) {
            LOG_INFO("Ignoring device with incompatible services: %s, ",
                     getListOfSupportedServicesInString(classOfDevice).c_str());
            return;
        }
        addNewDevice(packet, addr);
        sendDevices();
    }


@@ 284,5 291,13 @@ namespace bluetooth
            "ApplicationSettingsNew");
        return true;
    }

    auto GAP::isServiceSupportedByRemote(bd_addr_t addr, uint32_t typeOfService) -> bool
    {
        for (const auto &device : devices) {
            if (bd_addr_cmp(device.address, addr) == 0) {
                return (device.classOfDevice & typeOfService);
            }
        }
        return false;
    }
} // namespace bluetooth

M module-bluetooth/Bluetooth/interface/profiles/GAP/GAP.hpp => module-bluetooth/Bluetooth/interface/profiles/GAP/GAP.hpp +2 -0
@@ 52,6 52,8 @@ namespace bluetooth
        auto pair(uint8_t *addr, std::uint8_t protectionLevel = 0) -> bool;
        auto unpair(uint8_t *addr) -> bool;
        static auto getDevicesList() -> const std::vector<Devicei> &;
        static auto isServiceSupportedByRemote(bd_addr_t addr, uint32_t typeOfService) -> bool;

        static std::string currentlyProcessedDeviceAddr;
        explicit GAP(sys::Service *owner);
    };

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

#include <service-bluetooth/ServiceBluetooth.hpp>
#include "ProfileManager.hpp"
#include <GAP/GAP.hpp>

namespace bluetooth
{


@@ 34,10 38,21 @@ namespace bluetooth
    auto ProfileManager::connect(bd_addr_t address) -> Error::Code
    {
        bd_addr_copy(remoteAddr, address);
        for (auto &[profileName, ptr] : profilesList) {
            if (ptr != nullptr) {
                ptr->setDeviceAddress(remoteAddr);
                ptr->connect();
        ///> connect to remote only if we are sure that remote side supports our profiles
        if (GAP::isServiceSupportedByRemote(address, TYPE_OF_SERVICE::RENDERING)) {
            auto profilePtr = profilesList[AudioProfile::A2DP].get();
            if (profilePtr != nullptr) {
                LOG_DEBUG("Connecting device %s to A2DP", bd_addr_to_str(address));
                profilePtr->setDeviceAddress(remoteAddr);
                profilePtr->connect();
            }
        }
        if (GAP::isServiceSupportedByRemote(address, TYPE_OF_SERVICE::AUDIO)) {
            auto profilePtr = profilesList[AudioProfile::HSP].get();
            if (profilePtr != nullptr) {
                LOG_DEBUG("Connecting device %s to HSP", bd_addr_to_str(address));
                profilePtr->setDeviceAddress(remoteAddr);
                profilePtr->connect();
            }
        }
        return Error::Success;

M module-bluetooth/Bluetooth/interface/profiles/ProfileManager.hpp => module-bluetooth/Bluetooth/interface/profiles/ProfileManager.hpp +3 -0
@@ 1,3 1,6 @@
// 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 <Service/Service.hpp>

M module-bluetooth/README.md => module-bluetooth/README.md +8 -0
@@ 14,6 14,14 @@ It's meant to provide interface layer for service-bluetooth like that:
* `lib`
    Libraries used with as little modifications as possible

## Supported profiles
* `A2DP`
* `HSP`
* `HFP` (Currently not supported)

NOTE: Remote devices that do not support at least one of above profiles will not be added to list of devices during scan
process.

## Events flowchart
![Flowchart](./flowchart.svg)
<img src="./flowchart.svg">