diff options
| author | Dan Halbert <halbert@halwitz.org> | 2021-02-16 17:11:37 -0500 |
|---|---|---|
| committer | Dan Halbert <halbert@halwitz.org> | 2021-02-16 17:39:36 -0500 |
| commit | c26de0136a0ad746bf0ace600a1a9d3ff428c4c6 (patch) | |
| tree | 7d79966fa0fbfdb9604454cf7b3b8e44ba225816 | |
| parent | 0b8f1b9a9039ab2ad4d43cc1d9bc388518ab0d38 (diff) | |
works! no timeouts
| -rw-r--r-- | ports/cxd56/mpconfigport.mk | 3 | ||||
| -rw-r--r-- | shared-bindings/usb_cdc/Serial.c | 122 | ||||
| -rw-r--r-- | shared-bindings/usb_cdc/Serial.h | 13 | ||||
| -rw-r--r-- | shared-bindings/usb_cdc/__init__.c | 7 | ||||
| -rw-r--r-- | shared-module/usb_cdc/Serial.c | 27 | ||||
| -rw-r--r-- | tools/gen_usb_descriptor.py | 87 |
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, ) ) |
