luat_lib_fatfs.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. /*
  2. @module fatfs
  3. @summary 读写fatfs格式
  4. @version 1.0
  5. @date 2020.07.03
  6. @demo fatfs
  7. @tag LUAT_USE_FATFS
  8. @usage
  9. -- 通常只使用fatfs.mount挂载tf/sd卡,其他操作走io库就可以了
  10. */
  11. #include "luat_base.h"
  12. #include "luat_spi.h"
  13. #include "luat_sdio.h"
  14. #include "luat_timer.h"
  15. #include "luat_gpio.h"
  16. #include "luat_mem.h"
  17. #include "luat_fs.h"
  18. #include "ff.h" /* Obtains integer types */
  19. #include "diskio.h" /* Declarations of disk functions */
  20. #define LUAT_LOG_TAG "fatfs"
  21. #include "luat_log.h"
  22. static FATFS *fs = NULL; /* FatFs work area needed for each volume */
  23. extern BYTE FATFS_DEBUG; // debug log, 0 -- disable , 1 -- enable
  24. extern BYTE FATFS_POWER_PIN;
  25. extern uint16_t FATFS_POWER_DELAY;
  26. extern uint8_t FATFS_NO_CRC_CHECK;
  27. extern uint16_t FATFS_WRITE_TO;
  28. DRESULT diskio_open_ramdisk(BYTE pdrv, size_t len);
  29. DRESULT diskio_open_spitf(BYTE pdrv, void* userdata);
  30. DRESULT diskio_open_sdio(BYTE pdrv, void* userdata);
  31. #ifdef LUAT_USE_FS_VFS
  32. extern const struct luat_vfs_filesystem vfs_fs_fatfs;
  33. #endif
  34. static int s_fatfs_fmt = FM_FAT32;
  35. /*
  36. 挂载fatfs
  37. @api fatfs.mount(mode,mount_point, spiid_or_spidevice, spi_cs, spi_speed, power_pin, power_on_delay, auto_format)
  38. @int fatfs模式,可选fatfs.SPI,fatfs.SDIO,fatfs.RAM,fatfs.USB
  39. @string 虚拟文件系统的挂载点, 默认是 /fatfs
  40. @int 传入spi device指针,或者spi的id,或者sdio的id
  41. @int 片选脚的GPIO 号, spi模式有效. 特别约定,若前一个参数传的是spi device,这个参数要传SPI最高速度, 就是传2个"SPI最高速度", 也可以两个都填nil.
  42. @int SPI最高速度,默认10M.
  43. @int TF卡电源控制脚,TF卡初始前先拉低复位再拉高,如果没有,或者是内置电源控制方式,这个参数就不需要传
  44. @int TF卡电源复位过程时间,单位ms,默认值是1
  45. @bool 挂载失败是否尝试格式化,默认是true,即自动格式化. 本参数在2023.8.16添加
  46. @return bool 成功返回true, 否则返回nil或者false
  47. @return string 失败的原因
  48. @usage
  49. -- 方法1, 使用SPI模式
  50. local spiId = 2
  51. local result = spi.setup(
  52. spiId,--spi id
  53. 255, -- 不使用默认CS脚
  54. 0,--CPHA
  55. 0,--CPOL
  56. 8,--数据宽度
  57. 400*1000 -- 初始化时使用较低的频率
  58. )
  59. local TF_CS = 8
  60. gpio.setup(TF_CS, 1)
  61. --fatfs.debug(1) -- 若挂载失败,可以尝试打开调试信息,查找原因
  62. -- 提醒, 若TF/SD模块带电平转换, 通常不支持10M以上的波特率!!
  63. fatfs.mount(fatfs.SPI,"/sd", spiId, TF_CS, 24000000)
  64. local data, err = fatfs.getfree("/sd")
  65. if data then
  66. log.info("fatfs", "getfree", json.encode(data))
  67. else
  68. log.info("fatfs", "err", err)
  69. end
  70. -- 往下的操作, 使用 io.open("/sd/xxx", "w+") 等io库的API就可以了
  71. -- 方法2, 使用spi device方式
  72. local spiId = 2
  73. local TF_CS = 8
  74. -- 选一个合适的全局变量名
  75. tf_spi_dev = spi.device_setup(spiId, TF_CS, 0, 8, 20*1000*1000)
  76. fatfs.mount(fatfs.SPI,"/sd", tf_spi_dev)
  77. */
  78. static int fatfs_mount(lua_State *L)
  79. {
  80. if (FATFS_DEBUG)
  81. LLOGD("fatfs_init>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
  82. if (fs == NULL) {
  83. fs = luat_heap_malloc(sizeof(FATFS));
  84. if (fs == NULL) {
  85. lua_pushboolean(L, 0);
  86. LLOGD("out of memory when malloc FATFS");
  87. lua_pushstring(L, "out of memory when malloc FATFS");
  88. return 2;
  89. }
  90. }
  91. // 挂载点
  92. const char *mount_point = luaL_optstring(L, 2, "/fatfs");
  93. int fatfs_mode = luaL_checkinteger(L, 1);
  94. FATFS_POWER_PIN = luaL_optinteger(L, 6, 0xff);
  95. FATFS_POWER_DELAY = luaL_optinteger(L, 7, 1);
  96. if (fatfs_mode == DISK_SPI){
  97. luat_fatfs_spi_t *spit = luat_heap_malloc(sizeof(luat_fatfs_spi_t));
  98. if (spit == NULL) {
  99. lua_pushboolean(L, 0);
  100. LLOGD("out of memory when malloc luat_fatfs_spi_t");
  101. lua_pushstring(L, "out of memory when malloc luat_fatfs_spi_t");
  102. return 2;
  103. }
  104. memset(spit, 0, sizeof(luat_fatfs_spi_t));
  105. if (lua_type(L, 3) == LUA_TUSERDATA){
  106. spit->spi_device = (luat_spi_device_t*)lua_touserdata(L, 3);
  107. spit->fast_speed = luaL_optinteger(L, 4, 10000000);
  108. if (lua_isinteger(L, 5)) {
  109. spit->fast_speed = luaL_optinteger(L, 5, 10000000);
  110. }
  111. if (spit->fast_speed < 5*1000*1000) {
  112. spit->fast_speed = 5*1000*1000;
  113. }
  114. spit->type = 1;
  115. diskio_open_spitf(0, (void*)spit);
  116. } else {
  117. spit->type = 0;
  118. spit->spi_id = luaL_optinteger(L, 3, 0); // SPI_1
  119. spit->spi_cs = luaL_optinteger(L, 4, 3); // GPIO_3
  120. spit->fast_speed = luaL_optinteger(L, 5, 10000000);
  121. LLOGD("init sdcard at spi=%d cs=%d", spit->spi_id, spit->spi_cs);
  122. diskio_open_spitf(0, (void*)spit);
  123. }
  124. #ifdef LUAT_USE_SDIO
  125. }else if(fatfs_mode == DISK_SDIO){
  126. luat_fatfs_sdio_t *fatfs_sdio = luat_heap_malloc(sizeof(luat_fatfs_sdio_t));
  127. if (fatfs_sdio == NULL) {
  128. lua_pushboolean(L, 0);
  129. LLOGD("out of memory when malloc luat_fatfs_sdio_t");
  130. lua_pushstring(L, "out of memory when malloc luat_fatfs_sdio_t");
  131. return 2;
  132. }
  133. memset(fatfs_sdio, 0, sizeof(luat_fatfs_sdio_t));
  134. fatfs_sdio->id = luaL_optinteger(L, 3, 0); // SDIO_ID
  135. LLOGD("init FatFS at sdio");
  136. diskio_open_sdio(0, (void*)fatfs_sdio);
  137. #endif
  138. #if defined(LUA_USE_LINUX) || defined(LUA_USE_WINDOWS) || defined(LUA_USE_MACOSX)
  139. }else if(fatfs_mode == DISK_RAM){
  140. LLOGD("init ramdisk at FatFS");
  141. diskio_open_ramdisk(0, luaL_optinteger(L, 3, 64*1024));
  142. #endif
  143. }else if(fatfs_mode == DISK_USB){
  144. }else{
  145. LLOGD("fatfs_mode error %d", fatfs_mode);
  146. lua_pushboolean(L, 0);
  147. lua_pushstring(L, "fatfs_mode error");
  148. return 2;
  149. }
  150. FRESULT re = f_mount(fs, mount_point, 1);
  151. if (re != FR_OK) {
  152. if (lua_isboolean(L, 8) && lua_toboolean(L, 8) == 0) {
  153. LLOGI("sd/tf mount failed %d but auto-format is disabled", re);
  154. lua_pushboolean(L, 0);
  155. lua_pushstring(L, "mount error");
  156. return 2;
  157. }
  158. else {
  159. LLOGW("mount failed, try auto format");
  160. MKFS_PARM parm = {
  161. .fmt = s_fatfs_fmt,
  162. .au_size = 0,
  163. .align = 0,
  164. .n_fat = 0,
  165. .n_root = 0,
  166. };
  167. BYTE work[FF_MAX_SS] = {0};
  168. re = f_mkfs(mount_point, &parm, work, FF_MAX_SS);
  169. LLOGD("auto format ret %d", re);
  170. if (re == FR_OK) {
  171. re = f_mount(fs, mount_point, 1);
  172. LLOGD("remount again %d", re);
  173. if (re == FR_OK) {
  174. LLOGI("sd/tf mount success after auto format");
  175. }
  176. else {
  177. LLOGE("sd/tf mount failed again %d after auto format", re);
  178. lua_pushboolean(L, 0);
  179. lua_pushstring(L, "mount error");
  180. return 2;
  181. }
  182. }
  183. else {
  184. LLOGE("sd/tf format failed %d", re);
  185. lua_pushboolean(L, 0);
  186. lua_pushstring(L, "format error");
  187. return 2;
  188. }
  189. }
  190. }
  191. lua_pushboolean(L, re == FR_OK);
  192. lua_pushinteger(L, re);
  193. if (re == FR_OK) {
  194. LLOGI("mount success at %s", fs->fs_type == FS_EXFAT ? "exfat" : (fs->fs_type == FS_FAT32 ? "fat32" : "fat16"));
  195. #ifdef LUAT_USE_FS_VFS
  196. luat_fs_conf_t conf2 = {
  197. .busname = (char*)fs,
  198. .type = "fatfs",
  199. .filesystem = "fatfs",
  200. .mount_point = mount_point,
  201. };
  202. luat_fs_mount(&conf2);
  203. #endif
  204. }
  205. else {
  206. LLOGE("[FatFS]fatfs_init FAIL!! re=%d", re);
  207. }
  208. if (FATFS_DEBUG)
  209. LLOGD("fatfs_init<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
  210. return 2;
  211. }
  212. /*
  213. 取消挂载fatfs
  214. @api fatfs.unmount(mount_point)
  215. @string 虚拟文件系统的挂载点, 默认是 fatfs,必须与fatfs.mount一致
  216. @return int 成功返回0, 否则返回失败码
  217. @usage
  218. -- 注意, 取消挂载, 在 2025.9.29 之后编译的固件才真正支持
  219. fatfs.mount("/sd")
  220. */
  221. static int fatfs_unmount(lua_State *L) {
  222. const char *mount_point = luaL_optstring(L, 1, "/fatfs");
  223. #ifdef LUAT_USE_FS_VFS
  224. luat_fs_conf_t conf = {
  225. .busname = (char*)fs,
  226. .type = "fatfs",
  227. .filesystem = "fatfs",
  228. .mount_point = mount_point,
  229. };
  230. luat_fs_umount(&conf);
  231. #endif
  232. FRESULT re = f_mount(NULL, "/", 0);
  233. lua_pushinteger(L, re);
  234. return 1;
  235. }
  236. /**
  237. 获取可用空间信息
  238. @api fatfs.getfree(mount_point)
  239. @string 挂载点, 需要跟fatfs.mount传入的值一致
  240. @return table 若成功会返回table,否则返回nil
  241. @return int 导致失败的底层返回值
  242. @usage
  243. -- table包含的内容有
  244. -- total_sectors 总扇区数量
  245. -- free_sectors 空闲扇区数量
  246. -- total_kb 总字节数,单位kb
  247. -- free_kb 空闲字节数, 单位kb
  248. -- 注意,当前扇区大小固定在512字节
  249. local data, err = fatfs.getfree("SD")
  250. if data then
  251. log.info("fatfs", "getfree", json.encode(data))
  252. else
  253. log.info("fatfs", "err", err)
  254. end
  255. */
  256. static int fatfs_getfree(lua_State *L)
  257. {
  258. DWORD fre_clust, fre_sect, tot_sect;
  259. // 挂载点
  260. const char *mount_point = luaL_optstring(L, 1, "/fatfs");
  261. FATFS *fs2;
  262. FRESULT re2 = f_getfree(mount_point, &fre_clust, &fs2);
  263. if (re2) {
  264. lua_pushnil(L);
  265. lua_pushinteger(L, re2);
  266. return 2;
  267. }
  268. /* Get total sectors and free sectors */
  269. tot_sect = (fs2->n_fatent - 2) * fs2->csize;
  270. fre_sect = fre_clust * fs2->csize;
  271. lua_newtable(L);
  272. lua_pushstring(L, "total_sectors");
  273. lua_pushinteger(L, tot_sect);
  274. lua_settable(L, -3);
  275. lua_pushstring(L, "free_sectors");
  276. lua_pushinteger(L, fre_sect);
  277. lua_settable(L, -3);
  278. lua_pushstring(L, "total_kb");
  279. lua_pushinteger(L, tot_sect / 2);
  280. lua_settable(L, -3);
  281. lua_pushstring(L, "free_kb");
  282. lua_pushinteger(L, fre_sect / 2);
  283. lua_settable(L, -3);
  284. return 1;
  285. }
  286. /**
  287. 设置调试模式
  288. @api fatfs.debug(value)
  289. @int 是否进入调试模式,1代表进入调试模式,增加调试日志
  290. @return nil 无返回值
  291. */
  292. static int fatfs_debug_mode(lua_State *L) {
  293. FATFS_DEBUG = luaL_optinteger(L, 1, 1);
  294. return 0;
  295. }
  296. /**
  297. 设置fatfs一些特殊参数
  298. @api fatfs.config(crc_check, write_to, fmt)
  299. @int 读取时是否跳过CRC检查,1跳过不检查CRC,0不跳过检查CRC,默认不跳过,除非TF卡不支持CRC校验,否则不应该跳过!
  300. @int 单次写入超时时间,单位ms,默认100ms。
  301. @int 文件系统格式,默认FM_FAT32, 可选值 FM_FAT32, FM_EXFAT
  302. @return nil 无返回值
  303. -- 前2个配置项不建议修改
  304. */
  305. static int fatfs_config(lua_State *L) {
  306. if (lua_isinteger(L, 1)) {
  307. FATFS_NO_CRC_CHECK = luaL_optinteger(L, 1, 0);
  308. }
  309. if (lua_isinteger(L, 2)) {
  310. FATFS_WRITE_TO = luaL_optinteger(L, 2, 100);
  311. }
  312. if (lua_isinteger(L, 3)) {
  313. s_fatfs_fmt = luaL_optinteger(L, 3, FM_FAT32);
  314. if (s_fatfs_fmt != FM_FAT32 && s_fatfs_fmt != FM_EXFAT) {
  315. s_fatfs_fmt = FM_FAT32;
  316. }
  317. if (s_fatfs_fmt == FM_EXFAT) {
  318. LLOGI("fatfs set to exfat , when format sd/tf");
  319. }
  320. else {
  321. LLOGI("fatfs set to fat32 , when format sd/tf");
  322. }
  323. }
  324. return 0;
  325. }
  326. // Module function map
  327. #include "rotable2.h"
  328. static const rotable_Reg_t reg_fatfs[] =
  329. {
  330. { "init", ROREG_FUNC(fatfs_mount)}, //初始化,挂载, 别名方法
  331. { "mount", ROREG_FUNC(fatfs_mount)}, //初始化,挂载
  332. { "getfree", ROREG_FUNC(fatfs_getfree)}, // 获取文件系统大小,剩余空间
  333. { "debug", ROREG_FUNC(fatfs_debug_mode)}, // 调试模式,打印更多日志
  334. { "config", ROREG_FUNC(fatfs_config)}, //初始化,挂载, 别名方法
  335. { "unmount", ROREG_FUNC(fatfs_unmount)}, // 取消挂载
  336. { "SPI", ROREG_INT(DISK_SPI)},
  337. { "SDIO", ROREG_INT(DISK_SDIO)},
  338. { "RAM", ROREG_INT(DISK_RAM)},
  339. { "FM_FAT32", ROREG_INT(FM_FAT32)},
  340. { "FM_EXFAT", ROREG_INT(FM_EXFAT)},
  341. { NULL, ROREG_INT(0)}
  342. };
  343. int luaopen_fatfs( lua_State *L )
  344. {
  345. luat_newlib2(L, reg_fatfs);
  346. #ifdef LUAT_USE_FS_VFS
  347. luat_vfs_reg(&vfs_fs_fatfs);
  348. #endif
  349. return 1;
  350. }