~aleteoryx/muditaos

ref: 80bdde9c9629b946454439871b77dee94d57ef75 muditaos/module-bluetooth/Bluetooth/interface/profiles/GAP.cpp -rw-r--r-- 8.3 KiB
80bdde9c — Marcin Smoczyński ADd changelog for v0.53.1 5 years ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
// Copyright (c) 2017-2020, 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 "Service/Bus.hpp"
#include <Bluetooth/Device.hpp>
#include <Bluetooth/Error.hpp>
#include <log/log.hpp>
#include <service-bluetooth/BluetoothMessage.hpp>
#include <vector>

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

btstack_packet_callback_registration_t cb_handler;

std::vector<Devicei> 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
{
    int j;
    for (j = 0; j < devs.size(); j++) {
        if (bd_addr_cmp(addr, devs[j].address) == 0) {
            return j;
        }
    }
    return -1;
}

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

namespace Bt::GAP
{
    static sys::Service *ownerService = nullptr;

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

    auto register_scan() -> 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;
        hci_add_event_handler(&cb_handler);
        return Error();
    }

    auto 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) {
                LOG_ERROR("Start scan error!: 0x%X", ret);
                return Error(Error::LibraryError, ret);
            }
        }
        else {
            return Error(Error::NotReady);
        }
        return Error();
    }

    void stop_scan()
    {
        gap_inquiry_force_stop();
        LOG_INFO("Scan stopped!");
    }

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

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

#define INQUIRY_INTERVAL 5
static auto start_scan() -> int
{
    LOG_INFO("Starting inquiry scan..");
    return gap_inquiry_start(INQUIRY_INTERVAL);
}

static auto has_more_remote_name_requests() -> int
{
    int i;
    for (i = 0; i < devices.size(); i++) {
        if (devices[i].state == REMOTE_NAME_REQUEST) {
            return 1;
        }
    }
    return 0;
}

static void do_next_remote_name_request()
{
    int i;
    for (i = 0; i < devices.size(); i++) {
        // remote name request
        if (devices[i].state == REMOTE_NAME_REQUEST) {
            devices[i].state = REMOTE_NAME_INQUIRED;
            LOG_INFO("Get remote name of %s...", bd_addr_to_str(devices[i].address));
            gap_remote_name_request(
                devices[i].address, devices[i].pageScanRepetitionMode, devices[i].clockOffset | 0x8000);
            return;
        }
    }
}

static void continue_remote_names()
{
    if (has_more_remote_name_requests() != 0) {
        do_next_remote_name_request();
        return;
    }
    start_scan();
}

static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
{
    UNUSED(channel);
    UNUSED(size);

    bd_addr_t addr;
    int i;
    int index;

    if (packet_type != HCI_EVENT_PACKET) {
        return;
    }

    uint8_t event = hci_event_packet_get_type(packet);

    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;
            }
            break;
        default:
            break;
        }
        break;

        /* @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) {

        case GAP_EVENT_INQUIRY_RESULT: {
            gap_event_inquiry_result_get_bd_addr(packet, addr);
            index = getDeviceIndexForAddress(devices, addr);
            if (index >= 0) {
                break; // already in our list
            }

            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;
            }
            devices.push_back(dev);
            auto msg = std::make_shared<BluetoothScanResultMessage>(devices);
            sys::Bus::SendUnicast(msg, "ApplicationSettings", Bt::GAP::ownerService);
            sys::Bus::SendUnicast(msg, "ApplicationSettingsNew", Bt::GAP::ownerService);

        } break;

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

        case HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE: {
            reverse_bd_addr(&packet[3], addr);
            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  = reinterpret_cast<char *>(&packet[9]);
                }
                else {
                    LOG_INFO("Failed to get name: page timeout");
                }
            }
            if (index + 1 == 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);
            sys::Bus::SendUnicast(msg, "ApplicationSettings", Bt::GAP::ownerService);
            sys::Bus::SendUnicast(msg, "ApplicationSettingsNew", Bt::GAP::ownerService);
        } break;
        default:
            break;
        }
        break;

    default:
        break;
    }
}