Skip to content

Commit fa38d7c

Browse files
committed
pybricks.iodevices.LWP3Device: Simplify common data.
Instead of hardcoding for the remote, use a generic buffer. We could use a union of the various application formats, but it is nicer to just keep that near the implementation details.
1 parent bed4073 commit fa38d7c

1 file changed

Lines changed: 46 additions & 65 deletions

File tree

pybricks/iodevices/pb_type_iodevices_lwp3device.c

Lines changed: 46 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -107,25 +107,13 @@ typedef struct {
107107
*/
108108
mp_obj_t light;
109109
/**
110-
* Powered Up Remote Left button states, populated by notifications.
110+
* Application specific data, like cached button state, populated by notifications.
111111
*/
112-
uint8_t left[3];
113-
/**
114-
* Powered Up Remote Right button states, populated by notifications.
115-
*/
116-
uint8_t right[3];
117-
/**
118-
* Powered Up Remote Center button state, populated by notifications.
119-
*/
120-
uint8_t center;
112+
uint8_t data[8];
121113
/**
122114
* Routine to run after establishing a connection (e.g. subscribing to ports).
123115
*/
124116
pbio_os_process_func_t post_connect_setup_func;
125-
/**
126-
* Routine to before (re-)establishing a connection (e.g. clearing stale data.)
127-
*/
128-
mp_fun_1_t pre_connect_func;
129117
// Null-terminated name used to filter advertisements and responses.
130118
// Also used as the name of the device when setting the name, since this
131119
// is not updated in the driver until the next time it connects.
@@ -313,10 +301,14 @@ static void pb_type_lwp3device_intialize_connection(mp_obj_t self_in, mp_obj_t c
313301

314302
bool want_connection = mp_obj_is_true(connect_in);
315303

316-
// Reinitialize or clear data before connecting.
317-
if (self->pre_connect_func) {
318-
self->pre_connect_func(self_in);
319-
}
304+
// Clear data before reconnecting.
305+
memset(self->data, 0, sizeof(self->data));
306+
307+
// Clear past notifications (for generic LWP3 class).
308+
memset(self->notification_buffer, 0, LWP3_MAX_MESSAGE_SIZE * self->noti_num);
309+
self->noti_idx_read = 0;
310+
self->noti_idx_write = 0;
311+
self->noti_data_full = false;
320312

321313
// Attempt to re-use existing connection.
322314
pbio_error_t err = pbdrv_bluetooth_peripheral_get_connected(&self->peripheral, self, &self->scan_config);
@@ -394,13 +386,13 @@ static void pb_type_remote_handle_notification(void *user, const uint8_t *value,
394386
}
395387
if (value[0] == 5 && value[2] == LWP3_MSG_TYPE_HW_NET_CMDS && value[3] == LWP3_HW_NET_CMD_CONNECTION_REQ) {
396388
// This message is meant for something else, but contains the center button state
397-
self->center = value[4];
389+
self->data[6] = value[4];
398390
} else if (value[0] == 7 && value[2] == LWP3_MSG_TYPE_PORT_VALUE) {
399391
// This assumes that the handset button ports have already been set to mode KEYSD
400392
if (value[3] == REMOTE_PORT_LEFT_BUTTONS) {
401-
memcpy(self->left, &value[4], 3);
393+
memcpy(&self->data[0], &value[4], 3);
402394
} else if (value[3] == REMOTE_PORT_RIGHT_BUTTONS) {
403-
memcpy(self->right, &value[4], 3);
395+
memcpy(&self->data[3], &value[4], 3);
404396
}
405397
}
406398
}
@@ -415,25 +407,25 @@ mp_obj_t pb_type_remote_button_pressed(mp_obj_t self_in) {
415407
mp_obj_t pressed[7];
416408
size_t num = 0;
417409

418-
if (self->left[0]) {
410+
if (self->data[0]) {
419411
pressed[num++] = pb_type_button_new(MP_QSTR_LEFT_PLUS);
420412
}
421-
if (self->left[1]) {
413+
if (self->data[1]) {
422414
pressed[num++] = pb_type_button_new(MP_QSTR_LEFT);
423415
}
424-
if (self->left[2]) {
416+
if (self->data[2]) {
425417
pressed[num++] = pb_type_button_new(MP_QSTR_LEFT_MINUS);
426418
}
427-
if (self->right[0]) {
419+
if (self->data[3]) {
428420
pressed[num++] = pb_type_button_new(MP_QSTR_RIGHT_PLUS);
429421
}
430-
if (self->right[1]) {
422+
if (self->data[4]) {
431423
pressed[num++] = pb_type_button_new(MP_QSTR_RIGHT);
432424
}
433-
if (self->right[2]) {
425+
if (self->data[5]) {
434426
pressed[num++] = pb_type_button_new(MP_QSTR_RIGHT_MINUS);
435427
}
436-
if (self->center) {
428+
if (self->data[6]) {
437429
pressed[num++] = pb_type_button_new(MP_QSTR_CENTER);
438430
}
439431

@@ -564,15 +556,6 @@ static pbio_error_t pb_type_remote_post_connect(pbio_os_state_t *state, mp_obj_t
564556
PBIO_OS_ASYNC_END(PBIO_SUCCESS);
565557
}
566558

567-
static mp_obj_t pb_type_remote_clear(mp_obj_t self_in) {
568-
pb_type_lwp3device_obj_t *self = MP_OBJ_TO_PTR(self_in);
569-
// Ensure that no buttons are "pressed" after reconnecting
570-
memset(&self->left, 0, sizeof(self->left));
571-
memset(&self->right, 0, sizeof(self->right));
572-
self->center = 0;
573-
return mp_const_none;
574-
}
575-
576559
static mp_obj_t pb_type_remote_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
577560
PB_PARSE_ARGS_CLASS(n_args, n_kw, args,
578561
PB_ARG_DEFAULT_NONE(name),
@@ -589,7 +572,6 @@ static mp_obj_t pb_type_remote_make_new(const mp_obj_type_t *type, size_t n_args
589572
self->hub_kind = LWP3_HUB_KIND_HANDSET;
590573

591574
self->post_connect_setup_func = pb_type_remote_post_connect;
592-
self->pre_connect_func = pb_type_remote_clear;
593575

594576
self->scan_config = (pbdrv_bluetooth_peripheral_connect_config_t) {
595577
.match_adv = pb_type_lwp3device_advertisement_matches,
@@ -645,37 +627,49 @@ static void pb_type_technic_move_hub_handle_notification(void *user, const uint8
645627
// Not processing any notifications. We could monitor the hub's internal sensors.
646628
}
647629

630+
/**
631+
* Stored format for the common data field in the lwp3 object.
632+
*/
633+
typedef struct {
634+
uint8_t speed_now;
635+
uint8_t steering_now;
636+
uint8_t speed_last;
637+
uint8_t steering_last;
638+
} pb_type_lwp3device_technic_movehub_data_t;
639+
648640
static pbio_error_t pb_type_technic_move_hub_write_command(mp_obj_t self_in) {
649641
pb_type_lwp3device_obj_t *self = MP_OBJ_TO_PTR(self_in);
650642

651643
// Don't repeat again if already sent idential values this many
652644
// times in this interval.
653645
const uint8_t max_repeat = 2;
654646
const uint32_t max_repeat_timeout = 500;
655-
647+
648+
pb_type_lwp3device_technic_movehub_data_t *data = (void *)self->data;
649+
656650
// Reusing the remote button buffer to store drive state.
657-
bool identical = self->right[0] == self->left[0] && self->right[1] == self->left[1];
651+
bool identical = data->speed_last == data->speed_now && data->steering_last == data->steering_now;
658652

659653
// Count identical messages sent in short time span, using center for counter.
660654
if (!identical || pbio_os_timer_is_expired(&self->timer)) {
661-
self->center = 0;
655+
self->data[4] = 0;
662656
}
663657

664658
// If we sent the same thing several times within timeout, it probably arrived.
665-
if (self->center == max_repeat) {
659+
if (self->data[4] == max_repeat) {
666660
return PBIO_SUCCESS;
667661
}
668662

669663
// Send command and keep track of the time.
670664
uint8_t light_mode = 0;
671-
self->right[0] = self->left[0];
672-
self->right[1] = self->left[1];
665+
data->speed_last = data->speed_now;
666+
data->steering_last = data->steering_now;
673667

674-
self->center = pbio_int_math_min(self->center + 1, max_repeat);
668+
self->data[4] = pbio_int_math_min(self->data[4] + 1, max_repeat);
675669
pbio_os_timer_set(&self->timer, max_repeat_timeout);
676-
670+
677671
const uint8_t cmd[] = {
678-
0x0d, 0x00, 0x81, 0x36, 0x11, 0x51, 0x00, 0x03, 0x00, self->left[0], self->left[1], light_mode, 0,
672+
0x0d, 0x00, 0x81, 0x36, 0x11, 0x51, 0x00, 0x03, 0x00, data->speed_now, data->steering_now, light_mode, 0,
679673
};
680674
return pbdrv_bluetooth_peripheral_write_characteristic(self->peripheral, self->lwp3_char_handle, cmd, sizeof(cmd));
681675
}
@@ -728,9 +722,10 @@ static mp_obj_t pb_type_technic_move_hub_drive_power(size_t n_args, const mp_obj
728722
PB_PARSE_ARGS_METHOD(n_args, pos_args, kw_args,
729723
pb_type_lwp3device_obj_t, self,
730724
PB_ARG_REQUIRED(power));
731-
725+
732726
mp_obj_t self_in = MP_OBJ_FROM_PTR(self);
733-
self->left[0] = pbio_int_math_clamp(pb_obj_get_int(power_in), 100);
727+
pb_type_lwp3device_technic_movehub_data_t *data = (void *)self->data;
728+
data->speed_now = pbio_int_math_clamp(pb_obj_get_int(power_in), 100);
734729
pb_assert(pb_type_technic_move_hub_write_command(self_in));
735730
return wait_or_await_operation(self_in);
736731
}
@@ -744,7 +739,8 @@ static mp_obj_t pb_type_technic_move_hub_steer(size_t n_args, const mp_obj_t *po
744739

745740
// Steering is a percentage of the calibrated angle. Go just under maximum
746741
// to avoid pushing against the mechanical constraint.
747-
self->left[1] = pbio_int_math_clamp(pb_obj_get_int(percentage_in), 97);
742+
pb_type_lwp3device_technic_movehub_data_t *data = (void *)self->data;
743+
data->steering_now = pbio_int_math_clamp(pb_obj_get_int(percentage_in), 97);
748744
pb_assert(pb_type_technic_move_hub_write_command(self_in));
749745
return wait_or_await_operation(self_in);
750746
}
@@ -766,9 +762,6 @@ static mp_obj_t pb_type_technic_move_hub_make_new(const mp_obj_type_t *type, siz
766762
self->hub_kind = LWP3_HUB_KIND_TECHNIC_MOVE;
767763
self->post_connect_setup_func = pb_type_technic_move_hub_post_connect;
768764

769-
// Re-using the unused remote left buffer to store drive state.
770-
self->pre_connect_func = pb_type_remote_clear;
771-
772765
self->scan_config = (pbdrv_bluetooth_peripheral_connect_config_t) {
773766
.match_adv = pb_type_lwp3device_advertisement_matches,
774767
.match_adv_rsp = pb_type_lwp3device_advertisement_response_matches,
@@ -822,17 +815,6 @@ static void pb_type_lwp3device_handle_notification_generic(void *user, const uin
822815
self->noti_data_full = self->noti_idx_read == self->noti_idx_write;
823816
}
824817

825-
826-
static mp_obj_t pb_type_iodevices_lwp3device_clear(mp_obj_t self_in) {
827-
pb_type_lwp3device_obj_t *self = MP_OBJ_TO_PTR(self_in);
828-
// Clear past notifications.
829-
memset(self->notification_buffer, 0, LWP3_MAX_MESSAGE_SIZE * self->noti_num);
830-
self->noti_idx_read = 0;
831-
self->noti_idx_write = 0;
832-
self->noti_data_full = false;
833-
return mp_const_none;
834-
}
835-
836818
static mp_obj_t pb_type_lwp3device_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
837819
PB_PARSE_ARGS_CLASS(n_args, n_kw, args,
838820
PB_ARG_REQUIRED(hub_kind),
@@ -859,7 +841,6 @@ static mp_obj_t pb_type_lwp3device_make_new(const mp_obj_type_t *type, size_t n_
859841
.notification_handler = pb_type_lwp3device_handle_notification_generic,
860842
.options = mp_obj_is_true(pair_in) ? PBDRV_BLUETOOTH_PERIPHERAL_OPTIONS_PAIR : PBDRV_BLUETOOTH_PERIPHERAL_OPTIONS_NONE,
861843
};
862-
self->pre_connect_func = pb_type_iodevices_lwp3device_clear;
863844
self->post_connect_setup_func = NULL;
864845
pb_type_lwp3device_set_name_filter_and_timeout(self, name_in, timeout_in);
865846

0 commit comments

Comments
 (0)