diff --git a/main.c b/main.c index ec25bcbf08..5ff243ef58 100755 --- a/main.c +++ b/main.c @@ -755,7 +755,7 @@ STATIC int run_repl(void) { usb_setup_with_vm(); #endif - autoreload_suspend(); + autoreload_suspend(AUTORELOAD_LOCK_REPL); // Set the status LED to the REPL color before running the REPL. For // NeoPixels and DotStars this will be sticky but for PWM or single LED it @@ -785,7 +785,7 @@ STATIC int run_repl(void) { status_led_deinit(); #endif - autoreload_resume(); + autoreload_resume(AUTORELOAD_LOCK_REPL); return exit_code; } diff --git a/supervisor/shared/autoreload.c b/supervisor/shared/autoreload.c index 19b683fff7..5c66c44298 100644 --- a/supervisor/shared/autoreload.c +++ b/supervisor/shared/autoreload.c @@ -35,7 +35,7 @@ supervisor_allocation *next_code_allocation; static volatile uint32_t autoreload_delay_ms = 0; static bool autoreload_enabled = false; -static bool autoreload_suspended = false; +static size_t autoreload_suspended = 0; volatile bool reload_requested = false; @@ -44,7 +44,7 @@ inline void autoreload_tick() { return; } if (autoreload_delay_ms == 1 && autoreload_enabled && - !autoreload_suspended && !reload_requested) { + autoreload_suspended == 0 && !reload_requested) { mp_raise_reload_exception(); reload_requested = true; supervisor_set_run_reason(RUN_REASON_AUTO_RELOAD); @@ -62,12 +62,12 @@ void autoreload_disable() { autoreload_enabled = false; } -void autoreload_suspend() { - autoreload_suspended = true; +void autoreload_suspend(size_t lock_mask) { + autoreload_suspended |= lock_mask; } -void autoreload_resume() { - autoreload_suspended = false; +void autoreload_resume(size_t lock_mask) { + autoreload_suspended &= ~lock_mask; } inline bool autoreload_is_enabled() { diff --git a/supervisor/shared/autoreload.h b/supervisor/shared/autoreload.h index 41f9faea85..7282b11a69 100644 --- a/supervisor/shared/autoreload.h +++ b/supervisor/shared/autoreload.h @@ -40,6 +40,11 @@ enum { SUPERVISOR_NEXT_CODE_OPT_NEWLY_SET = 0x20, }; +enum { + AUTORELOAD_LOCK_REPL = 0x1, + AUTORELOAD_LOCK_BLE = 0x2 +}; + typedef struct { uint8_t options; char filename[]; @@ -58,8 +63,8 @@ void autoreload_disable(void); bool autoreload_is_enabled(void); // Temporarily turn it off. Used during the REPL. -void autoreload_suspend(void); -void autoreload_resume(void); +void autoreload_suspend(size_t lock_mask); +void autoreload_resume(size_t lock_mask); void autoreload_now(void); diff --git a/supervisor/shared/bluetooth/file_transfer.c b/supervisor/shared/bluetooth/file_transfer.c index 943aed8c0f..d105892582 100644 --- a/supervisor/shared/bluetooth/file_transfer.c +++ b/supervisor/shared/bluetooth/file_transfer.c @@ -47,6 +47,7 @@ #include "supervisor/usb.h" #include "py/mpstate.h" +#include "py/stackctrl.h" STATIC bleio_service_obj_t supervisor_ble_service; STATIC bleio_uuid_obj_t supervisor_ble_service_uuid; @@ -97,7 +98,7 @@ void supervisor_start_bluetooth_file_transfer(void) { NULL, // no initial value NULL); // no description - uint32_t version = 1; + uint32_t version = 2; mp_buffer_info_t bufinfo; bufinfo.buf = &version; bufinfo.len = sizeof(version); @@ -291,7 +292,7 @@ STATIC uint8_t _process_write(const uint8_t *raw_buf, size_t command_len) { // Don't reload until everything is written out of the packet buffer. common_hal_bleio_packet_buffer_flush(&_transfer_packet_buffer); // Trigger an autoreload - autoreload_now(); + autoreload_start(); return ANY_COMMAND; } @@ -345,12 +346,45 @@ STATIC uint8_t _process_write_data(const uint8_t *raw_buf, size_t command_len) { // Don't reload until everything is written out of the packet buffer. common_hal_bleio_packet_buffer_flush(&_transfer_packet_buffer); // Trigger an autoreload - autoreload_now(); + autoreload_start(); return ANY_COMMAND; } return WRITE_DATA; } +STATIC FRESULT _delete_directory_contents(FATFS *fs, const TCHAR *path) { + FF_DIR dir; + FRESULT res = f_opendir(fs, &dir, path); + FILINFO file_info; + // Check the stack since we're putting paths on it. + if (mp_stack_usage() >= MP_STATE_THREAD(stack_limit)) { + return FR_INT_ERR; + } + while (res == FR_OK) { + res = f_readdir(&dir, &file_info); + if (res != FR_OK || file_info.fname[0] == '\0') { + break; + } + size_t pathlen = strlen(path); + size_t fnlen = strlen(file_info.fname); + TCHAR full_path[pathlen + 1 + fnlen]; + memcpy(full_path, path, pathlen); + full_path[pathlen] = '/'; + size_t full_pathlen = pathlen + 1 + fnlen; + memcpy(full_path + pathlen + 1, file_info.fname, fnlen); + full_path[full_pathlen] = '\0'; + if ((file_info.fattrib & AM_DIR) != 0) { + res = _delete_directory_contents(fs, full_path); + } + if (res != FR_OK) { + break; + } + res = f_unlink(fs, full_path); + } + f_closedir(&dir); + return res; +} + STATIC uint8_t _process_delete(const uint8_t *raw_buf, size_t command_len) { const struct delete_command *command = (struct delete_command *)raw_buf; size_t header_size = 4; @@ -370,7 +404,16 @@ STATIC uint8_t _process_delete(const uint8_t *raw_buf, size_t command_len) { FATFS *fs = &((fs_user_mount_t *)MP_STATE_VM(vfs_mount_table)->obj)->fatfs; char *path = (char *)((uint8_t *)command) + header_size; path[command->path_length] = '\0'; - FRESULT result = f_unlink(fs, path); + FRESULT result; + FILINFO file; + if (f_stat(fs, path, &file) == FR_OK) { + if ((file.fattrib & AM_DIR) != 0) { + result = _delete_directory_contents(fs, path); + } + if (result == FR_OK) { + result = f_unlink(fs, path); + } + } if (result != FR_OK) { response.status = STATUS_ERROR; } @@ -504,6 +547,7 @@ void supervisor_bluetooth_file_transfer_background(void) { if (size == 0) { break; } + autoreload_suspend(AUTORELOAD_LOCK_BLE); // TODO: If size < 0 return an error. current_offset += size; #if CIRCUITPY_VERBOSE_BLE @@ -521,6 +565,7 @@ void supervisor_bluetooth_file_transfer_background(void) { response[0] = next_command; response[1] = STATUS_ERROR_PROTOCOL; common_hal_bleio_packet_buffer_write(&_transfer_packet_buffer, response, 2, NULL, 0); + autoreload_resume(AUTORELOAD_LOCK_BLE); break; } switch (current_state) { @@ -550,6 +595,9 @@ void supervisor_bluetooth_file_transfer_background(void) { if (next_command != THIS_COMMAND) { current_offset = 0; } + if (next_command == ANY_COMMAND) { + autoreload_resume(AUTORELOAD_LOCK_BLE); + } } running = false; } @@ -558,4 +606,5 @@ void supervisor_bluetooth_file_transfer_disconnected(void) { next_command = ANY_COMMAND; current_offset = 0; f_close(&active_file); + autoreload_resume(AUTORELOAD_LOCK_BLE); }