lv_ufs.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  1. /**
  2. * @file lv_ufs.c
  3. * Implementation of RAM file system which do NOT support directories.
  4. * The API is compatible with the lv_fs_int module.
  5. */
  6. /*********************
  7. * INCLUDES
  8. *********************/
  9. #include "lv_ufs.h"
  10. #if USE_LV_FILESYSTEM
  11. #include "lv_ll.h"
  12. #include <string.h>
  13. #include <stdio.h>
  14. #include <errno.h>
  15. /*********************
  16. * DEFINES
  17. *********************/
  18. /**********************
  19. * TYPEDEFS
  20. **********************/
  21. /**********************
  22. * STATIC PROTOTYPES
  23. **********************/
  24. static lv_ufs_ent_t* lv_ufs_ent_get(const char * fn);
  25. static lv_ufs_ent_t* lv_ufs_ent_new(const char * fn);
  26. /**********************
  27. * STATIC VARIABLES
  28. **********************/
  29. static lv_ll_t file_ll;
  30. static bool inited = false;
  31. /**********************
  32. * MACROS
  33. **********************/
  34. /**********************
  35. * GLOBAL FUNCTIONS
  36. **********************/
  37. /**
  38. * Create a driver for ufs and initialize it.
  39. */
  40. void lv_ufs_init(void)
  41. {
  42. lv_ll_init(&file_ll, sizeof(lv_ufs_ent_t));
  43. lv_fs_drv_t ufs_drv;
  44. memset(&ufs_drv, 0, sizeof(lv_fs_drv_t)); /*Initialization*/
  45. ufs_drv.file_size = sizeof(lv_ufs_file_t);
  46. ufs_drv.rddir_size = sizeof(lv_ufs_dir_t);
  47. ufs_drv.letter = UFS_LETTER;
  48. ufs_drv.ready = lv_ufs_ready;
  49. ufs_drv.open = lv_ufs_open;
  50. ufs_drv.close = lv_ufs_close;
  51. ufs_drv.remove = lv_ufs_remove;
  52. ufs_drv.read = lv_ufs_read;
  53. ufs_drv.write = lv_ufs_write;
  54. ufs_drv.seek = lv_ufs_seek;
  55. ufs_drv.tell = lv_ufs_tell;
  56. ufs_drv.size = lv_ufs_size;
  57. ufs_drv.trunc = lv_ufs_trunc;
  58. ufs_drv.free = lv_ufs_free;
  59. ufs_drv.dir_open = lv_ufs_dir_open;
  60. ufs_drv.dir_read = lv_ufs_dir_read;
  61. ufs_drv.dir_close = lv_ufs_dir_close;
  62. lv_fs_add_drv(&ufs_drv);
  63. inited = true;
  64. }
  65. /**
  66. * Give the state of the ufs
  67. * @return true if ufs is initialized and can be used else false
  68. */
  69. bool lv_ufs_ready(void)
  70. {
  71. return inited;
  72. }
  73. /**
  74. * Open a file in ufs
  75. * @param file_p pointer to a lv_ufs_file_t variable
  76. * @param fn name of the file. There are no directories so e.g. "myfile.txt"
  77. * @param mode element of 'fs_mode_t' enum or its 'OR' connection (e.g. FS_MODE_WR | FS_MODE_RD)
  78. * @return LV_FS_RES_OK: no error, the file is opened
  79. * any error from lv__fs_res_t enum
  80. */
  81. lv_fs_res_t lv_ufs_open (void * file_p, const char * fn, lv_fs_mode_t mode)
  82. {
  83. lv_ufs_file_t * fp = file_p; /*Convert type*/
  84. lv_ufs_ent_t* ent = lv_ufs_ent_get(fn);
  85. fp->ent = NULL;
  86. /*If the file not exists ...*/
  87. if( ent == NULL) {
  88. if((mode & LV_FS_MODE_WR) != 0) { /*Create the file if opened for write*/
  89. ent = lv_ufs_ent_new(fn);
  90. if(ent == NULL) return LV_FS_RES_FULL; /*No space for the new file*/
  91. } else {
  92. return LV_FS_RES_NOT_EX; /*Can not read not existing file*/
  93. }
  94. }
  95. /*Can not write already opened and const data files*/
  96. if((mode & LV_FS_MODE_WR) != 0) {
  97. if(ent->oc != 0) return LV_FS_RES_LOCKED;
  98. if(ent->const_data != 0) return LV_FS_RES_DENIED;
  99. }
  100. /*No error, the file can be opened*/
  101. fp->ent = ent;
  102. fp->ar = mode & LV_FS_MODE_RD ? 1 : 0;
  103. fp->aw = mode & LV_FS_MODE_WR ? 1 : 0;
  104. fp->rwp = 0;
  105. ent->oc ++;
  106. return LV_FS_RES_OK;
  107. }
  108. /**
  109. * Create a file with a constant data
  110. * @param fn name of the file (directories are not supported)
  111. * @param const_p pointer to a constant data
  112. * @param len length of the data pointed by 'const_p' in bytes
  113. * @return LV_FS_RES_OK: no error, the file is read
  114. * any error from lv__fs_res_t enum
  115. */
  116. lv_fs_res_t lv_ufs_create_const(const char * fn, const void * const_p, uint32_t len)
  117. {
  118. lv_ufs_file_t file;
  119. lv_fs_res_t res;
  120. /*Error if the file already exists*/
  121. res = lv_ufs_open(&file, fn, LV_FS_MODE_RD);
  122. if(res == LV_FS_RES_OK) {
  123. lv_ufs_close(&file);
  124. return LV_FS_RES_DENIED;
  125. }
  126. lv_ufs_close(&file);
  127. res = lv_ufs_open(&file, fn, LV_FS_MODE_WR);
  128. if(res != LV_FS_RES_OK) return res;
  129. lv_ufs_ent_t* ent = file.ent;
  130. if(ent->data_d != NULL) return LV_FS_RES_DENIED;
  131. ent->data_d = (void *) const_p;
  132. ent->size = len;
  133. ent->const_data = 1;
  134. res = lv_ufs_close(&file);
  135. if(res != LV_FS_RES_OK) return res;
  136. return LV_FS_RES_OK;
  137. }
  138. /**
  139. * Close an opened file
  140. * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open)
  141. * @return LV_FS_RES_OK: no error, the file is read
  142. * any error from lv__fs_res_t enum
  143. */
  144. lv_fs_res_t lv_ufs_close (void * file_p)
  145. {
  146. lv_ufs_file_t * fp = file_p; /*Convert type*/
  147. if(fp->ent == NULL) return LV_FS_RES_OK;
  148. /*Decrement the Open counter*/
  149. if(fp->ent->oc > 0) {
  150. fp->ent->oc--;
  151. }
  152. return LV_FS_RES_OK;
  153. }
  154. /**
  155. * Remove a file. The file can not be opened.
  156. * @param fn '\0' terminated string
  157. * @return LV_FS_RES_OK: no error, the file is removed
  158. * LV_FS_RES_DENIED: the file was opened, remove failed
  159. */
  160. lv_fs_res_t lv_ufs_remove(const char * fn)
  161. {
  162. lv_ufs_ent_t* ent = lv_ufs_ent_get(fn);
  163. if(ent == NULL) return LV_FS_RES_DENIED; /*File not exists*/
  164. /*Can not be deleted is opened*/
  165. if(ent->oc != 0) return LV_FS_RES_DENIED;
  166. lv_ll_rem(&file_ll, ent);
  167. lv_mem_free(ent->fn_d);
  168. ent->fn_d = NULL;
  169. if(ent->const_data == 0){
  170. lv_mem_free(ent->data_d);
  171. ent->data_d = NULL;
  172. }
  173. lv_mem_free(ent);
  174. return LV_FS_RES_OK;
  175. }
  176. /**
  177. * Read data from an opened file
  178. * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open )
  179. * @param buf pointer to a memory block where to store the read data
  180. * @param btr number of Bytes To Read
  181. * @param br the real number of read bytes (Byte Read)
  182. * @return LV_FS_RES_OK: no error, the file is read
  183. * any error from lv__fs_res_t enum
  184. */
  185. lv_fs_res_t lv_ufs_read (void * file_p, void * buf, uint32_t btr, uint32_t * br)
  186. {
  187. lv_ufs_file_t * fp = file_p; /*Convert type*/
  188. lv_ufs_ent_t* ent = fp->ent;
  189. *br = 0;
  190. if(ent->data_d == NULL || ent->size == 0) { /*Don't read empty files*/
  191. return LV_FS_RES_OK;
  192. } else if(fp->ar == 0) { /*The file is not opened for read*/
  193. return LV_FS_RES_DENIED;
  194. }
  195. /*No error, read the file*/
  196. if(fp->rwp + btr > ent->size) { /*Check too much bytes read*/
  197. *br = ent->size - fp->rwp;
  198. } else {
  199. *br = btr;
  200. }
  201. /*Read the data*/
  202. uint8_t * data8_p;
  203. if(ent->const_data == 0) {
  204. data8_p = (uint8_t*) ent->data_d;
  205. } else {
  206. data8_p = ent->data_d;
  207. }
  208. data8_p += fp->rwp;
  209. memcpy(buf, data8_p, *br);
  210. fp->rwp += *br; /*Refresh the read write pointer*/
  211. return LV_FS_RES_OK;
  212. }
  213. /**
  214. * Write data to an opened file
  215. * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open)
  216. * @param buf pointer to a memory block which content will be written
  217. * @param btw the number Bytes To Write
  218. * @param bw The real number of written bytes (Byte Written)
  219. * @return LV_FS_RES_OK: no error, the file is read
  220. * any error from lv__fs_res_t enum
  221. */
  222. lv_fs_res_t lv_ufs_write (void * file_p, const void * buf, uint32_t btw, uint32_t * bw)
  223. {
  224. lv_ufs_file_t * fp = file_p; /*Convert type*/
  225. *bw = 0;
  226. if(fp->aw == 0) return LV_FS_RES_DENIED; /*Not opened for write*/
  227. lv_ufs_ent_t* ent = fp->ent;
  228. /*Reallocate data array if it necessary*/
  229. uint32_t new_size = fp->rwp + btw;
  230. if(new_size > ent->size) {
  231. uint8_t* new_data = lv_mem_realloc(ent->data_d, new_size);
  232. if(new_data == NULL) return LV_FS_RES_FULL; /*Cannot allocate the new memory*/
  233. ent->data_d = new_data;
  234. ent->size = new_size;
  235. }
  236. /*Write the file*/
  237. uint8_t * data8_p = (uint8_t*) ent->data_d;
  238. data8_p += fp->rwp;
  239. memcpy(data8_p, buf, btw);
  240. *bw = btw;
  241. fp->rwp += *bw;
  242. return LV_FS_RES_OK;
  243. }
  244. /**
  245. * Set the read write pointer. Also expand the file size if necessary.
  246. * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open )
  247. * @param pos the new position of read write pointer
  248. * @return LV_FS_RES_OK: no error, the file is read
  249. * any error from lv__fs_res_t enum
  250. */
  251. lv_fs_res_t lv_ufs_seek (void * file_p, uint32_t pos)
  252. {
  253. lv_ufs_file_t * fp = file_p; /*Convert type*/
  254. lv_ufs_ent_t* ent = fp->ent;
  255. /*Simply move the rwp before EOF*/
  256. if(pos < ent->size) {
  257. fp->rwp = pos;
  258. } else { /*Expand the file size*/
  259. if(fp->aw == 0) return LV_FS_RES_DENIED; /*Not opened for write*/
  260. uint8_t* new_data = lv_mem_realloc(ent->data_d, pos);
  261. if(new_data == NULL) return LV_FS_RES_FULL; /*Out of memory*/
  262. ent->data_d = new_data;
  263. ent->size = pos;
  264. fp->rwp = pos;
  265. }
  266. return LV_FS_RES_OK;
  267. }
  268. /**
  269. * Give the position of the read write pointer
  270. * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open )
  271. * @param pos_p pointer to to store the result
  272. * @return LV_FS_RES_OK: no error, the file is read
  273. * any error from lv__fs_res_t enum
  274. */
  275. lv_fs_res_t lv_ufs_tell (void * file_p, uint32_t * pos_p)
  276. {
  277. lv_ufs_file_t * fp = file_p; /*Convert type*/
  278. *pos_p = fp->rwp;
  279. return LV_FS_RES_OK;
  280. }
  281. /**
  282. * Truncate the file size to the current position of the read write pointer
  283. * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open )
  284. * @return LV_FS_RES_OK: no error, the file is read
  285. * any error from lv__fs_res_t enum
  286. */
  287. lv_fs_res_t lv_ufs_trunc (void * file_p)
  288. {
  289. lv_ufs_file_t * fp = file_p; /*Convert type*/
  290. lv_ufs_ent_t* ent = fp->ent;
  291. if(fp->aw == 0) return LV_FS_RES_DENIED; /*Not opened for write*/
  292. void * new_data = lv_mem_realloc(ent->data_d, fp->rwp);
  293. if(new_data == NULL) return LV_FS_RES_FULL; /*Out of memory*/
  294. ent->data_d = new_data;
  295. ent->size = fp->rwp;
  296. return LV_FS_RES_OK;
  297. }
  298. /**
  299. * Give the size of the file in bytes
  300. * @param file_p file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open )
  301. * @param size_p pointer to store the size
  302. * @return LV_FS_RES_OK: no error, the file is read
  303. * any error from lv__fs_res_t enum
  304. */
  305. lv_fs_res_t lv_ufs_size (void * file_p, uint32_t * size_p)
  306. {
  307. lv_ufs_file_t * fp = file_p; /*Convert type*/
  308. lv_ufs_ent_t* ent = fp->ent;
  309. *size_p = ent->size;
  310. return LV_FS_RES_OK;
  311. }
  312. /**
  313. * Initialize a lv_ufs_read_dir_t variable to directory reading
  314. * @param rddir_p pointer to a 'ufs_dir_t' variable
  315. * @param path uFS doesn't support folders so it has to be ""
  316. * @return LV_FS_RES_OK or any error from lv__fs_res_t enum
  317. */
  318. lv_fs_res_t lv_ufs_dir_open(void * rddir_p, const char * path)
  319. {
  320. lv_ufs_dir_t * lv_ufs_rddir_p = rddir_p;
  321. lv_ufs_rddir_p->last_ent = NULL;
  322. if(path[0] != '\0') return LV_FS_RES_NOT_EX; /*Must be "" */
  323. else return LV_FS_RES_OK;
  324. }
  325. /**
  326. * Read the next file name
  327. * @param dir_p pointer to an initialized 'ufs_dir_t' variable
  328. * @param fn pointer to buffer to sore the file name
  329. * @return LV_FS_RES_OK or any error from lv__fs_res_t enum
  330. */
  331. lv_fs_res_t lv_ufs_dir_read(void * dir_p, char * fn)
  332. {
  333. lv_ufs_dir_t * ufs_dir_p = dir_p;
  334. if(ufs_dir_p->last_ent == NULL) {
  335. ufs_dir_p->last_ent = lv_ll_get_head(&file_ll);
  336. } else {
  337. ufs_dir_p->last_ent = lv_ll_get_next(&file_ll, ufs_dir_p->last_ent);
  338. }
  339. if(ufs_dir_p->last_ent != NULL) {
  340. strcpy(fn, ufs_dir_p->last_ent->fn_d);
  341. } else {
  342. fn[0] = '\0';
  343. }
  344. return LV_FS_RES_OK;
  345. }
  346. /**
  347. * Close the directory reading
  348. * @param rddir_p pointer to an initialized 'ufs_dir_t' variable
  349. * @return LV_FS_RES_OK or any error from lv__fs_res_t enum
  350. */
  351. lv_fs_res_t lv_ufs_dir_close(void * rddir_p)
  352. {
  353. (void)rddir_p;
  354. return LV_FS_RES_OK;
  355. }
  356. /**
  357. * Give the size of a drive
  358. * @param total_p pointer to store the total size [kB]
  359. * @param free_p pointer to store the free site [kB]
  360. * @return LV_FS_RES_OK or any error from 'lv_fs_res_t'
  361. */
  362. lv_fs_res_t lv_ufs_free (uint32_t * total_p, uint32_t * free_p)
  363. {
  364. #if LV_MEM_CUSTOM == 0
  365. lv_mem_monitor_t mon;
  366. lv_mem_monitor(&mon);
  367. *total_p = LV_MEM_SIZE >> 10; /*Convert bytes to kB*/
  368. *free_p = mon.free_size >> 10;
  369. #else
  370. *free_p = 0;
  371. #endif
  372. return LV_FS_RES_OK;
  373. }
  374. /**********************
  375. * STATIC FUNCTIONS
  376. **********************/
  377. /**
  378. * Gives the lv_ufs_entry from a filename
  379. * @param fn filename ('\0' terminated string)
  380. * @return pointer to the dynamically allocated entry with 'fn' filename.
  381. * NULL if no entry found with that name.
  382. */
  383. static lv_ufs_ent_t* lv_ufs_ent_get(const char * fn)
  384. {
  385. lv_ufs_ent_t* fp;
  386. LL_READ(file_ll, fp) {
  387. if(strcmp(fp->fn_d, fn) == 0) {
  388. return fp;
  389. }
  390. }
  391. return NULL;
  392. }
  393. /**
  394. * Create a new entry with 'fn' filename
  395. * @param fn filename ('\0' terminated string)
  396. * @return pointer to the dynamically allocated new entry.
  397. * NULL if no space for the entry.
  398. */
  399. static lv_ufs_ent_t* lv_ufs_ent_new(const char * fn)
  400. {
  401. lv_ufs_ent_t* new_ent = NULL;
  402. new_ent = lv_ll_ins_head(&file_ll); /*Create a new file*/
  403. if(new_ent == NULL) {
  404. return NULL;
  405. }
  406. new_ent->fn_d = lv_mem_alloc(strlen(fn) + 1); /*Save the name*/
  407. strcpy(new_ent->fn_d, fn);
  408. new_ent->data_d = NULL;
  409. new_ent->size = 0;
  410. new_ent->oc = 0;
  411. new_ent->const_data = 0;
  412. return new_ent;
  413. }
  414. #endif /*USE_LV_FILESYSTEM*/