Skip to content

Commit 938eefb

Browse files
committed
pbio/drv/bluetooth: Get reference to peripheral.
This the next step towards supporting multiple peripherals.
1 parent 134683a commit 938eefb

7 files changed

Lines changed: 88 additions & 21 deletions

File tree

lib/pbio/drv/bluetooth/bluetooth.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,15 @@ pbio_error_t pbdrv_bluetooth_send_event_notification(pbio_os_state_t *state, pbi
149149

150150
pbdrv_bluetooth_peripheral_t peripheral_singleton;
151151

152+
pbio_error_t pbdrv_bluetooth_peripheral_get_available(pbdrv_bluetooth_peripheral_t **peripheral) {
153+
// Only a single peripheral instance supported for now.
154+
if (peripheral_singleton.func || pbdrv_bluetooth_is_connected(PBDRV_BLUETOOTH_CONNECTION_PERIPHERAL)) {
155+
return PBIO_ERROR_BUSY;
156+
}
157+
*peripheral = &peripheral_singleton;
158+
return PBIO_SUCCESS;
159+
}
160+
152161
const char *pbdrv_bluetooth_peripheral_get_name(void) {
153162
pbdrv_bluetooth_peripheral_t *peri = &peripheral_singleton;
154163
return peri->name;

lib/pbio/drv/bluetooth/bluetooth_btstack.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe
361361
if (peri->config->notification_handler) {
362362
uint16_t length = gatt_event_notification_get_value_length(packet);
363363
const uint8_t *value = gatt_event_notification_get_value(packet);
364-
peri->config->notification_handler(value, length);
364+
peri->config->notification_handler(peri, value, length);
365365
}
366366
break;
367367
}

lib/pbio/drv/bluetooth/bluetooth_stm32_bluenrg.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -952,7 +952,7 @@ static void handle_event(hci_event_pckt *event) {
952952
evt_gatt_attr_notification *subevt = (void *)evt->data;
953953
pbdrv_bluetooth_peripheral_t *peri = &peripheral_singleton;
954954
if (peri->config->notification_handler) {
955-
peri->config->notification_handler(subevt->attr_value, subevt->event_data_length - 2);
955+
peri->config->notification_handler(peri, subevt->attr_value, subevt->event_data_length - 2);
956956
}
957957
}
958958
break;

lib/pbio/drv/bluetooth/bluetooth_stm32_cc2640.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1310,7 +1310,7 @@ static void handle_event(uint8_t *packet) {
13101310
// uint8_t attr_handle = (data[7] << 8) | data[6];
13111311
pbdrv_bluetooth_peripheral_t *peri = &peripheral_singleton;
13121312
if (peri->config->notification_handler) {
1313-
peri->config->notification_handler(&data[8], pdu_len - 2);
1313+
peri->config->notification_handler(peri, &data[8], pdu_len - 2);
13141314
}
13151315
}
13161316
break;

lib/pbio/include/pbdrv/bluetooth.h

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,14 +132,25 @@ typedef enum {
132132
PBDRV_BLUETOOTH_PERIPHERAL_OPTIONS_DISCONNECT_HOST = 1 << 1,
133133
} pbdrv_bluetooth_peripheral_options_t;
134134

135+
typedef struct _pbdrv_bluetooth_peripheral_t pbdrv_bluetooth_peripheral_t;
136+
137+
/**
138+
* Callback that is called when peripheral sends a notification.
139+
*
140+
* @param [in] peripheral The peripheral that sent the notification.
141+
* @param [in] data The data that was received.
142+
* @param [in] size The size of @p data in bytes.
143+
*/
144+
typedef void (*pbdrv_bluetooth_peripheral_notification_handler_t)(pbdrv_bluetooth_peripheral_t *peripheral, const uint8_t *data, uint32_t size);
145+
135146
/** Peripheral scan and connection configuration */
136147
typedef struct {
137148
/** Matcher for advertisement */
138149
pbdrv_bluetooth_ad_match_t match_adv;
139150
/** Matcher for scan response */
140151
pbdrv_bluetooth_ad_match_t match_adv_rsp;
141152
/** Handler for received notifications after connecting */
142-
pbdrv_bluetooth_receive_handler_t notification_handler;
153+
pbdrv_bluetooth_peripheral_notification_handler_t notification_handler;
143154
/** Option flags governing connection and pairing */
144155
pbdrv_bluetooth_peripheral_options_t options;
145156
/** Timeout before aborting scan and connect. Use 0 for no timeout. */
@@ -149,7 +160,7 @@ typedef struct {
149160
/**
150161
* State of a peripheral that the hub may be connected to, such as a remote.
151162
*/
152-
typedef struct {
163+
struct _pbdrv_bluetooth_peripheral_t {
153164
uint16_t con_handle;
154165
uint8_t status;
155166
uint8_t bdaddr_type;
@@ -169,7 +180,7 @@ typedef struct {
169180
pbio_os_timer_t watchdog;
170181
/** Cancellation requested */
171182
bool cancel;
172-
} pbdrv_bluetooth_peripheral_t;
183+
};
173184

174185
/** Advertisement types. */
175186
typedef enum {
@@ -341,6 +352,16 @@ pbio_error_t pbdrv_bluetooth_send_event_notification(pbio_os_state_t *state, pbi
341352
// Functions related to connections to peripherals.
342353
//
343354

355+
/**
356+
* Gets an available peripheral instance.
357+
*
358+
* @param [out] peripheral Pointer to the peripheral instance if found.
359+
* @return ::PBIO_SUCCESS if a peripheral instance is available.
360+
* ::PBIO_ERROR_NO_DEV if no peripheral instance is available.
361+
* ::PBIO_ERROR_BUSY if all peripheral instances are in use.
362+
*/
363+
pbio_error_t pbdrv_bluetooth_peripheral_get_available(pbdrv_bluetooth_peripheral_t **peripheral);
364+
344365
/**
345366
* Gets the name of the connected peripheral.
346367
*

pybricks/iodevices/pb_type_iodevices_lwp3device.c

Lines changed: 51 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -91,13 +91,37 @@ static mp_obj_t self_obj;
9191

9292
typedef struct {
9393
mp_obj_base_t base;
94+
/**
95+
* The peripheral instance associated with this MicroPython object.
96+
*/
97+
pbdrv_bluetooth_peripheral_t *peripheral;
98+
/**
99+
* Async iterable state.
100+
*/
94101
pb_type_async_t *iter;
95-
pbio_os_state_t sub;
102+
/**
103+
* Buttons object (property of Remote class).
104+
*/
96105
mp_obj_t buttons;
106+
/**
107+
* Light object (property of Remote class).
108+
*/
97109
mp_obj_t light;
110+
/**
111+
* Powered Up Remote Left button states, populated by notifications.
112+
*/
98113
uint8_t left[3];
114+
/**
115+
* Powered Up Remote Right button states, populated by notifications.
116+
*/
99117
uint8_t right[3];
118+
/**
119+
* Powered Up Remote Center button state, populated by notifications.
120+
*/
100121
uint8_t center;
122+
/**
123+
* The hub kind to filter advertisements for.
124+
*/
101125
lwp3_hub_kind_t hub_kind;
102126
// Null-terminated name used to filter advertisements and responses.
103127
// Also used as the name of the device when setting the name, since this
@@ -128,15 +152,20 @@ typedef struct {
128152
} pb_lwp3device_obj_t;
129153

130154
// Handles LEGO Wireless protocol messages from the Powered Up Remote.
131-
static pbio_pybricks_error_t handle_remote_notification(const uint8_t *value, uint32_t size) {
155+
static void handle_remote_notification(pbdrv_bluetooth_peripheral_t *peripheral, const uint8_t *value, uint32_t size) {
132156

157+
// No object registered for processing notifcations.
133158
if (self_obj == MP_OBJ_NULL) {
134-
// Silently ignore incoming notifications when we aren't expecting any.
135-
return PBIO_PYBRICKS_ERROR_OK;
159+
return;
136160
}
137161

138162
pb_lwp3device_obj_t *self = MP_OBJ_TO_PTR(self_obj);
139163

164+
// It's not for us.
165+
if (self->peripheral != peripheral) {
166+
return;
167+
}
168+
140169
if (value[0] == 5 && value[2] == LWP3_MSG_TYPE_HW_NET_CMDS && value[3] == LWP3_HW_NET_CMD_CONNECTION_REQ) {
141170
// This message is meant for something else, but contains the center button state
142171
self->center = value[4];
@@ -148,8 +177,6 @@ static pbio_pybricks_error_t handle_remote_notification(const uint8_t *value, ui
148177
memcpy(self->right, &value[4], 3);
149178
}
150179
}
151-
152-
return PBIO_PYBRICKS_ERROR_OK;
153180
}
154181

155182
static pbdrv_bluetooth_ad_match_result_flags_t lwp3_advertisement_matches(uint8_t event_type, const uint8_t *data, const char *name, const uint8_t *addr, const uint8_t *match_addr) {
@@ -278,6 +305,9 @@ static pbio_error_t pb_lwp3device_connect_thread(pbio_os_state_t *state, mp_obj_
278305

279306
PBIO_OS_ASYNC_BEGIN(state);
280307

308+
// Get available peripheral instance.
309+
pb_assert(pbdrv_bluetooth_peripheral_get_available(&self->peripheral));
310+
281311
// Scan and connect with timeout.
282312
pb_assert(pbdrv_bluetooth_peripheral_scan_and_connect(&scan_config));
283313
PBIO_OS_AWAIT(state, &unused, err = pbdrv_bluetooth_await_peripheral_command(&unused, NULL));
@@ -376,7 +406,7 @@ static pbio_error_t pb_lwp3device_connect_thread(pbio_os_state_t *state, mp_obj_
376406
PBIO_OS_ASYNC_END(PBIO_ERROR_IO);
377407
}
378408

379-
static mp_obj_t pb_lwp3device_connect(mp_obj_t self_in, mp_obj_t name_in, mp_obj_t timeout_in, lwp3_hub_kind_t hub_kind, pbdrv_bluetooth_receive_handler_t notification_handler, bool pair) {
409+
static mp_obj_t pb_lwp3device_connect(mp_obj_t self_in, mp_obj_t name_in, mp_obj_t timeout_in, lwp3_hub_kind_t hub_kind, pbdrv_bluetooth_peripheral_notification_handler_t notification_handler, bool pair) {
380410

381411
pb_lwp3device_obj_t *self = MP_OBJ_TO_PTR(self_in);
382412

@@ -555,18 +585,26 @@ MP_DEFINE_CONST_OBJ_TYPE(pb_type_pupdevices_Remote,
555585

556586
#if PYBRICKS_PY_IODEVICES_LWP3_DEVICE
557587

558-
static pbio_pybricks_error_t handle_lwp3_generic_notification(const uint8_t *value, uint32_t size) {
588+
/**
589+
* Handles LEGO Wireless protocol messages from generic LWP3 devices.
590+
*/
591+
static void handle_lwp3_generic_notification(pbdrv_bluetooth_peripheral_t *peripheral, const uint8_t *value, uint32_t size) {
559592

593+
// No object registered for processing notifcations.
560594
if (self_obj == MP_OBJ_NULL) {
561-
// Silently ignore incoming notifications when we aren't expecting any.
562-
return PBIO_PYBRICKS_ERROR_OK;
595+
return;
563596
}
564597

565598
pb_lwp3device_obj_t *self = MP_OBJ_TO_PTR(self_obj);
566599

600+
// It's not for us.
601+
if (self->peripheral != peripheral) {
602+
return;
603+
}
604+
567605
if (!self->noti_num) {
568-
// Allocated data not ready, but no error.
569-
return PBIO_PYBRICKS_ERROR_OK;
606+
// Allocated data not ready.
607+
return;
570608
}
571609

572610
// Buffer is full, so drop oldest sample by advancing read index.
@@ -581,7 +619,7 @@ static pbio_pybricks_error_t handle_lwp3_generic_notification(const uint8_t *val
581619
// to-be-read data. If it was already full when we started writing, both
582620
// indexes have now advanced so it is still full now.
583621
self->noti_data_full = self->noti_idx_read == self->noti_idx_write;
584-
return PBIO_PYBRICKS_ERROR_OK;
622+
return;
585623
}
586624

587625

pybricks/iodevices/pb_type_iodevices_xbox_controller.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,12 +82,11 @@ typedef struct {
8282
static pb_xbox_t pb_xbox_singleton;
8383

8484
// Handles LEGO Wireless protocol messages from the XBOX Device.
85-
static pbio_pybricks_error_t handle_notification(const uint8_t *value, uint32_t size) {
85+
static void handle_notification(pbdrv_bluetooth_peripheral_t *peripheral, const uint8_t *value, uint32_t size) {
8686
pb_xbox_t *xbox = &pb_xbox_singleton;
8787
if (size <= sizeof(xbox_input_map_t)) {
8888
memcpy(&xbox->state, &value[0], size);
8989
}
90-
return PBIO_PYBRICKS_ERROR_OK;
9190
}
9291

9392
#define _16BIT_AS_LE(x) ((x) & 0xff), (((x) >> 8) & 0xff)

0 commit comments

Comments
 (0)