Skip to content

Commit f79b9bf

Browse files
laurensvalkjaguilar
andcommitted
pybricks.messaging: Implement bluetooth_scan skeleton.
This allocates data for the async bluetooth_scan results, and returns a list of dictionaries. Doesn't do any scanning yet. Co-authored-by: James Aguilar <aguilar.james@gmail.com>
1 parent bec0e12 commit f79b9bf

2 files changed

Lines changed: 129 additions & 0 deletions

File tree

lib/pbio/include/pbdrv/bluetooth.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,20 @@ typedef enum {
245245
*/
246246
typedef void (*pbdrv_bluetooth_start_observing_callback_t)(pbdrv_bluetooth_ad_type_t type, const uint8_t *data, uint8_t length, int8_t rssi);
247247

248+
/**
249+
* A single result from an inquiry scan.
250+
*/
251+
typedef struct {
252+
/** Bluetooth device address. */
253+
uint8_t bdaddr[6];
254+
/** Received signal strength indicator. */
255+
int8_t rssi;
256+
/** Device name. */
257+
char name[249];
258+
/** Class of device. */
259+
uint32_t class_of_device;
260+
} pbdrv_bluetooth_inquiry_result_t;
261+
248262
#ifdef PBDRV_CONFIG_BLUETOOTH_MAX_MTU_SIZE
249263
#if PBDRV_CONFIG_BLUETOOTH_MAX_MTU_SIZE < 23 || PBDRV_CONFIG_BLUETOOTH_MAX_MTU_SIZE > 515
250264
#error PBDRV_CONFIG_BLUETOOTH_MAX_MTU_SIZE out of range

pybricks/messaging/pb_module_messaging.c

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,136 @@
55

66
#if PYBRICKS_PY_MESSAGING
77

8+
#include <stdio.h>
9+
#include <string.h>
10+
811
#include "py/mphal.h"
912
#include "py/obj.h"
1013
#include "py/objstr.h"
1114
#include "py/runtime.h"
1215
#include "py/mperrno.h"
1316

17+
#include <pbdrv/bluetooth.h>
18+
19+
#include <pbio/int_math.h>
1420
#include <pbio/util.h>
1521

1622
#include <pybricks/util_mp/pb_obj_helper.h>
1723
#include <pybricks/util_mp/pb_kwarg_helper.h>
1824

1925
#include <pybricks/util_pb/pb_error.h>
26+
#include <pybricks/tools/pb_type_async.h>
27+
28+
#define DEBUG 0
29+
30+
#if DEBUG
31+
#include <pbio/debug.h>
32+
#define DEBUG_PRINT pbio_debug
33+
#else
34+
#define DEBUG_PRINT(...)
35+
#endif
36+
37+
typedef struct {
38+
mp_obj_base_t base;
39+
uint32_t num_results;
40+
uint32_t num_results_max;
41+
pbdrv_bluetooth_inquiry_result_t results[];
42+
} pb_messaging_bluetooth_scan_result_obj_t;
43+
44+
static mp_obj_t pb_messaging_bluetooth_scan_close(mp_obj_t self_in) {
45+
pb_messaging_bluetooth_scan_result_obj_t *self = MP_OBJ_TO_PTR(self_in);
46+
DEBUG_PRINT("rfcomm scan data freed\n");
47+
self->num_results_max = 0;
48+
return mp_const_none;
49+
}
50+
MP_DEFINE_CONST_FUN_OBJ_1(pb_messaging_bluetooth_scan_close_obj, pb_messaging_bluetooth_scan_close);
51+
52+
static const mp_rom_map_elem_t pb_messaging_bluetooth_scan_locals_dict_table[] = {
53+
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&pb_messaging_bluetooth_scan_close_obj) },
54+
};
55+
static MP_DEFINE_CONST_DICT(pb_messaging_bluetooth_scan_locals_dict, pb_messaging_bluetooth_scan_locals_dict_table);
56+
57+
MP_DEFINE_CONST_OBJ_TYPE(pb_type_messaging_bluetooth_scan, MP_QSTR_bluetooth_scan, MP_TYPE_FLAG_NONE, locals_dict, &pb_messaging_bluetooth_scan_locals_dict);
58+
59+
/**
60+
* Utility for converting a bluetooth address byte buffer to a string.
61+
*
62+
* The result does not persist. Intended for instant consumption.
63+
*
64+
* @param [in] address 6-byte bluetooth address.
65+
* @return Formatted bluetooth address string.
66+
*/
67+
static char *format_bluetooth_address(uint8_t *address) {
68+
static char bdaddr_str[18];
69+
snprintf(bdaddr_str, sizeof(bdaddr_str), "%02X:%02X:%02X:%02X:%02X:%02X",
70+
address[0], address[1], address[2], address[3], address[4], address[5]);
71+
return bdaddr_str;
72+
}
73+
74+
/**
75+
* To be replaced by driver task.
76+
*/
77+
static pbio_error_t pb_messaging_bluetooth_scan_thread(pbio_os_state_t *state, mp_obj_t parent_obj) {
78+
return PBIO_SUCCESS;
79+
}
80+
81+
/**
82+
* Maps the inquiry results to a list of dictionary, to be returned to the user.
83+
*/
84+
static mp_obj_t pb_messaging_bluetooth_scan_return_map(mp_obj_t parent_obj) {
85+
86+
pb_messaging_bluetooth_scan_result_obj_t *scanner = MP_OBJ_TO_PTR(parent_obj);
87+
88+
mp_obj_t list = mp_obj_new_list(0, NULL);
89+
90+
for (uint32_t i = 0; i < scanner->num_results; i++) {
91+
mp_obj_t dict = mp_obj_new_dict(0);
92+
pbdrv_bluetooth_inquiry_result_t *result = &scanner->results[i];
93+
mp_obj_dict_store(dict, MP_ROM_QSTR(MP_QSTR_address), mp_obj_new_str(format_bluetooth_address(result->bdaddr), 17));
94+
mp_obj_dict_store(dict, MP_ROM_QSTR(MP_QSTR_name), mp_obj_new_str(result->name, strlen(result->name)));
95+
mp_obj_dict_store(dict, MP_ROM_QSTR(MP_QSTR_rssi), mp_obj_new_int(result->rssi));
96+
mp_obj_dict_store(dict, MP_ROM_QSTR(MP_QSTR_class), mp_obj_new_int(result->class_of_device));
97+
mp_obj_list_append(list, dict);
98+
}
99+
return list;
100+
}
101+
102+
// pybricks.messaging.bluetooth_scan
103+
static mp_obj_t pb_messaging_bluetooth_scan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
104+
PB_PARSE_ARGS_FUNCTION(n_args, pos_args, kw_args,
105+
PB_ARG_DEFAULT_INT(timeout, 10000),
106+
PB_ARG_DEFAULT_INT(num_results, 5));
107+
108+
// Allocate the maximum number of expected results.
109+
uint32_t num_results_max = mp_obj_get_int(num_results_in);
110+
if (!num_results_max) {
111+
num_results_max = 1;
112+
}
113+
pb_messaging_bluetooth_scan_result_obj_t *scanner = mp_obj_malloc_var_with_finaliser(
114+
pb_messaging_bluetooth_scan_result_obj_t, pbdrv_bluetooth_inquiry_result_t,
115+
num_results_max, &pb_type_messaging_bluetooth_scan);
116+
117+
// Initialize at zero results.
118+
scanner->num_results = 0;
119+
scanner->num_results_max = mp_obj_get_int(num_results_in);
120+
(void)timeout_in;
121+
122+
// Create an awaitable with a reference to our result to keep it from being
123+
// garbage collected.
124+
pb_type_async_t *iter = NULL;
125+
pb_type_async_t config = {
126+
.iter_once = pb_messaging_bluetooth_scan_thread,
127+
.parent_obj = MP_OBJ_FROM_PTR(scanner),
128+
.return_map = pb_messaging_bluetooth_scan_return_map,
129+
};
130+
return pb_type_async_wait_or_await(&config, &iter, false);
131+
}
132+
// See also messaging_globals_table below. This function object is added there to make it importable.
133+
static MP_DEFINE_CONST_FUN_OBJ_KW(pb_messaging_bluetooth_scan_obj, 0, pb_messaging_bluetooth_scan);
20134

21135
static const mp_rom_map_elem_t messaging_globals_table[] = {
22136
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_messaging) },
137+
{ MP_ROM_QSTR(MP_QSTR_bluetooth_scan), MP_ROM_PTR(&pb_messaging_bluetooth_scan_obj) },
23138
};
24139
static MP_DEFINE_CONST_DICT(pb_module_messaging_globals, messaging_globals_table);
25140

0 commit comments

Comments
 (0)