storage_ext.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637
  1. #include "fatfs.h"
  2. #include "../filesystem_api_internal.h"
  3. #include "storage_ext.h"
  4. #include <furi_hal.h>
  5. #include "sd_notify.h"
  6. #include <furi_hal_sd.h>
  7. typedef FIL SDFile;
  8. typedef DIR SDDir;
  9. typedef FILINFO SDFileInfo;
  10. typedef FRESULT SDError;
  11. #define TAG "StorageExt"
  12. /********************* Definitions ********************/
  13. typedef struct {
  14. FATFS* fs;
  15. const char* path;
  16. bool sd_was_present;
  17. } SDData;
  18. static FS_Error storage_ext_parse_error(SDError error);
  19. /******************* Core Functions *******************/
  20. static bool sd_mount_card(StorageData* storage, bool notify) {
  21. bool result = false;
  22. uint8_t counter = sd_max_mount_retry_count();
  23. uint8_t bsp_result;
  24. SDData* sd_data = storage->data;
  25. while(result == false && counter > 0 && hal_sd_detect()) {
  26. if(notify) {
  27. NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
  28. sd_notify_wait(notification);
  29. furi_record_close(RECORD_NOTIFICATION);
  30. }
  31. if((counter % 2) == 0) {
  32. // power reset sd card
  33. bsp_result = sd_init(true);
  34. } else {
  35. bsp_result = sd_init(false);
  36. }
  37. if(bsp_result) {
  38. // bsp error
  39. storage->status = StorageStatusErrorInternal;
  40. } else {
  41. SDError status = f_mount(sd_data->fs, sd_data->path, 1);
  42. if(status == FR_OK || status == FR_NO_FILESYSTEM) {
  43. #ifndef FURI_RAM_EXEC
  44. FATFS* fs;
  45. uint32_t free_clusters;
  46. status = f_getfree(sd_data->path, &free_clusters, &fs);
  47. #endif
  48. if(status == FR_OK || status == FR_NO_FILESYSTEM) {
  49. result = true;
  50. }
  51. if(status == FR_OK) {
  52. storage->status = StorageStatusOK;
  53. } else if(status == FR_NO_FILESYSTEM) {
  54. storage->status = StorageStatusNoFS;
  55. } else {
  56. storage->status = StorageStatusNotAccessible;
  57. }
  58. } else {
  59. storage->status = StorageStatusNotMounted;
  60. }
  61. }
  62. if(notify) {
  63. NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
  64. sd_notify_wait_off(notification);
  65. furi_record_close(RECORD_NOTIFICATION);
  66. }
  67. if(!result) {
  68. furi_delay_ms(1000);
  69. FURI_LOG_E(
  70. TAG, "init cycle %d, error: %s", counter, storage_data_status_text(storage));
  71. counter--;
  72. }
  73. }
  74. storage_data_timestamp(storage);
  75. return result;
  76. }
  77. FS_Error sd_unmount_card(StorageData* storage) {
  78. SDData* sd_data = storage->data;
  79. SDError error;
  80. storage->status = StorageStatusNotReady;
  81. error = FR_DISK_ERR;
  82. // TODO do i need to close the files?
  83. f_mount(0, sd_data->path, 0);
  84. return storage_ext_parse_error(error);
  85. }
  86. FS_Error sd_format_card(StorageData* storage) {
  87. #ifdef FURI_RAM_EXEC
  88. UNUSED(storage);
  89. return FSE_NOT_READY;
  90. #else
  91. uint8_t* work_area;
  92. SDData* sd_data = storage->data;
  93. SDError error;
  94. work_area = malloc(_MAX_SS);
  95. error = f_mkfs(sd_data->path, FM_ANY, 0, work_area, _MAX_SS);
  96. free(work_area);
  97. do {
  98. storage->status = StorageStatusNotAccessible;
  99. if(error != FR_OK) break;
  100. storage->status = StorageStatusNoFS;
  101. error = f_setlabel("Flipper SD");
  102. if(error != FR_OK) break;
  103. storage->status = StorageStatusNotMounted;
  104. error = f_mount(sd_data->fs, sd_data->path, 1);
  105. if(error != FR_OK) break;
  106. storage->status = StorageStatusOK;
  107. } while(false);
  108. return storage_ext_parse_error(error);
  109. #endif
  110. }
  111. FS_Error sd_card_info(StorageData* storage, SDInfo* sd_info) {
  112. #ifndef FURI_RAM_EXEC
  113. uint32_t free_clusters, free_sectors, total_sectors;
  114. FATFS* fs;
  115. #endif
  116. SDData* sd_data = storage->data;
  117. SDError error;
  118. // clean data
  119. memset(sd_info, 0, sizeof(SDInfo));
  120. // get fs info
  121. error = f_getlabel(sd_data->path, sd_info->label, NULL);
  122. if(error == FR_OK) {
  123. #ifndef FURI_RAM_EXEC
  124. error = f_getfree(sd_data->path, &free_clusters, &fs);
  125. #endif
  126. }
  127. if(error == FR_OK) {
  128. // calculate size
  129. #ifndef FURI_RAM_EXEC
  130. total_sectors = (fs->n_fatent - 2) * fs->csize;
  131. free_sectors = free_clusters * fs->csize;
  132. #endif
  133. uint16_t sector_size = _MAX_SS;
  134. #if _MAX_SS != _MIN_SS
  135. sector_size = fs->ssize;
  136. #endif
  137. #ifdef FURI_RAM_EXEC
  138. sd_info->fs_type = 0;
  139. sd_info->kb_total = 0;
  140. sd_info->kb_free = 0;
  141. sd_info->cluster_size = 512;
  142. sd_info->sector_size = sector_size;
  143. #else
  144. sd_info->fs_type = fs->fs_type;
  145. switch(fs->fs_type) {
  146. case FS_FAT12:
  147. sd_info->fs_type = FST_FAT12;
  148. break;
  149. case FS_FAT16:
  150. sd_info->fs_type = FST_FAT16;
  151. break;
  152. case FS_FAT32:
  153. sd_info->fs_type = FST_FAT32;
  154. break;
  155. case FS_EXFAT:
  156. sd_info->fs_type = FST_EXFAT;
  157. break;
  158. default:
  159. sd_info->fs_type = FST_UNKNOWN;
  160. break;
  161. }
  162. sd_info->kb_total = total_sectors / 1024 * sector_size;
  163. sd_info->kb_free = free_sectors / 1024 * sector_size;
  164. sd_info->cluster_size = fs->csize;
  165. sd_info->sector_size = sector_size;
  166. #endif
  167. }
  168. SD_CID cid;
  169. SdSpiStatus status = sd_get_cid(&cid);
  170. if(status == SdSpiStatusOK) {
  171. sd_info->manufacturer_id = cid.ManufacturerID;
  172. memcpy(sd_info->oem_id, cid.OEM_AppliID, sizeof(cid.OEM_AppliID));
  173. memcpy(sd_info->product_name, cid.ProdName, sizeof(cid.ProdName));
  174. sd_info->product_revision_major = cid.ProdRev >> 4;
  175. sd_info->product_revision_minor = cid.ProdRev & 0x0F;
  176. sd_info->product_serial_number = cid.ProdSN;
  177. sd_info->manufacturing_year = 2000 + cid.ManufactYear;
  178. sd_info->manufacturing_month = cid.ManufactMonth;
  179. }
  180. return storage_ext_parse_error(error);
  181. }
  182. static void storage_ext_tick_internal(StorageData* storage, bool notify) {
  183. SDData* sd_data = storage->data;
  184. if(sd_data->sd_was_present) {
  185. if(hal_sd_detect()) {
  186. FURI_LOG_I(TAG, "card detected");
  187. sd_mount_card(storage, notify);
  188. if(storage->status != StorageStatusOK) {
  189. FURI_LOG_E(TAG, "sd init error: %s", storage_data_status_text(storage));
  190. if(notify) {
  191. NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
  192. sd_notify_error(notification);
  193. furi_record_close(RECORD_NOTIFICATION);
  194. }
  195. } else {
  196. FURI_LOG_I(TAG, "card mounted");
  197. if(notify) {
  198. NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
  199. sd_notify_success(notification);
  200. furi_record_close(RECORD_NOTIFICATION);
  201. }
  202. }
  203. sd_data->sd_was_present = false;
  204. if(!hal_sd_detect()) {
  205. FURI_LOG_I(TAG, "card removed while mounting");
  206. sd_unmount_card(storage);
  207. sd_data->sd_was_present = true;
  208. }
  209. }
  210. } else {
  211. if(!hal_sd_detect()) {
  212. FURI_LOG_I(TAG, "card removed");
  213. sd_data->sd_was_present = true;
  214. sd_unmount_card(storage);
  215. if(notify) {
  216. NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
  217. sd_notify_eject(notification);
  218. furi_record_close(RECORD_NOTIFICATION);
  219. }
  220. }
  221. }
  222. }
  223. static void storage_ext_tick(StorageData* storage) {
  224. storage_ext_tick_internal(storage, true);
  225. }
  226. /****************** Common Functions ******************/
  227. static FS_Error storage_ext_parse_error(SDError error) {
  228. FS_Error result;
  229. switch(error) {
  230. case FR_OK:
  231. result = FSE_OK;
  232. break;
  233. case FR_NOT_READY:
  234. result = FSE_NOT_READY;
  235. break;
  236. case FR_NO_FILE:
  237. case FR_NO_PATH:
  238. case FR_NO_FILESYSTEM:
  239. result = FSE_NOT_EXIST;
  240. break;
  241. case FR_EXIST:
  242. result = FSE_EXIST;
  243. break;
  244. case FR_INVALID_NAME:
  245. result = FSE_INVALID_NAME;
  246. break;
  247. case FR_INVALID_OBJECT:
  248. case FR_INVALID_PARAMETER:
  249. result = FSE_INVALID_PARAMETER;
  250. break;
  251. case FR_DENIED:
  252. result = FSE_DENIED;
  253. break;
  254. default:
  255. result = FSE_INTERNAL;
  256. break;
  257. }
  258. return result;
  259. }
  260. /******************* File Functions *******************/
  261. static bool storage_ext_file_open(
  262. void* ctx,
  263. File* file,
  264. const char* path,
  265. FS_AccessMode access_mode,
  266. FS_OpenMode open_mode) {
  267. StorageData* storage = ctx;
  268. uint8_t _mode = 0;
  269. if(access_mode & FSAM_READ) _mode |= FA_READ;
  270. if(access_mode & FSAM_WRITE) _mode |= FA_WRITE;
  271. if(open_mode & FSOM_OPEN_EXISTING) _mode |= FA_OPEN_EXISTING;
  272. if(open_mode & FSOM_OPEN_ALWAYS) _mode |= FA_OPEN_ALWAYS;
  273. if(open_mode & FSOM_OPEN_APPEND) _mode |= FA_OPEN_APPEND;
  274. if(open_mode & FSOM_CREATE_NEW) _mode |= FA_CREATE_NEW;
  275. if(open_mode & FSOM_CREATE_ALWAYS) _mode |= FA_CREATE_ALWAYS;
  276. SDFile* file_data = malloc(sizeof(SDFile));
  277. storage_set_storage_file_data(file, file_data, storage);
  278. file->internal_error_id = f_open(file_data, path, _mode);
  279. file->error_id = storage_ext_parse_error(file->internal_error_id);
  280. return (file->error_id == FSE_OK);
  281. }
  282. static bool storage_ext_file_close(void* ctx, File* file) {
  283. StorageData* storage = ctx;
  284. SDFile* file_data = storage_get_storage_file_data(file, storage);
  285. file->internal_error_id = f_close(file_data);
  286. file->error_id = storage_ext_parse_error(file->internal_error_id);
  287. free(file_data);
  288. storage_set_storage_file_data(file, NULL, storage);
  289. return (file->error_id == FSE_OK);
  290. }
  291. static uint16_t
  292. storage_ext_file_read(void* ctx, File* file, void* buff, uint16_t const bytes_to_read) {
  293. StorageData* storage = ctx;
  294. SDFile* file_data = storage_get_storage_file_data(file, storage);
  295. uint16_t bytes_read = 0;
  296. file->internal_error_id = f_read(file_data, buff, bytes_to_read, &bytes_read);
  297. file->error_id = storage_ext_parse_error(file->internal_error_id);
  298. return bytes_read;
  299. }
  300. static uint16_t
  301. storage_ext_file_write(void* ctx, File* file, const void* buff, uint16_t const bytes_to_write) {
  302. #ifdef FURI_RAM_EXEC
  303. UNUSED(ctx);
  304. UNUSED(file);
  305. UNUSED(buff);
  306. UNUSED(bytes_to_write);
  307. return FSE_NOT_READY;
  308. #else
  309. StorageData* storage = ctx;
  310. SDFile* file_data = storage_get_storage_file_data(file, storage);
  311. uint16_t bytes_written = 0;
  312. file->internal_error_id = f_write(file_data, buff, bytes_to_write, &bytes_written);
  313. file->error_id = storage_ext_parse_error(file->internal_error_id);
  314. return bytes_written;
  315. #endif
  316. }
  317. static bool
  318. storage_ext_file_seek(void* ctx, File* file, const uint32_t offset, const bool from_start) {
  319. StorageData* storage = ctx;
  320. SDFile* file_data = storage_get_storage_file_data(file, storage);
  321. if(from_start) {
  322. file->internal_error_id = f_lseek(file_data, offset);
  323. } else {
  324. uint64_t position = f_tell(file_data);
  325. position += offset;
  326. file->internal_error_id = f_lseek(file_data, position);
  327. }
  328. file->error_id = storage_ext_parse_error(file->internal_error_id);
  329. return (file->error_id == FSE_OK);
  330. }
  331. static uint64_t storage_ext_file_tell(void* ctx, File* file) {
  332. StorageData* storage = ctx;
  333. SDFile* file_data = storage_get_storage_file_data(file, storage);
  334. uint64_t position = 0;
  335. position = f_tell(file_data);
  336. file->error_id = FSE_OK;
  337. return position;
  338. }
  339. static bool storage_ext_file_truncate(void* ctx, File* file) {
  340. #ifdef FURI_RAM_EXEC
  341. UNUSED(ctx);
  342. UNUSED(file);
  343. return FSE_NOT_READY;
  344. #else
  345. StorageData* storage = ctx;
  346. SDFile* file_data = storage_get_storage_file_data(file, storage);
  347. file->internal_error_id = f_truncate(file_data);
  348. file->error_id = storage_ext_parse_error(file->internal_error_id);
  349. return (file->error_id == FSE_OK);
  350. #endif
  351. }
  352. static bool storage_ext_file_sync(void* ctx, File* file) {
  353. #ifdef FURI_RAM_EXEC
  354. UNUSED(ctx);
  355. UNUSED(file);
  356. return FSE_NOT_READY;
  357. #else
  358. StorageData* storage = ctx;
  359. SDFile* file_data = storage_get_storage_file_data(file, storage);
  360. file->internal_error_id = f_sync(file_data);
  361. file->error_id = storage_ext_parse_error(file->internal_error_id);
  362. return (file->error_id == FSE_OK);
  363. #endif
  364. }
  365. static uint64_t storage_ext_file_size(void* ctx, File* file) {
  366. StorageData* storage = ctx;
  367. SDFile* file_data = storage_get_storage_file_data(file, storage);
  368. uint64_t size = 0;
  369. size = f_size(file_data);
  370. file->error_id = FSE_OK;
  371. return size;
  372. }
  373. static bool storage_ext_file_eof(void* ctx, File* file) {
  374. StorageData* storage = ctx;
  375. SDFile* file_data = storage_get_storage_file_data(file, storage);
  376. bool eof = f_eof(file_data);
  377. file->internal_error_id = 0;
  378. file->error_id = FSE_OK;
  379. return eof;
  380. }
  381. /******************* Dir Functions *******************/
  382. static bool storage_ext_dir_open(void* ctx, File* file, const char* path) {
  383. StorageData* storage = ctx;
  384. SDDir* file_data = malloc(sizeof(SDDir));
  385. storage_set_storage_file_data(file, file_data, storage);
  386. file->internal_error_id = f_opendir(file_data, path);
  387. file->error_id = storage_ext_parse_error(file->internal_error_id);
  388. return (file->error_id == FSE_OK);
  389. }
  390. static bool storage_ext_dir_close(void* ctx, File* file) {
  391. StorageData* storage = ctx;
  392. SDDir* file_data = storage_get_storage_file_data(file, storage);
  393. file->internal_error_id = f_closedir(file_data);
  394. file->error_id = storage_ext_parse_error(file->internal_error_id);
  395. free(file_data);
  396. return (file->error_id == FSE_OK);
  397. }
  398. static bool storage_ext_dir_read(
  399. void* ctx,
  400. File* file,
  401. FileInfo* fileinfo,
  402. char* name,
  403. const uint16_t name_length) {
  404. StorageData* storage = ctx;
  405. SDDir* file_data = storage_get_storage_file_data(file, storage);
  406. SDFileInfo _fileinfo;
  407. file->internal_error_id = f_readdir(file_data, &_fileinfo);
  408. file->error_id = storage_ext_parse_error(file->internal_error_id);
  409. if(fileinfo != NULL) {
  410. fileinfo->size = _fileinfo.fsize;
  411. fileinfo->flags = 0;
  412. if(_fileinfo.fattrib & AM_DIR) fileinfo->flags |= FSF_DIRECTORY;
  413. }
  414. if(name != NULL) {
  415. snprintf(name, name_length, "%s", _fileinfo.fname);
  416. }
  417. if(_fileinfo.fname[0] == 0) {
  418. file->error_id = FSE_NOT_EXIST;
  419. }
  420. return (file->error_id == FSE_OK);
  421. }
  422. static bool storage_ext_dir_rewind(void* ctx, File* file) {
  423. StorageData* storage = ctx;
  424. SDDir* file_data = storage_get_storage_file_data(file, storage);
  425. file->internal_error_id = f_readdir(file_data, NULL);
  426. file->error_id = storage_ext_parse_error(file->internal_error_id);
  427. return (file->error_id == FSE_OK);
  428. }
  429. /******************* Common FS Functions *******************/
  430. static FS_Error storage_ext_common_stat(void* ctx, const char* path, FileInfo* fileinfo) {
  431. UNUSED(ctx);
  432. SDFileInfo _fileinfo;
  433. SDError result = f_stat(path, &_fileinfo);
  434. if(fileinfo != NULL) {
  435. fileinfo->size = _fileinfo.fsize;
  436. fileinfo->flags = 0;
  437. if(_fileinfo.fattrib & AM_DIR) fileinfo->flags |= FSF_DIRECTORY;
  438. }
  439. return storage_ext_parse_error(result);
  440. }
  441. static FS_Error storage_ext_common_remove(void* ctx, const char* path) {
  442. UNUSED(ctx);
  443. #ifdef FURI_RAM_EXEC
  444. UNUSED(path);
  445. return FSE_NOT_READY;
  446. #else
  447. SDError result = f_unlink(path);
  448. return storage_ext_parse_error(result);
  449. #endif
  450. }
  451. static FS_Error storage_ext_common_mkdir(void* ctx, const char* path) {
  452. UNUSED(ctx);
  453. #ifdef FURI_RAM_EXEC
  454. UNUSED(path);
  455. return FSE_NOT_READY;
  456. #else
  457. SDError result = f_mkdir(path);
  458. return storage_ext_parse_error(result);
  459. #endif
  460. }
  461. static FS_Error storage_ext_common_fs_info(
  462. void* ctx,
  463. const char* fs_path,
  464. uint64_t* total_space,
  465. uint64_t* free_space) {
  466. UNUSED(fs_path);
  467. #ifdef FURI_RAM_EXEC
  468. UNUSED(ctx);
  469. UNUSED(total_space);
  470. UNUSED(free_space);
  471. return FSE_NOT_READY;
  472. #else
  473. StorageData* storage = ctx;
  474. SDData* sd_data = storage->data;
  475. DWORD free_clusters;
  476. FATFS* fs;
  477. SDError fresult = f_getfree(sd_data->path, &free_clusters, &fs);
  478. if((FRESULT)fresult == FR_OK) {
  479. uint32_t total_sectors = (fs->n_fatent - 2) * fs->csize;
  480. uint32_t free_sectors = free_clusters * fs->csize;
  481. uint16_t sector_size = _MAX_SS;
  482. #if _MAX_SS != _MIN_SS
  483. sector_size = fs->ssize;
  484. #endif
  485. if(total_space != NULL) {
  486. *total_space = (uint64_t)total_sectors * (uint64_t)sector_size;
  487. }
  488. if(free_space != NULL) {
  489. *free_space = (uint64_t)free_sectors * (uint64_t)sector_size;
  490. }
  491. }
  492. return storage_ext_parse_error(fresult);
  493. #endif
  494. }
  495. /******************* Init Storage *******************/
  496. static const FS_Api fs_api = {
  497. .file =
  498. {
  499. .open = storage_ext_file_open,
  500. .close = storage_ext_file_close,
  501. .read = storage_ext_file_read,
  502. .write = storage_ext_file_write,
  503. .seek = storage_ext_file_seek,
  504. .tell = storage_ext_file_tell,
  505. .truncate = storage_ext_file_truncate,
  506. .size = storage_ext_file_size,
  507. .sync = storage_ext_file_sync,
  508. .eof = storage_ext_file_eof,
  509. },
  510. .dir =
  511. {
  512. .open = storage_ext_dir_open,
  513. .close = storage_ext_dir_close,
  514. .read = storage_ext_dir_read,
  515. .rewind = storage_ext_dir_rewind,
  516. },
  517. .common =
  518. {
  519. .stat = storage_ext_common_stat,
  520. .mkdir = storage_ext_common_mkdir,
  521. .remove = storage_ext_common_remove,
  522. .fs_info = storage_ext_common_fs_info,
  523. },
  524. };
  525. void storage_ext_init(StorageData* storage) {
  526. fatfs_init();
  527. SDData* sd_data = malloc(sizeof(SDData));
  528. sd_data->fs = &fatfs_object;
  529. sd_data->path = "0:/";
  530. sd_data->sd_was_present = true;
  531. storage->data = sd_data;
  532. storage->api.tick = storage_ext_tick;
  533. storage->fs_api = &fs_api;
  534. hal_sd_detect_init();
  535. // do not notify on first launch, notifications app is waiting for our thread to read settings
  536. storage_ext_tick_internal(storage, false);
  537. }