aboutsummaryrefslogtreecommitdiff
path: root/circuitpython/shared-module/usb_cdc
diff options
context:
space:
mode:
authorRaghuram Subramani <raghus2247@gmail.com>2022-06-19 19:47:51 +0530
committerRaghuram Subramani <raghus2247@gmail.com>2022-06-19 19:47:51 +0530
commit4fd287655a72b9aea14cdac715ad5b90ed082ed2 (patch)
tree65d393bc0e699dd12d05b29ba568e04cea666207 /circuitpython/shared-module/usb_cdc
parent0150f70ce9c39e9e6dd878766c0620c85e47bed0 (diff)
add circuitpython code
Diffstat (limited to 'circuitpython/shared-module/usb_cdc')
-rw-r--r--circuitpython/shared-module/usb_cdc/Serial.c158
-rw-r--r--circuitpython/shared-module/usb_cdc/Serial.h39
-rw-r--r--circuitpython/shared-module/usb_cdc/__init__.c417
-rw-r--r--circuitpython/shared-module/usb_cdc/__init__.h51
4 files changed, 665 insertions, 0 deletions
diff --git a/circuitpython/shared-module/usb_cdc/Serial.c b/circuitpython/shared-module/usb_cdc/Serial.c
new file mode 100644
index 0000000..7f1bc75
--- /dev/null
+++ b/circuitpython/shared-module/usb_cdc/Serial.c
@@ -0,0 +1,158 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared/runtime/interrupt_char.h"
+#include "shared-bindings/usb_cdc/Serial.h"
+#include "shared-module/usb_cdc/Serial.h"
+#include "supervisor/shared/tick.h"
+
+#include "tusb.h"
+
+size_t common_hal_usb_cdc_serial_read(usb_cdc_serial_obj_t *self, uint8_t *data, size_t len, int *errcode) {
+
+ const bool wait_forever = self->timeout < 0.0f;
+ const bool wait_for_timeout = self->timeout > 0.0f;
+
+ // Read up to len bytes immediately.
+ // The number of bytes read will not be larger than what is already in the TinyUSB FIFO.
+ uint32_t total_num_read = tud_cdc_n_read(self->idx, data, len);
+
+ if (wait_forever || wait_for_timeout) {
+ // Continue filling the buffer past what we already read.
+ len -= total_num_read;
+ data += total_num_read;
+
+ // Read more if we have time.
+ // Use special routine to avoid pulling in uint64-float-compatible math routines.
+ uint64_t timeout_ms = float_to_uint64(self->timeout * 1000); // Junk value if timeout < 0.
+ uint64_t start_ticks = supervisor_ticks_ms64();
+
+ uint32_t num_read = 0;
+ while (total_num_read < len &&
+ (wait_forever || supervisor_ticks_ms64() - start_ticks <= timeout_ms)) {
+
+ // Wait for a bit, and check for ctrl-C.
+ RUN_BACKGROUND_TASKS;
+ if (mp_hal_is_interrupted()) {
+ return 0;
+ }
+
+ // Advance buffer pointer and reduce number of bytes that need to be read.
+ len -= num_read;
+ data += num_read;
+
+ // Try to read another batch of bytes.
+ num_read = tud_cdc_n_read(self->idx, data, len);
+ total_num_read += num_read;
+ }
+ }
+
+ return total_num_read;
+}
+
+size_t common_hal_usb_cdc_serial_write(usb_cdc_serial_obj_t *self, const uint8_t *data, size_t len, int *errcode) {
+ const bool wait_forever = self->write_timeout < 0.0f;
+ const bool wait_for_timeout = self->write_timeout > 0.0f;
+
+ // Write as many bytes as possible immediately.
+ // The number of bytes written at once will not be larger than what can fit in the TinyUSB FIFO.
+ uint32_t total_num_written = tud_cdc_n_write(self->idx, data, len);
+ tud_cdc_n_write_flush(self->idx);
+
+ if (wait_forever || wait_for_timeout) {
+ // Continue writing the rest of the buffer.
+ len -= total_num_written;
+ data += total_num_written;
+
+ // Write more if we have time.
+ // Use special routine to avoid pulling in uint64-float-compatible math routines.
+ uint64_t timeout_ms = float_to_uint64(self->write_timeout * 1000); // Junk value if write_timeout < 0.
+ uint64_t start_ticks = supervisor_ticks_ms64();
+
+ uint32_t num_written = 0;
+ while (total_num_written < len &&
+ (wait_forever || supervisor_ticks_ms64() - start_ticks <= timeout_ms)) {
+
+ // Wait for a bit, and check for ctrl-C.
+ RUN_BACKGROUND_TASKS;
+ if (mp_hal_is_interrupted()) {
+ return 0;
+ }
+
+ // Advance buffer pointer and reduce number of bytes that need to be written.
+ len -= num_written;
+ data += num_written;
+
+ // Try to write another batch of bytes.
+ num_written = tud_cdc_n_write(self->idx, data, len);
+ tud_cdc_n_write_flush(self->idx);
+ total_num_written += num_written;
+ }
+ }
+
+ return total_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);
+}
+
+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_get_connected(usb_cdc_serial_obj_t *self) {
+ return tud_cdc_n_connected(self->idx);
+}
+
+mp_float_t common_hal_usb_cdc_serial_get_timeout(usb_cdc_serial_obj_t *self) {
+ return self->timeout;
+}
+
+void common_hal_usb_cdc_serial_set_timeout(usb_cdc_serial_obj_t *self, mp_float_t timeout) {
+ self->timeout = timeout;
+}
+
+mp_float_t common_hal_usb_cdc_serial_get_write_timeout(usb_cdc_serial_obj_t *self) {
+ return self->write_timeout;
+}
+
+void common_hal_usb_cdc_serial_set_write_timeout(usb_cdc_serial_obj_t *self, mp_float_t write_timeout) {
+ self->write_timeout = write_timeout;
+}
diff --git a/circuitpython/shared-module/usb_cdc/Serial.h b/circuitpython/shared-module/usb_cdc/Serial.h
new file mode 100644
index 0000000..ddf78ee
--- /dev/null
+++ b/circuitpython/shared-module/usb_cdc/Serial.h
@@ -0,0 +1,39 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef SHARED_MODULE_USB_CDC_SERIAL_H
+#define SHARED_MODULE_USB_CDC_SERIAL_H
+
+#include "py/obj.h"
+
+typedef struct {
+ mp_obj_base_t base;
+ mp_float_t timeout; // if negative, wait forever.
+ mp_float_t write_timeout; // if negative, wait forever.
+ uint8_t idx; // which CDC device?
+} usb_cdc_serial_obj_t;
+
+#endif // SHARED_MODULE_USB_CDC_SERIAL_H
diff --git a/circuitpython/shared-module/usb_cdc/__init__.c b/circuitpython/shared-module/usb_cdc/__init__.c
new file mode 100644
index 0000000..9961d6d
--- /dev/null
+++ b/circuitpython/shared-module/usb_cdc/__init__.c
@@ -0,0 +1,417 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/gc.h"
+#include "py/obj.h"
+#include "py/mphal.h"
+#include "py/runtime.h"
+#include "py/objtuple.h"
+#include "shared-bindings/usb_cdc/__init__.h"
+#include "shared-bindings/usb_cdc/Serial.h"
+#include "supervisor/usb.h"
+
+#include "tusb.h"
+
+#if CIRCUITPY_USB_VENDOR
+// todo - this doesn't feel like it should be here.
+#include "supervisor/memory.h"
+#endif
+
+#if CFG_TUD_CDC != 2
+#error CFG_TUD_CDC must be exactly 2
+#endif
+
+static const uint8_t usb_cdc_descriptor_template[] = {
+ // CDC IAD Descriptor
+ 0x08, // 0 bLength
+ 0x0B, // 1 bDescriptorType: IAD Descriptor
+ 0xFF, // 2 bFirstInterface [SET AT RUNTIME]
+#define CDC_FIRST_INTERFACE_INDEX 2
+ 0x02, // 3 bInterfaceCount: 2
+ 0x02, // 4 bFunctionClass: COMM
+ 0x02, // 5 bFunctionSubclass: ACM
+ 0x00, // 6 bFunctionProtocol: NONE
+ 0x00, // 7 iFunction
+
+ // CDC Comm Interface Descriptor
+ 0x09, // 8 bLength
+ 0x04, // 9 bDescriptorType (Interface)
+ 0xFF, // 10 bInterfaceNumber [SET AT RUNTIME]
+#define CDC_COMM_INTERFACE_INDEX 10
+ 0x00, // 11 bAlternateSetting
+ 0x01, // 12 bNumEndpoints 1
+ 0x02, // 13 bInterfaceClass: COMM
+ 0x02, // 14 bInterfaceSubClass: ACM
+ 0x00, // 15 bInterfaceProtocol: NONE
+ 0xFF, // 16 iInterface (String Index)
+#define CDC_COMM_INTERFACE_STRING_INDEX 16
+
+ // CDC Header Descriptor
+ 0x05, // 17 bLength
+ 0x24, // 18 bDescriptorType: CLASS SPECIFIC INTERFACE
+ 0x00, // 19 bDescriptorSubtype: NONE
+ 0x10, 0x01, // 20,21 bcdCDC: 1.10
+
+ // CDC Call Management Descriptor
+ 0x05, // 22 bLength
+ 0x24, // 23 bDescriptorType: CLASS SPECIFIC INTERFACE
+ 0x01, // 24 bDescriptorSubtype: CALL MANAGEMENT
+ 0x01, // 25 bmCapabilities
+ 0xFF, // 26 bDataInterface [SET AT RUNTIME]
+#define CDC_CALL_MANAGEMENT_DATA_INTERFACE_INDEX 26
+
+ // CDC Abstract Control Management Descriptor
+ 0x04, // 27 bLength
+ 0x24, // 28 bDescriptorType: CLASS SPECIFIC INTERFACE
+ 0x02, // 29 bDescriptorSubtype: ABSTRACT CONTROL MANAGEMENT
+ 0x02, // 30 bmCapabilities
+
+ // CDC Union Descriptor
+ 0x05, // 31 bLength
+ 0x24, // 32 bDescriptorType: CLASS SPECIFIC INTERFACE
+ 0x06, // 33 bDescriptorSubtype: CDC
+ 0xFF, // 34 bMasterInterface [SET AT RUNTIME]
+#define CDC_UNION_MASTER_INTERFACE_INDEX 34
+ 0xFF, // 35 bSlaveInterface_list (1 item)
+#define CDC_UNION_SLAVE_INTERFACE_INDEX 35
+
+ // CDC Control IN Endpoint Descriptor
+ 0x07, // 36 bLength
+ 0x05, // 37 bDescriptorType (Endpoint)
+ 0xFF, // 38 bEndpointAddress (IN/D2H) [SET AT RUNTIME: 0x80 | number]
+#define CDC_CONTROL_IN_ENDPOINT_INDEX 38
+ 0x03, // 39 bmAttributes (Interrupt)
+ 0x40, 0x00, // 40, 41 wMaxPacketSize 64
+ 0x10, // 42 bInterval 16 (unit depends on device speed)
+
+ // CDC Data Interface
+ 0x09, // 43 bLength
+ 0x04, // 44 bDescriptorType (Interface)
+ 0xFF, // 45 bInterfaceNumber [SET AT RUNTIME]
+#define CDC_DATA_INTERFACE_INDEX 45
+ 0x00, // 46 bAlternateSetting
+ 0x02, // 47 bNumEndpoints 2
+ 0x0A, // 48 bInterfaceClass: DATA
+ 0x00, // 49 bInterfaceSubClass: NONE
+ 0x00, // 50 bInterfaceProtocol
+ 0x05, // 51 iInterface (String Index)
+#define CDC_DATA_INTERFACE_STRING_INDEX 51
+
+ // CDC Data OUT Endpoint Descriptor
+ 0x07, // 52 bLength
+ 0x05, // 53 bDescriptorType (Endpoint)
+ 0xFF, // 54 bEndpointAddress (OUT/H2D) [SET AT RUNTIME]
+#define CDC_DATA_OUT_ENDPOINT_INDEX 54
+ 0x02, // 55 bmAttributes (Bulk)
+ #if USB_HIGHSPEED
+ 0x00, 0x02, // 56,57 wMaxPacketSize 512
+ #else
+ 0x40, 0x00, // 56,57 wMaxPacketSize 64
+ #endif
+ 0x00, // 58 bInterval 0 (unit depends on device speed)
+
+ // CDC Data IN Endpoint Descriptor
+ 0x07, // 59 bLength
+ 0x05, // 60 bDescriptorType (Endpoint)
+ 0xFF, // 61 bEndpointAddress (IN/D2H) [SET AT RUNTIME: 0x80 | number]
+#define CDC_DATA_IN_ENDPOINT_INDEX 61
+ 0x02, // 62 bmAttributes (Bulk)
+ #if USB_HIGHSPEED
+ 0x00, 0x02, // 63,64 wMaxPacketSize 512
+ #else
+ 0x40, 0x00, // 63,64 wMaxPacketSize 64
+ #endif
+ 0x00, // 65 bInterval 0 (unit depends on device speed)
+};
+
+static const char console_cdc_comm_interface_name[] = USB_INTERFACE_NAME " CDC control";
+static const char data_cdc_comm_interface_name[] = USB_INTERFACE_NAME " CDC2 control";
+static const char console_cdc_data_interface_name[] = USB_INTERFACE_NAME " CDC data";
+static const char data_cdc_data_interface_name[] = USB_INTERFACE_NAME " CDC2 data";
+
+// .idx is set later.
+
+static usb_cdc_serial_obj_t usb_cdc_console_obj = {
+ .base.type = &usb_cdc_serial_type,
+ .timeout = -1.0f,
+ .write_timeout = -1.0f,
+};
+
+static usb_cdc_serial_obj_t usb_cdc_data_obj = {
+ .base.type = &usb_cdc_serial_type,
+ .timeout = -1.0f,
+ .write_timeout = -1.0f,
+};
+
+static bool usb_cdc_console_is_enabled;
+static bool usb_cdc_data_is_enabled;
+
+void usb_cdc_set_defaults(void) {
+ common_hal_usb_cdc_enable(CIRCUITPY_USB_CDC_CONSOLE_ENABLED_DEFAULT,
+ CIRCUITPY_USB_CDC_DATA_ENABLED_DEFAULT);
+}
+
+bool usb_cdc_console_enabled(void) {
+ return usb_cdc_console_is_enabled;
+}
+
+bool usb_cdc_data_enabled(void) {
+ return usb_cdc_data_is_enabled;
+}
+
+size_t usb_cdc_descriptor_length(void) {
+ return sizeof(usb_cdc_descriptor_template);
+}
+
+size_t usb_cdc_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *descriptor_counts, uint8_t *current_interface_string, bool console) {
+ memcpy(descriptor_buf, usb_cdc_descriptor_template, sizeof(usb_cdc_descriptor_template));
+
+ // Store comm interface number.
+ descriptor_buf[CDC_FIRST_INTERFACE_INDEX] = descriptor_counts->current_interface;
+ descriptor_buf[CDC_COMM_INTERFACE_INDEX] = descriptor_counts->current_interface;
+ descriptor_buf[CDC_UNION_MASTER_INTERFACE_INDEX] = descriptor_counts->current_interface;
+ descriptor_counts->current_interface++;
+
+ // Now store data interface number.
+ descriptor_buf[CDC_CALL_MANAGEMENT_DATA_INTERFACE_INDEX] = descriptor_counts->current_interface;
+ descriptor_buf[CDC_UNION_SLAVE_INTERFACE_INDEX] = descriptor_counts->current_interface;
+ descriptor_buf[CDC_DATA_INTERFACE_INDEX] = descriptor_counts->current_interface;
+ descriptor_counts->current_interface++;
+
+ descriptor_buf[CDC_CONTROL_IN_ENDPOINT_INDEX] = 0x80 | (
+ console
+ ? (USB_CDC_EP_NUM_NOTIFICATION ? USB_CDC_EP_NUM_NOTIFICATION : descriptor_counts->current_endpoint)
+ : (USB_CDC2_EP_NUM_NOTIFICATION ? USB_CDC2_EP_NUM_NOTIFICATION : descriptor_counts->current_endpoint));
+ descriptor_counts->num_in_endpoints++;
+ descriptor_counts->current_endpoint++;
+
+ descriptor_buf[CDC_DATA_IN_ENDPOINT_INDEX] = 0x80 | (
+ console
+ ? (USB_CDC_EP_NUM_DATA_IN ? USB_CDC_EP_NUM_DATA_IN : descriptor_counts->current_endpoint)
+ : (USB_CDC2_EP_NUM_DATA_IN ? USB_CDC2_EP_NUM_DATA_IN : descriptor_counts->current_endpoint));
+ descriptor_counts->num_in_endpoints++;
+ descriptor_buf[CDC_DATA_OUT_ENDPOINT_INDEX] =
+ console
+ ? (USB_CDC_EP_NUM_DATA_OUT ? USB_CDC_EP_NUM_DATA_OUT : descriptor_counts->current_endpoint)
+ : (USB_CDC2_EP_NUM_DATA_OUT ? USB_CDC2_EP_NUM_DATA_OUT : descriptor_counts->current_endpoint);
+ descriptor_counts->num_out_endpoints++;
+ descriptor_counts->current_endpoint++;
+
+ usb_add_interface_string(*current_interface_string,
+ console ? console_cdc_comm_interface_name : data_cdc_comm_interface_name);
+ descriptor_buf[CDC_COMM_INTERFACE_STRING_INDEX] = *current_interface_string;
+ (*current_interface_string)++;
+
+ usb_add_interface_string(*current_interface_string,
+ console ? console_cdc_data_interface_name : data_cdc_data_interface_name);
+ descriptor_buf[CDC_DATA_INTERFACE_STRING_INDEX] = *current_interface_string;
+ (*current_interface_string)++;
+
+ return sizeof(usb_cdc_descriptor_template);
+}
+
+bool common_hal_usb_cdc_disable(void) {
+ return common_hal_usb_cdc_enable(false, false);
+}
+
+bool common_hal_usb_cdc_enable(bool console, bool data) {
+ // We can't change the descriptors once we're connected.
+ if (tud_connected()) {
+ return false;
+ }
+
+ // Right now these objects contain no heap objects, but if that changes,
+ // they will need to be protected against gc.
+
+ // Assign only as many idx values as necessary. They must start at 0.
+ uint8_t idx = 0;
+ usb_cdc_console_is_enabled = console;
+ usb_cdc_set_console(console ? MP_OBJ_FROM_PTR(&usb_cdc_console_obj) : mp_const_none);
+ if (console) {
+ usb_cdc_console_obj.idx = idx;
+ idx++;
+ }
+
+ usb_cdc_data_is_enabled = data;
+ usb_cdc_set_data(data ? MP_OBJ_FROM_PTR(&usb_cdc_data_obj) : mp_const_none);
+ if (data) {
+ usb_cdc_data_obj.idx = idx;
+ }
+
+
+ return true;
+}
+
+#if CIRCUITPY_USB_VENDOR
+#include "usb_vendor_descriptors.h"
+
+#define BOS_TOTAL_LEN (TUD_BOS_DESC_LEN + TUD_BOS_WEBUSB_DESC_LEN + TUD_BOS_MICROSOFT_OS_DESC_LEN)
+
+#define MS_OS_20_DESC_LEN 0xB2
+
+// BOS Descriptor is required for webUSB
+uint8_t const desc_bos[] =
+{
+ // total length, number of device caps
+ TUD_BOS_DESCRIPTOR(BOS_TOTAL_LEN, 2),
+
+ // Vendor Code, iLandingPage
+ TUD_BOS_WEBUSB_DESCRIPTOR(VENDOR_REQUEST_WEBUSB, 1),
+
+ // Microsoft OS 2.0 descriptor
+ TUD_BOS_MS_OS_20_DESCRIPTOR(MS_OS_20_DESC_LEN, VENDOR_REQUEST_MICROSOFT)
+};
+
+uint8_t const *tud_descriptor_bos_cb(void) {
+ return desc_bos;
+}
+
+#define MS_OS_20_ITF_NUM_MAGIC 0x5b
+#define MS_OS_20_ITF_NUM_OFFSET 22
+
+const uint8_t ms_os_20_descriptor_template[] =
+{
+ // 10 Set header: length, type, windows version, total length
+ U16_TO_U8S_LE(0x000A), U16_TO_U8S_LE(MS_OS_20_SET_HEADER_DESCRIPTOR), U32_TO_U8S_LE(0x06030000), U16_TO_U8S_LE(MS_OS_20_DESC_LEN),
+
+ // 8 Configuration subset header: length, type, configuration index, reserved, configuration total length
+ U16_TO_U8S_LE(0x0008), U16_TO_U8S_LE(MS_OS_20_SUBSET_HEADER_CONFIGURATION), 0, 0, U16_TO_U8S_LE(MS_OS_20_DESC_LEN - 0x0A),
+
+ // 8 Function Subset header: length, type, first interface, reserved, subset length
+ U16_TO_U8S_LE(0x0008), U16_TO_U8S_LE(MS_OS_20_SUBSET_HEADER_FUNCTION), /* 22 */ MS_OS_20_ITF_NUM_MAGIC, 0, U16_TO_U8S_LE(MS_OS_20_DESC_LEN - 0x0A - 0x08),
+
+ // 20 MS OS 2.0 Compatible ID descriptor: length, type, compatible ID, sub compatible ID
+ U16_TO_U8S_LE(0x0014), U16_TO_U8S_LE(MS_OS_20_FEATURE_COMPATBLE_ID), 'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // sub-compatible
+
+ // MS OS 2.0 Registry property descriptor: length, type
+ U16_TO_U8S_LE(MS_OS_20_DESC_LEN - 0x0A - 0x08 - 0x08 - 0x14), U16_TO_U8S_LE(MS_OS_20_FEATURE_REG_PROPERTY),
+ U16_TO_U8S_LE(0x0007), U16_TO_U8S_LE(0x002A), // wPropertyDataType, wPropertyNameLength and PropertyName "DeviceInterfaceGUIDs\0" in UTF-16
+ 'D', 0x00, 'e', 0x00, 'v', 0x00, 'i', 0x00, 'c', 0x00, 'e', 0x00, 'I', 0x00, 'n', 0x00, 't', 0x00, 'e', 0x00,
+ 'r', 0x00, 'f', 0x00, 'a', 0x00, 'c', 0x00, 'e', 0x00, 'G', 0x00, 'U', 0x00, 'I', 0x00, 'D', 0x00, 's', 0x00, 0x00, 0x00,
+ U16_TO_U8S_LE(0x0050), // wPropertyDataLength
+ // bPropertyData: “{975F44D9-0D08-43FD-8B3E-127CA8AFFF9D}”.
+ '{', 0x00, '9', 0x00, '7', 0x00, '5', 0x00, 'F', 0x00, '4', 0x00, '4', 0x00, 'D', 0x00, '9', 0x00, '-', 0x00,
+ '0', 0x00, 'D', 0x00, '0', 0x00, '8', 0x00, '-', 0x00, '4', 0x00, '3', 0x00, 'F', 0x00, 'D', 0x00, '-', 0x00,
+ '8', 0x00, 'B', 0x00, '3', 0x00, 'E', 0x00, '-', 0x00, '1', 0x00, '2', 0x00, '7', 0x00, 'C', 0x00, 'A', 0x00,
+ '8', 0x00, 'A', 0x00, 'F', 0x00, 'F', 0x00, 'F', 0x00, '9', 0x00, 'D', 0x00, '}', 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+TU_VERIFY_STATIC(sizeof(ms_os_20_descriptor_template) == MS_OS_20_DESC_LEN, "Incorrect size");
+
+static const uint8_t usb_vendor_descriptor_template[] = {
+ // Vendor Descriptor
+ 0x09, // 0 bLength
+ 0x04, // 1 bDescriptorType (Interface)
+ 0xFF, // 2 bInterfaceNumber [SET AT RUNTIME]
+#define VENDOR_INTERFACE_INDEX 2
+ 0x00, // 3 bAlternateSetting
+ 0x02, // 4 bNumEndpoints 2
+ 0xFF, // 5 bInterfaceClass: Vendor Specific
+ 0x00, // 6 bInterfaceSubClass: NONE
+ 0x00, // 7 bInterfaceProtocol: NONE
+ 0xFF, // 8 iInterface (String Index)
+#define VENDOR_INTERFACE_STRING_INDEX 8
+
+ // Vendor OUT Endpoint Descriptor
+ 0x07, // 9 bLength
+ 0x05, // 10 bDescriptorType (Endpoint)
+ 0xFF, // 11 bEndpointAddress (IN/D2H) [SET AT RUNTIME: number]
+#define VENDOR_OUT_ENDPOINT_INDEX 11
+ 0x02, // 12 bmAttributes (Bulk)
+ #if USB_HIGHSPEED
+ 0x00, 0x02, // 13,14 wMaxPacketSize 512
+ #else
+ 0x40, 0x00, // 13,14 wMaxPacketSize 64
+ #endif
+ 0x0, // 15 bInterval 0
+
+ // Vendor IN Endpoint Descriptor
+ 0x07, // 16 bLength
+ 0x05, // 17 bDescriptorType (Endpoint)
+ 0xFF, // 18 bEndpointAddress (IN/D2H) [SET AT RUNTIME: 0x80 | number]
+#define VENDOR_IN_ENDPOINT_INDEX 18
+ 0x02, // 19 bmAttributes (Bulk)
+ 0x40, 0x00, // 20, 21 wMaxPacketSize 64
+ 0x0 // 22 bInterval 0
+};
+
+static const char vendor_interface_name[] = USB_INTERFACE_NAME " WebUSB";
+
+
+bool usb_vendor_enabled(void) {
+ return usb_cdc_console_enabled();
+}
+
+size_t usb_vendor_descriptor_length(void) {
+ return sizeof(usb_vendor_descriptor_template);
+}
+
+static supervisor_allocation *ms_os_20_descriptor_allocation;
+
+size_t vendor_ms_os_20_descriptor_length() {
+ return sizeof(ms_os_20_descriptor_template);
+}
+uint8_t const *vendor_ms_os_20_descriptor() {
+ return (uint8_t *)ms_os_20_descriptor_allocation->ptr;
+}
+
+
+size_t usb_vendor_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *descriptor_counts, uint8_t *current_interface_string) {
+
+ if (ms_os_20_descriptor_template[MS_OS_20_ITF_NUM_OFFSET] == MS_OS_20_ITF_NUM_MAGIC) {
+ ms_os_20_descriptor_allocation =
+ allocate_memory(align32_size(sizeof(ms_os_20_descriptor_template)),
+ /*high_address*/ false, /*movable*/ false);
+ uint8_t *ms_os_20_descriptor_buf = (uint8_t *)ms_os_20_descriptor_allocation->ptr;
+ memcpy(ms_os_20_descriptor_buf, ms_os_20_descriptor_template, sizeof(ms_os_20_descriptor_template));
+ ms_os_20_descriptor_buf[MS_OS_20_ITF_NUM_OFFSET] = descriptor_counts->current_interface;
+ ms_os_20_descriptor_buf[VENDOR_IN_ENDPOINT_INDEX] = 0x80 | descriptor_counts->current_endpoint;
+ ms_os_20_descriptor_buf[VENDOR_OUT_ENDPOINT_INDEX] = descriptor_counts->current_endpoint;
+ }
+
+ memcpy(descriptor_buf, usb_vendor_descriptor_template, sizeof(usb_vendor_descriptor_template));
+
+ descriptor_buf[VENDOR_INTERFACE_INDEX] = descriptor_counts->current_interface;
+ descriptor_counts->current_interface++;
+
+ descriptor_buf[VENDOR_IN_ENDPOINT_INDEX] = 0x80 | descriptor_counts->current_endpoint;
+ descriptor_counts->num_in_endpoints++;
+ descriptor_buf[VENDOR_OUT_ENDPOINT_INDEX] = descriptor_counts->current_endpoint;
+ descriptor_counts->num_out_endpoints++;
+ descriptor_counts->current_endpoint++;
+
+ usb_add_interface_string(*current_interface_string, vendor_interface_name);
+ descriptor_buf[VENDOR_INTERFACE_STRING_INDEX] = *current_interface_string;
+ (*current_interface_string)++;
+
+ return sizeof(usb_vendor_descriptor_template);
+}
+
+
+
+
+#endif
diff --git a/circuitpython/shared-module/usb_cdc/__init__.h b/circuitpython/shared-module/usb_cdc/__init__.h
new file mode 100644
index 0000000..87dabf0
--- /dev/null
+++ b/circuitpython/shared-module/usb_cdc/__init__.h
@@ -0,0 +1,51 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef SHARED_MODULE_USB_CDC___INIT___H
+#define SHARED_MODULE_USB_CDC___INIT___H
+
+#include "py/mpconfig.h"
+#include "py/objtuple.h"
+#include "supervisor/usb.h"
+
+bool usb_cdc_console_enabled(void);
+bool usb_cdc_data_enabled(void);
+
+void usb_cdc_set_defaults(void);
+
+size_t usb_cdc_descriptor_length(void);
+size_t usb_cdc_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *descriptor_counts, uint8_t *current_interface_string, bool console);
+
+#if CIRCUITPY_USB_VENDOR
+bool usb_vendor_enabled(void);
+size_t usb_vendor_descriptor_length(void);
+size_t usb_vendor_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *descriptor_counts, uint8_t *current_interface_string);
+
+size_t vendor_ms_os_20_descriptor_length(void);
+uint8_t const *vendor_ms_os_20_descriptor(void);
+#endif
+
+#endif /* SHARED_MODULE_USB_CDC___INIT___H */