Skip to content

Commit

Permalink
pybricks.common.BLE: Implement observe_enable()
Browse files Browse the repository at this point in the history
This allows users to toggle observing off and on so that they can alternate between observing and broadcasting.

This results in better stability on Technic Hub which can lock up when simultaneous advertising and broadcasting.

Fixes pybricks/support#1806
  • Loading branch information
laurensvalk committed Oct 4, 2024
1 parent f47c21f commit 3a5d824
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 10 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
- Allow color objects to be iterated as h, s, v = color_object or indexed
as color_object[0]. This allows access to these properties in block
coding ([support#1661]).
- Added `observe_enable` to the hub `BLE` class to selectively turn observing
on and off, just like you can with broadcasting ([support#1806]).

### Changed

Expand All @@ -32,6 +34,7 @@
[support#1623]: https://github.com/pybricks/support/issues/1623
[support#1661]: https://github.com/pybricks/support/issues/1661
[support#1668]: https://github.com/pybricks/support/issues/1668
[support#1806]: https://github.com/pybricks/support/issues/1806
[support#1846]: https://github.com/pybricks/support/issues/1846
[support#1858]: https://github.com/pybricks/support/issues/1858
[support#1863]: https://github.com/pybricks/support/issues/1863
Expand Down
41 changes: 31 additions & 10 deletions pybricks/common/pb_type_ble.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,11 @@ static observed_data_t *observed_data;
static uint8_t num_observed_data;

static pbio_task_t broadcast_task;
static pbio_task_t toggle_observe_task;

typedef struct {
mp_obj_base_t base;
mp_obj_t broadcast_channel;
pbio_task_t *broadcast_task;
observed_data_t observed_data[];
} pb_obj_BLE_t;

Expand Down Expand Up @@ -306,8 +306,8 @@ static mp_obj_t pb_module_ble_broadcast(size_t n_args, const mp_obj_t *pos_args,
pbio_set_uint16_le(&value.v.data[2], LEGO_CID);
value.v.data[4] = mp_obj_get_int(self->broadcast_channel);

pbdrv_bluetooth_start_broadcasting(self->broadcast_task, &value.v);
return pb_module_tools_pbio_task_wait_or_await(self->broadcast_task);
pbdrv_bluetooth_start_broadcasting(&broadcast_task, &value.v);
return pb_module_tools_pbio_task_wait_or_await(&broadcast_task);
}
static MP_DEFINE_CONST_FUN_OBJ_KW(pb_module_ble_broadcast_obj, 1, pb_module_ble_broadcast);

Expand Down Expand Up @@ -406,7 +406,7 @@ static const observed_data_t *pb_module_ble_get_channel_data(mp_obj_t channel_in
observed_data_t *ch_data = lookup_observed_data(channel);

if (!ch_data) {
mp_raise_ValueError(MP_ERROR_TEXT("channel not allocated"));
mp_raise_ValueError(MP_ERROR_TEXT("channel not configured"));
}

// Reset the data if it is too old.
Expand Down Expand Up @@ -467,6 +467,28 @@ static mp_obj_t pb_module_ble_observe(mp_obj_t self_in, mp_obj_t channel_in) {
}
static MP_DEFINE_CONST_FUN_OBJ_2(pb_module_ble_observe_obj, pb_module_ble_observe);

/**
* Enables or disable observing
*
* @param [in] self_in The BLE object.
* @param [in] enable_in Thruthy to enable, falsy to disable.
* @returns Awaitable.
*/
static mp_obj_t pb_module_ble_observe_enable(mp_obj_t self_in, mp_obj_t enable_in) {

if (num_observed_data == 0) {
mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("channel not configured"));
}

if (mp_obj_is_true(enable_in)) {
pbdrv_bluetooth_start_observing(&toggle_observe_task, handle_observe_event);
} else {
pbdrv_bluetooth_stop_observing(&toggle_observe_task);
}
return pb_module_tools_pbio_task_wait_or_await(&toggle_observe_task);
}
static MP_DEFINE_CONST_FUN_OBJ_2(pb_module_ble_observe_enable_obj, pb_module_ble_observe_enable);

/**
* Retrieves the filtered RSSI signal strength of the given channel.
*
Expand Down Expand Up @@ -496,6 +518,7 @@ static MP_DEFINE_CONST_FUN_OBJ_1(pb_module_ble_version_obj, pb_module_ble_versio
static const mp_rom_map_elem_t common_BLE_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_broadcast), MP_ROM_PTR(&pb_module_ble_broadcast_obj) },
{ MP_ROM_QSTR(MP_QSTR_observe), MP_ROM_PTR(&pb_module_ble_observe_obj) },
{ MP_ROM_QSTR(MP_QSTR_observe_enable), MP_ROM_PTR(&pb_module_ble_observe_enable_obj) },
{ MP_ROM_QSTR(MP_QSTR_signal_strength), MP_ROM_PTR(&pb_module_ble_signal_strength_obj) },
{ MP_ROM_QSTR(MP_QSTR_version), MP_ROM_PTR(&pb_module_ble_version_obj) },
};
Expand All @@ -519,6 +542,7 @@ static MP_DEFINE_CONST_OBJ_TYPE(pb_type_BLE,
mp_obj_t pb_type_BLE_new(mp_obj_t broadcast_channel_in, mp_obj_t observe_channels_in) {
// making the assumption that this is only called once before each pb_type_ble_start_cleanup()
assert(observed_data == NULL);
pb_module_tools_assert_blocking();

// Validate channel arguments.
if (broadcast_channel_in != mp_const_none && (mp_obj_get_int(broadcast_channel_in) < 0 || mp_obj_get_int(broadcast_channel_in) > UINT8_MAX)) {
Expand All @@ -537,7 +561,6 @@ mp_obj_t pb_type_BLE_new(mp_obj_t broadcast_channel_in, mp_obj_t observe_channel
#endif // PBSYS_CONFIG_BLUETOOTH_TOGGLE

pb_obj_BLE_t *self = mp_obj_malloc_var(pb_obj_BLE_t, observed_data_t, num_observe_channels, &pb_type_BLE);
self->broadcast_task = &broadcast_task;
self->broadcast_channel = broadcast_channel_in;

for (mp_int_t i = 0; i < num_observe_channels; i++) {
Expand All @@ -559,11 +582,9 @@ mp_obj_t pb_type_BLE_new(mp_obj_t broadcast_channel_in, mp_obj_t observe_channel
observed_data = self->observed_data;
num_observed_data = num_observe_channels;

// Start observing.
// Start observing right away by default.
if (num_observe_channels > 0) {
pbio_task_t task;
pbdrv_bluetooth_start_observing(&task, handle_observe_event);
pb_module_tools_pbio_task_do_blocking(&task, -1);
pb_module_ble_observe_enable(MP_OBJ_FROM_PTR(self), mp_const_true);
}

return MP_OBJ_FROM_PTR(self);
Expand All @@ -576,7 +597,7 @@ void pb_type_ble_start_cleanup(void) {
pbdrv_bluetooth_stop_observing(&stop_observing_task);
observed_data = NULL;
num_observed_data = 0;
// Tasks awaited in pybricks de-init.
// The aforementioned tasks started here are awaited in pybricks de-init.
}

#endif // PYBRICKS_PY_COMMON_BLE

0 comments on commit 3a5d824

Please sign in to comment.