mass_storage_scene_work.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. #include "../mass_storage_app_i.h"
  2. #include "../views/mass_storage_view.h"
  3. #include "../helpers/mass_storage_usb.h"
  4. #include <lib/toolbox/path.h>
  5. #define TAG "MassStorageSceneWork"
  6. static bool file_read(
  7. void* ctx,
  8. uint32_t lba,
  9. uint16_t count,
  10. uint8_t* out,
  11. uint32_t* out_len,
  12. uint32_t out_cap) {
  13. MassStorageApp* app = ctx;
  14. FURI_LOG_T(TAG, "file_read lba=%08lX count=%04X out_cap=%08lX", lba, count, out_cap);
  15. if(!storage_file_seek(app->file, lba * SCSI_BLOCK_SIZE, true)) {
  16. FURI_LOG_W(TAG, "seek failed");
  17. return false;
  18. }
  19. uint16_t clamp = MIN(out_cap, count * SCSI_BLOCK_SIZE);
  20. *out_len = storage_file_read(app->file, out, clamp);
  21. FURI_LOG_T(TAG, "%lu/%lu", *out_len, count * SCSI_BLOCK_SIZE);
  22. app->bytes_read += *out_len;
  23. return *out_len == clamp;
  24. }
  25. static bool file_write(void* ctx, uint32_t lba, uint16_t count, uint8_t* buf, uint32_t len) {
  26. MassStorageApp* app = ctx;
  27. FURI_LOG_T(TAG, "file_write lba=%08lX count=%04X len=%08lX", lba, count, len);
  28. if(len != count * SCSI_BLOCK_SIZE) {
  29. FURI_LOG_W(TAG, "bad write params count=%u len=%lu", count, len);
  30. return false;
  31. }
  32. if(!storage_file_seek(app->file, lba * SCSI_BLOCK_SIZE, true)) {
  33. FURI_LOG_W(TAG, "seek failed");
  34. return false;
  35. }
  36. app->bytes_written += len;
  37. return storage_file_write(app->file, buf, len) == len;
  38. }
  39. static uint32_t file_num_blocks(void* ctx) {
  40. MassStorageApp* app = ctx;
  41. return storage_file_size(app->file) / SCSI_BLOCK_SIZE;
  42. }
  43. static void file_eject(void* ctx) {
  44. MassStorageApp* app = ctx;
  45. FURI_LOG_D(TAG, "EJECT");
  46. furi_check(furi_mutex_acquire(app->usb_mutex, FuriWaitForever) == FuriStatusOk);
  47. mass_storage_usb_stop(app->usb);
  48. app->usb = NULL;
  49. furi_check(furi_mutex_release(app->usb_mutex) == FuriStatusOk);
  50. }
  51. bool mass_storage_scene_work_on_event(void* context, SceneManagerEvent event) {
  52. MassStorageApp* app = context;
  53. bool consumed = false;
  54. if(event.type == SceneManagerEventTypeTick) {
  55. // Update stats
  56. mass_storage_set_stats(app->mass_storage_view, app->bytes_read, app->bytes_written);
  57. // Handle eject
  58. bool ejected;
  59. furi_check(furi_mutex_acquire(app->usb_mutex, FuriWaitForever) == FuriStatusOk);
  60. ejected = app->usb == NULL;
  61. furi_check(furi_mutex_release(app->usb_mutex) == FuriStatusOk);
  62. if(ejected) {
  63. scene_manager_previous_scene(app->scene_manager);
  64. consumed = true;
  65. }
  66. } else if(event.type == SceneManagerEventTypeBack) {
  67. consumed = scene_manager_search_and_switch_to_previous_scene(
  68. app->scene_manager, MassStorageSceneFileSelect);
  69. if(!consumed) {
  70. consumed = scene_manager_search_and_switch_to_previous_scene(
  71. app->scene_manager, MassStorageSceneStart);
  72. }
  73. }
  74. return consumed;
  75. }
  76. void mass_storage_scene_work_on_enter(void* context) {
  77. MassStorageApp* app = context;
  78. app->bytes_read = app->bytes_written = 0;
  79. if(!storage_file_exists(app->fs_api, furi_string_get_cstr(app->file_path))) {
  80. scene_manager_search_and_switch_to_previous_scene(
  81. app->scene_manager, MassStorageSceneStart);
  82. return;
  83. }
  84. mass_storage_app_show_loading_popup(app, true);
  85. app->usb_mutex = furi_mutex_alloc(FuriMutexTypeNormal);
  86. FuriString* file_name = furi_string_alloc();
  87. path_extract_filename(app->file_path, file_name, true);
  88. mass_storage_set_file_name(app->mass_storage_view, file_name);
  89. app->file = storage_file_alloc(app->fs_api);
  90. furi_assert(storage_file_open(
  91. app->file,
  92. furi_string_get_cstr(app->file_path),
  93. FSAM_READ | FSAM_WRITE,
  94. FSOM_OPEN_EXISTING));
  95. SCSIDeviceFunc fn = {
  96. .ctx = app,
  97. .read = file_read,
  98. .write = file_write,
  99. .num_blocks = file_num_blocks,
  100. .eject = file_eject,
  101. };
  102. app->usb = mass_storage_usb_start(furi_string_get_cstr(file_name), fn);
  103. furi_string_free(file_name);
  104. mass_storage_app_show_loading_popup(app, false);
  105. view_dispatcher_switch_to_view(app->view_dispatcher, MassStorageAppViewWork);
  106. }
  107. void mass_storage_scene_work_on_exit(void* context) {
  108. MassStorageApp* app = context;
  109. mass_storage_app_show_loading_popup(app, true);
  110. if(app->usb_mutex) {
  111. furi_mutex_free(app->usb_mutex);
  112. app->usb_mutex = NULL;
  113. }
  114. if(app->usb) {
  115. mass_storage_usb_stop(app->usb);
  116. app->usb = NULL;
  117. }
  118. if(app->file) {
  119. storage_file_free(app->file);
  120. app->file = NULL;
  121. }
  122. mass_storage_app_show_loading_popup(app, false);
  123. }