Skip to content

Commit dbd9175

Browse files
committed
pbio/drv/legodev: Replace unplug reset by watchdog.
This keeps the device connection manager in control even if the UART device and PT threads get in a confused state. Fixes pybricks/support#1137
1 parent 920bd47 commit dbd9175

File tree

5 files changed

+48
-22
lines changed

5 files changed

+48
-22
lines changed

CHANGELOG.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@
44

55
## [Unreleased]
66

7+
### Fixed
78
- Fixed Technic (Extra) Large motors not working ([support#1131]) on all hubs.
89
- Fixed Powered Up Light not working ([support#1131]) on all hubs.
10+
- Fixed UART sensors not working on Technic Hub ([support#1137]).
911

10-
[support#1064]: https://github.com/pybricks/support/issues/1131
12+
[support#1131]: https://github.com/pybricks/support/issues/1131
13+
[support#1137]: https://github.com/pybricks/support/issues/1137
1114

1215
## [3.3.0b7] - 2023-06-30
1316

lib/pbio/drv/legodev/legodev_pup.c

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@
3434
/** The number of consecutive repeated detections needed for an affirmative ID. */
3535
#define AFFIRMATIVE_MATCH_COUNT 20
3636

37+
/** If the UART device did not call back to this driver after this time, assume
38+
it is disconnected and restart device detection. */
39+
#define UART_WATCHDOG_TIMEOUT 1100
40+
3741
typedef enum {
3842
DEV_ID_GROUP_GND,
3943
DEV_ID_GROUP_VCC,
@@ -49,6 +53,7 @@ typedef struct {
4953
uint8_t gpio_value;
5054
uint8_t prev_gpio_value;
5155
uint8_t dev_id_match_count;
56+
struct timer watchdog;
5257
} dcm_data_t;
5358

5459
typedef struct {
@@ -325,6 +330,13 @@ PROCESS_THREAD(pbio_legodev_pup_process, ev, data) {
325330
for (int i = 0; i < PBDRV_CONFIG_LEGODEV_PUP_NUM_EXT_DEV; i++) {
326331
dev = &ext_devs[i];
327332

333+
// If UART device was connected but not reporting data, restart detection.
334+
if (dev->connected_type_id == PBDRV_LEGODEV_TYPE_ID_LPF2_UNKNOWN_UART &&
335+
dev->connected_type_id == dev->prev_type_id && timer_expired(&dev->dcm.watchdog)) {
336+
dev->connected_type_id = PBDRV_LEGODEV_TYPE_ID_NONE;
337+
dev->dcm.dev_id_match_count = 0;
338+
}
339+
328340
// Keep running device detection unless UART sensor is attached.
329341
if (dev->connected_type_id != PBDRV_LEGODEV_TYPE_ID_LPF2_UNKNOWN_UART) {
330342
poll_dcm(dev);
@@ -383,6 +395,7 @@ void pbdrv_legodev_init(void) {
383395
const pbdrv_ioport_pup_port_platform_data_t *port_data = &pbdrv_ioport_pup_platform_data.ports[legodev_data->ioport_index];
384396
legodev->ext_dev->pdata = legodev_data;
385397
legodev->ext_dev->pins = &port_data->pins;
398+
timer_set(&legodev->ext_dev->dcm.watchdog, UART_WATCHDOG_TIMEOUT);
386399

387400
// Initialize uart device manager.
388401
pbio_dcmotor_t *dcmotor;
@@ -394,25 +407,28 @@ void pbdrv_legodev_init(void) {
394407
pbdrv_legodev_pup_uart_process_start();
395408
}
396409

410+
static pbdrv_legodev_dev_t *pbdrv_legodev_get_parent_of(pbdrv_legodev_pup_uart_dev_t *uartdev) {
411+
for (uint8_t i = 0; i < PBIO_ARRAY_SIZE(devs); i++) {
412+
pbdrv_legodev_dev_t *dev = &devs[i];
413+
if (!dev->is_internal && dev->ext_dev->uart_dev == uartdev) {
414+
return dev;
415+
}
416+
}
417+
return NULL;
418+
}
419+
397420
/**
398-
* Resets device detection. Called by legodev_uart if a device gets out of sync, usually by unplugging.
421+
* Resets device connection watchdog timer. This allows the detection manager
422+
* to resume when a UART device stopped working, usually by being unplugged.
399423
*
400424
* @param [in] dev legodev device.
401425
*/
402-
void pbdrv_legodev_pup_reset_device_detection(pbdrv_legodev_pup_uart_dev_t *uartdev) {
403-
for (uint8_t i = 0; i < PBIO_ARRAY_SIZE(devs); i++) {
404-
pbdrv_legodev_dev_t *dev = &devs[i];
405-
if (dev->is_internal) {
406-
// Internal devices don't have a uart device.
407-
continue;
408-
}
409-
if (dev->ext_dev->uart_dev == uartdev) {
410-
// On match reset device connection manager state.
411-
dev->ext_dev->connected_type_id = PBDRV_LEGODEV_TYPE_ID_NONE;
412-
dev->ext_dev->dcm.dev_id_match_count = 0;
413-
return;
414-
}
426+
void pbdrv_legodev_pup_reset_watchdog(pbdrv_legodev_pup_uart_dev_t *uartdev) {
427+
pbdrv_legodev_dev_t *dev = pbdrv_legodev_get_parent_of(uartdev);
428+
if (dev == NULL) {
429+
return;
415430
}
431+
timer_restart(&dev->ext_dev->dcm.watchdog);
416432
}
417433

418434
pbdrv_legodev_pup_uart_dev_t *pbdrv_legodev_get_uart_dev(pbdrv_legodev_dev_t *legodev) {

lib/pbio/drv/legodev/legodev_pup.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@ extern const pbdrv_legodev_pup_int_platform_data_t
3333
extern const pbdrv_legodev_pup_ext_platform_data_t
3434
pbdrv_legodev_pup_ext_platform_data[PBDRV_CONFIG_LEGODEV_PUP_NUM_EXT_DEV];
3535

36-
void pbdrv_legodev_pup_reset_device_detection(pbdrv_legodev_pup_uart_dev_t *dev);
36+
void pbdrv_legodev_pup_reset_watchdog(pbdrv_legodev_pup_uart_dev_t *uartdev);
3737

3838
#else
3939

40-
static inline void pbdrv_legodev_pup_reset_device_detection(pbdrv_legodev_pup_uart_dev_t *dev) {
40+
static inline void pbdrv_legodev_pup_reset_watchdog(pbdrv_legodev_pup_uart_dev_t *uartdev) {
4141
}
4242

4343
#endif // PBDRV_CONFIG_LEGODEV_PUP

lib/pbio/drv/legodev/legodev_pup_uart.c

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,7 @@ static void pbdrv_legodev_request_data_set(pbdrv_legodev_pup_uart_dev_t *port_da
264264
void pbdrv_legodev_pup_uart_start_sync(pbdrv_legodev_pup_uart_dev_t *dev) {
265265
debug_pr_str("Wait for STATUS_SYNCING: set\n");
266266
dev->status = PBDRV_LEGODEV_PUP_UART_STATUS_SYNCING;
267+
pbdrv_legodev_pup_reset_watchdog(dev);
267268
process_poll(&pbdrv_legodev_pup_uart_process);
268269
}
269270

@@ -294,6 +295,9 @@ static void pbdrv_legodev_pup_uart_parse_msg(pbdrv_legodev_pup_uart_dev_t *data)
294295
uint32_t speed;
295296
uint8_t msg_type, cmd, msg_size, mode, cmd2;
296297

298+
// Getting messages from the device means it is alive.
299+
pbdrv_legodev_pup_reset_watchdog(data);
300+
297301
msg_type = data->rx_msg[0] & LUMP_MSG_TYPE_MASK;
298302
cmd = data->rx_msg[0] & LUMP_MSG_CMD_MASK;
299303
msg_size = ev3_uart_get_msg_size(data->rx_msg[0]);
@@ -633,7 +637,6 @@ static void pbdrv_legodev_pup_uart_parse_msg(pbdrv_legodev_pup_uart_dev_t *data)
633637
err:
634638
data->status = PBDRV_LEGODEV_PUP_UART_STATUS_ERR;
635639
debug_pr("Data error: %s\n", data->last_err);
636-
pbdrv_legodev_pup_reset_device_detection(data);
637640
}
638641

639642
static uint8_t ev3_uart_set_msg_hdr(lump_msg_type_t type, lump_msg_size_t size, lump_cmd_t cmd) {
@@ -726,6 +729,9 @@ static PT_THREAD(pbdrv_legodev_pup_uart_update(pbdrv_legodev_pup_uart_dev_t * da
726729
uint8_t speed_payload[4];
727730
pbio_set_uint32_le(speed_payload, EV3_UART_SPEED_LPF2);
728731
ev3_uart_prepare_tx_msg(data, LUMP_MSG_TYPE_CMD, LUMP_CMD_SPEED, speed_payload, sizeof(speed_payload));
732+
733+
pbdrv_uart_flush(data->uart);
734+
729735
PT_SPAWN(&data->pt, &data->write_pt, pbdrv_legodev_pup_uart_send_prepared_msg(data, &err));
730736
if (err != PBIO_SUCCESS) {
731737
DBG_ERR(data->last_err = "Speed tx failed");
@@ -734,6 +740,8 @@ static PT_THREAD(pbdrv_legodev_pup_uart_update(pbdrv_legodev_pup_uart_dev_t * da
734740

735741
pbdrv_uart_flush(data->uart);
736742

743+
pbdrv_legodev_pup_reset_watchdog(data);
744+
737745
// read one byte to check for ACK
738746
PBIO_PT_WAIT_READY(&data->pt, err = pbdrv_uart_read_begin(data->uart, data->rx_msg, 1, 10));
739747
if (err != PBIO_SUCCESS) {
@@ -755,6 +763,9 @@ static PT_THREAD(pbdrv_legodev_pup_uart_update(pbdrv_legodev_pup_uart_dev_t * da
755763

756764
// To get in sync with the data stream from the sensor, we look for a valid TYPE command.
757765
for (;;) {
766+
767+
pbdrv_legodev_pup_reset_watchdog(data);
768+
758769
PBIO_PT_WAIT_READY(&data->pt, err = pbdrv_uart_read_begin(data->uart, data->rx_msg, 1, EV3_UART_IO_TIMEOUT));
759770
if (err != PBIO_SUCCESS) {
760771
DBG_ERR(data->last_err = "UART Rx error during sync");
@@ -974,9 +985,6 @@ static PT_THREAD(pbdrv_legodev_pup_uart_update(pbdrv_legodev_pup_uart_dev_t * da
974985
// Turn off battery supply to this port
975986
pbdrv_motor_driver_coast(data->dcmotor->motor_driver);
976987

977-
// reset device detection manager
978-
pbdrv_legodev_pup_reset_device_detection(data);
979-
980988
PT_END(&data->pt);
981989
}
982990

lib/pbio/test/src/test_uartdev.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
#include <pbio/util.h>
2020
#include <test-pbio.h>
2121

22-
#include "../drv/legodev/legodev_pup.h"
2322
#include "../drv/legodev/legodev_pup_uart.h"
2423

2524
#include "../src/processes.h"

0 commit comments

Comments
 (0)