Skip to content

Commit 9d4442e

Browse files
committed
handle reads/writes larger than buffers; add .write_timeout
1 parent e344c6d commit 9d4442e

File tree

5 files changed

+104
-16
lines changed

5 files changed

+104
-16
lines changed

shared-bindings/usb_cdc/Serial.c

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
//| :rtype: bytes"""
5757
//| ...
5858
//|
59-
//| def readinto(self, buf: WriteableBuffer) -> bytes:
59+
//| def readinto(self, buf: WriteableBuffer) -> int:
6060
//| """Read bytes into the ``buf``. If ``nbytes`` is specified then read at most
6161
//| that many bytes, subject to `timeout`. Otherwise, read at most ``len(buf)`` bytes.
6262
//|
@@ -219,6 +219,33 @@ const mp_obj_property_t usb_cdc_serial_timeout_obj = {
219219
(mp_obj_t)&mp_const_none_obj},
220220
};
221221

222+
//| write_timeout: Optional[float]
223+
//| """The initial value of `write_timeout` is ``None``. If ``None``, wait indefinitely to finish
224+
//| writing all the bytes passed to ``write()``.If 0, do not wait.
225+
//| If > 0, wait only ``write_timeout`` seconds."""
226+
//|
227+
STATIC mp_obj_t usb_cdc_serial_get_write_timeout(mp_obj_t self_in) {
228+
usb_cdc_serial_obj_t *self = MP_OBJ_TO_PTR(self_in);
229+
mp_float_t write_timeout = common_hal_usb_cdc_serial_get_write_timeout(self);
230+
return (write_timeout < 0.0f) ? mp_const_none : mp_obj_new_float(self->write_timeout);
231+
}
232+
MP_DEFINE_CONST_FUN_OBJ_1(usb_cdc_serial_get_write_timeout_obj, usb_cdc_serial_get_write_timeout);
233+
234+
STATIC mp_obj_t usb_cdc_serial_set_write_timeout(mp_obj_t self_in, mp_obj_t write_timeout_in) {
235+
usb_cdc_serial_obj_t *self = MP_OBJ_TO_PTR(self_in);
236+
common_hal_usb_cdc_serial_set_write_timeout(self,
237+
write_timeout_in == mp_const_none ? -1.0f : mp_obj_get_float(write_timeout_in));
238+
return mp_const_none;
239+
}
240+
MP_DEFINE_CONST_FUN_OBJ_2(usb_cdc_serial_set_write_timeout_obj, usb_cdc_serial_set_write_timeout);
241+
242+
const mp_obj_property_t usb_cdc_serial_write_timeout_obj = {
243+
.base.type = &mp_type_property,
244+
.proxy = {(mp_obj_t)&usb_cdc_serial_get_write_timeout_obj,
245+
(mp_obj_t)&usb_cdc_serial_set_write_timeout_obj,
246+
(mp_obj_t)&mp_const_none_obj},
247+
};
248+
222249

