acid-drop

- Hacking the planet from a LilyGo T-Deck using custom firmware
git clone git://git.acid.vegas/acid-drop.git
Log | Files | Refs | Archive | README | LICENSE

lv_fs.c (14032B)

      1 /**
      2  * @file lv_fs.c
      3  *
      4  */
      5 
      6 /*********************
      7  *      INCLUDES
      8  *********************/
      9 #include "lv_fs.h"
     10 
     11 #include "../misc/lv_assert.h"
     12 #include "lv_ll.h"
     13 #include <string.h>
     14 #include "lv_gc.h"
     15 
     16 /*********************
     17  *      DEFINES
     18  *********************/
     19 
     20 /**********************
     21  *      TYPEDEFS
     22  **********************/
     23 
     24 /**********************
     25  *  STATIC PROTOTYPES
     26  **********************/
     27 static const char * lv_fs_get_real_path(const char * path);
     28 
     29 /**********************
     30  *  STATIC VARIABLES
     31  **********************/
     32 
     33 /**********************
     34  *      MACROS
     35  **********************/
     36 
     37 /**********************
     38  *   GLOBAL FUNCTIONS
     39  **********************/
     40 
     41 void _lv_fs_init(void)
     42 {
     43     _lv_ll_init(&LV_GC_ROOT(_lv_fsdrv_ll), sizeof(lv_fs_drv_t *));
     44 }
     45 
     46 bool lv_fs_is_ready(char letter)
     47 {
     48     lv_fs_drv_t * drv = lv_fs_get_drv(letter);
     49 
     50     if(drv == NULL) return false; /*An unknown driver in not ready*/
     51 
     52     if(drv->ready_cb == NULL) return true; /*Assume the driver is always ready if no handler provided*/
     53 
     54     return drv->ready_cb(drv);
     55 }
     56 
     57 lv_fs_res_t lv_fs_open(lv_fs_file_t * file_p, const char * path, lv_fs_mode_t mode)
     58 {
     59     if(path == NULL) {
     60         LV_LOG_WARN("Can't open file: path is NULL");
     61         return LV_FS_RES_INV_PARAM;
     62     }
     63 
     64     char letter = path[0];
     65     lv_fs_drv_t * drv = lv_fs_get_drv(letter);
     66 
     67     if(drv == NULL) {
     68         LV_LOG_WARN("Can't open file (%s): unknown driver letter", path);
     69         return LV_FS_RES_NOT_EX;
     70     }
     71 
     72     if(drv->ready_cb) {
     73         if(drv->ready_cb(drv) == false) {
     74             LV_LOG_WARN("Can't open file (%s): driver not ready", path);
     75             return LV_FS_RES_HW_ERR;
     76         }
     77     }
     78 
     79     if(drv->open_cb == NULL) {
     80         LV_LOG_WARN("Can't open file (%s): open function not exists", path);
     81         return LV_FS_RES_NOT_IMP;
     82     }
     83 
     84     const char * real_path = lv_fs_get_real_path(path);
     85     void * file_d = drv->open_cb(drv, real_path, mode);
     86 
     87     if(file_d == NULL || file_d == (void *)(-1)) {
     88         return LV_FS_RES_UNKNOWN;
     89     }
     90 
     91     file_p->drv = drv;
     92     file_p->file_d = file_d;
     93 
     94     if(drv->cache_size) {
     95         file_p->cache = lv_mem_alloc(sizeof(lv_fs_file_cache_t));
     96         LV_ASSERT_MALLOC(file_p->cache);
     97         lv_memset_00(file_p->cache, sizeof(lv_fs_file_cache_t));
     98         file_p->cache->start = UINT32_MAX;  /*Set an invalid range by default*/
     99         file_p->cache->end = UINT32_MAX - 1;
    100     }
    101 
    102     return LV_FS_RES_OK;
    103 }
    104 
    105 lv_fs_res_t lv_fs_close(lv_fs_file_t * file_p)
    106 {
    107     if(file_p->drv == NULL) {
    108         return LV_FS_RES_INV_PARAM;
    109     }
    110 
    111     if(file_p->drv->close_cb == NULL) {
    112         return LV_FS_RES_NOT_IMP;
    113     }
    114 
    115     lv_fs_res_t res = file_p->drv->close_cb(file_p->drv, file_p->file_d);
    116 
    117     if(file_p->drv->cache_size && file_p->cache) {
    118         if(file_p->cache->buffer) {
    119             lv_mem_free(file_p->cache->buffer);
    120         }
    121 
    122         lv_mem_free(file_p->cache);
    123     }
    124 
    125     file_p->file_d = NULL;
    126     file_p->drv    = NULL;
    127     file_p->cache  = NULL;
    128 
    129     return res;
    130 }
    131 
    132 static lv_fs_res_t lv_fs_read_cached(lv_fs_file_t * file_p, char * buf, uint32_t btr, uint32_t * br)
    133 {
    134     lv_fs_res_t res = LV_FS_RES_OK;
    135     uint32_t file_position = file_p->cache->file_position;
    136     uint32_t start = file_p->cache->start;
    137     uint32_t end = file_p->cache->end;
    138     char * buffer = file_p->cache->buffer;
    139     uint16_t buffer_size = file_p->drv->cache_size;
    140 
    141     if(start <= file_position && file_position < end) {
    142         /* Data can be read from cache buffer */
    143         uint16_t buffer_offset = file_position - start;
    144         uint32_t buffer_remaining_length = LV_MIN((uint32_t)buffer_size - buffer_offset, (uint32_t)end - file_position);
    145 
    146         if(btr <= buffer_remaining_length) {
    147             /*Data is in cache buffer, and buffer end not reached, no need to read from FS*/
    148             lv_memcpy(buf, buffer + buffer_offset, btr);
    149             *br = btr;
    150         }
    151         else {
    152             /*First part of data is in cache buffer, but we need to read rest of data from FS*/
    153             lv_memcpy(buf, buffer + buffer_offset, buffer_remaining_length);
    154 
    155             uint32_t bytes_read_to_buffer = 0;
    156             if(btr > buffer_size) {
    157                 /*If remaining data chuck is bigger than buffer size, then do not use cache, instead read it directly from FS*/
    158                 res = file_p->drv->read_cb(file_p->drv, file_p->file_d, (void *)(buf + buffer_remaining_length),
    159                                            btr - buffer_remaining_length, &bytes_read_to_buffer);
    160             }
    161             else {
    162                 /*If remaining data chunk is smaller than buffer size, then read into cache buffer*/
    163                 res = file_p->drv->read_cb(file_p->drv, file_p->file_d, (void *)buffer, buffer_size, &bytes_read_to_buffer);
    164                 file_p->cache->start = file_p->cache->end;
    165                 file_p->cache->end = file_p->cache->start + bytes_read_to_buffer;
    166 
    167                 uint16_t data_chunk_remaining = LV_MIN(btr - buffer_remaining_length, bytes_read_to_buffer);
    168                 lv_memcpy(buf + buffer_remaining_length, buffer, data_chunk_remaining);
    169             }
    170             *br = LV_MIN(buffer_remaining_length + bytes_read_to_buffer, btr);
    171         }
    172     }
    173     else {
    174         /*Data is not in cache buffer*/
    175         if(btr > buffer_size) {
    176             /*If bigger data is requested, then do not use cache, instead read it directly*/
    177             res = file_p->drv->read_cb(file_p->drv, file_p->file_d, (void *)buf, btr, br);
    178         }
    179         else {
    180             /*If small data is requested, then read from FS into cache buffer*/
    181             if(buffer == NULL) {
    182                 file_p->cache->buffer = lv_mem_alloc(buffer_size);
    183                 LV_ASSERT_MALLOC(file_p->cache->buffer);
    184                 buffer = file_p->cache->buffer;
    185             }
    186 
    187             uint32_t bytes_read_to_buffer = 0;
    188             res = file_p->drv->read_cb(file_p->drv, file_p->file_d, (void *)buffer, buffer_size, &bytes_read_to_buffer);
    189             file_p->cache->start = file_position;
    190             file_p->cache->end = file_p->cache->start + bytes_read_to_buffer;
    191 
    192             *br = LV_MIN(btr, bytes_read_to_buffer);
    193             lv_memcpy(buf, buffer, *br);
    194 
    195         }
    196     }
    197 
    198     if(res == LV_FS_RES_OK) {
    199         file_p->cache->file_position += *br;
    200     }
    201 
    202     return res;
    203 }
    204 
    205 lv_fs_res_t lv_fs_read(lv_fs_file_t * file_p, void * buf, uint32_t btr, uint32_t * br)
    206 {
    207     if(br != NULL) *br = 0;
    208     if(file_p->drv == NULL) return LV_FS_RES_INV_PARAM;
    209     if(file_p->drv->read_cb == NULL) return LV_FS_RES_NOT_IMP;
    210 
    211     uint32_t br_tmp = 0;
    212     lv_fs_res_t res;
    213 
    214     if(file_p->drv->cache_size) {
    215         res = lv_fs_read_cached(file_p, (char *)buf, btr, &br_tmp);
    216     }
    217     else {
    218         res = file_p->drv->read_cb(file_p->drv, file_p->file_d, buf, btr, &br_tmp);
    219     }
    220 
    221     if(br != NULL) *br = br_tmp;
    222 
    223     return res;
    224 }
    225 
    226 lv_fs_res_t lv_fs_write(lv_fs_file_t * file_p, const void * buf, uint32_t btw, uint32_t * bw)
    227 {
    228     if(bw != NULL) *bw = 0;
    229 
    230     if(file_p->drv == NULL) {
    231         return LV_FS_RES_INV_PARAM;
    232     }
    233 
    234     if(file_p->drv->write_cb == NULL) {
    235         return LV_FS_RES_NOT_IMP;
    236     }
    237 
    238     uint32_t bw_tmp = 0;
    239     lv_fs_res_t res = file_p->drv->write_cb(file_p->drv, file_p->file_d, buf, btw, &bw_tmp);
    240     if(bw != NULL) *bw = bw_tmp;
    241 
    242     return res;
    243 }
    244 
    245 lv_fs_res_t lv_fs_seek(lv_fs_file_t * file_p, uint32_t pos, lv_fs_whence_t whence)
    246 {
    247     if(file_p->drv == NULL) {
    248         return LV_FS_RES_INV_PARAM;
    249     }
    250 
    251     if(file_p->drv->seek_cb == NULL) {
    252         return LV_FS_RES_NOT_IMP;
    253     }
    254 
    255     lv_fs_res_t res = LV_FS_RES_OK;
    256     if(file_p->drv->cache_size) {
    257         switch(whence) {
    258             case LV_FS_SEEK_SET: {
    259                     file_p->cache->file_position = pos;
    260 
    261                     /*FS seek if new position is outside cache buffer*/
    262                     if(file_p->cache->file_position < file_p->cache->start || file_p->cache->file_position > file_p->cache->end) {
    263                         res = file_p->drv->seek_cb(file_p->drv, file_p->file_d, file_p->cache->file_position, LV_FS_SEEK_SET);
    264                     }
    265 
    266                     break;
    267                 }
    268             case LV_FS_SEEK_CUR: {
    269                     file_p->cache->file_position += pos;
    270 
    271                     /*FS seek if new position is outside cache buffer*/
    272                     if(file_p->cache->file_position < file_p->cache->start || file_p->cache->file_position > file_p->cache->end) {
    273                         res = file_p->drv->seek_cb(file_p->drv, file_p->file_d, file_p->cache->file_position, LV_FS_SEEK_SET);
    274                     }
    275 
    276                     break;
    277                 }
    278             case LV_FS_SEEK_END: {
    279                     /*Because we don't know the file size, we do a little trick: do a FS seek, then get new file position from FS*/
    280                     res = file_p->drv->seek_cb(file_p->drv, file_p->file_d, pos, whence);
    281                     if(res == LV_FS_RES_OK) {
    282                         uint32_t tmp_position;
    283                         res = file_p->drv->tell_cb(file_p->drv, file_p->file_d, &tmp_position);
    284 
    285                         if(res == LV_FS_RES_OK) {
    286                             file_p->cache->file_position = tmp_position;
    287                         }
    288                     }
    289                     break;
    290                 }
    291         }
    292     }
    293     else {
    294         res = file_p->drv->seek_cb(file_p->drv, file_p->file_d, pos, whence);
    295     }
    296 
    297     return res;
    298 }
    299 
    300 lv_fs_res_t lv_fs_tell(lv_fs_file_t * file_p, uint32_t * pos)
    301 {
    302     if(file_p->drv == NULL) {
    303         *pos = 0;
    304         return LV_FS_RES_INV_PARAM;
    305     }
    306 
    307     if(file_p->drv->tell_cb == NULL) {
    308         *pos = 0;
    309         return LV_FS_RES_NOT_IMP;
    310     }
    311 
    312     lv_fs_res_t res;
    313     if(file_p->drv->cache_size) {
    314         *pos = file_p->cache->file_position;
    315         res = LV_FS_RES_OK;
    316     }
    317     else {
    318         res = file_p->drv->tell_cb(file_p->drv, file_p->file_d, pos);
    319     }
    320 
    321     return res;
    322 }
    323 
    324 lv_fs_res_t lv_fs_dir_open(lv_fs_dir_t * rddir_p, const char * path)
    325 {
    326     if(path == NULL) return LV_FS_RES_INV_PARAM;
    327 
    328     char letter = path[0];
    329     lv_fs_drv_t * drv = lv_fs_get_drv(letter);
    330 
    331     if(drv == NULL) {
    332         return LV_FS_RES_NOT_EX;
    333     }
    334 
    335     if(drv->ready_cb) {
    336         if(drv->ready_cb(drv) == false) {
    337             return LV_FS_RES_HW_ERR;
    338         }
    339     }
    340 
    341     if(drv->dir_open_cb == NULL) {
    342         return LV_FS_RES_NOT_IMP;
    343     }
    344 
    345     const char * real_path = lv_fs_get_real_path(path);
    346     void * dir_d = drv->dir_open_cb(drv, real_path);
    347 
    348     if(dir_d == NULL || dir_d == (void *)(-1)) {
    349         return LV_FS_RES_UNKNOWN;
    350     }
    351 
    352     rddir_p->drv = drv;
    353     rddir_p->dir_d = dir_d;
    354 
    355     return LV_FS_RES_OK;
    356 }
    357 
    358 lv_fs_res_t lv_fs_dir_read(lv_fs_dir_t * rddir_p, char * fn)
    359 {
    360     if(rddir_p->drv == NULL || rddir_p->dir_d == NULL) {
    361         fn[0] = '\0';
    362         return LV_FS_RES_INV_PARAM;
    363     }
    364 
    365     if(rddir_p->drv->dir_read_cb == NULL) {
    366         fn[0] = '\0';
    367         return LV_FS_RES_NOT_IMP;
    368     }
    369 
    370     lv_fs_res_t res = rddir_p->drv->dir_read_cb(rddir_p->drv, rddir_p->dir_d, fn);
    371 
    372     return res;
    373 }
    374 
    375 lv_fs_res_t lv_fs_dir_close(lv_fs_dir_t * rddir_p)
    376 {
    377     if(rddir_p->drv == NULL || rddir_p->dir_d == NULL) {
    378         return LV_FS_RES_INV_PARAM;
    379     }
    380 
    381     if(rddir_p->drv->dir_close_cb == NULL) {
    382         return LV_FS_RES_NOT_IMP;
    383     }
    384 
    385     lv_fs_res_t res = rddir_p->drv->dir_close_cb(rddir_p->drv, rddir_p->dir_d);
    386 
    387     rddir_p->dir_d = NULL;
    388     rddir_p->drv   = NULL;
    389 
    390     return res;
    391 }
    392 
    393 void lv_fs_drv_init(lv_fs_drv_t * drv)
    394 {
    395     lv_memset_00(drv, sizeof(lv_fs_drv_t));
    396 }
    397 
    398 void lv_fs_drv_register(lv_fs_drv_t * drv_p)
    399 {
    400     /*Save the new driver*/
    401     lv_fs_drv_t ** new_drv;
    402     new_drv = _lv_ll_ins_head(&LV_GC_ROOT(_lv_fsdrv_ll));
    403     LV_ASSERT_MALLOC(new_drv);
    404     if(new_drv == NULL) return;
    405 
    406     *new_drv = drv_p;
    407 }
    408 
    409 lv_fs_drv_t * lv_fs_get_drv(char letter)
    410 {
    411     lv_fs_drv_t ** drv;
    412 
    413     _LV_LL_READ(&LV_GC_ROOT(_lv_fsdrv_ll), drv) {
    414         if((*drv)->letter == letter) {
    415             return *drv;
    416         }
    417     }
    418 
    419     return NULL;
    420 }
    421 
    422 char * lv_fs_get_letters(char * buf)
    423 {
    424     lv_fs_drv_t ** drv;
    425     uint8_t i = 0;
    426 
    427     _LV_LL_READ(&LV_GC_ROOT(_lv_fsdrv_ll), drv) {
    428         buf[i] = (*drv)->letter;
    429         i++;
    430     }
    431 
    432     buf[i] = '\0';
    433 
    434     return buf;
    435 }
    436 
    437 const char * lv_fs_get_ext(const char * fn)
    438 {
    439     size_t i;
    440     for(i = strlen(fn); i > 0; i--) {
    441         if(fn[i] == '.') {
    442             return &fn[i + 1];
    443         }
    444         else if(fn[i] == '/' || fn[i] == '\\') {
    445             return ""; /*No extension if a '\' or '/' found*/
    446         }
    447     }
    448 
    449     return ""; /*Empty string if no '.' in the file name.*/
    450 }
    451 
    452 char * lv_fs_up(char * path)
    453 {
    454     size_t len = strlen(path);
    455     if(len == 0) return path;
    456 
    457     len--; /*Go before the trailing '\0'*/
    458 
    459     /*Ignore trailing '/' or '\'*/
    460     while(path[len] == '/' || path[len] == '\\') {
    461         path[len] = '\0';
    462         if(len > 0)
    463             len--;
    464         else
    465             return path;
    466     }
    467 
    468     size_t i;
    469     for(i = len; i > 0; i--) {
    470         if(path[i] == '/' || path[i] == '\\') break;
    471     }
    472 
    473     if(i > 0) path[i] = '\0';
    474 
    475     return path;
    476 }
    477 
    478 const char * lv_fs_get_last(const char * path)
    479 {
    480     size_t len = strlen(path);
    481     if(len == 0) return path;
    482 
    483     len--; /*Go before the trailing '\0'*/
    484 
    485     /*Ignore trailing '/' or '\'*/
    486     while(path[len] == '/' || path[len] == '\\') {
    487         if(len > 0)
    488             len--;
    489         else
    490             return path;
    491     }
    492 
    493     size_t i;
    494     for(i = len; i > 0; i--) {
    495         if(path[i] == '/' || path[i] == '\\') break;
    496     }
    497 
    498     /*No '/' or '\' in the path so return with path itself*/
    499     if(i == 0) return path;
    500 
    501     return &path[i + 1];
    502 }
    503 /**********************
    504  *   STATIC FUNCTIONS
    505  **********************/
    506 
    507 /**
    508  * Skip the driver letter and the possible : after the letter
    509  * @param path path string (E.g. S:/folder/file.txt)
    510  * @return pointer to the beginning of the real path (E.g. /folder/file.txt)
    511  */
    512 static const char * lv_fs_get_real_path(const char * path)
    513 {
    514     path++; /*Ignore the driver letter*/
    515     if(*path == ':') path++;
    516 
    517     return path;
    518 }