Skip to content

Commit

Permalink
pybricks.common.BLE: Allow sending single object.
Browse files Browse the repository at this point in the history
This makes it simple to send and receive single values.

It is also necessary for an upcoming non-Python implementation.
  • Loading branch information
laurensvalk committed Oct 24, 2023
1 parent 42a1b63 commit 357fdd7
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 9 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
in beta versions, this is not a breaking change ([support#1054]).
- New color distance function used by the color sensors that is more
consistent when distinguishing user-provided colors ([pybricks-micropython#104]).
- Updated the unreleased BLE API to ensure sent and received objects are the
same. Allows one of the supported types or a list/tuple thereof.

### Fixed
- Improved external device detection speed ([support#1140]).
Expand Down
42 changes: 33 additions & 9 deletions pybricks/common/pb_type_ble.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ typedef enum {
PB_BLE_BROADCAST_DATA_TYPE_STR = 5,
/** The Python @c bytes type. */
PB_BLE_BROADCAST_DATA_TYPE_BYTES = 6,
/** Indicator that the next value is the one and only value (instead of a tuple). */
PB_BLE_BROADCAST_DATA_TYPE_SINGLE_OBJECT = 7,
} pb_ble_broadcast_data_type_t;

#define MFG_SPECIFIC 0xFF
Expand Down Expand Up @@ -244,14 +246,14 @@ STATIC size_t pb_module_ble_encode(void *dst, size_t index, mp_obj_t arg) {
* Sets the broadcast advertising data and enables broadcasting on the Bluetooth
* radio if it is not already enabled.
*
* The first argument is the "channel" and the remaining arguments are encoded
* in the advertising data.
* The data can be one object of the allowed types, or a tuple/list thereof.
*
* @param [in] n_args The number of args.
* @param [in] args The args passed in Python code.
* @throws ValueError If the channel is out of range or the encoded arguments
* exceeded the available space.
* @throws TypeError If any of the arguments are of a type that can't be encoded.
* @param [in] n_args The number of args.
* @param [in] pos_args The args passed in Python code.
* @param [in] kw_args The kwargs passed in Python code.
* @throws ValueError If the channel is out of range or the encoded arguments
* exceed the available space.
* @throws TypeError If any of the arguments are of a type that can't be encoded.
*/
STATIC mp_obj_t pb_module_ble_broadcast(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
PB_PARSE_ARGS_METHOD(n_args, pos_args, kw_args,
Expand All @@ -268,11 +270,23 @@ STATIC mp_obj_t pb_module_ble_broadcast(size_t n_args, const mp_obj_t *pos_args,
uint8_t d[5 + OBSERVED_DATA_MAX_SIZE];
} value;

// Get either one or several data objects ready for transmission.
mp_obj_t *objs;
size_t n_objs;
size_t index = 0;
mp_obj_get_array(data_in, &n_objs, &objs);
size_t index;
if (mp_obj_is_type(data_in, &mp_type_tuple) || mp_obj_is_type(data_in, &mp_type_list)) {
index = 0;
mp_obj_get_array(data_in, &n_objs, &objs);
} else {
// Set first type to indicate single object.
value.v.data[5] = PB_BLE_BROADCAST_DATA_TYPE_SINGLE_OBJECT << 5;
// The one and only value is included directly after.
index = 1;
n_objs = 1;
objs = &data_in;
}

// Encode all objects.
for (size_t i = 0; i < n_objs; i++) {
index = pb_module_ble_encode(&value.v.data[5], index, objs[i]);
}
Expand Down Expand Up @@ -360,6 +374,10 @@ STATIC mp_obj_t pb_module_ble_decode(observed_data_t *data, size_t *index) {
(*index) += size;
return mp_obj_new_bytes(bytes_data, size);
}
case PB_BLE_BROADCAST_DATA_TYPE_SINGLE_OBJECT:
// Does not contain data by itself, is only used as indicator
// that the next data is the one and only object.
break;
}

mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("received bad data"));
Expand Down Expand Up @@ -411,6 +429,12 @@ STATIC mp_obj_t pb_module_ble_observe(mp_obj_t self_in, mp_obj_t channel_in) {
return mp_const_none;
}

// Handle single object.
if (ch_data->size != 0 && ch_data->data[0] >> 5 == PB_BLE_BROADCAST_DATA_TYPE_SINGLE_OBJECT) {
size_t value_index = 1;
return pb_module_ble_decode(ch_data, &value_index);
}

// Objects can be encoded in as little as one byte so we could have up to
// this many objects received.
mp_obj_t items[OBSERVED_DATA_MAX_SIZE];
Expand Down

0 comments on commit 357fdd7

Please sign in to comment.