223250
STATIC const mp_rom_map_elem_t usb_cdc_serial_locals_dict_table[] = {
224251
// Standard stream methods.
@@ -235,6 +262,7 @@ STATIC const mp_rom_map_elem_t usb_cdc_serial_locals_dict_table[] = {
235262
{ MP_OBJ_NEW_QSTR(MP_QSTR_reset_input_buffer), MP_ROM_PTR(&usb_cdc_serial_reset_input_buffer_obj) },
236263
{ MP_OBJ_NEW_QSTR(MP_QSTR_reset_output_buffer), MP_ROM_PTR(&usb_cdc_serial_reset_output_buffer_obj) },
237264
{ MP_OBJ_NEW_QSTR(MP_QSTR_timeout), MP_ROM_PTR(&usb_cdc_serial_timeout_obj) },
265+
{ MP_OBJ_NEW_QSTR(MP_QSTR_write_timeout), MP_ROM_PTR(&usb_cdc_serial_write_timeout_obj) },
238266

239267
// Not in pyserial protocol.
240268
{ MP_OBJ_NEW_QSTR(MP_QSTR_connected), MP_ROM_PTR(&usb_cdc_serial_connected_obj) },

shared-bindings/usb_cdc/Serial.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,7 @@ extern bool common_hal_usb_cdc_serial_get_connected(usb_cdc_serial_obj_t *self);
4747
extern mp_float_t common_hal_usb_cdc_serial_get_timeout(usb_cdc_serial_obj_t *self);
4848
extern void common_hal_usb_cdc_serial_set_timeout(usb_cdc_serial_obj_t *self, mp_float_t timeout);
4949

50+
extern mp_float_t common_hal_usb_cdc_serial_get_write_timeout(usb_cdc_serial_obj_t *self);
51+
extern void common_hal_usb_cdc_serial_set_write_timeout(usb_cdc_serial_obj_t *self, mp_float_t write_timeout);
52+
5053
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_USB_CDC_SERIAL_H

shared-module/usb_cdc/Serial.c

Lines changed: 67 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -31,32 +31,78 @@
3131
#include "tusb.h"
3232

3333
size_t common_hal_usb_cdc_serial_read(usb_cdc_serial_obj_t *self, uint8_t *data, size_t len, int *errcode) {
34-
if (self->timeout < 0.0f) {
35-
while (tud_cdc_n_available(self->idx) < len) {
34+
35+
const bool wait_forever = self->timeout < 0.0f;
36+
const bool wait_for_timeout = self->timeout > 0.0f;
37+
38+
// Read up to len bytes immediately.
39+
// The number of bytes read will not be larger than what is already in the TinyUSB FIFO.
40+
uint32_t total_num_read = tud_cdc_n_read(self->idx, data, len);
41+
42+
if (wait_forever || wait_for_timeout) {
43+
// Read more if we have time.
44+
uint64_t timeout_ms = self->timeout * 1000; // Junk value if timeout < 0.
45+
uint64_t start_ticks = supervisor_ticks_ms64();
46+
47+
uint32_t num_read = 0;
48+
while (total_num_read < len &&
49+
(wait_forever || supervisor_ticks_ms64() - start_ticks <= timeout_ms)) {
50+
51+
// Wait for a bit, and check for ctrl-C.
3652
RUN_BACKGROUND_TASKS;
3753
if (mp_hal_is_interrupted()) {
3854
return 0;
3955
}
56+
57+
// Advance buffer pointer and reduce number of bytes that need to be read.
58+
len -= num_read;
59+
data += num_read;
60+
61+
// Try to read another batch of bytes.
62+
num_read = tud_cdc_n_read(self->idx, data, len);
63+
total_num_read += num_read;
4064
}
41-
} else if (self->timeout > 0.0f) {
42-
uint64_t timeout_ms = self->timeout * 1000;
65+
}
66+
67+
return total_num_read;
68+
}
69+
70+
size_t common_hal_usb_cdc_serial_write(usb_cdc_serial_obj_t *self, const uint8_t *data, size_t len, int *errcode) {
71+
const bool wait_forever = self->write_timeout < 0.0f;
72+
const bool wait_for_timeout = self->write_timeout > 0.0f;
73+
74+
// Write as many bytes as possible immediately.
75+
// The number of bytes written at once will not be larger than what can fit in the TinyUSB FIFO.
76+
uint32_t total_num_written = tud_cdc_n_write(self->idx, data, len);
77+
tud_cdc_n_write_flush(self->idx);
78+
79+
if (wait_forever || wait_for_timeout) {
80+
// Write more if we have time.
81+
uint64_t timeout_ms = self->write_timeout * 1000; // Junk value if write_timeout < 0.
4382
uint64_t start_ticks = supervisor_ticks_ms64();
44-
while (tud_cdc_n_available(self->idx) < len &&
45-
supervisor_ticks_ms64() - start_ticks <= timeout_ms) {
83+
84+
uint32_t num_written = 0;
85+
while (total_num_written < len &&
86+
(wait_forever || supervisor_ticks_ms64() - start_ticks <= timeout_ms)) {
87+
88+
// Wait for a bit, and check for ctrl-C.
4689
RUN_BACKGROUND_TASKS;
4790
if (mp_hal_is_interrupted()) {
4891
return 0;
4992
}
93+
94+
// Advance buffer pointer and reduce number of bytes that need to be written.
95+
len -= num_written;
96+
data += num_written;
97+
98+
// Try to write another batch of bytes.
99+
num_written = tud_cdc_n_write(self->idx, data, len);
100+
tud_cdc_n_write_flush(self->idx);
101+
total_num_written += num_written;
50102
}
51103
}
52-
// Timeout of 0.0f falls through to here with no waiting or unnecessary calculation.
53-
return tud_cdc_n_read(self->idx, data, len);
54-
}
55104

56-
size_t common_hal_usb_cdc_serial_write(usb_cdc_serial_obj_t *self, const uint8_t *data, size_t len, int *errcode) {
57-
uint32_t num_written = tud_cdc_n_write(self->idx, data, len);
58-
tud_cdc_n_write_flush(self->idx);
59-
return num_written;
105+
return total_num_written;
60106
}
61107

62108
uint32_t common_hal_usb_cdc_serial_get_in_waiting(usb_cdc_serial_obj_t *self) {
@@ -91,3 +137,11 @@ mp_float_t common_hal_usb_cdc_serial_get_timeout(usb_cdc_serial_obj_t *self) {
91137
void common_hal_usb_cdc_serial_set_timeout(usb_cdc_serial_obj_t *self, mp_float_t timeout) {
92138
self->timeout = timeout;
93139
}
140+
141+
mp_float_t common_hal_usb_cdc_serial_get_write_timeout(usb_cdc_serial_obj_t *self) {
142+
return self->write_timeout;
143+
}
144+
145+
void common_hal_usb_cdc_serial_set_write_timeout(usb_cdc_serial_obj_t *self, mp_float_t write_timeout) {
146+
self->write_timeout = write_timeout;
147+
}

shared-module/usb_cdc/Serial.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,9 @@
3131

3232
typedef struct {
3333
mp_obj_base_t base;
34-
mp_float_t timeout; // if negative, wait forever.
35-
uint8_t idx; // which CDC device?
34+
mp_float_t timeout; // if negative, wait forever.
35+
mp_float_t write_timeout; // if negative, wait forever.
36+
uint8_t idx; // which CDC device?
3637
} usb_cdc_serial_obj_t;
3738

3839
#endif // SHARED_MODULE_USB_CDC_SERIAL_H

shared-module/usb_cdc/__init__.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,12 @@
4141
static usb_cdc_serial_obj_t serial_objs[CFG_TUD_CDC] = {
4242
{ .base.type = &usb_cdc_serial_type,
4343
.timeout = -1.0f,
44+
.write_timeout = -1.0f,
4445
.idx = 0,
4546
}, {
4647
.base.type = &usb_cdc_serial_type,
4748
.timeout = -1.0f,
49+
.write_timeout = -1.0f,
4850
.idx = 1,
4951
}
5052
};

0 commit comments

Comments
 (0)