rework storage allocation
This commit is contained in:
parent
8500e846c6
commit
587aedd14f
223
main.c
223
main.c
@ -266,97 +266,6 @@ 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"));
|
||||
@ -369,7 +278,7 @@ STATIC void print_code_py_status_message(safe_mode_t safe_mode) {
|
||||
}
|
||||
}
|
||||
|
||||
STATIC bool run_code_py(safe_mode_t safe_mode, supervisor_allocation *heap) {
|
||||
STATIC bool run_code_py(safe_mode_t safe_mode) {
|
||||
bool serial_connected_at_start = serial_connected();
|
||||
#if CIRCUITPY_AUTORELOAD_DELAY_MS > 0
|
||||
serial_write("\n");
|
||||
@ -397,6 +306,11 @@ STATIC bool run_code_py(safe_mode_t safe_mode, supervisor_allocation *heap) {
|
||||
"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){
|
||||
@ -534,9 +448,103 @@ STATIC bool run_code_py(safe_mode_t safe_mode, supervisor_allocation *heap) {
|
||||
}
|
||||
}
|
||||
|
||||
STATIC int run_repl(supervisor_allocation *heap) {
|
||||
int exit_code = PYEXEC_FORCED_EXIT;
|
||||
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 int run_repl(void) {
|
||||
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) {
|
||||
@ -580,7 +588,6 @@ int __attribute__((used)) main(void) {
|
||||
// Port-independent devices, like CIRCUITPY_BLEIO_HCI.
|
||||
reset_devices();
|
||||
reset_board();
|
||||
reset_usb();
|
||||
|
||||
// This is first time we are running CircuitPython after a reset or power-up.
|
||||
supervisor_set_run_reason(RUN_REASON_STARTUP);
|
||||
@ -597,18 +604,7 @@ int __attribute__((used)) main(void) {
|
||||
|
||||
run_boot_py(safe_mode);
|
||||
|
||||
#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);
|
||||
|
||||
// Start USB after giving boot.py a chance to tweak behavior.
|
||||
#if CIRCUITPY_USB
|
||||
// Setup USB connection after heap is available.
|
||||
// It needs the heap to build descriptors.
|
||||
@ -618,19 +614,24 @@ int __attribute__((used)) main(void) {
|
||||
// Set up any other serial connection.
|
||||
serial_init();
|
||||
|
||||
#if CIRCUITPY_BLEIO
|
||||
supervisor_start_bluetooth();
|
||||
#endif
|
||||
|
||||
// Boot script is finished, so now go into REPL/main mode.
|
||||
int exit_code = PYEXEC_FORCED_EXIT;
|
||||
bool skip_repl = true;
|
||||
bool first_run = true;
|
||||
for (;;) {
|
||||
if (!skip_repl) {
|
||||
exit_code = run_repl(heap);
|
||||
exit_code = run_repl();
|
||||
}
|
||||
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, heap);
|
||||
skip_repl = run_code_py(safe_mode);
|
||||
} else if (exit_code != 0) {
|
||||
break;
|
||||
}
|
||||
@ -651,10 +652,6 @@ void gc_collect(void) {
|
||||
|
||||
background_callback_gc_collect();
|
||||
|
||||
#if CIRCUITPY_USB
|
||||
usb_gc_collect();
|
||||
#endif
|
||||
|
||||
#if CIRCUITPY_ALARM
|
||||
common_hal_alarm_gc_collect();
|
||||
#endif
|
||||
|
@ -35,7 +35,6 @@ extern mp_obj_tuple_t common_hal_usb_hid_devices;
|
||||
|
||||
void usb_hid_set_devices(mp_obj_t devices);
|
||||
|
||||
void common_hal_usb_hid_configure_usb_defaults(void);
|
||||
bool common_hal_usb_hid_configure_usb(mp_obj_t devices_seq);
|
||||
|
||||
#endif // SHARED_BINDINGS_USB_HID_H
|
||||
|
@ -79,8 +79,8 @@ 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;
|
||||
void storage_pre_boot_py(void) {
|
||||
storage_usb_is_enabled = CIRCUITPY_USB_MSC_ENABLED_DEFAULT;
|
||||
}
|
||||
|
||||
bool storage_usb_enabled(void) {
|
||||
|
@ -31,7 +31,7 @@
|
||||
|
||||
#if CIRCUITPY_USB
|
||||
bool storage_usb_enabled(void);
|
||||
void storage_init_usb(void);
|
||||
void storage_pre_boot_py(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
|
||||
|
@ -213,10 +213,9 @@ size_t usb_cdc_add_descriptor(uint8_t *descriptor_buf, uint8_t *current_interfac
|
||||
return sizeof(usb_cdc_descriptor_template);
|
||||
}
|
||||
|
||||
// Called only once, before boot.py
|
||||
void usb_cdc_init_usb(void) {
|
||||
usb_cdc_repl_is_enabled = true;
|
||||
usb_cdc_data_is_enabled = false;
|
||||
void usb_cdc_pre_boot_py(void) {
|
||||
usb_cdc_repl_is_enabled = CIRCUITPY_USB_CDC_REPL_ENABLED_DEFAULT;
|
||||
usb_cdc_data_is_enabled = CIRCUITPY_USB_CDC_DATA_ENABLED_DEFAULT;
|
||||
}
|
||||
|
||||
bool common_hal_usb_cdc_configure_usb(bool repl_enabled, bool data_enabled) {
|
||||
|
@ -33,7 +33,7 @@
|
||||
bool usb_cdc_repl_enabled(void);
|
||||
bool usb_cdc_data_enabled(void);
|
||||
|
||||
void usb_cdc_init_usb(void);
|
||||
void usb_cdc_pre_boot_py(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);
|
||||
|
||||
|
@ -85,6 +85,23 @@ static size_t total_hid_report_descriptor_length;
|
||||
static supervisor_allocation *hid_devices_allocation;
|
||||
static mp_int_t hid_devices_num;
|
||||
|
||||
static mp_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),
|
||||
},
|
||||
};
|
||||
|
||||
void usb_hid_pre_boot_py(void) {
|
||||
usb_hid_is_enabled = true;
|
||||
common_hal_usb_hid_configure_usb(&default_hid_devices_tuple);
|
||||
}
|
||||
|
||||
// This is the interface descriptor, not the report descriptor.
|
||||
size_t usb_hid_descriptor_length(void) {
|
||||
return sizeof(usb_hid_descriptor_template);
|
||||
@ -122,23 +139,6 @@ size_t usb_hid_add_descriptor(uint8_t *descriptor_buf, uint8_t *current_interfac
|
||||
return sizeof(usb_hid_descriptor_template);
|
||||
}
|
||||
|
||||
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(&default_hid_devices_tuple);
|
||||
}
|
||||
|
||||
bool common_hal_usb_hid_configure_usb(mp_obj_t devices) {
|
||||
// We can't change the devices once we're connected.
|
||||
if (tud_connected()) {
|
||||
@ -150,11 +150,6 @@ bool common_hal_usb_hid_configure_usb(mp_obj_t devices) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Called only once, before boot.py
|
||||
void usb_hid_init_usb(void) {
|
||||
usb_hid_is_enabled = true;
|
||||
}
|
||||
|
||||
// Build the combined HID report descriptor and save the chosen devices.
|
||||
// Both are saved in supervisor allocations.
|
||||
void usb_hid_post_boot_py(void) {
|
||||
@ -220,11 +215,6 @@ void usb_hid_post_boot_py(void) {
|
||||
}
|
||||
|
||||
void usb_hid_gc_collect(void) {
|
||||
if (tud_mounted()) {
|
||||
// Once tud_mounted() is true, we're done with the constructed descriptors.
|
||||
free_memory(hid_report_descriptor_allocation);
|
||||
}
|
||||
|
||||
gc_collect_ptr(hid_devices_seq);
|
||||
gc_collect_ptr(hid_report_descriptor_allocation->ptr);
|
||||
gc_collect_ptr(hid_devices_allocation->ptr);
|
||||
|
@ -33,7 +33,7 @@ extern usb_hid_device_obj_t usb_hid_devices[];
|
||||
|
||||
bool usb_hid_enabled(void);
|
||||
|
||||
void usb_hid_init_usb(void);
|
||||
void usb_hid_pre_boot_py(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);
|
||||
|
@ -159,6 +159,10 @@ static const uint8_t usb_midi_descriptor_template[] = {
|
||||
// Is the USB MIDI device enabled?
|
||||
static bool usb_midi_is_enabled;
|
||||
|
||||
void usb_midi_pre_boot_py(void) {
|
||||
usb_midi_is_enabled = CIRCUITPY_USB_MIDI_ENABLED_DEFAULT;
|
||||
}
|
||||
|
||||
bool usb_midi_enabled(void) {
|
||||
return usb_midi_is_enabled;
|
||||
}
|
||||
@ -208,35 +212,32 @@ size_t usb_midi_add_descriptor(uint8_t *descriptor_buf, uint8_t *current_interfa
|
||||
return sizeof(usb_midi_descriptor_template);
|
||||
}
|
||||
|
||||
static const usb_midi_portin_obj_t midi_portin_obj = {
|
||||
.base = {
|
||||
.type = &usb_midi_portin_type,
|
||||
},
|
||||
};
|
||||
|
||||
// Called once, before
|
||||
void usb_midi_init_usb(void) {
|
||||
usb_midi_is_enabled = true;
|
||||
}
|
||||
|
||||
// Called before REPL or code.py
|
||||
void usb_midi_setup(void) {
|
||||
mp_obj_tuple_t *ports;
|
||||
|
||||
if (usb_midi_is_enabled) {
|
||||
// Make these objects long-lived, because they will not be going away.
|
||||
|
||||
usb_midi_portin_obj_t *in = gc_alloc(sizeof(usb_midi_portin_obj_t), false, true);
|
||||
in->base.type = &usb_midi_portin_type;
|
||||
|
||||
usb_midi_portout_obj_t *out = gc_alloc(sizeof(usb_midi_portout_obj_t), false, true);
|
||||
out->base.type = &usb_midi_portout_type;
|
||||
|
||||
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;
|
||||
static const usb_midi_portout_obj_t midi_portout_obj = {
|
||||
.base = {
|
||||
.type = &usb_midi_portout_type,
|
||||
}
|
||||
};
|
||||
|
||||
static const mp_rom_obj_tuple_t midi_ports_tuple = {
|
||||
.base = {
|
||||
.type = &mp_type_tuple,
|
||||
},
|
||||
.len = 2,
|
||||
.items = {
|
||||
MP_ROM_PTR(&midi_portin_obj),
|
||||
MP_ROM_PTR(&midi_portout_obj),
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
void usb_midi_post_boot_py(void) {
|
||||
mp_obj_tuple_t *ports = usb_midi_is_enabled ? MP_OBJ_FROM_PTR(&midi_ports_tuple) : 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);
|
||||
}
|
||||
|
@ -28,8 +28,8 @@
|
||||
#define SHARED_MODULE_USB_MIDI___INIT___H
|
||||
|
||||
|
||||
void usb_midi_init_usb(void);
|
||||
void usb_midi_setup(void);
|
||||
void usb_midi_pre_boot_py(void);
|
||||
void usb_midi_post_boot_py(void);
|
||||
|
||||
bool usb_midi_enabled(void);
|
||||
size_t usb_midi_descriptor_length(void);
|
||||
|
@ -35,33 +35,43 @@
|
||||
enum {
|
||||
CIRCUITPY_SUPERVISOR_IMMOVABLE_ALLOC_COUNT =
|
||||
// stack + heap
|
||||
2
|
||||
#if INTERNAL_FLASH_FILESYSTEM == 0
|
||||
+ 1
|
||||
#endif
|
||||
2
|
||||
|
||||
#if INTERNAL_FLASH_FILESYSTEM == 0
|
||||
+ 1
|
||||
#endif
|
||||
|
||||
#if CIRCUITPY_USB
|
||||
+1 // device_descriptor_allocation
|
||||
+1 // configuration_descriptor_allocation
|
||||
+1 // string_descriptors_allocation
|
||||
#endif
|
||||
|
||||
#if CIRCUITPY_USB_HID
|
||||
+ 1 // hid_report_descriptor_allocation
|
||||
+ 1 // hid_devices_allocation
|
||||
#endif
|
||||
,
|
||||
|
||||
CIRCUITPY_SUPERVISOR_MOVABLE_ALLOC_COUNT =
|
||||
0
|
||||
#if CIRCUITPY_DISPLAYIO
|
||||
#if CIRCUITPY_TERMINALIO
|
||||
+ 1
|
||||
#endif
|
||||
+ CIRCUITPY_DISPLAY_LIMIT * (
|
||||
// Maximum needs of one display: max(4 if RGBMATRIX, 1 if SHARPDISPLAY, 0)
|
||||
#if CIRCUITPY_RGBMATRIX
|
||||
4
|
||||
#elif CIRCUITPY_SHARPDISPLAY
|
||||
1
|
||||
#else
|
||||
0
|
||||
#if CIRCUITPY_USB_HID
|
||||
+ 1 // hid_report_descriptor_allocation
|
||||
+ 1 // hid_devices_allocation
|
||||
#endif
|
||||
#if CIRCUITPY_DISPLAYIO
|
||||
#if CIRCUITPY_TERMINALIO
|
||||
+ 1
|
||||
#endif
|
||||
+ CIRCUITPY_DISPLAY_LIMIT * (
|
||||
// Maximum needs of one display: max(4 if RGBMATRIX, 1 if SHARPDISPLAY, 0)
|
||||
#if CIRCUITPY_RGBMATRIX
|
||||
4
|
||||
#elif CIRCUITPY_SHARPDISPLAY
|
||||
1
|
||||
#else
|
||||
0
|
||||
#endif
|
||||
)
|
||||
#endif
|
||||
)
|
||||
#endif
|
||||
,
|
||||
|
||||
CIRCUITPY_SUPERVISOR_ALLOC_COUNT = CIRCUITPY_SUPERVISOR_IMMOVABLE_ALLOC_COUNT + CIRCUITPY_SUPERVISOR_MOVABLE_ALLOC_COUNT
|
||||
};
|
||||
|
||||
|
@ -66,18 +66,10 @@ bool usb_enabled(void) {
|
||||
return tusb_inited();
|
||||
}
|
||||
|
||||
// Initialization done only once, before boot.py is run.
|
||||
void reset_usb(void) {
|
||||
reset_usb_desc();
|
||||
}
|
||||
|
||||
|
||||
MP_WEAK void post_usb_init(void) {
|
||||
}
|
||||
|
||||
void usb_init(void) {
|
||||
usb_desc_init();
|
||||
|
||||
init_usb_hardware();
|
||||
|
||||
tusb_init();
|
||||
@ -89,34 +81,40 @@ void usb_init(void) {
|
||||
// This usb_callback always got invoked regardless of mp_interrupt_char value since we only set it once here
|
||||
tud_cdc_set_wanted_char(CHAR_CTRL_C);
|
||||
#endif
|
||||
|
||||
#if CIRCUITPY_USB_MIDI
|
||||
usb_midi_setup();
|
||||
#endif
|
||||
}
|
||||
|
||||
// Set up USB defaults before any USB changes are made in boot.py
|
||||
void usb_pre_boot_py(void) {
|
||||
#if CIRCUITPY_STORAGE
|
||||
storage_init_usb();
|
||||
storage_pre_boot_py();
|
||||
#endif
|
||||
|
||||
#if CIRCUITPY_USB_CDC
|
||||
usb_cdc_init_usb();
|
||||
usb_cdc_pre_boot_py();
|
||||
#endif
|
||||
|
||||
#if CIRCUITPY_USB_HID
|
||||
usb_hid_init_usb();
|
||||
usb_hid_pre_boot_py();
|
||||
#endif
|
||||
|
||||
#if CIRCUITPY_USB_MIDI
|
||||
usb_midi_init_usb();
|
||||
usb_midi_pre_boot_py();
|
||||
#endif
|
||||
};
|
||||
|
||||
// Remember USB settings done during boot.py.
|
||||
// The boot.py heap is still valid at this point.
|
||||
// Act on USB settings done during boot.py.
|
||||
void usb_post_boot_py(void) {
|
||||
#if CIRCUITPY_USB
|
||||
usb_desc_post_boot_py();
|
||||
#endif
|
||||
|
||||
#if CIRCUITPY_USB_MIDI
|
||||
usb_midi_post_boot_py();
|
||||
#endif
|
||||
|
||||
#if CIRCUITPY_USB_HID
|
||||
usb_hid_post_boot_py();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -147,11 +145,6 @@ void usb_irq_handler(void) {
|
||||
usb_background_schedule();
|
||||
}
|
||||
|
||||
void usb_gc_collect(void) {
|
||||
usb_desc_gc_collect();
|
||||
usb_hid_gc_collect();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------+
|
||||
// tinyusb callbacks
|
||||
// --------------------------------------------------------------------+
|
||||
|
@ -26,9 +26,9 @@
|
||||
|
||||
#include "lib/tinyusb/src/tusb.h"
|
||||
|
||||
#include "py/gc.h"
|
||||
#include "py/objstr.h"
|
||||
#include "py/runtime.h"
|
||||
#include "supervisor/memory.h"
|
||||
#include "supervisor/usb.h"
|
||||
|
||||
#if CIRCUITPY_USB_CDC
|
||||
@ -51,17 +51,29 @@
|
||||
|
||||
|
||||
// Table for collecting interface strings (interface names) as descriptor is built.
|
||||
// We reuse the same table after collection, replacing the char string pointers with le16 string pointers.
|
||||
#define MAX_INTERFACE_STRINGS 16
|
||||
// slot 0 is always the Language ID
|
||||
static uint16_t *collected_interface_strings[MAX_INTERFACE_STRINGS];
|
||||
typedef union {
|
||||
const char *char_str;
|
||||
const uint16_t *descriptor;
|
||||
} interface_string_t;
|
||||
static interface_string_t collected_interface_strings[MAX_INTERFACE_STRINGS];
|
||||
|
||||
static size_t collected_interface_strings_length;
|
||||
static uint8_t current_interface_string;
|
||||
|
||||
supervisor_allocation *device_descriptor_allocation;
|
||||
supervisor_allocation *configuration_descriptor_allocation;
|
||||
supervisor_allocation *string_descriptors_allocation;
|
||||
|
||||
static const char manufacturer_name[] = USB_MANUFACTURER;
|
||||
static const char product_name[] = USB_PRODUCT;
|
||||
|
||||
// Serial number string is UID length * 2 (2 nibbles per byte) + 1 byte for null termination.
|
||||
static char serial_number_hex_string[COMMON_HAL_MCU_PROCESSOR_UID_LENGTH * 2 + 1];
|
||||
|
||||
|
||||
static const uint8_t device_descriptor_template[] = {
|
||||
0x12, // 0 bLength
|
||||
0x01, // 1 bDescriptorType (Device)
|
||||
@ -86,8 +98,6 @@ static const uint8_t device_descriptor_template[] = {
|
||||
0x01, // 17 bNumConfigurations 1
|
||||
};
|
||||
|
||||
static uint8_t device_descriptor[sizeof(device_descriptor_template)];
|
||||
|
||||
static const uint8_t configuration_descriptor_template[] = {
|
||||
0x09, // 0 bLength
|
||||
0x02, // 1 bDescriptorType (Configuration)
|
||||
@ -102,33 +112,10 @@ static const uint8_t configuration_descriptor_template[] = {
|
||||
0x32, // 8 bMaxPower 100mA
|
||||
};
|
||||
|
||||
static uint8_t *configuration_descriptor;
|
||||
|
||||
// Initialization done before boot.py is run.
|
||||
// Turn on or off various USB devices. On devices with limited endpoints,
|
||||
// some may be off by default.
|
||||
void reset_usb_desc(void) {
|
||||
// Set defaults for enabling/disabling of various USB devices.
|
||||
#if CIRCUITPY_USB_CDC
|
||||
common_hal_usb_cdc_configure_usb(
|
||||
(bool) CIRCUITPY_USB_CDC_REPL_ENABLED_DEFAULT,
|
||||
(bool) CIRCUITPY_USB_CDC_DATA_ENABLED_DEFAULT);
|
||||
#endif
|
||||
|
||||
#if CIRCUITPY_USB_MSC
|
||||
common_hal_storage_configure_usb((bool) CIRCUITPY_USB_MSC_ENABLED_DEFAULT);
|
||||
#endif
|
||||
|
||||
#if CIRCUITPY_USB_MIDI
|
||||
common_hal_usb_midi_configure_usb((bool) CIRCUITPY_USB_MIDI_ENABLED_DEFAULT);
|
||||
#endif
|
||||
|
||||
#if CIRCUITPY_USB_HID
|
||||
common_hal_usb_hid_configure_usb_defaults();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void usb_build_device_descriptor(uint16_t vid, uint16_t pid) {
|
||||
device_descriptor_allocation =
|
||||
allocate_memory(sizeof(device_descriptor_template), /*high_address*/ false, /*movable*/ false);
|
||||
uint8_t *device_descriptor = (uint8_t *) device_descriptor_allocation->ptr;
|
||||
memcpy(device_descriptor, device_descriptor_template, sizeof(device_descriptor_template));
|
||||
|
||||
device_descriptor[DEVICE_VID_LO_INDEX] = vid & 0xFF;
|
||||
@ -181,9 +168,13 @@ static void usb_build_configuration_descriptor(void) {
|
||||
}
|
||||
#endif
|
||||
|
||||
// Now we now how big the configuration descriptor will be.
|
||||
// Now we now how big the configuration descriptor will be, so we can allocate space for it.
|
||||
configuration_descriptor_allocation =
|
||||
allocate_memory(total_descriptor_length, /*high_address*/ false, /*movable*/ false);
|
||||
uint8_t *configuration_descriptor = (uint8_t *) configuration_descriptor_allocation->ptr;
|
||||
|
||||
// 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;
|
||||
@ -234,10 +225,7 @@ static void usb_build_configuration_descriptor(void) {
|
||||
#endif
|
||||
|
||||
// Now we know how many interfaces have been used.
|
||||
// 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;
|
||||
configuration_descriptor[CONFIG_NUM_INTERFACES_INDEX] = current_interface;
|
||||
|
||||
// Did we run out of endpoints?
|
||||
if (current_endpoint - 1 > USB_NUM_EP) {
|
||||
@ -246,40 +234,59 @@ static void usb_build_configuration_descriptor(void) {
|
||||
|
||||
}
|
||||
|
||||
// str must not be on the heap.
|
||||
void usb_add_interface_string(uint8_t interface_string_index, const char str[]) {
|
||||
if (interface_string_index > MAX_INTERFACE_STRINGS) {
|
||||
mp_raise_RuntimeError(translate("Too many USB interface names"));
|
||||
}
|
||||
// 2 bytes for String Descriptor header, then 2 bytes for each character
|
||||
const size_t str_len = strlen(str);
|
||||
uint8_t descriptor_size = 2 + (str_len * 2);
|
||||
uint16_t *string_descriptor = (uint16_t *) m_malloc(descriptor_size, false);
|
||||
string_descriptor[0] = 0x0300 | descriptor_size;
|
||||
// Convert to le16
|
||||
for (size_t i = 0; i <= str_len; i++) {
|
||||
string_descriptor[i + 1] = str[i];
|
||||
}
|
||||
|
||||
collected_interface_strings[interface_string_index] = string_descriptor;
|
||||
collected_interface_strings[interface_string_index].char_str = str;
|
||||
collected_interface_strings_length += strlen(str);
|
||||
}
|
||||
|
||||
static void usb_build_interface_string_table(void) {
|
||||
// Allocate space for the le16 String descriptors.
|
||||
// Space needed is 2 bytes for String Descriptor header, then 2 bytes for each character
|
||||
string_descriptors_allocation =
|
||||
allocate_memory(current_interface_string * 2 + collected_interface_strings_length * 2,
|
||||
/*high_address*/ false, /*movable*/ false);
|
||||
uint16_t *string_descriptors = (uint16_t *) string_descriptors_allocation->ptr;
|
||||
|
||||
// Remember USB information that must persist from the boot.py VM to the next VM.
|
||||
// Some of this is already remembered in globals, for example, usb_midi_enabled and similar bools.
|
||||
void usb_desc_post_boot_py(void) {
|
||||
usb_hid_post_boot_py();
|
||||
}
|
||||
|
||||
// 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));
|
||||
uint16_t *string_descriptor = string_descriptors;
|
||||
|
||||
// Language ID is always the 0th string descriptor.
|
||||
collected_interface_strings[0] = (uint16_t[]) {
|
||||
collected_interface_strings[0].descriptor = (uint16_t[]) {
|
||||
0x0304,
|
||||
0x0409,
|
||||
};
|
||||
|
||||
// Build the le16 versions of all the descriptor strings.
|
||||
// Start at 1 to skip the Language ID.
|
||||
for (uint8_t string_index = 1; string_index < current_interface_string; string_index++) {
|
||||
const char *str = collected_interface_strings[string_index].char_str;
|
||||
const size_t str_len = strlen(str);
|
||||
uint8_t descriptor_size = 2 + (str_len * 2);
|
||||
string_descriptor[0] = 0x0300 | descriptor_size;
|
||||
|
||||
// Convert to le16.
|
||||
for (size_t i = 0; i <= str_len; i++) {
|
||||
string_descriptor[i + 1] = str[i];
|
||||
}
|
||||
|
||||
// Save ptr to string descriptor with le16 str.
|
||||
collected_interface_strings[string_index].descriptor = string_descriptor;
|
||||
|
||||
// Move to next descriptor slot.
|
||||
string_descriptor += descriptor_size;
|
||||
}
|
||||
}
|
||||
|
||||
// After boot.py runs, the USB devices to be used have been chosen, and the descriptors can be set up.
|
||||
// This should be called before the heap is destroyed, so that any objects in the heap,
|
||||
// such as
|
||||
// can be used.
|
||||
void usb_desc_post_boot_py(void) {
|
||||
uint8_t raw_id[COMMON_HAL_MCU_PROCESSOR_UID_LENGTH];
|
||||
common_hal_mcu_processor_get_uid(raw_id);
|
||||
|
||||
@ -294,31 +301,17 @@ void usb_desc_init(void) {
|
||||
serial_number_hex_string[sizeof(serial_number_hex_string) - 1] = '\0';
|
||||
|
||||
current_interface_string = 1;
|
||||
collected_interface_strings_length = 0;
|
||||
|
||||
usb_build_device_descriptor(USB_VID, USB_PID);
|
||||
usb_build_configuration_descriptor();
|
||||
usb_build_interface_string_table();
|
||||
}
|
||||
|
||||
void usb_desc_gc_collect(void) {
|
||||
// Once tud_mounted() is true, we're done with the constructed descriptors.
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Invoked when GET DEVICE DESCRIPTOR is received.
|
||||
// Application return pointer to descriptor
|
||||
uint8_t const *tud_descriptor_device_cb(void) {
|
||||
return device_descriptor;
|
||||
return (uint8_t *) device_descriptor_allocation;
|
||||
}
|
||||
|
||||
// Invoked when GET CONFIGURATION DESCRIPTOR is received.
|
||||
@ -326,7 +319,7 @@ uint8_t const *tud_descriptor_device_cb(void) {
|
||||
// Descriptor contents must exist long enough for transfer to complete
|
||||
uint8_t const *tud_descriptor_configuration_cb(uint8_t index) {
|
||||
(void)index; // for multiple configurations
|
||||
return configuration_descriptor;
|
||||
return (uint8_t *) configuration_descriptor_allocation->ptr;
|
||||
}
|
||||
|
||||
// Invoked when GET STRING DESCRIPTOR request is received.
|
||||
@ -335,5 +328,5 @@ uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
|
||||
if (index > MAX_INTERFACE_STRINGS) {
|
||||
return NULL;
|
||||
}
|
||||
return collected_interface_strings[index];
|
||||
return collected_interface_strings[index].descriptor;
|
||||
}
|
||||
|
@ -49,20 +49,14 @@ void init_usb_hardware(void);
|
||||
void post_usb_init(void);
|
||||
|
||||
// Shared implementation.
|
||||
void reset_usb(void);
|
||||
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[]);
|
||||
|
||||
void reset_usb_desc(void);
|
||||
void usb_desc_gc_collect(void);
|
||||
void usb_desc_init(void);
|
||||
void usb_desc_post_boot_py(void);
|
||||
void usb_add_interface_string(uint8_t interface_string_index, const char str[]);
|
||||
|
||||
// Propagate plug/unplug events to the MSC logic.
|
||||
#if CIRCUITPY_USB_MSC
|
||||
|
Loading…
Reference in New Issue
Block a user