Skip to content

Commit fbaa411

Browse files
committed
pybricks.iodevices.UARTDevice: Use new awaitable.
Also flush UART when opening, in case program stopped during prior transmission.
1 parent a8e5de8 commit fbaa411

File tree

1 file changed

+34
-59
lines changed

1 file changed

+34
-59
lines changed

pybricks/iodevices/pb_type_uart_device.c

Lines changed: 34 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@
1616

1717
#include <pybricks/common.h>
1818
#include <pybricks/parameters.h>
19+
#include <pybricks/tools/pb_type_async.h>
1920

2021
#include <pybricks/util_mp/pb_kwarg_helper.h>
2122
#include <pybricks/util_mp/pb_obj_helper.h>
22-
#include <pybricks/common/pb_type_device.h>
2323
#include <pybricks/util_pb/pb_error.h>
2424

2525
// pybricks.iodevices.uart_device class object
@@ -28,12 +28,10 @@ typedef struct _pb_type_uart_device_obj_t {
2828
pbio_port_t *port;
2929
pbdrv_uart_dev_t *uart_dev;
3030
uint32_t timeout;
31-
pbio_os_state_t write_pt;
31+
pb_type_async_t *write_iter;
3232
mp_obj_t write_obj;
33-
mp_obj_t write_awaitables;
34-
pbio_os_state_t read_pt;
33+
pb_type_async_t *read_iter;
3534
mp_obj_t read_obj;
36-
mp_obj_t read_awaitables;
3735
} pb_type_uart_device_obj_t;
3836

3937
// pybricks.iodevices.UARTDevice.__init__
@@ -62,31 +60,27 @@ static mp_obj_t pb_type_uart_device_make_new(const mp_obj_type_t *type, size_t n
6260
pb_assert(pbio_port_get_port(port_id, &self->port));
6361
pbio_port_set_mode(self->port, PBIO_PORT_MODE_UART);
6462
pb_assert(pbio_port_get_uart_dev(self->port, &self->uart_dev));
63+
pbdrv_uart_flush(self->uart_dev);
6564

66-
// List of awaitables associated with reading and writing.
67-
self->write_awaitables = mp_obj_new_list(0, NULL);
68-
self->read_awaitables = mp_obj_new_list(0, NULL);
65+
// Awaitables associated with reading and writing.
66+
self->write_iter = NULL;
67+
self->read_iter = NULL;
6968

7069
return MP_OBJ_FROM_PTR(self);
7170
}
7271

73-
static bool pb_type_uart_device_write_test_completion(mp_obj_t self_in, uint32_t end_time) {
72+
static pbio_error_t pb_type_uart_device_write_iter_once(pbio_os_state_t *state, mp_obj_t self_in) {
7473
pb_type_uart_device_obj_t *self = MP_OBJ_TO_PTR(self_in);
7574
GET_STR_DATA_LEN(self->write_obj, data, data_len);
75+
return pbdrv_uart_write(state, self->uart_dev, (uint8_t *)data, data_len, self->timeout);
76+
}
7677

77-
// Runs one iteration of the write protothread.
78-
pbio_error_t err = pbdrv_uart_write(&self->read_pt, self->uart_dev, (uint8_t *)data, data_len, self->timeout);
79-
if (err == PBIO_ERROR_AGAIN) {
80-
// Not done yet, so return false.
81-
return false;
82-
}
83-
84-
// Complete or stopped, so allow written object to be garbage collected.
85-
self->write_obj = mp_const_none;
86-
87-
// Either completed or timed out, so assert it.
88-
pb_assert(err);
89-
return true;
78+
static mp_obj_t pb_type_uart_device_write_return_map(mp_obj_t self_in) {
79+
pb_type_uart_device_obj_t *self = MP_OBJ_TO_PTR(self_in);
80+
// Write always returns none, but this is effectively a completion callback.
81+
// So we can use it to disconnect the write object so it can be garbage collected.
82+
self->write_obj = MP_OBJ_NULL;
83+
return mp_const_none;
9084
}
9185

9286
// pybricks.iodevices.UARTDevice.write
@@ -101,20 +95,16 @@ static mp_obj_t pb_type_uart_device_write(size_t n_args, const mp_obj_t *pos_arg
10195
pb_assert(PBIO_ERROR_INVALID_ARG);
10296
}
10397

104-
// Reset protothread state.
105-
self->write_pt = 0;
106-
10798
// Prevents this object from being garbage collected while the write is in progress.
10899
self->write_obj = data_in;
109100

110-
return pb_type_awaitable_await_or_wait(
111-
MP_OBJ_FROM_PTR(self),
112-
self->write_awaitables,
113-
pb_type_awaitable_end_time_none,
114-
pb_type_uart_device_write_test_completion,
115-
pb_type_awaitable_return_none,
116-
pb_type_awaitable_cancel_none,
117-
PB_TYPE_AWAITABLE_OPT_RAISE_ON_BUSY);
101+
pb_type_async_t config = {
102+
.iter_once = pb_type_uart_device_write_iter_once,
103+
.parent_obj = MP_OBJ_FROM_PTR(self),
104+
.return_map = pb_type_uart_device_write_return_map,
105+
};
106+
pb_type_async_schedule_cancel(self->write_iter);
107+
return pb_type_async_wait_or_await(&config, &self->write_iter);
118108
}
119109
static MP_DEFINE_CONST_FUN_OBJ_KW(pb_type_uart_device_write_obj, 1, pb_type_uart_device_write);
120110

