works! no timeouts

This commit is contained in:
Dan Halbert 2021-02-16 17:11:37 -05:00
parent 0b8f1b9a90
commit c26de0136a
6 changed files with 213 additions and 46 deletions

View File

@ -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

View File

@ -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;
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;
}
if ((flags & MP_IOCTL_POLL_WR) && common_hal_usb_cdc_serial_ready_to_tx(self)) {
ret |= MP_IOCTL_POLL_WR;
}
} 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);

View File

@ -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

View File

@ -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[] = {

View File

@ -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);
}
bool common_hal_usb_cdc_serial_ready_to_tx(usb_cdc_serial_obj_t *self) {
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_get_connected(usb_cdc_serial_obj_t *self) {
return tud_cdc_n_connected(self->idx);
}

View File

@ -76,12 +76,27 @@ parser.add_argument(
default=0,
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"
)
@ -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,
)
)