summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Halbert <halbert@halwitz.org>2021-02-16 17:11:37 -0500
committerDan Halbert <halbert@halwitz.org>2021-02-16 17:39:36 -0500
commitc26de0136a0ad746bf0ace600a1a9d3ff428c4c6 (patch)
tree7d79966fa0fbfdb9604454cf7b3b8e44ba225816
parent0b8f1b9a9039ab2ad4d43cc1d9bc388518ab0d38 (diff)
works! no timeouts
-rw-r--r--ports/cxd56/mpconfigport.mk3
-rw-r--r--shared-bindings/usb_cdc/Serial.c122
-rw-r--r--shared-bindings/usb_cdc/Serial.h13
-rw-r--r--shared-bindings/usb_cdc/__init__.c7
-rw-r--r--shared-module/usb_cdc/Serial.c27
-rw-r--r--tools/gen_usb_descriptor.py87
6 files changed, 213 insertions, 46 deletions
diff --git a/ports/cxd56/mpconfigport.mk b/ports/cxd56/mpconfigport.mk
index e1ffc79d0..ab39e3bb7 100644
--- a/ports/cxd56/mpconfigport.mk
+++ b/ports/cxd56/mpconfigport.mk
@@ -7,6 +7,9 @@ USB_CDC_EP_NUM_DATA_IN = 1
USB_MSC_EP_NUM_OUT = 5
USB_MSC_EP_NUM_IN = 4
+# Number of USB endpoint pairs.
+USB_NUM_EP = 5
+
MPY_TOOL_LONGINT_IMPL = -mlongint-impl=mpz
CIRCUITPY_AUDIOBUSIO = 0
diff --git a/shared-bindings/usb_cdc/Serial.c b/shared-bindings/usb_cdc/Serial.c
index 72e9482a2..03fb94f31 100644
--- a/shared-bindings/usb_cdc/Serial.c
+++ b/shared-bindings/usb_cdc/Serial.c
@@ -67,12 +67,16 @@
//| ...
//|
//| def write(self, buf: ReadableBuffer) -> Optional[int]:
-//| """Write the buffer of bytes to the bus.
+//| """Write as many bytes as possible from the buffer of bytes.
//|
//| :return: the number of bytes written
//| :rtype: int or None"""
//| ...
//|
+//| def flush(self) -> None:
+//| """Force out any unwritten bytes, waiting until they are written."""
+//| ...
+//|
// These three methods are used by the shared stream methods.
STATIC mp_uint_t usb_cdc_serial_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) {
@@ -97,27 +101,121 @@ STATIC mp_uint_t usb_cdc_serial_write(mp_obj_t self_in, const void *buf_in, mp_u
STATIC mp_uint_t usb_cdc_serial_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) {
usb_cdc_serial_obj_t *self = MP_OBJ_TO_PTR(self_in);
mp_uint_t ret;
- if (request == MP_IOCTL_POLL) {
- mp_uint_t flags = arg;
- ret = 0;
- if ((flags & MP_IOCTL_POLL_RD) && common_hal_usb_cdc_serial_bytes_available(self) > 0) {
- ret |= MP_IOCTL_POLL_RD;
- }
- if ((flags & MP_IOCTL_POLL_WR) && common_hal_usb_cdc_serial_ready_to_tx(self)) {
- ret |= MP_IOCTL_POLL_WR;
+ switch (request) {
+ case MP_IOCTL_POLL: {
+ mp_uint_t flags = arg;
+ ret = 0;
+ if ((flags & MP_IOCTL_POLL_RD) && common_hal_usb_cdc_serial_get_in_waiting(self) > 0) {
+ ret |= MP_IOCTL_POLL_RD;
+ }
+ if ((flags & MP_IOCTL_POLL_WR) && common_hal_usb_cdc_serial_get_out_waiting(self) == 0) {
+ ret |= MP_IOCTL_POLL_WR;
+ }
+ break;
}
- } else {
- *errcode = MP_EINVAL;
- ret = MP_STREAM_ERROR;
+
+ case MP_STREAM_FLUSH:
+ common_hal_usb_cdc_serial_flush(self);
+ break;
+
+ default:
+ *errcode = MP_EINVAL;
+ ret = MP_STREAM_ERROR;
}
return ret;
}
+//| connected: bool
+//| """True if this Serial is connected to a host. (read-only)"""
+//|
+STATIC mp_obj_t usb_cdc_serial_get_connected(mp_obj_t self_in) {
+ usb_cdc_serial_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return mp_obj_new_bool(common_hal_usb_cdc_serial_get_connected(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(usb_cdc_serial_get_connected_obj, usb_cdc_serial_get_connected);
+
+const mp_obj_property_t usb_cdc_serial__connected_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&usb_cdc_serial_get_connected_obj,
+ (mp_obj_t)&mp_const_none_obj,
+ (mp_obj_t)&mp_const_none_obj},
+};
+
+//| in_waiting: int
+//| """Returns the number of bytes waiting to be read on the USB serial input. (read-only)"""
+//|
+STATIC mp_obj_t usb_cdc_serial_get_in_waiting(mp_obj_t self_in) {
+ usb_cdc_serial_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return mp_obj_new_int(common_hal_usb_cdc_serial_get_in_waiting(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(usb_cdc_serial_get_in_waiting_obj, usb_cdc_serial_get_in_waiting);
+
+const mp_obj_property_t usb_cdc_serial_in_waiting_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&usb_cdc_serial_get_in_waiting_obj,
+ (mp_obj_t)&mp_const_none_obj,
+ (mp_obj_t)&mp_const_none_obj},
+};
+
+//| out_waiting: int
+//| """Returns the number of bytes waiting to be written on the USB serial output. (read-only)"""
+//|
+STATIC mp_obj_t usb_cdc_serial_get_out_waiting(mp_obj_t self_in) {
+ usb_cdc_serial_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return mp_obj_new_int(common_hal_usb_cdc_serial_get_out_waiting(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(usb_cdc_serial_get_out_waiting_obj, usb_cdc_serial_get_out_waiting);
+
+const mp_obj_property_t usb_cdc_serial_out_waiting_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&usb_cdc_serial_get_out_waiting_obj,
+ (mp_obj_t)&mp_const_none_obj,
+ (mp_obj_t)&mp_const_none_obj},
+};
+
+//| def reset_input_buffer(self) -> None:
+//| """Clears any unread bytes."""
+//| ...
+//|
+STATIC mp_obj_t usb_cdc_serial_reset_input_buffer(mp_obj_t self_in) {
+ usb_cdc_serial_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_usb_cdc_serial_reset_input_buffer(self);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(usb_cdc_serial_reset_input_buffer_obj, usb_cdc_serial_reset_input_buffer);
+
+//| def reset_output_buffer(self) -> None:
+//| """Clears any unwritten bytes."""
+//| ...
+//|
+STATIC mp_obj_t usb_cdc_serial_reset_output_buffer(mp_obj_t self_in) {
+ usb_cdc_serial_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_usb_cdc_serial_reset_output_buffer(self);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(usb_cdc_serial_reset_output_buffer_obj, usb_cdc_serial_reset_output_buffer);
+
+
STATIC const mp_rom_map_elem_t usb_cdc_serial_locals_dict_table[] = {
// Standard stream methods.
+ { MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&mp_stream_flush_obj) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
+ { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj)},
+ { MP_ROM_QSTR(MP_QSTR_readlines), MP_ROM_PTR(&mp_stream_unbuffered_readlines_obj)},
{ MP_OBJ_NEW_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
+
+ // Other pyserial-inspired attributes.
+ { MP_OBJ_NEW_QSTR(MP_QSTR_in_waiting), MP_ROM_PTR(&usb_cdc_serial_in_waiting_obj) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_out_waiting), MP_ROM_PTR(&usb_cdc_serial_out_waiting_obj) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_reset_input_buffer), MP_ROM_PTR(&usb_cdc_serial_reset_input_buffer_obj) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_reset_output_buffer), MP_ROM_PTR(&usb_cdc_serial_reset_output_buffer_obj) },
+
+ // Not in pyserial protocol.
+ { MP_OBJ_NEW_QSTR(MP_QSTR_connected), MP_ROM_PTR(&usb_cdc_serial_get_connected_obj) },
+
+
+
};
STATIC MP_DEFINE_CONST_DICT(usb_cdc_serial_locals_dict, usb_cdc_serial_locals_dict_table);
diff --git a/shared-bindings/usb_cdc/Serial.h b/shared-bindings/usb_cdc/Serial.h
index 1ef4167d5..6e54b9ad3 100644
--- a/shared-bindings/usb_cdc/Serial.h
+++ b/shared-bindings/usb_cdc/Serial.h
@@ -32,9 +32,16 @@
extern const mp_obj_type_t usb_cdc_serial_type;
extern size_t common_hal_usb_cdc_serial_read(usb_cdc_serial_obj_t *self, uint8_t *data, size_t len, int *errcode);
-extern uint32_t common_hal_usb_cdc_serial_bytes_available(usb_cdc_serial_obj_t *self);
-extern void common_hal_usb_cdc_serial_clear_buffer(usb_cdc_serial_obj_t *self);
extern size_t common_hal_usb_cdc_serial_write(usb_cdc_serial_obj_t *self, const uint8_t *data, size_t len, int *errcode);
-extern bool common_hal_usb_cdc_serial_ready_to_tx(usb_cdc_serial_obj_t *self);
+
+extern uint32_t common_hal_usb_cdc_serial_get_in_waiting(usb_cdc_serial_obj_t *self);
+extern uint32_t common_hal_usb_cdc_serial_get_out_waiting(usb_cdc_serial_obj_t *self);
+
+extern void common_hal_usb_cdc_serial_reset_input_buffer(usb_cdc_serial_obj_t *self);
+extern uint32_t common_hal_usb_cdc_serial_reset_output_buffer(usb_cdc_serial_obj_t *self);
+
+extern uint32_t common_hal_usb_cdc_serial_flush(usb_cdc_serial_obj_t *self);
+
+extern bool common_hal_usb_cdc_serial_get_connected(usb_cdc_serial_obj_t *self);
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_USB_CDC_SERIAL_H
diff --git a/shared-bindings/usb_cdc/__init__.c b/shared-bindings/usb_cdc/__init__.c
index 6ded44c4f..eb9c25e00 100644
--- a/shared-bindings/usb_cdc/__init__.c
+++ b/shared-bindings/usb_cdc/__init__.c
@@ -36,10 +36,13 @@
//| """USB CDC Serial streams
//|
-//| The `usb_cdc` module allows access to USB CDC (serial) communications.
+//| The `usb_cdc` module allows access to USB CDC (serial) communications."""
//|
//| serials: Tuple[Serial, ...]
-//| """Tuple of all CDC streams. Each item is a `Serial`."""
+//| """Tuple of all CDC streams. Each item is a `Serial`.
+//| ``serials[0]`` is the USB REPL connection.
+//| ``serials[1]`` is a second USB serial connection, unconnected to the REPL.
+//| """
//|
static const mp_map_elem_t usb_cdc_module_globals_table[] = {
diff --git a/shared-module/usb_cdc/Serial.c b/shared-module/usb_cdc/Serial.c
index 663b23c25..bd3972c8d 100644
--- a/shared-module/usb_cdc/Serial.c
+++ b/shared-module/usb_cdc/Serial.c
@@ -31,14 +31,33 @@ size_t common_hal_usb_cdc_serial_read(usb_cdc_serial_obj_t *self, uint8_t *data,
return tud_cdc_n_read(self->idx, data, len);
}
-uint32_t common_hal_usb_cdc_serial_bytes_available(usb_cdc_serial_obj_t *self) {
+size_t common_hal_usb_cdc_serial_write(usb_cdc_serial_obj_t *self, const uint8_t *data, size_t len, int *errcode) {
+ uint32_t num_written = tud_cdc_n_write(self->idx, data, len);
+ tud_cdc_n_write_flush(self->idx);
+ return num_written;
+}
+
+uint32_t common_hal_usb_cdc_serial_get_in_waiting(usb_cdc_serial_obj_t *self) {
return tud_cdc_n_available(self->idx);
}
-size_t common_hal_usb_cdc_serial_write(usb_cdc_serial_obj_t *self, const uint8_t *data, size_t len, int *errcode) {
- return tud_cdc_n_write(self->idx, data, len);
+uint32_t common_hal_usb_cdc_serial_get_out_waiting(usb_cdc_serial_obj_t *self) {
+ // Return number of FIFO bytes currently occupied.
+ return CFG_TUD_CDC_TX_BUFSIZE - tud_cdc_n_write_available(self->idx);
+}
+
+void common_hal_usb_cdc_serial_reset_input_buffer(usb_cdc_serial_obj_t *self) {
+ tud_cdc_n_read_flush(self->idx);
+}
+
+uint32_t common_hal_usb_cdc_serial_reset_output_buffer(usb_cdc_serial_obj_t *self) {
+ return tud_cdc_n_write_clear(self->idx);
+}
+
+uint32_t common_hal_usb_cdc_serial_flush(usb_cdc_serial_obj_t *self) {
+ return tud_cdc_n_write_flush(self->idx);
}
-bool common_hal_usb_cdc_serial_ready_to_tx(usb_cdc_serial_obj_t *self) {
+bool common_hal_usb_cdc_serial_get_connected(usb_cdc_serial_obj_t *self) {
return tud_cdc_n_connected(self->idx);
}
diff --git a/tools/gen_usb_descriptor.py b/tools/gen_usb_descriptor.py
index 3f4249f0a..089d00ff2 100644
--- a/tools/gen_usb_descriptor.py
+++ b/tools/gen_usb_descriptor.py
@@ -77,12 +77,27 @@ parser.add_argument(
help="endpoint number of CDC NOTIFICATION",
)
parser.add_argument(
+ "--cdc2_ep_num_notification",
+ type=int,
+ default=0,
+ help="endpoint number of CDC2 NOTIFICATION",
+)
+parser.add_argument(
"--cdc_ep_num_data_out", type=int, default=0, help="endpoint number of CDC DATA OUT"
)
parser.add_argument(
"--cdc_ep_num_data_in", type=int, default=0, help="endpoint number of CDC DATA IN"
)
parser.add_argument(
+ "--cdc2_ep_num_data_out",
+ type=int,
+ default=0,
+ help="endpoint number of CDC2 DATA OUT",
+)
+parser.add_argument(
+ "--cdc2_ep_num_data_in", type=int, default=0, help="endpoint number of CDC2 DATA IN"
+)
+parser.add_argument(
"--msc_ep_num_out", type=int, default=0, help="endpoint number of MSC OUT"
)
parser.add_argument(
@@ -146,36 +161,41 @@ if not args.renumber_endpoints:
if include_cdc:
if args.cdc_ep_num_notification == 0:
raise ValueError("CDC notification endpoint number must not be 0")
- elif args.cdc_ep_num_data_out == 0:
+ if args.cdc_ep_num_data_out == 0:
raise ValueError("CDC data OUT endpoint number must not be 0")
- elif args.cdc_ep_num_data_in == 0:
+ if args.cdc_ep_num_data_in == 0:
raise ValueError("CDC data IN endpoint number must not be 0")
if include_cdc2:
- raise ValueError("Second CDC not supported without renumbering endpoints")
+ if args.cdc2_ep_num_notification == 0:
+ raise ValueError("CDC2 notification endpoint number must not be 0")
+ if args.cdc2_ep_num_data_out == 0:
+ raise ValueError("CDC2 data OUT endpoint number must not be 0")
+ if args.cdc2_ep_num_data_in == 0:
+ raise ValueError("CDC2 data IN endpoint number must not be 0")
if include_msc:
if args.msc_ep_num_out == 0:
raise ValueError("MSC endpoint OUT number must not be 0")
- elif args.msc_ep_num_in == 0:
+ if args.msc_ep_num_in == 0:
raise ValueError("MSC endpoint IN number must not be 0")
if include_hid:
if args.args.hid_ep_num_out == 0:
raise ValueError("HID endpoint OUT number must not be 0")
- elif args.hid_ep_num_in == 0:
+ if args.hid_ep_num_in == 0:
raise ValueError("HID endpoint IN number must not be 0")
if include_audio:
if args.args.midi_ep_num_out == 0:
raise ValueError("MIDI endpoint OUT number must not be 0")
- elif args.midi_ep_num_in == 0:
+ if args.midi_ep_num_in == 0:
raise ValueError("MIDI endpoint IN number must not be 0")
if include_vendor:
if args.vendor_ep_num_out == 0:
raise ValueError("VENDOR endpoint OUT number must not be 0")
- elif args.vendor_ep_num_in == 0:
+ if args.vendor_ep_num_in == 0:
raise ValueError("VENDOR endpoint IN number must not be 0")
@@ -228,18 +248,22 @@ device = standard.DeviceDescriptor(
def make_cdc_union(name):
return cdc.Union(
description="{} comm".format(name),
- bMasterInterface=0x00, # Adjust this after interfaces are renumbered.
+ # Set bMasterInterface and bSlaveInterface_list to proper values after interfaces are renumbered.
+ bMasterInterface=0x00,
bSlaveInterface_list=[0x01],
- ) # Adjust this after interfaces are renumbered.
+ )
def make_cdc_call_management(name):
+ # Set bDataInterface to proper value after interfaces are renumbered.
return cdc.CallManagement(
description="{} comm".format(name), bmCapabilities=0x01, bDataInterface=0x01
- ) # Adjust this after interfaces are renumbered.
+ )
-def make_cdc_comm_interface(name, cdc_union):
+def make_cdc_comm_interface(
+ name, cdc_union, cdc_call_management, cdc_ep_num_notification
+):
return standard.InterfaceDescriptor(
description="{} comm".format(name),
bInterfaceClass=cdc.CDC_CLASS_COMM, # Communications Device Class
@@ -255,7 +279,7 @@ def make_cdc_comm_interface(name, cdc_union):
cdc_union,
standard.EndpointDescriptor(
description="{} comm in".format(name),
- bEndpointAddress=args.cdc_ep_num_notification
+ bEndpointAddress=cdc_ep_num_notification
| standard.EndpointDescriptor.DIRECTION_IN,
bmAttributes=standard.EndpointDescriptor.TYPE_INTERRUPT,
wMaxPacketSize=0x0040,
@@ -265,7 +289,7 @@ def make_cdc_comm_interface(name, cdc_union):
)
-def make_cdc_data_interface(name):
+def make_cdc_data_interface(name, cdc_ep_num_data_in, cdc_ep_num_data_out):
return standard.InterfaceDescriptor(
description="{} data".format(name),
bInterfaceClass=cdc.CDC_CLASS_DATA,
@@ -273,7 +297,7 @@ def make_cdc_data_interface(name):
subdescriptors=[
standard.EndpointDescriptor(
description="{} data out".format(name),
- bEndpointAddress=args.cdc_ep_num_data_out
+ bEndpointAddress=cdc_ep_num_data_out
| standard.EndpointDescriptor.DIRECTION_OUT,
bmAttributes=standard.EndpointDescriptor.TYPE_BULK,
bInterval=0,
@@ -281,7 +305,7 @@ def make_cdc_data_interface(name):
),
standard.EndpointDescriptor(
description="{} data in".format(name),
- bEndpointAddress=args.cdc_ep_num_data_in
+ bEndpointAddress=cdc_ep_num_data_in
| standard.EndpointDescriptor.DIRECTION_IN,
bmAttributes=standard.EndpointDescriptor.TYPE_BULK,
bInterval=0,
@@ -294,16 +318,24 @@ def make_cdc_data_interface(name):
if include_cdc:
cdc_union = make_cdc_union("CDC")
cdc_call_management = make_cdc_call_management("CDC")
- cdc_comm_interface = make_cdc_comm_interface("CDC", cdc_union)
- cdc_data_interface = make_cdc_data_interface("CDC")
+ cdc_comm_interface = make_cdc_comm_interface(
+ "CDC", cdc_union, cdc_call_management, args.cdc_ep_num_notification
+ )
+ cdc_data_interface = make_cdc_data_interface(
+ "CDC", args.cdc_ep_num_data_in, args.cdc_ep_num_data_out
+ )
-cdc_interfaces = [cdc_comm_interface, cdc_data_interface]
+ cdc_interfaces = [cdc_comm_interface, cdc_data_interface]
if include_cdc2:
cdc2_union = make_cdc_union("CDC2")
cdc2_call_management = make_cdc_call_management("CDC2")
- cdc2_comm_interface = make_cdc_comm_interface("CDC2", cdc2_union)
- cdc2_data_interface = make_cdc_data_interface("CDC2")
+ cdc2_comm_interface = make_cdc_comm_interface(
+ "CDC2", cdc2_union, cdc2_call_management, args.cdc2_ep_num_notification
+ )
+ cdc2_data_interface = make_cdc_data_interface(
+ "CDC2", args.cdc2_ep_num_data_in, args.cdc2_ep_num_data_out
+ )
cdc2_interfaces = [cdc2_comm_interface, cdc2_data_interface]
@@ -842,10 +874,10 @@ extern const uint8_t hid_report_descriptor[{hid_report_descriptor_length}];
#define USB_HID_NUM_DEVICES {hid_num_devices}
""".format(
- hid_report_descriptor_length=len(bytes(combined_hid_report_descriptor)),
- hid_num_devices=len(args.hid_devices),
+ hid_report_descriptor_length=len(bytes(combined_hid_report_descriptor)),
+ hid_num_devices=len(args.hid_devices),
+ )
)
-)
if include_vendor:
h_file.write(
@@ -876,7 +908,10 @@ if include_hid:
c_file.write(
"""\
const uint8_t hid_report_descriptor[{HID_DESCRIPTOR_LENGTH}] = {{
-""".format(HID_DESCRIPTOR_LENGTH=hid_descriptor_length))
+""".format(
+ HID_DESCRIPTOR_LENGTH=hid_descriptor_length
+ )
+ )
for b in bytes(combined_hid_report_descriptor):
c_file.write("0x{:02x}, ".format(b))
@@ -895,7 +930,9 @@ const uint8_t hid_report_descriptor[{HID_DESCRIPTOR_LENGTH}] = {{
static uint8_t {name}_report_buffer[{report_length}];
""".format(
name=name.lower(),
- report_length=hid_report_descriptors.HID_DEVICE_DATA[name].report_length,
+ report_length=hid_report_descriptors.HID_DEVICE_DATA[
+ name
+ ].report_length,
)
)