partially working

This commit is contained in:
Dan Halbert 2021-04-27 23:53:23 -04:00
parent f98a54628b
commit 8500e846c6
16 changed files with 273 additions and 230 deletions

232
main.c
View File

@ -182,24 +182,6 @@ STATIC void start_mp(supervisor_allocation* heap) {
#if CIRCUITPY_NETWORK
network_module_init();
#endif
// Do before boot.py.
#if CIRCUITPY_STORAGE
storage_init();
#endif
#if CIRCUITPY_USB_CDC
usb_cdc_init();
#endif
#if CIRCUITPY_USB_HID
usb_hid_init();
#endif
#if CIRCUITPY_USB_MIDI
usb_midi_init();
#endif
}
STATIC void stop_mp(void) {
@ -284,6 +266,97 @@ STATIC void cleanup_after_vm(supervisor_allocation* heap) {
reset_status_led();
}
FIL* boot_output_file;
STATIC void __attribute__ ((noinline)) run_boot_py(safe_mode_t safe_mode) {
// If not in safe mode, run boot before initing USB and capture output in a
// file.
if (filesystem_present() && safe_mode == NO_SAFE_MODE && MP_STATE_VM(vfs_mount_table) != NULL) {
static const char * const boot_py_filenames[] = STRING_LIST("settings.txt", "settings.py", "boot.py", "boot.txt");
new_status_color(BOOT_RUNNING);
#ifdef CIRCUITPY_BOOT_OUTPUT_FILE
FIL file_pointer;
boot_output_file = &file_pointer;
// Get the base filesystem.
FATFS *fs = &((fs_user_mount_t *) MP_STATE_VM(vfs_mount_table)->obj)->fatfs;
bool have_boot_py = first_existing_file_in_list(boot_py_filenames) != NULL;
bool skip_boot_output = false;
// If there's no boot.py file that might write some changing output,
// read the existing copy of CIRCUITPY_BOOT_OUTPUT_FILE and see if its contents
// match the version info we would print anyway. If so, skip writing CIRCUITPY_BOOT_OUTPUT_FILE.
// This saves wear and tear on the flash and also prevents filesystem damage if power is lost
// during the write, which may happen due to bobbling the power connector or weak power.
static const size_t NUM_CHARS_TO_COMPARE = 160;
if (!have_boot_py && f_open(fs, boot_output_file, CIRCUITPY_BOOT_OUTPUT_FILE, FA_READ) == FR_OK) {
char file_contents[NUM_CHARS_TO_COMPARE];
UINT chars_read = 0;
f_read(boot_output_file, file_contents, NUM_CHARS_TO_COMPARE, &chars_read);
f_close(boot_output_file);
skip_boot_output =
// + 2 accounts for \r\n.
chars_read == strlen(MICROPY_FULL_VERSION_INFO) + 2 &&
strncmp(file_contents, MICROPY_FULL_VERSION_INFO, strlen(MICROPY_FULL_VERSION_INFO)) == 0;
}
if (!skip_boot_output) {
// Wait 1.5 seconds before opening CIRCUITPY_BOOT_OUTPUT_FILE for write,
// in case power is momentary or will fail shortly due to, say a low, battery.
if (common_hal_mcu_processor_get_reset_reason() == RESET_REASON_POWER_ON) {
mp_hal_delay_ms(1500);
}
// USB isn't up, so we can write the file.
filesystem_set_internal_writable_by_usb(false);
f_open(fs, boot_output_file, CIRCUITPY_BOOT_OUTPUT_FILE, FA_WRITE | FA_CREATE_ALWAYS);
// Switch the filesystem back to non-writable by Python now instead of later,
// since boot.py might change it back to writable.
filesystem_set_internal_writable_by_usb(true);
// Write version info to boot_out.txt.
mp_hal_stdout_tx_str(MICROPY_FULL_VERSION_INFO);
mp_hal_stdout_tx_str("\r\n");
}
#endif
filesystem_flush();
supervisor_allocation* heap = allocate_remaining_memory();
start_mp(heap);
#if CIRCUITPY_USB
// Set up default USB values after boot.py VM starts but before running boot.py.
usb_pre_boot_py();
#endif
// TODO(tannewt): Re-add support for flashing boot error output.
bool found_boot = maybe_run_list(boot_py_filenames, NULL);
(void) found_boot;
#ifdef CIRCUITPY_BOOT_OUTPUT_FILE
if (!skip_boot_output) {
f_close(boot_output_file);
filesystem_flush();
}
boot_output_file = NULL;
#endif
#if CIRCUITPY_USB
// Remember USB settings, which may have changed during boot.py.
// Call this before the boot.py heap is destroyed.
usb_post_boot_py();
#endif
cleanup_after_vm(heap);
}
}
STATIC void print_code_py_status_message(safe_mode_t safe_mode) {
if (autoreload_is_enabled()) {
serial_write_compressed(translate("Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.\n"));
@ -296,7 +369,7 @@ STATIC void print_code_py_status_message(safe_mode_t safe_mode) {
}
}
STATIC bool run_code_py(safe_mode_t safe_mode) {
STATIC bool run_code_py(safe_mode_t safe_mode, supervisor_allocation *heap) {
bool serial_connected_at_start = serial_connected();
#if CIRCUITPY_AUTORELOAD_DELAY_MS > 0
serial_write("\n");
@ -324,11 +397,6 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
"main.txt.py", "main.py.txt", "main.txt.txt","main.py.py");
#endif
stack_resize();
filesystem_flush();
supervisor_allocation* heap = allocate_remaining_memory();
start_mp(heap);
found_main = maybe_run_list(supported_filenames, &result);
#if CIRCUITPY_FULL_BUILD
if (!found_main){
@ -466,98 +534,9 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
}
}
FIL* boot_output_file;
STATIC void __attribute__ ((noinline)) run_boot_py(safe_mode_t safe_mode) {
// If not in safe mode, run boot before initing USB and capture output in a
// file.
if (filesystem_present() && safe_mode == NO_SAFE_MODE && MP_STATE_VM(vfs_mount_table) != NULL) {
static const char * const boot_py_filenames[] = STRING_LIST("settings.txt", "settings.py", "boot.py", "boot.txt");
new_status_color(BOOT_RUNNING);
#ifdef CIRCUITPY_BOOT_OUTPUT_FILE
FIL file_pointer;
boot_output_file = &file_pointer;
// Get the base filesystem.
FATFS *fs = &((fs_user_mount_t *) MP_STATE_VM(vfs_mount_table)->obj)->fatfs;
bool have_boot_py = first_existing_file_in_list(boot_py_filenames) != NULL;
bool skip_boot_output = false;
// If there's no boot.py file that might write some changing output,
// read the existing copy of CIRCUITPY_BOOT_OUTPUT_FILE and see if its contents
// match the version info we would print anyway. If so, skip writing CIRCUITPY_BOOT_OUTPUT_FILE.
// This saves wear and tear on the flash and also prevents filesystem damage if power is lost
// during the write, which may happen due to bobbling the power connector or weak power.
static const size_t NUM_CHARS_TO_COMPARE = 160;
if (!have_boot_py && f_open(fs, boot_output_file, CIRCUITPY_BOOT_OUTPUT_FILE, FA_READ) == FR_OK) {
char file_contents[NUM_CHARS_TO_COMPARE];
UINT chars_read = 0;
f_read(boot_output_file, file_contents, NUM_CHARS_TO_COMPARE, &chars_read);
f_close(boot_output_file);
skip_boot_output =
// + 2 accounts for \r\n.
chars_read == strlen(MICROPY_FULL_VERSION_INFO) + 2 &&
strncmp(file_contents, MICROPY_FULL_VERSION_INFO, strlen(MICROPY_FULL_VERSION_INFO)) == 0;
}
if (!skip_boot_output) {
// Wait 1.5 seconds before opening CIRCUITPY_BOOT_OUTPUT_FILE for write,
// in case power is momentary or will fail shortly due to, say a low, battery.
if (common_hal_mcu_processor_get_reset_reason() == RESET_REASON_POWER_ON) {
mp_hal_delay_ms(1500);
}
// USB isn't up, so we can write the file.
filesystem_set_internal_writable_by_usb(false);
f_open(fs, boot_output_file, CIRCUITPY_BOOT_OUTPUT_FILE, FA_WRITE | FA_CREATE_ALWAYS);
// Switch the filesystem back to non-writable by Python now instead of later,
// since boot.py might change it back to writable.
filesystem_set_internal_writable_by_usb(true);
// Write version info to boot_out.txt.
mp_hal_stdout_tx_str(MICROPY_FULL_VERSION_INFO);
mp_hal_stdout_tx_str("\r\n");
}
#endif
filesystem_flush();
supervisor_allocation* heap = allocate_remaining_memory();
start_mp(heap);
// TODO(tannewt): Re-add support for flashing boot error output.
bool found_boot = maybe_run_list(boot_py_filenames, NULL);
(void) found_boot;
#ifdef CIRCUITPY_BOOT_OUTPUT_FILE
if (!skip_boot_output) {
f_close(boot_output_file);
filesystem_flush();
}
boot_output_file = NULL;
#endif
#if CIRCUITPY_USB
// Remember USB settings done during boot.py.
// Call this before the boot.py heap is destroyed.
usb_post_boot_py();
#endif
cleanup_after_vm(heap);
}
}
STATIC int run_repl(void) {
STATIC int run_repl(supervisor_allocation *heap) {
int exit_code = PYEXEC_FORCED_EXIT;
stack_resize();
filesystem_flush();
supervisor_allocation* heap = allocate_remaining_memory();
start_mp(heap);
autoreload_suspend();
new_status_color(REPL_RUNNING);
if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) {
@ -618,27 +597,40 @@ int __attribute__((used)) main(void) {
run_boot_py(safe_mode);
// Start serial and HID after giving boot.py a chance to tweak behavior.
serial_init();
#if CIRCUITPY_BLEIO
supervisor_start_bluetooth();
#endif
// Boot script is finished, so now go into REPL/main mode.
// Set up heap for REPL or code.py
stack_resize();
filesystem_flush();
supervisor_allocation* heap = allocate_remaining_memory();
start_mp(heap);
#if CIRCUITPY_USB
// Setup USB connection after heap is available.
// It needs the heap to build descriptors.
usb_init();
#endif
// Set up any other serial connection.
serial_init();
int exit_code = PYEXEC_FORCED_EXIT;
bool skip_repl = true;
bool first_run = true;
for (;;) {
if (!skip_repl) {
exit_code = run_repl();
exit_code = run_repl(heap);
}
if (exit_code == PYEXEC_FORCED_EXIT) {
if (!first_run) {
serial_write_compressed(translate("soft reboot\n"));
}
first_run = false;
skip_repl = run_code_py(safe_mode);
skip_repl = run_code_py(safe_mode, heap);
} else if (exit_code != 0) {
break;
}

View File

@ -51,7 +51,7 @@ CIRCUITPY_SDCARDIO ?= 0
CIRCUITPY_FRAMEBUFFERIO ?= 0
# Not enough room in 192kB or 256kB builds for secondary CDC.
CIRCUITPY_USB_CDC ?= 0
CIRCUITPY_USB_CDC ?= 1
CIRCUITPY_ULAB = 0

View File

@ -339,9 +339,9 @@ CFLAGS += -DCIRCUITPY_USB=$(CIRCUITPY_USB)
CIRCUITPY_USB_CDC ?= 1
CFLAGS += -DCIRCUITPY_USB_CDC=$(CIRCUITPY_USB_CDC)
CIRCUITPY_USB_CDC_REPL_ENABLED ?= 1
CFLAGS += -DCIRCUITPY_USB_CDC_DATA_ENABLED_DEFAULT=$(CIRCUITPY_USB_CDC_DATA_ENABLED_DEFAULT)
CIRCUITPY_USB_CDC_DATA_ENABLED ?= 0
CIRCUITPY_USB_CDC_REPL_ENABLED_DEFAULT ?= 1
CFLAGS += -DCIRCUITPY_USB_CDC_REPL_ENABLED_DEFAULT=$(CIRCUITPY_USB_CDC_REPL_ENABLED_DEFAULT)
CIRCUITPY_USB_CDC_DATA_ENABLED_DEFAULT ?= 0
CFLAGS += -DCIRCUITPY_USB_CDC_DATA_ENABLED_DEFAULT=$(CIRCUITPY_USB_CDC_DATA_ENABLED_DEFAULT)
CIRCUITPY_USB_HID ?= 1

View File

@ -39,6 +39,8 @@
#include "supervisor/filesystem.h"
#include "supervisor/flash.h"
#include "supervisor/usb.h"
#if CIRCUITPY_USB_MSC
#include "tusb.h"
static const uint8_t usb_msc_descriptor_template[] = {
@ -77,6 +79,10 @@ static const uint8_t usb_msc_descriptor_template[] = {
// Is the MSC device enabled?
bool storage_usb_is_enabled;
void storage_init_usb(void) {
storage_usb_is_enabled = true;
}
bool storage_usb_enabled(void) {
return storage_usb_is_enabled;
}
@ -92,8 +98,8 @@ size_t storage_usb_add_descriptor(uint8_t *descriptor_buf, uint8_t *current_inte
descriptor_buf[MSC_INTERFACE_INDEX] = *current_interface;
(*current_interface)++;
descriptor_buf[MSC_IN_ENDPOINT_INDEX] = USB_MSC_EP_NUM_IN ? USB_MSC_EP_NUM_IN : *current_endpoint;
descriptor_buf[MSC_OUT_ENDPOINT_INDEX] = 0x80 | (USB_MSC_EP_NUM_OUT ? USB_MSC_EP_NUM_OUT : *current_endpoint);
descriptor_buf[MSC_IN_ENDPOINT_INDEX] = 0x80 | (USB_MSC_EP_NUM_IN ? USB_MSC_EP_NUM_IN : *current_endpoint);
descriptor_buf[MSC_OUT_ENDPOINT_INDEX] = USB_MSC_EP_NUM_OUT ? USB_MSC_EP_NUM_OUT : *current_endpoint;
(*current_endpoint)++;
usb_add_interface_string(*current_interface_string, storage_interface_name);
@ -103,6 +109,15 @@ size_t storage_usb_add_descriptor(uint8_t *descriptor_buf, uint8_t *current_inte
return sizeof(usb_msc_descriptor_template);
}
bool common_hal_storage_configure_usb(bool enabled) {
// We can't change the descriptors once we're connected.
if (tud_connected()) {
return false;
}
storage_usb_is_enabled = enabled;
return true;
}
#endif // CIRCUITPY_USB_MSC
STATIC mp_obj_t mp_vfs_proxy_call(mp_vfs_mount_t *vfs, qstr meth_name, size_t n_args, const mp_obj_t *args) {
if (vfs == MP_VFS_NONE) {
@ -121,10 +136,6 @@ STATIC mp_obj_t mp_vfs_proxy_call(mp_vfs_mount_t *vfs, qstr meth_name, size_t n_
return mp_call_method_n_kw(n_args, 0, meth);
}
void storage_init(void) {
storage_usb_is_enabled = true;
}
void common_hal_storage_mount(mp_obj_t vfs_obj, const char *mount_path, bool readonly) {
// create new object
mp_vfs_mount_t *vfs = m_new_obj(mp_vfs_mount_t);
@ -236,12 +247,3 @@ void common_hal_storage_erase_filesystem(void) {
common_hal_mcu_reset();
// We won't actually get here, since we're resetting.
}
bool common_hal_storage_configure_usb(bool enabled) {
// We can't change the descriptors once we're connected.
if (tud_connected()) {
return false;
}
storage_usb_is_enabled = enabled;
return true;
}

View File

@ -27,10 +27,13 @@
#ifndef SHARED_MODULE_STORAGE___INIT___H
#define SHARED_MODULE_STORAGE___INIT___H
bool storage_usb_enabled(void);
#include "py/mpconfig.h"
void storage_init(void);
#if CIRCUITPY_USB
bool storage_usb_enabled(void);
void storage_init_usb(void);
size_t storage_usb_descriptor_length(void);
size_t storage_usb_add_descriptor(uint8_t *descriptor_buf, uint8_t *current_interface, uint8_t *current_endpoint, uint8_t* current_interface_string);
#endif
#endif // SHARED_MODULE_STORAGE___INIT___H

View File

@ -31,6 +31,8 @@
#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 CFG_TUD_CDC != 2
@ -94,7 +96,7 @@ static const uint8_t usb_cdc_descriptor_template[] = {
// CDC Control IN Endpoint Descriptor
0x07, // 36 bLength
0x05, // 37 bDescriptorType (Endpoint)
0xFF, // 38 bEndpointAddress (IN/D2H) [SET AT RUNTIME: 0x8 | number]
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
@ -125,17 +127,17 @@ static const uint8_t usb_cdc_descriptor_template[] = {
// CDC Data IN Endpoint Descriptor
0x07, // 59 bLength
0x05, // 60 bDescriptorType (Endpoint)
0xFF, // 61 bEndpointAddress (IN/D2H) [SET AT RUNTIME: 0x8 | number]
0xFF, // 61 bEndpointAddress (IN/D2H) [SET AT RUNTIME: 0x80 | number]
#define CDC_DATA_IN_ENDPOINT_INDEX 61
0x02, // 62 bmAttributes (Bulk)
0x40, 0x00, // 63,64 wMaxPacketSize 64
0x00, // 65 bInterval 0 (unit depends on device speed)
};
static const char[] repl_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[] repl_cdc_data_interface_name = USB_INTERFACE_NAME " CDC data";
static const char[] data_cdc_data_interface_name = USB_INTERFACE_NAME " CDC2 data";
static const char repl_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 repl_cdc_data_interface_name[] = USB_INTERFACE_NAME " CDC data";
static const char data_cdc_data_interface_name[] = USB_INTERFACE_NAME " CDC2 data";
static usb_cdc_serial_obj_t usb_cdc_repl_obj = {
.base.type = &usb_cdc_serial_type,
@ -159,7 +161,7 @@ bool usb_cdc_repl_enabled(void) {
}
bool usb_cdc_data_enabled(void) {
return usb_cdc_data_enabled;
return usb_cdc_data_is_enabled;
}
size_t usb_cdc_descriptor_length(void) {
@ -167,7 +169,7 @@ size_t usb_cdc_descriptor_length(void) {
}
size_t usb_cdc_add_descriptor(uint8_t *descriptor_buf, uint8_t *current_interface, uint8_t *current_endpoint, uint8_t* current_interface_string, bool repl) {
memcpy(descriptor_buf, usb_midi_descriptor_template, sizeof(usb_midi_descriptor_template));
memcpy(descriptor_buf, usb_cdc_descriptor_template, sizeof(usb_cdc_descriptor_template));
// Store comm interface number.
descriptor_buf[CDC_FIRST_INTERFACE_INDEX] = *current_interface;
@ -179,19 +181,23 @@ size_t usb_cdc_add_descriptor(uint8_t *descriptor_buf, uint8_t *current_interfac
descriptor_buf[CDC_CALL_MANAGEMENT_DATA_INTERFACE_INDEX] = *current_interface;
descriptor_buf[CDC_UNION_SLAVE_INTERFACE_INDEX] = *current_interface;
descriptor_buf[CDC_DATA_INTERFACE_INDEX] = *current_interface;
(*current_interface)++;
descriptor_buf[CDC_CONTROL_IN_ENDPOINT_INDEX] = repl
descriptor_buf[CDC_CONTROL_IN_ENDPOINT_INDEX] = 0x80 | (
repl
? (USB_CDC_EP_NUM_NOTIFICATION ? USB_CDC_EP_NUM_NOTIFICATION : *current_endpoint)
: (USB_CDC2_EP_NUM_NOTIFICATION ? USB_CDC2_EP_NUM_NOTIFICATION : *current_endpoint);
: (USB_CDC2_EP_NUM_NOTIFICATION ? USB_CDC2_EP_NUM_NOTIFICATION : *current_endpoint));
(*current_endpoint)++;
descriptor_buf[CDC_DATA_OUT_ENDPOINT_INDEX] = repl
descriptor_buf[CDC_DATA_OUT_ENDPOINT_INDEX] =
repl
? (USB_CDC_EP_NUM_DATA_OUT ? USB_CDC_EP_NUM_DATA_OUT : *current_endpoint)
: (USB_CDC2_EP_NUM_DATA_OUT ? USB_CDC2_EP_NUM_DATA_OUT : *current_endpoint);
descriptor_buf[CDC_DATA_IN_ENDPOINT_INDEX] = repl
descriptor_buf[CDC_DATA_IN_ENDPOINT_INDEX] = 0x80 | (
repl
? (USB_CDC_EP_NUM_DATA_IN ? USB_CDC_EP_NUM_DATA_IN : *current_endpoint)
: (USB_CDC2_EP_NUM_DATA_IN ? USB_CDC2_EP_NUM_DATA_IN : *current_endpoint);
: (USB_CDC2_EP_NUM_DATA_IN ? USB_CDC2_EP_NUM_DATA_IN : *current_endpoint));
(*current_endpoint)++;
usb_add_interface_string(*current_interface_string,
@ -204,10 +210,11 @@ size_t usb_cdc_add_descriptor(uint8_t *descriptor_buf, uint8_t *current_interfac
descriptor_buf[CDC_DATA_INTERFACE_STRING_INDEX] = *current_interface_string;
(*current_interface_string)++;
return sizeof(usb_midi_descriptor_template);
return sizeof(usb_cdc_descriptor_template);
}
void usb_cdc_init(void) {
// Called only once, before boot.py
void usb_cdc_init_usb(void) {
usb_cdc_repl_is_enabled = true;
usb_cdc_data_is_enabled = false;
}
@ -218,10 +225,10 @@ bool common_hal_usb_cdc_configure_usb(bool repl_enabled, bool data_enabled) {
return false;
}
usb_cdc_repl_enabled = repl_enabled;
usb_cdc_repl_is_enabled = repl_enabled;
usb_cdc_set_repl(repl_enabled ? MP_OBJ_FROM_PTR(&usb_cdc_repl_obj) : mp_const_none);
usb_cdc_data_enabled = data_enabled;
usb_cdc_data_is_enabled = data_enabled;
usb_cdc_set_data(data_enabled ? MP_OBJ_FROM_PTR(&usb_cdc_data_obj) : mp_const_none);
return true;

View File

@ -27,12 +27,13 @@
#ifndef SHARED_MODULE_USB_CDC___INIT___H
#define SHARED_MODULE_USB_CDC___INIT___H
#include "py/mpconfig.h"
#include "py/objtuple.h"
bool usb_cdc_repl_enabled(void);
bool usb_cdc_data_enabled(void);
void usb_cdc_init(void);
void usb_cdc_init_usb(void);
size_t usb_cdc_descriptor_length(void);
size_t usb_cdc_add_descriptor(uint8_t *descriptor_buf, uint8_t *current_interface, uint8_t *current_endpoint, uint8_t* current_interface_string, bool repl);

View File

@ -67,7 +67,7 @@ static const uint8_t usb_hid_descriptor_template[] = {
0x07, // 25 bLength
0x05, // 26 bDescriptorType (Endpoint)
0xFF, // 27 bEndpointAddress (OUT/H2D) [SET AT RUNTIME]
#define HID_OUT_ENDPOINT_INDEX (26)
#define HID_OUT_ENDPOINT_INDEX (27)
0x03, // 28 bmAttributes (Interrupt)
0x40, 0x00, // 29,30 wMaxPacketSize 64
0x08, // 31 bInterval 8 (unit depends on device speed)
@ -115,22 +115,28 @@ size_t usb_hid_add_descriptor(uint8_t *descriptor_buf, uint8_t *current_interfac
descriptor_buf[HID_DESCRIPTOR_LENGTH_INDEX] = report_descriptor_length & 0xFF;
descriptor_buf[HID_DESCRIPTOR_LENGTH_INDEX + 1] = (report_descriptor_length >> 8);
descriptor_buf[HID_IN_ENDPOINT_INDEX] = USB_HID_EP_NUM_IN ? USB_HID_EP_NUM_IN : *current_endpoint;
descriptor_buf[HID_OUT_ENDPOINT_INDEX] = 0x80 | (USB_HID_EP_NUM_OUT ? USB_HID_EP_NUM_OUT : *current_endpoint);
descriptor_buf[HID_IN_ENDPOINT_INDEX] = 0x80 | (USB_HID_EP_NUM_IN ? USB_HID_EP_NUM_IN : *current_endpoint);
descriptor_buf[HID_OUT_ENDPOINT_INDEX] = USB_HID_EP_NUM_OUT ? USB_HID_EP_NUM_OUT : *current_endpoint;
(*current_endpoint)++;
return sizeof(usb_hid_descriptor_template);
}
static mp_obj_t default_hid_devices[] = {
MP_OBJ_FROM_PTR(&usb_hid_device_keyboard_obj),
MP_OBJ_FROM_PTR(&usb_hid_device_mouse_obj),
MP_OBJ_FROM_PTR(&usb_hid_device_consumer_control_obj),
static mp_rom_obj_tuple_t default_hid_devices_tuple = {
.base = {
.type = &mp_type_tuple,
},
.len = 3,
.items = {
MP_OBJ_FROM_PTR(&usb_hid_device_keyboard_obj),
MP_OBJ_FROM_PTR(&usb_hid_device_mouse_obj),
MP_OBJ_FROM_PTR(&usb_hid_device_consumer_control_obj),
},
};
// Set the default list of devices that will be included. Called before boot.py runs, in the boot.py VM.
void common_hal_usb_hid_configure_usb_defaults(void) {
common_hal_usb_hid_configure_usb(mp_obj_new_tuple(sizeof(default_hid_devices), default_hid_devices));
common_hal_usb_hid_configure_usb(&default_hid_devices_tuple);
}
bool common_hal_usb_hid_configure_usb(mp_obj_t devices) {
@ -144,7 +150,8 @@ bool common_hal_usb_hid_configure_usb(mp_obj_t devices) {
return true;
}
void usb_hid_init(void) {
// Called only once, before boot.py
void usb_hid_init_usb(void) {
usb_hid_is_enabled = true;
}
@ -170,7 +177,7 @@ void usb_hid_post_boot_py(void) {
total_hid_report_descriptor_length -= 2;
}
// Allocate storage that persists across VMs to build the combined descriptor
// Allocate storage that persists across VMs to build the combined report descriptor
// and to remember the device details.
hid_report_descriptor_allocation =

View File

@ -33,7 +33,7 @@ extern usb_hid_device_obj_t usb_hid_devices[];
bool usb_hid_enabled(void);
void usb_hid_init(void);
void usb_hid_init_usb(void);
void usb_hid_post_boot_py(void);
size_t usb_hid_add_descriptor(uint8_t *descriptor_buf, uint8_t *current_interface, uint8_t *current_endpoint, uint8_t* current_interface_string, uint16_t report_descriptor_length);

View File

@ -26,6 +26,7 @@
#include "shared-bindings/usb_midi/__init__.h"
#include "py/gc.h"
#include "py/obj.h"
#include "py/mphal.h"
#include "py/runtime.h"
@ -72,7 +73,7 @@ static const uint8_t usb_midi_descriptor_template[] = {
0x01, // 23 bInterfaceClass (Audio)
0x03, // 24 bInterfaceSubClass (MIDI Streaming)
0x00, // 25 bInterfaceProtocol
0xFF, // 26 iInterface (String Index) [SET AT RUNTIME]
0xFF, // 26 iInterface (String Index) [SET AT RUNTIME]
#define MIDI_STREAMING_INTERFACE_STRING_INDEX (26)
// MIDI Header Descriptor
@ -141,7 +142,7 @@ static const uint8_t usb_midi_descriptor_template[] = {
// MIDI IN Data Endpoint
0x07, // 76 bLength
0x05, // 77 bDescriptorType: Endpoint
0xFF, // 78 bEndpointAddress (IN/D2H) [SET AT RUNTIME: 0x8 | number]
0xFF, // 78 bEndpointAddress (IN/D2H) [SET AT RUNTIME: 0x80 | number]
#define MIDI_STREAMING_IN_ENDPOINT_INDEX (78)
0x02, // 79 bmAttributes (Bulk)
0x40, 0x00, // 8081 wMaxPacketSize 64
@ -179,9 +180,9 @@ size_t usb_midi_add_descriptor(uint8_t *descriptor_buf, uint8_t *current_interfa
(*current_interface)++;
descriptor_buf[MIDI_STREAMING_IN_ENDPOINT_INDEX] =
USB_MIDI_EP_NUM_IN ? USB_MIDI_EP_NUM_IN : *current_endpoint;
0x80 | (USB_MIDI_EP_NUM_IN ? USB_MIDI_EP_NUM_IN : *current_endpoint);
descriptor_buf[MIDI_STREAMING_OUT_ENDPOINT_INDEX] =
0x80 | (USB_MIDI_EP_NUM_OUT ? USB_MIDI_EP_NUM_OUT : *current_endpoint);
USB_MIDI_EP_NUM_OUT ? USB_MIDI_EP_NUM_OUT : *current_endpoint;
(*current_endpoint)++;
descriptor_buf[MIDI_STREAMING_INTERFACE_NUMBER_INDEX] = *current_interface;
@ -208,38 +209,36 @@ size_t usb_midi_add_descriptor(uint8_t *descriptor_buf, uint8_t *current_interfa
}
void usb_midi_init(void) {
// Called once, before
void usb_midi_init_usb(void) {
usb_midi_is_enabled = true;
}
void usb_midi_usb_init(void) {
// Called before REPL or code.py
void usb_midi_setup(void) {
mp_obj_tuple_t *ports;
if (usb_midi_is_enabled) {
// TODO(tannewt): Make this dynamic.
size_t tuple_size = align32_size(sizeof(mp_obj_tuple_t) + sizeof(mp_obj_t *) * 2);
size_t portin_size = align32_size(sizeof(usb_midi_portin_obj_t));
size_t portout_size = align32_size(sizeof(usb_midi_portout_obj_t));
// Make these objects long-lived, because they will not be going away.
// For each embedded MIDI Jack in the descriptor we create a Port
usb_midi_allocation = allocate_memory(tuple_size + portin_size + portout_size, false, false);
ports = (mp_obj_tuple_t *)usb_midi_allocation->ptr;
ports->base.type = &mp_type_tuple;
ports->len = 2;
usb_midi_portin_obj_t *in = (usb_midi_portin_obj_t *)(usb_midi_allocation->ptr + tuple_size / 4);
usb_midi_portin_obj_t *in = gc_alloc(sizeof(usb_midi_portin_obj_t), false, true);
in->base.type = &usb_midi_portin_type;
ports->items[0] = MP_OBJ_FROM_PTR(in);
usb_midi_portout_obj_t *out = (usb_midi_portout_obj_t *)(usb_midi_allocation->ptr + tuple_size / 4 + portin_size / 4);
usb_midi_portout_obj_t *out = gc_alloc(sizeof(usb_midi_portout_obj_t), false, true);
out->base.type = &usb_midi_portout_type;
ports->items[1] = MP_OBJ_FROM_PTR(out);
mp_obj_t tuple_items[2] = {
MP_OBJ_FROM_PTR(in),
MP_OBJ_FROM_PTR(out),
};
ports = mp_obj_new_tuple(2, tuple_items);
} else {
ports = mp_const_empty_tuple;
}
mp_map_lookup(&usb_midi_module_globals.map, MP_ROM_QSTR(MP_QSTR_ports), MP_MAP_LOOKUP)->value = MP_OBJ_FROM_PTR(ports);
mp_map_lookup(&usb_midi_module_globals.map, MP_ROM_QSTR(MP_QSTR_ports), MP_MAP_LOOKUP)->value =
MP_OBJ_FROM_PTR(ports);
}
bool common_hal_usb_midi_configure_usb(bool enabled) {

View File

@ -28,8 +28,8 @@
#define SHARED_MODULE_USB_MIDI___INIT___H
void usb_midi_init(void);
void usb_midi_usb_init(void);
void usb_midi_init_usb(void);
void usb_midi_setup(void);
bool usb_midi_enabled(void);
size_t usb_midi_descriptor_length(void);

View File

@ -39,16 +39,9 @@ enum {
#if INTERNAL_FLASH_FILESYSTEM == 0
+ 1
#endif
#if CIRCUITPY_USB_MIDI
+ 1
#endif
,
CIRCUITPY_SUPERVISOR_MOVABLE_ALLOC_COUNT =
0
#if CIRCUITPY_USB
+ 1 // device_descriptor_allocation
+ 1 // config_descriptor_allocation
#endif
#if CIRCUITPY_USB_HID
+ 1 // hid_report_descriptor_allocation
+ 1 // hid_devices_allocation

View File

@ -67,7 +67,7 @@ void serial_early_init(void) {
}
void serial_init(void) {
usb_init();
// USB serial is set up separately.
}
bool serial_connected(void) {

View File

@ -34,6 +34,14 @@
#include "lib/utils/interrupt_char.h"
#include "lib/mp-readline/readline.h"
#if CIRCUITPY_STORAGE
#include "shared-module/storage/__init__.h"
#endif
#if CIRCUITPY_USB_CDC
#include "shared-module/usb_cdc/__init__.h"
#endif
#if CIRCUITPY_USB_HID
#include "shared-module/usb_hid/__init__.h"
#endif
@ -82,14 +90,28 @@ void usb_init(void) {
tud_cdc_set_wanted_char(CHAR_CTRL_C);
#endif
#if CIRCUITPY_USB_MIDI
usb_midi_setup();
#endif
}
void usb_pre_boot_py(void) {
#if CIRCUITPY_STORAGE
storage_init_usb();
#endif
#if CIRCUITPY_USB_CDC
usb_cdcx_usb_init();
usb_cdc_init_usb();
#endif
#if CIRCUITPY_USB_HID
usb_hid_init_usb();
#endif
#if CIRCUITPY_USB_MIDI
usb_midi_usb_init();
usb_midi_init_usb();
#endif
}
};
// Remember USB settings done during boot.py.
// The boot.py heap is still valid at this point.

View File

@ -52,8 +52,8 @@
// Table for collecting interface strings (interface names) as descriptor is built.
#define MAX_INTERFACE_STRINGS 16
// slot 0 is not used.
static uint16_t **collected_interface_strings;
// slot 0 is always the Language ID
static uint16_t *collected_interface_strings[MAX_INTERFACE_STRINGS];
static uint8_t current_interface_string;
static const char manufacturer_name[] = USB_MANUFACTURER;
@ -77,11 +77,11 @@ static const uint8_t device_descriptor_template[] = {
#define DEVICE_PID_LO_INDEX (10)
#define DEVICE_PID_HI_INDEX (11)
0x00, 0x01, // 12,13 bcdDevice 2.00
0x02, // 14 iManufacturer (String Index) [SET AT RUNTIME]
0xFF, // 14 iManufacturer (String Index) [SET AT RUNTIME]
#define DEVICE_MANUFACTURER_STRING_INDEX (14)
0x03, // 15 iProduct (String Index) [SET AT RUNTIME]
0xFF, // 15 iProduct (String Index) [SET AT RUNTIME]
#define DEVICE_PRODUCT_STRING_INDEX (15)
0x01, // 16 iSerialNumber (String Index) [SET AT RUNTIME]
0xFF, // 16 iSerialNumber (String Index) [SET AT RUNTIME]
#define DEVICE_SERIAL_NUMBER_STRING_INDEX (16)
0x01, // 17 bNumConfigurations 1
};
@ -102,7 +102,7 @@ static const uint8_t configuration_descriptor_template[] = {
0x32, // 8 bMaxPower 100mA
};
static uint8_t configuration_descriptor[sizeof(configuration_descriptor_template)];
static uint8_t *configuration_descriptor;
// Initialization done before boot.py is run.
// Turn on or off various USB devices. On devices with limited endpoints,
@ -169,20 +169,23 @@ static void usb_build_configuration_descriptor(void) {
}
#endif
#if CIRCUITPY_USB_MIDI
if (usb_midi_enabled()) {
total_descriptor_length += usb_midi_descriptor_length();
}
#endif
#if CIRCUITPY_USB_HID
if (usb_hid_enabled()) {
total_descriptor_length += usb_hid_descriptor_length();
}
#endif
#if CIRCUITPY_USB_MIDI
if (usb_midi_enabled()) {
total_descriptor_length += usb_midi_descriptor_length();
}
#endif
// Now we now how big the configuration descriptor will be.
// Copy the top-level template, and fix up its length.
// Copy the template, which is the first part of the descriptor, and fix up its length.
configuration_descriptor = gc_alloc(total_descriptor_length, false, false);
memcpy(configuration_descriptor, configuration_descriptor_template, sizeof(configuration_descriptor_template));
configuration_descriptor[CONFIG_TOTAL_LENGTH_LO_INDEX] = total_descriptor_length & 0xFF;
configuration_descriptor[CONFIG_TOTAL_LENGTH_HI_INDEX] = (total_descriptor_length >> 8) & 0xFF;
@ -214,14 +217,6 @@ static void usb_build_configuration_descriptor(void) {
}
#endif
#if CIRCUITPY_USB_MIDI
if (usb_midi_enabled()) {
// Concatenate and fix up the MIDI descriptor.
descriptor_buf_remaining += usb_midi_add_descriptor(
descriptor_buf_remaining, &current_interface, &current_endpoint, &current_interface_string);
}
#endif
#if CIRCUITPY_USB_HID
if (usb_hid_enabled()) {
descriptor_buf_remaining += usb_hid_add_descriptor(
@ -230,8 +225,19 @@ static void usb_build_configuration_descriptor(void) {
}
#endif
#if CIRCUITPY_USB_MIDI
if (usb_midi_enabled()) {
// Concatenate and fix up the MIDI descriptor.
descriptor_buf_remaining += usb_midi_add_descriptor(
descriptor_buf_remaining, &current_interface, &current_endpoint, &current_interface_string);
}
#endif
// Now we know how many interfaces have been used.
configuration_descriptor[CONFIG_NUM_INTERFACES_INDEX] = current_interface - 1;
// current_interface is the next free interface, counting from 0,
// so move back to the last interface number, and then get a count.
// (E.g., interfaces 0-5 are used, so the number of interfaces is 6.)
configuration_descriptor[CONFIG_NUM_INTERFACES_INDEX] = current_interface - 1 + 1;
// Did we run out of endpoints?
if (current_endpoint - 1 > USB_NUM_EP) {
@ -266,6 +272,14 @@ void usb_desc_post_boot_py(void) {
// Called in the new VM created after boot.py is run. The USB devices to be used are now chosen.
void usb_desc_init(void) {
memset(collected_interface_strings, 0, sizeof(collected_interface_strings));
// Language ID is always the 0th string descriptor.
collected_interface_strings[0] = (uint16_t[]) {
0x0304,
0x0409,
};
uint8_t raw_id[COMMON_HAL_MCU_PROCESSOR_UID_LENGTH];
common_hal_mcu_processor_get_uid(raw_id);
@ -277,10 +291,8 @@ void usb_desc_init(void) {
}
// Null-terminate the string.
serial_number_hex_string[sizeof(serial_number_hex_string)] = '\0';
serial_number_hex_string[sizeof(serial_number_hex_string) - 1] = '\0';
// Memory is cleared to zero when allocated; we depend on that.
collected_interface_strings = m_malloc(MAX_INTERFACE_STRINGS + 1, false);
current_interface_string = 1;
usb_build_device_descriptor(USB_VID, USB_PID);
@ -292,9 +304,13 @@ void usb_desc_gc_collect(void) {
if (tud_mounted()) {
gc_free(device_descriptor);
gc_free(configuration_descriptor);
for (size_t i = 0; i < MAX_INTERFACE_STRINGS; i ++) {
gc_free(collected_interface_strings[i]);
}
} else {
gc_collect_ptr(device_descriptor);
gc_collect_ptr(configuration_descriptor);
gc_collect_root((void **) collected_interface_strings, MAX_INTERFACE_STRINGS);
}
}

View File

@ -54,6 +54,7 @@ bool usb_enabled(void);
void usb_init(void);
void usb_disconnect(void);
void usb_gc_collect(void);
void usb_pre_boot_py(void);
void usb_post_boot_py(void);
void usb_add_interface_string(uint8_t interface_string_index, const char str[]);