@@ -127,27 +117,16 @@ static mp_obj_t pb_type_uart_device_in_waiting(mp_obj_t self_in) {
127117
}
128118
static MP_DEFINE_CONST_FUN_OBJ_1(pb_type_uart_device_in_waiting_obj, pb_type_uart_device_in_waiting);
129119

130-
static bool pb_type_uart_device_read_test_completion(mp_obj_t self_in, uint32_t end_time) {
120+
static pbio_error_t pb_type_uart_device_read_iter_once(pbio_os_state_t *state, mp_obj_t self_in) {
131121
pb_type_uart_device_obj_t *self = MP_OBJ_TO_PTR(self_in);
132-
133122
mp_obj_str_t *str = MP_OBJ_TO_PTR(self->read_obj);
134-
135-
// Runs one iteration of the read protothread.
136-
pbio_error_t err = pbdrv_uart_read(&self->read_pt, self->uart_dev, (uint8_t *)str->data, str->len, self->timeout);
137-
if (err == PBIO_ERROR_AGAIN) {
138-
// Not done yet, so return false.
139-
return false;
140-
}
141-
142-
// Either completed or timed out, so assert it.
143-
pb_assert(err);
144-
return true;
123+
return pbdrv_uart_read(state, self->uart_dev, (uint8_t *)str->data, str->len, self->timeout);
145124
}
146125

147-
static mp_obj_t pb_type_uart_device_read_return_value(mp_obj_t self_in) {
126+
static mp_obj_t pb_type_uart_device_read_return_map(mp_obj_t self_in) {
148127
pb_type_uart_device_obj_t *self = MP_OBJ_TO_PTR(self_in);
149128
mp_obj_t ret = self->read_obj;
150-
self->read_obj = mp_const_none;
129+
self->read_obj = MP_OBJ_NULL;
151130
return ret;
152131
}
153132

@@ -162,17 +141,13 @@ static mp_obj_t pb_type_uart_device_read(size_t n_args, const mp_obj_t *pos_args
162141
mp_obj_t args[] = { length_in };
163142
self->read_obj = MP_OBJ_TYPE_GET_SLOT(&mp_type_bytes, make_new)((mp_obj_t)&mp_type_bytes, MP_ARRAY_SIZE(args), 0, args);
164143

165-
// Reset protothread state.
166-
self->read_pt = 0;
167-
168-
return pb_type_awaitable_await_or_wait(
169-
MP_OBJ_FROM_PTR(self),
170-
self->read_awaitables,
171-
pb_type_awaitable_end_time_none,
172-
pb_type_uart_device_read_test_completion,
173-
pb_type_uart_device_read_return_value,
174-
pb_type_awaitable_cancel_none,
175-
PB_TYPE_AWAITABLE_OPT_RAISE_ON_BUSY);
144+
pb_type_async_t config = {
145+
.iter_once = pb_type_uart_device_read_iter_once,
146+
.parent_obj = MP_OBJ_FROM_PTR(self),
147+
.return_map = pb_type_uart_device_read_return_map,
148+
};
149+
pb_type_async_schedule_cancel(self->read_iter);
150+
return pb_type_async_wait_or_await(&config, &self->read_iter);
176151
}
177152
static MP_DEFINE_CONST_FUN_OBJ_KW(pb_type_uart_device_read_obj, 1, pb_type_uart_device_read);
178153

0 commit comments

Comments
 (0)