@@ -133,6 +133,9 @@ void supervisor_start_bluetooth_file_transfer(void) {
133133#define ANY_COMMAND 0x00
134134#define THIS_COMMAND 0x01
135135
136+ // FATFS has a two second timestamp resolution but the BLE API allows for nanosecond resolution.
137+ // This function truncates the time the time to a resolution storable by FATFS and fills in the
138+ // FATFS encoded version into fattime.
136139uint64_t truncate_time (uint64_t input_time , DWORD * fattime ) {
137140 timeutils_struct_time_t tm ;
138141 uint64_t seconds_since_epoch = timeutils_seconds_since_epoch_from_nanoseconds_since_1970 (input_time );
@@ -245,6 +248,22 @@ STATIC uint8_t _process_read_pacing(const uint8_t *raw_buf, size_t command_len)
245248STATIC size_t total_write_length ;
246249STATIC uint64_t _truncated_time ;
247250
251+ // Returns true if usb is active and replies with an error if so. If not, it grabs
252+ // the USB mass storage lock and returns false. Make sure to release the lock with
253+ // usb_msc_unlock() when the transaction is complete.
254+ STATIC bool _usb_active (void * response , size_t response_size ) {
255+ // Check to see if USB has already been mounted. If not, then we "eject" from USB until we're done.
256+ #if CIRCUITPY_USB && CIRCUITPY_USB_MSC
257+ if (storage_usb_enabled () && !usb_msc_lock ()) {
258+ // Status is always the second byte of the response.
259+ ((uint8_t * )response )[1 ] = STATUS_ERROR_READONLY ;
260+ common_hal_bleio_packet_buffer_write (& _transfer_packet_buffer , (const uint8_t * )response , response_size , NULL , 0 );
261+ return true;
262+ }
263+ #endif
264+ return false;
265+ }
266+
248267STATIC uint8_t _process_write (const uint8_t * raw_buf , size_t command_len ) {
249268 struct write_command * command = (struct write_command * )raw_buf ;
250269 size_t header_size = sizeof (struct write_command );
@@ -265,15 +284,9 @@ STATIC uint8_t _process_write(const uint8_t *raw_buf, size_t command_len) {
265284
266285 char * path = (char * )command -> path ;
267286 path [command -> path_length ] = '\0' ;
268-
269- // Check to see if USB has already been mounted. If not, then we "eject" from USB until we're done.
270- #if CIRCUITPY_USB && CIRCUITPY_USB_MSC
271- if (storage_usb_enabled () && !usb_msc_lock ()) {
272- response .status = STATUS_ERROR_READONLY ;
273- common_hal_bleio_packet_buffer_write (& _transfer_packet_buffer , (const uint8_t * )& response , sizeof (struct write_pacing ), NULL , 0 );
287+ if (_usb_active (& response , sizeof (struct write_pacing ))) {
274288 return ANY_COMMAND ;
275289 }
276- #endif
277290
278291 FATFS * fs = & ((fs_user_mount_t * )MP_STATE_VM (vfs_mount_table )-> obj )-> fatfs ;
279292 DWORD fattime ;
@@ -421,14 +434,9 @@ STATIC uint8_t _process_delete(const uint8_t *raw_buf, size_t command_len) {
421434 common_hal_bleio_packet_buffer_write (& _transfer_packet_buffer , (const uint8_t * )& response , sizeof (struct delete_status ), NULL , 0 );
422435 return ANY_COMMAND ;
423436 }
424- // Check to see if USB has already been mounted. If not, then we "eject" from USB until we're done.
425- #if CIRCUITPY_USB && CIRCUITPY_USB_MSC
426- if (storage_usb_enabled () && !usb_msc_lock ()) {
427- response .status = STATUS_ERROR_READONLY ;
428- common_hal_bleio_packet_buffer_write (& _transfer_packet_buffer , (const uint8_t * )& response , sizeof (struct delete_status ), NULL , 0 );
437+ if (_usb_active (& response , sizeof (struct delete_status ))) {
429438 return ANY_COMMAND ;
430439 }
431- #endif
432440 // We need to receive another packet to have the full path.
433441 if (command_len < header_size + command -> path_length ) {
434442 return THIS_COMMAND ;
@@ -462,6 +470,17 @@ STATIC uint8_t _process_delete(const uint8_t *raw_buf, size_t command_len) {
462470 return ANY_COMMAND ;
463471}
464472
473+ // NULL-terminate the path and remove any trailing /. Older versions of the
474+ // protocol require it but newer ones do not.
475+ STATIC void _terminate_path (char * path , size_t path_length ) {
476+ // -1 because fatfs doesn't want a trailing /
477+ if (path [path_length - 1 ] == '/' ) {
478+ path [path_length - 1 ] = '\0' ;
479+ } else {
480+ path [path_length ] = '\0' ;
481+ }
482+ }
483+
465484STATIC uint8_t _process_mkdir (const uint8_t * raw_buf , size_t command_len ) {
466485 const struct mkdir_command * command = (struct mkdir_command * )raw_buf ;
467486 size_t header_size = sizeof (struct mkdir_command );
@@ -474,26 +493,17 @@ STATIC uint8_t _process_mkdir(const uint8_t *raw_buf, size_t command_len) {
474493 common_hal_bleio_packet_buffer_write (& _transfer_packet_buffer , (const uint8_t * )& response , sizeof (struct mkdir_status ), NULL , 0 );
475494 return ANY_COMMAND ;
476495 }
477- // Check to see if USB has already been mounted. If not, then we "eject" from USB until we're done.
478- #if CIRCUITPY_USB && CIRCUITPY_USB_MSC
479- if (storage_usb_enabled () && !usb_msc_lock ()) {
480- response .status = STATUS_ERROR_READONLY ;
481- common_hal_bleio_packet_buffer_write (& _transfer_packet_buffer , (const uint8_t * )& response , sizeof (struct mkdir_status ), NULL , 0 );
496+ if (_usb_active (& response , sizeof (struct mkdir_status ))) {
482497 return ANY_COMMAND ;
483498 }
484- #endif
485499 // We need to receive another packet to have the full path.
486500 if (command_len < header_size + command -> path_length ) {
487501 return THIS_COMMAND ;
488502 }
489503 FATFS * fs = & ((fs_user_mount_t * )MP_STATE_VM (vfs_mount_table )-> obj )-> fatfs ;
490504 char * path = (char * )command -> path ;
491- // -1 because fatfs doesn't want a trailing /
492- if (path [command -> path_length - 1 ] == '/' ) {
493- path [command -> path_length - 1 ] = '\0' ;
494- } else {
495- path [command -> path_length ] = '\0' ;
496- }
505+ _terminate_path (path , command -> path_length );
506+
497507 DWORD fattime ;
498508 response .truncated_time = truncate_time (command -> modification_time , & fattime );
499509 override_fattime (fattime );
@@ -536,12 +546,7 @@ STATIC uint8_t _process_listdir(uint8_t *raw_buf, size_t command_len) {
536546
537547 FATFS * fs = & ((fs_user_mount_t * )MP_STATE_VM (vfs_mount_table )-> obj )-> fatfs ;
538548 char * path = (char * )& command -> path ;
539- // -1 because fatfs doesn't want a trailing /
540- if (path [command -> path_length - 1 ] == '/' ) {
541- path [command -> path_length - 1 ] = '\0' ;
542- } else {
543- path [command -> path_length ] = '\0' ;
544- }
549+ _terminate_path (path , command -> path_length );
545550 // mp_printf(&mp_plat_print, "list %s\n", path);
546551 FF_DIR dir ;
547552 FRESULT res = f_opendir (fs , & dir , path );
@@ -620,14 +625,9 @@ STATIC uint8_t _process_move(const uint8_t *raw_buf, size_t command_len) {
620625 common_hal_bleio_packet_buffer_write (& _transfer_packet_buffer , (const uint8_t * )& response , sizeof (struct move_status ), NULL , 0 );
621626 return ANY_COMMAND ;
622627 }
623- // Check to see if USB has already been mounted. If not, then we "eject" from USB until we're done.
624- #if CIRCUITPY_USB && CIRCUITPY_USB_MSC
625- if (storage_usb_enabled () && !usb_msc_lock ()) {
626- response .status = STATUS_ERROR_READONLY ;
627- common_hal_bleio_packet_buffer_write (& _transfer_packet_buffer , (const uint8_t * )& response , sizeof (struct move_status ), NULL , 0 );
628+ if (_usb_active (& response , sizeof (struct move_status ))) {
628629 return ANY_COMMAND ;
629630 }
630- #endif
631631 // We need to receive another packet to have the full path.
632632 if (command_len < header_size + total_path_length ) {
633633 return THIS_COMMAND ;
0 commit comments