mass_storage_scene_work.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  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. view_dispatcher_send_custom_event(app->view_dispatcher, MassStorageCustomEventEject);
  47. }
  48. bool mass_storage_scene_work_on_event(void* context, SceneManagerEvent event) {
  49. MassStorageApp* app = context;
  50. bool consumed = false;
  51. if(event.type == SceneManagerEventTypeCustom) {
  52. if(event.event == MassStorageCustomEventEject) {
  53. consumed = scene_manager_search_and_switch_to_previous_scene(
  54. app->scene_manager, MassStorageSceneFileSelect);
  55. if(!consumed) {
  56. consumed = scene_manager_search_and_switch_to_previous_scene(
  57. app->scene_manager, MassStorageSceneStart);
  58. }
  59. }
  60. } else if(event.type == SceneManagerEventTypeTick) {
  61. mass_storage_set_stats(app->mass_storage_view, app->bytes_read, app->bytes_written);
  62. } else if(event.type == SceneManagerEventTypeBack) {
  63. consumed = scene_manager_search_and_switch_to_previous_scene(
  64. app->scene_manager, MassStorageSceneFileSelect);
  65. if(!consumed) {
  66. consumed = scene_manager_search_and_switch_to_previous_scene(
  67. app->scene_manager, MassStorageSceneStart);
  68. }
  69. }
  70. return consumed;
  71. }
  72. void mass_storage_scene_work_on_enter(void* context) {
  73. MassStorageApp* app = context;
  74. app->bytes_read = app->bytes_written = 0;
  75. if(!storage_file_exists(app->fs_api, furi_string_get_cstr(app->file_path))) {
  76. scene_manager_search_and_switch_to_previous_scene(
  77. app->scene_manager, MassStorageSceneStart);
  78. return;
  79. }
  80. mass_storage_app_show_loading_popup(app, true);
  81. app->usb_mutex = furi_mutex_alloc(FuriMutexTypeNormal);
  82. FuriString* file_name = furi_string_alloc();
  83. path_extract_filename(app->file_path, file_name, true);
  84. mass_storage_set_file_name(app->mass_storage_view, file_name);
  85. app->file = storage_file_alloc(app->fs_api);
  86. furi_assert(storage_file_open(
  87. app->file,
  88. furi_string_get_cstr(app->file_path),
  89. FSAM_READ | FSAM_WRITE,
  90. FSOM_OPEN_EXISTING));
  91. SCSIDeviceFunc fn = {
  92. .ctx = app,
  93. .read = file_read,
  94. .write = file_write,
  95. .num_blocks = file_num_blocks,
  96. .eject = file_eject,
  97. };
  98. app->usb = mass_storage_usb_start(furi_string_get_cstr(file_name), fn);
  99. furi_string_free(file_name);
  100. mass_storage_app_show_loading_popup(app, false);
  101. view_dispatcher_switch_to_view(app->view_dispatcher, MassStorageAppViewWork);
  102. }
  103. void mass_storage_scene_work_on_exit(void* context) {
  104. MassStorageApp* app = context;
  105. mass_storage_app_show_loading_popup(app, true);
  106. if(app->usb_mutex) {
  107. furi_mutex_free(app->usb_mutex);
  108. app->usb_mutex = NULL;
  109. }
  110. if(app->usb) {
  111. mass_storage_usb_stop(app->usb);
  112. app->usb = NULL;
  113. }
  114. if(app->file) {
  115. storage_file_free(app->file);
  116. app->file = NULL;
  117. }
  118. mass_storage_app_show_loading_popup(app, false);
  119. }