|
|
|
|
/******************************************************************************
|
|
|
|
|
|
|
|
|
|
版权所有 (C), 2018-2099, Radkil
|
|
|
|
|
|
|
|
|
|
******************************************************************************
|
|
|
|
|
文 件 名 : rd_stdio.c
|
|
|
|
|
版 本 号 : 初稿
|
|
|
|
|
作 者 : Radkil
|
|
|
|
|
生成日期 : 2026年3月11日星期三
|
|
|
|
|
最近修改 :
|
|
|
|
|
功能描述 : 标准IO的实现
|
|
|
|
|
|
|
|
|
|
修改历史 :
|
|
|
|
|
1.日 期 : 2026年3月11日星期三
|
|
|
|
|
作 者 : Radkil
|
|
|
|
|
修改内容 : 创建文件
|
|
|
|
|
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
#include "rd_stdio.h"
|
|
|
|
|
#if LV_USE_FS_LITTLEFS
|
|
|
|
|
#include "../../lvgl/lvgl.h"
|
|
|
|
|
#endif
|
|
|
|
|
/*----------------------------------------------*
|
|
|
|
|
* 外部变量说明 *
|
|
|
|
|
*----------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------*
|
|
|
|
|
* 外部函数原型说明 *
|
|
|
|
|
*----------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------*
|
|
|
|
|
* 内部函数原型说明 *
|
|
|
|
|
*----------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------*
|
|
|
|
|
* 全局变量 *
|
|
|
|
|
*----------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------*
|
|
|
|
|
* 模块级变量 *
|
|
|
|
|
*----------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------*
|
|
|
|
|
* 常量定义 *
|
|
|
|
|
*----------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------*
|
|
|
|
|
* 宏定义 *
|
|
|
|
|
*----------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
#ifdef USE_W25QXX
|
|
|
|
|
#include "../littlefs/include/lfs.h"
|
|
|
|
|
#include "../littlefs/include/lfs_flashbd.h"
|
|
|
|
|
lfs_t g_lfs;
|
|
|
|
|
lfs_flashbd_t g_bd;
|
|
|
|
|
struct lfs_flashbd_config g_bd_cfg;
|
|
|
|
|
struct lfs_config g_cfg;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifndef WIN32
|
|
|
|
|
WEAK void *Rd_Fopen(const char *path, const char *mode)
|
|
|
|
|
{
|
|
|
|
|
#ifdef USE_W25QXX
|
|
|
|
|
#if LV_USE_FS_LITTLEFS
|
|
|
|
|
lv_fs_mode_t lv_mode;
|
|
|
|
|
if (strchr(mode, 'r') != NULL) lv_mode = LV_FS_MODE_RD;
|
|
|
|
|
else lv_mode = LV_FS_MODE_WR;
|
|
|
|
|
|
|
|
|
|
lv_fs_file_t *file = RD_MALLOC(sizeof(lv_fs_file_t));
|
|
|
|
|
if (NULL == file) return NULL;
|
|
|
|
|
lv_fs_res_t res = lv_fs_open(file, path, lv_mode);
|
|
|
|
|
if (LV_FS_RES_OK == res)
|
|
|
|
|
{
|
|
|
|
|
return (void *)file;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
printf("%s[%d]fs errno is %d\n", __FILE__, __LINE__, res);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
const char *p = path;
|
|
|
|
|
lfs_file_t *file = RD_MALLOC(sizeof(lfs_file_t));
|
|
|
|
|
int flags = 0;
|
|
|
|
|
if (strlen(path) >= 2 && path[1] == ':') p = path + 2;
|
|
|
|
|
/* 按 mode 首字符解析:r 只读 / w 写并截断 / a 追加;
|
|
|
|
|
带 '+' 则为读写。避免 "a+" 被误判为 TRUNC 清空文件 */
|
|
|
|
|
if (mode[0] == 'r') {
|
|
|
|
|
flags = LFS_O_RDONLY;
|
|
|
|
|
if (strchr(mode, '+')) flags = LFS_O_RDWR;
|
|
|
|
|
} else if (mode[0] == 'w') {
|
|
|
|
|
flags = LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC;
|
|
|
|
|
if (strchr(mode, '+')) flags = LFS_O_RDWR | LFS_O_CREAT | LFS_O_TRUNC;
|
|
|
|
|
} else if (mode[0] == 'a') {
|
|
|
|
|
flags = LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND;
|
|
|
|
|
if (strchr(mode, '+')) flags = LFS_O_RDWR | LFS_O_CREAT | LFS_O_APPEND;
|
|
|
|
|
} else {
|
|
|
|
|
flags = LFS_O_RDONLY; /* 未知 mode 默认只读 */
|
|
|
|
|
}
|
|
|
|
|
int err = lfs_file_open(&g_lfs, file, p, flags);
|
|
|
|
|
if(err) return NULL;
|
|
|
|
|
else return (void *)file;
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WEAK void *Rd_Open(const char *path, int flags, mode_t mode)
|
|
|
|
|
{
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WEAK ssize_t Rd_Mread(void *buf, size_t count, void *file)
|
|
|
|
|
{
|
|
|
|
|
#ifdef USE_W25QXX
|
|
|
|
|
#if LV_USE_FS_LITTLEFS
|
|
|
|
|
uint32_t size = 0;
|
|
|
|
|
lv_fs_file_t *fp = (lv_fs_file_t *)file;
|
|
|
|
|
lv_fs_res_t res = lv_fs_read(fp, buf, count, &size);
|
|
|
|
|
if (LV_FS_RES_OK == res)
|
|
|
|
|
{
|
|
|
|
|
return (ssize_t)size;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
printf("%s[%d]fs errno is %d\n", __FILE__, __LINE__, res);
|
|
|
|
|
return RD_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
lfs_ssize_t size = 0;
|
|
|
|
|
lfs_file_t *fp = (lfs_file_t *)file;
|
|
|
|
|
size = lfs_file_read(&g_lfs, fp, buf, count);
|
|
|
|
|
if (size >= 0)
|
|
|
|
|
{
|
|
|
|
|
return (ssize_t)size;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
printf("%s[%d]fs errno is %ld\n", __FILE__, __LINE__, size);
|
|
|
|
|
return RD_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
return RD_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WEAK ssize_t Rd_Mwrite(const void *buf, size_t count, void *file)
|
|
|
|
|
{
|
|
|
|
|
#ifdef USE_W25QXX
|
|
|
|
|
#if LV_USE_FS_LITTLEFS
|
|
|
|
|
uint32_t size = 0;
|
|
|
|
|
lv_fs_file_t *fp = (lv_fs_file_t *)file;
|
|
|
|
|
lv_fs_res_t res = lv_fs_write(fp, buf, count, &size);
|
|
|
|
|
if (LV_FS_RES_OK == res)
|
|
|
|
|
{
|
|
|
|
|
return (ssize_t)size;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
printf("%s[%d]fs errno is %d\n", __FILE__, __LINE__, res);
|
|
|
|
|
return RD_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
uint32_t size = 0;
|
|
|
|
|
lfs_file_t *fp = (lfs_file_t *)file;
|
|
|
|
|
size = lfs_file_write(&g_lfs, fp, buf, count);
|
|
|
|
|
if (size >= 0)
|
|
|
|
|
{
|
|
|
|
|
return (ssize_t)size;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
printf("%s[%d]fs errno is %ld\n", __FILE__, __LINE__, size);
|
|
|
|
|
return RD_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
return RD_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WEAK int Rd_Mclose(void *file)
|
|
|
|
|
{
|
|
|
|
|
#ifdef USE_W25QXX
|
|
|
|
|
#if LV_USE_FS_LITTLEFS
|
|
|
|
|
lv_fs_file_t *fp = (lv_fs_file_t *)file;
|
|
|
|
|
lv_fs_close(fp);
|
|
|
|
|
RD_FREE(file);
|
|
|
|
|
return 0;
|
|
|
|
|
#else
|
|
|
|
|
lfs_file_t *fp = (lfs_file_t *)file;
|
|
|
|
|
lfs_file_close(&g_lfs, fp);
|
|
|
|
|
RD_FREE(file);
|
|
|
|
|
return 0;
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
return RD_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WEAK int Rd_Mseek(void *file, long offset, int whence)
|
|
|
|
|
{
|
|
|
|
|
#ifdef USE_W25QXX
|
|
|
|
|
#if LV_USE_FS_LITTLEFS
|
|
|
|
|
lv_fs_file_t *fp = (lv_fs_file_t *)file;
|
|
|
|
|
lv_fs_whence_t lv_whence;
|
|
|
|
|
if (SEEK_END == whence) lv_whence = LV_FS_SEEK_END;
|
|
|
|
|
else if (SEEK_CUR == whence) lv_whence = LV_FS_SEEK_CUR;
|
|
|
|
|
else lv_whence = LV_FS_SEEK_SET;
|
|
|
|
|
|
|
|
|
|
lv_fs_res_t res = lv_fs_seek(fp, offset, lv_whence);
|
|
|
|
|
if (LV_FS_RES_OK == res)
|
|
|
|
|
{
|
|
|
|
|
return offset;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
printf("%s[%d]fs errno is %d\n", __FILE__, __LINE__, res);
|
|
|
|
|
return RD_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
lfs_file_t *fp = (lfs_file_t *)file;
|
|
|
|
|
int flags;
|
|
|
|
|
if (SEEK_END == whence) flags = LFS_SEEK_END;
|
|
|
|
|
else if (SEEK_CUR == whence) flags = LFS_SEEK_CUR;
|
|
|
|
|
else flags = LFS_SEEK_SET;
|
|
|
|
|
|
|
|
|
|
int res = lfs_file_seek(&g_lfs, fp, offset, flags);
|
|
|
|
|
if (res >= 0)
|
|
|
|
|
{
|
|
|
|
|
return offset;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
printf("%s[%d]fs errno is %d\n", __FILE__, __LINE__, res);
|
|
|
|
|
return RD_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
return RD_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WEAK char *Rd_Mgets(char *buf, int size, void *file)
|
|
|
|
|
{
|
|
|
|
|
if (!file || !buf || size <= 0) return NULL;
|
|
|
|
|
int i = 0;
|
|
|
|
|
char c;
|
|
|
|
|
|
|
|
|
|
while (i < size - 1)
|
|
|
|
|
{
|
|
|
|
|
ssize_t n = Rd_Mread(&c, 1, file);
|
|
|
|
|
if (n != 0)
|
|
|
|
|
{
|
|
|
|
|
// 读到 EOF 或 错误(Rd_Mread 返回 0 表示读满请求的字节数)
|
|
|
|
|
if (i == 0) return NULL; // 什么都没读到
|
|
|
|
|
break; // 读到了部分数据,也返回
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
buf[i++] = c;
|
|
|
|
|
if (c == '\n') break; // 遇到换行符停止
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
buf[i] = '\0'; // 添加字符串结束符
|
|
|
|
|
return buf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WEAK int Rd_Mputs(const char *str, void *file)
|
|
|
|
|
{
|
|
|
|
|
if (!file || !str) return RD_FAILURE;
|
|
|
|
|
size_t len = RD_STRLEN(str);
|
|
|
|
|
ssize_t written = Rd_Mwrite(str, len, file);
|
|
|
|
|
return (written == (ssize_t)len) ? RD_SUCCESS : RD_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WEAK long Rd_Mtell(void *file)
|
|
|
|
|
{
|
|
|
|
|
#ifdef USE_W25QXX
|
|
|
|
|
#if LV_USE_FS_LITTLEFS
|
|
|
|
|
uint32_t pos = 0;
|
|
|
|
|
lv_fs_file_t *fp = (lv_fs_file_t *)file;
|
|
|
|
|
lv_fs_res_t res = lv_fs_tell(fp, &pos);
|
|
|
|
|
if (LV_FS_RES_OK == res)
|
|
|
|
|
{
|
|
|
|
|
return pos;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
printf("%s[%d]fs errno is %d\n", __FILE__, __LINE__, res);
|
|
|
|
|
return RD_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
lfs_file_t *fp = (lfs_file_t *)file;
|
|
|
|
|
long pos = lfs_file_tell(&g_lfs, fp);
|
|
|
|
|
if (pos >= 0)
|
|
|
|
|
{
|
|
|
|
|
return pos;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
printf("%s[%d]fs errno is %ld\n", __FILE__, __LINE__, pos);
|
|
|
|
|
return RD_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
return RD_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WEAK int Rd_fflush(void *file)
|
|
|
|
|
{
|
|
|
|
|
return RD_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WEAK int Rd_remove(const char *filename)
|
|
|
|
|
{
|
|
|
|
|
#ifdef USE_W25QXX
|
|
|
|
|
const char *p = filename;
|
|
|
|
|
if (strlen(filename) >= 2 && filename[1] == ':') p = filename + 2;
|
|
|
|
|
int err = lfs_remove(&g_lfs, p);
|
|
|
|
|
if (err) { printf("lfs_remove(%s) failed: %d\n", p, err); return RD_FAILURE; }
|
|
|
|
|
return RD_SUCCESS;
|
|
|
|
|
#else
|
|
|
|
|
return RD_FAILURE;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WEAK int Rd_rename(const char *oldpath, const char *newpath)
|
|
|
|
|
{
|
|
|
|
|
#ifdef USE_W25QXX
|
|
|
|
|
const char *o = oldpath, *n = newpath;
|
|
|
|
|
if (strlen(oldpath) >= 2 && oldpath[1] == ':') o = oldpath + 2;
|
|
|
|
|
if (strlen(newpath) >= 2 && newpath[1] == ':') n = newpath + 2;
|
|
|
|
|
int err = lfs_rename(&g_lfs, o, n);
|
|
|
|
|
if (err) { printf("lfs_rename(%s,%s) failed: %d\n", o, n, err); return RD_FAILURE; }
|
|
|
|
|
return RD_SUCCESS;
|
|
|
|
|
#else
|
|
|
|
|
return RD_FAILURE;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WEAK void Rd_LittleFSInit(void)
|
|
|
|
|
{
|
|
|
|
|
#ifdef USE_W25QXX
|
|
|
|
|
// 1MB = 256 个扇区,从地址 1M 开始全部使用,即前边空出1M留做他用(1*1024*1024表示空出1M,12*256表示使用12M空间)
|
|
|
|
|
lfs_flashbd_default_config(&g_cfg, &g_bd, &g_bd_cfg, 1 * 1024 * 1024, 12 * 256, NULL, NULL, NULL);
|
|
|
|
|
|
|
|
|
|
int err = lfs_mount(&g_lfs, &g_cfg);
|
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
printf("mount error format...\n");
|
|
|
|
|
lfs_format(&g_lfs, &g_cfg);
|
|
|
|
|
lfs_mount(&g_lfs, &g_cfg);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
#else
|
|
|
|
|
return;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WEAK void Rd_FatFSInit(void)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WEAK int Rd_ListDir(const char *path, Rd_DirEntryCb callback, void *arg)
|
|
|
|
|
{
|
|
|
|
|
#ifdef USE_W25QXX
|
|
|
|
|
const char *p = path;
|
|
|
|
|
if (strlen(path) >= 2 && path[1] == ':') p = path + 2;
|
|
|
|
|
if (*p == '\0') p = "/";
|
|
|
|
|
|
|
|
|
|
lfs_dir_t dir;
|
|
|
|
|
int err = lfs_dir_open(&g_lfs, &dir, p);
|
|
|
|
|
if (err) return RD_FAILURE;
|
|
|
|
|
|
|
|
|
|
struct lfs_info info;
|
|
|
|
|
while (lfs_dir_read(&g_lfs, &dir, &info) > 0)
|
|
|
|
|
{
|
|
|
|
|
if (strcmp(info.name, ".") == 0 || strcmp(info.name, "..") == 0)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
int is_dir = (info.type == LFS_TYPE_DIR) ? 1 : 0;
|
|
|
|
|
if (callback(info.name, is_dir, info.size, arg) != 0)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lfs_dir_close(&g_lfs, &dir);
|
|
|
|
|
return RD_SUCCESS;
|
|
|
|
|
#else
|
|
|
|
|
(void)path;
|
|
|
|
|
(void)callback;
|
|
|
|
|
(void)arg;
|
|
|
|
|
return RD_FAILURE;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif
|