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