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}
119109static 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}
128118static 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}
177152static MP_DEFINE_CONST_FUN_OBJ_KW (pb_type_uart_device_read_obj , 1 , pb_type_uart_device_read ) ;
178153
0 commit comments