mass_storage_scene_work.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  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. return *out_len == clamp;
  23. }
  24. static bool file_write(void* ctx, uint32_t lba, uint16_t count, uint8_t* buf, uint32_t len) {
  25. MassStorageApp* app = ctx;
  26. FURI_LOG_T(TAG, "file_write lba=%08lX count=%04X len=%08lX", lba, count, len);
  27. if(len != count * SCSI_BLOCK_SIZE) {
  28. FURI_LOG_W(TAG, "bad write params count=%u len=%lu", count, len);
  29. return false;
  30. }
  31. if(!storage_file_seek(app->file, lba * SCSI_BLOCK_SIZE, true)) {
  32. FURI_LOG_W(TAG, "seek failed");
  33. return false;
  34. }
  35. return storage_file_write(app->file, buf, len) == len;
  36. }
  37. static uint32_t file_num_blocks(void* ctx) {
  38. MassStorageApp* app = ctx;
  39. return storage_file_size(app->file) / SCSI_BLOCK_SIZE;
  40. }
  41. static void file_eject(void* ctx) {
  42. MassStorageApp* app = ctx;
  43. FURI_LOG_D(TAG, "EJECT");
  44. furi_check(furi_mutex_acquire(app->usb_mutex, FuriWaitForever) == FuriStatusOk);
  45. mass_storage_usb_stop(app->usb);
  46. app->usb = NULL;
  47. furi_check(furi_mutex_release(app->usb_mutex) == FuriStatusOk);
  48. }
  49. bool mass_storage_scene_work_on_event(void* context, SceneManagerEvent event) {
  50. MassStorageApp* app = context;
  51. bool consumed = false;
  52. if(event.type == SceneManagerEventTypeTick) {
  53. bool ejected;
  54. furi_check(furi_mutex_acquire(app->usb_mutex, FuriWaitForever) == FuriStatusOk);
  55. ejected = app->usb == NULL;
  56. furi_check(furi_mutex_release(app->usb_mutex) == FuriStatusOk);
  57. if(ejected) {
  58. scene_manager_previous_scene(app->scene_manager);
  59. consumed = true;
  60. }
  61. } else if(event.type == SceneManagerEventTypeBack) {
  62. consumed = scene_manager_search_and_switch_to_previous_scene(
  63. app->scene_manager, MassStorageSceneFileSelect);
  64. if(!consumed) {
  65. consumed = scene_manager_search_and_switch_to_previous_scene(
  66. app->scene_manager, MassStorageSceneStart);
  67. }
  68. }
  69. return consumed;
  70. }
  71. void mass_storage_scene_work_on_enter(void* context) {
  72. MassStorageApp* app = context;
  73. if(!storage_file_exists(app->fs_api, furi_string_get_cstr(app->file_path))) {
  74. scene_manager_search_and_switch_to_previous_scene(
  75. app->scene_manager, MassStorageSceneStart);
  76. return;
  77. }
  78. mass_storage_app_show_loading_popup(app, true);
  79. app->usb_mutex = furi_mutex_alloc(FuriMutexTypeNormal);
  80. FuriString* file_name = furi_string_alloc();
  81. path_extract_filename(app->file_path, file_name, true);
  82. mass_storage_set_file_name(app->mass_storage_view, file_name);
  83. app->file = storage_file_alloc(app->fs_api);
  84. furi_assert(storage_file_open(
  85. app->file,
  86. furi_string_get_cstr(app->file_path),
  87. FSAM_READ | FSAM_WRITE,
  88. FSOM_OPEN_EXISTING));
  89. SCSIDeviceFunc fn = {
  90. .ctx = app,
  91. .read = file_read,
  92. .write = file_write,
  93. .num_blocks = file_num_blocks,
  94. .eject = file_eject,
  95. };
  96. app->usb = mass_storage_usb_start(furi_string_get_cstr(file_name), fn);
  97. furi_string_free(file_name);
  98. mass_storage_app_show_loading_popup(app, false);
  99. view_dispatcher_switch_to_view(app->view_dispatcher, MassStorageAppViewWork);
  100. }
  101. void mass_storage_scene_work_on_exit(void* context) {
  102. MassStorageApp* app = context;
  103. mass_storage_app_show_loading_popup(app, true);
  104. if(app->usb_mutex) {
  105. furi_mutex_free(app->usb_mutex);
  106. app->usb_mutex = NULL;
  107. }
  108. if(app->usb) {
  109. mass_storage_usb_stop(app->usb);
  110. app->usb = NULL;
  111. }
  112. if(app->file) {
  113. storage_file_free(app->file);
  114. app->file = NULL;
  115. }
  116. mass_storage_app_show_loading_popup(app, false);
  117. }