tfcard_app.lua 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. --[[
  2. @module tfcard_app
  3. @summary TF卡文件操作测试模块
  4. @version 1.0.0
  5. @date 2025.08.25
  6. @author 王棚嶙
  7. @usage
  8. 本文件为TF卡的文件操作测试流程:
  9. 1. 创建目录
  10. 2. 创建并写入文件
  11. 3. 检查文件是否存在
  12. 4. 获取文件大小
  13. 5. 读取文件内容
  14. 6. 启动计数文件操作
  15. 7. 文件追加测试
  16. 8. 按行读取测试
  17. 9. 读取后关闭文件
  18. 10. 文件重命名
  19. 11. 列举目录内容
  20. 12. 删除文件
  21. 13. 删除目录
  22. 本文件没有对外接口,直接在main.lua中require "tfcard_app"就可以加载运行
  23. ]]
  24. function tfcard_main_task() -- 开始进行主测试流程。
  25. -- ########## SPI初始化 ##########
  26. -- Air8000整机开发板上TF卡的的pin_cs为gpio20,spi_id为1.请根据实际硬件修改
  27. spi_id, pin_cs = 1, 20
  28. spi.setup(spi_id, nil, 0, 0, 400 * 1000)
  29. --设置片选引脚同一spi总线上的所有从设备在初始化时必须要先拉高CS脚,防止从设备之间互相干扰。
  30. -- 在air8000开发板上,TF卡和ch390共用SPI1总线。
  31. gpio.setup(pin_cs, 1)
  32. -- ########## 开始进行tf卡挂载 ##########
  33. --挂载失败默认格式化,
  34. -- 如无需格式化应改为fatfs.mount(fatfs.SPI, "/sd", spi_id, pin_cs, 24 * 1000 * 1000, nil, 1, false),
  35. -- 一般是在测试硬件是否有问题的时候把格式化取消掉
  36. mount_ok, mount_err = fatfs.mount(fatfs.SPI, "/sd", spi_id, pin_cs, 24 * 1000 * 1000)
  37. if mount_ok then
  38. log.info("fatfs.mount", "挂载成功", mount_err)
  39. else
  40. log.error("fatfs.mount", "挂载失败", mount_err)
  41. goto resource_cleanup
  42. end
  43. -- ########## 获取SD卡的可用空间信息并打印。 ##########
  44. data, err = fatfs.getfree("/sd")
  45. if data then
  46. --打印SD卡的可用空间信息
  47. log.info("fatfs", "getfree", json.encode(data))
  48. else
  49. --打印错误信息
  50. log.info("fatfs", "getfree", "err", err)
  51. goto resource_cleanup
  52. end
  53. -- 列出所有挂载点,如不需要,可注释掉。
  54. data = io.lsmount()
  55. log.info("fs", "lsmount", json.encode(data))
  56. -- ########## 功能: 启用fatfs调试模式 ##########
  57. -- fatfs.debug(1) -- 若挂载失败,可以尝试打开调试信息,查找原因.(设置调试模式)
  58. -- 执行tfcard文件操作演示
  59. log.info("文件操作", "===== 开始文件操作 =====")
  60. dir_path = "/sd/io_test"
  61. -- 1. 创建目录
  62. if io.mkdir(dir_path) then
  63. log.info("io.mkdir", "目录创建成功", "路径:" .. dir_path)
  64. else
  65. -- 检查是否目录已存在
  66. if io.exists(dir_path) then
  67. log.warn("io.mkdir", "目录已存在,跳过创建", "路径:" .. dir_path)
  68. else
  69. log.error("io.mkdir", "目录创建失败且目录不存在", "路径:" .. dir_path)
  70. goto resource_cleanup
  71. end
  72. end
  73. -- 2. 创建并写入文件
  74. file_path = dir_path .. "/boottime"
  75. file = io.open(file_path, "wb")
  76. if file then
  77. file:write("这是io库API文档示例的测试内容")
  78. file:close()
  79. --在LuatOS文件操作中,执行file:close()是必须且关键的操作,它用于关闭文件句柄,释放资源,并确保数据被正确写入磁盘。
  80. -- 如果不执行file:close(),可能会导致数据丢失、文件损坏或其他不可预测的问题。
  81. log.info("文件创建", "文件写入成功", "路径:" .. file_path)
  82. else
  83. log.error("文件创建", "文件创建失败", "路径:" .. file_path)
  84. goto resource_cleanup
  85. end
  86. -- 3. 检查文件是否存在
  87. if io.exists(file_path) then
  88. log.info("io.exists", "文件存在", "路径:" .. file_path)
  89. else
  90. log.error("io.exists", "文件不存在", "路径:" .. file_path)
  91. goto resource_cleanup
  92. end
  93. -- 4. 获取文件大小
  94. file_size = io.fileSize(file_path)
  95. if file_size then
  96. log.info("io.fileSize", "文件大小:" .. file_size .. "字节", "路径:" .. file_path)
  97. else
  98. log.error("io.fileSize", "获取文件大小失败", "路径:" .. file_path)
  99. goto resource_cleanup
  100. end
  101. -- 5. 读取文件内容
  102. file = io.open(file_path, "rb")
  103. if file then
  104. content = file:read("*a")
  105. log.info("文件读取", "路径:" .. file_path, "内容:" .. content)
  106. file:close()
  107. else
  108. log.error("文件操作", "无法打开文件读取内容", "路径:" .. file_path)
  109. goto resource_cleanup
  110. end
  111. -- 6. 启动计数文件操作
  112. count = 0
  113. --以只读模式打开文件
  114. file = io.open(file_path, "rb")
  115. if file then
  116. data = file:read("*a")
  117. log.info("启动计数", "文件内容:", data, "十六进制:", data:toHex())
  118. count = tonumber(data) or 0
  119. file:close()
  120. else
  121. log.warn("启动计数", "文件不存在或无法打开")
  122. end
  123. log.info("启动计数", "当前值:", count)
  124. count=count + 1
  125. log.info("启动计数", "更新值:", count)
  126. file = io.open(file_path, "wb")
  127. if file then
  128. file:write(tostring(count))
  129. file:close()
  130. log.info("文件写入", "路径:" .. file_path, "内容:", count)
  131. else
  132. log.error("文件写入", "无法打开文件", "路径:" .. file_path)
  133. goto resource_cleanup
  134. end
  135. -- 7. 文件追加测试
  136. append_file = dir_path .. "/test_a"
  137. -- 清理旧文件
  138. os.remove(append_file)
  139. -- 创建并写入初始内容
  140. file = io.open(append_file, "wb")
  141. if file then
  142. file:write("ABC")
  143. file:close()
  144. log.info("文件创建", "路径:" .. append_file, "初始内容:ABC")
  145. else
  146. log.error("文件创建", "无法创建文件", "路径:" .. append_file)
  147. goto resource_cleanup
  148. end
  149. -- 追加内容
  150. file = io.open(append_file, "a+")
  151. if file then
  152. file:write("def")
  153. file:close()
  154. log.info("文件追加", "路径:" .. append_file, "追加内容:def")
  155. else
  156. log.error("文件追加", "无法打开文件进行追加", "路径:" .. append_file)
  157. goto resource_cleanup
  158. end
  159. -- 验证追加结果
  160. file = io.open(append_file, "r")
  161. if file then
  162. data = file:read("*a")
  163. log.info("文件验证", "路径:" .. append_file, "内容:" .. data, "结果:",
  164. data == "ABCdef" and "成功" or "失败")
  165. file:close()
  166. else
  167. log.error("文件验证", "无法打开文件进行验证", "路径:" .. append_file)
  168. goto resource_cleanup
  169. end
  170. -- 8. 按行读取测试
  171. line_file = dir_path .. "/testline"
  172. file = io.open(line_file, "w")
  173. if file then
  174. file:write("abc\n")
  175. file:write("123\n")
  176. file:write("wendal\n")
  177. file:close()
  178. log.info("文件创建", "路径:" .. line_file, "写入3行文本")
  179. else
  180. log.error("文件创建", "无法创建文件", "路径:" .. line_file)
  181. goto resource_cleanup
  182. end
  183. -- 按行读取文件
  184. file = io.open(line_file, "r")
  185. if file then
  186. log.info("按行读取", "路径:" .. line_file, "第1行:", file:read("*l"))
  187. log.info("按行读取", "路径:" .. line_file, "第2行:", file:read("*l"))
  188. log.info("按行读取", "路径:" .. line_file, "第3行:", file:read("*l"))
  189. file:close()
  190. else
  191. log.error("按行读取", "无法打开文件", "路径:" .. line_file)
  192. goto resource_cleanup
  193. end
  194. -- 9. 文件重命名
  195. old_path = append_file
  196. new_path = dir_path .. "/renamed_file.txt"
  197. success, err = os.rename(old_path, new_path)
  198. if success then
  199. log.info("os.rename", "文件重命名成功", "原路径:" .. old_path, "新路径:" .. new_path)
  200. -- 验证重命名结果
  201. if io.exists(new_path) and not io.exists(old_path) then
  202. log.info("验证结果", "重命名验证成功", "新文件存在", "原文件不存在")
  203. else
  204. log.error("验证结果", "重命名验证失败")
  205. end
  206. else
  207. log.error("os.rename", "重命名失败", "错误:" .. tostring(err), "原路径:" .. old_path)
  208. goto resource_cleanup
  209. end
  210. -- 10. 列举目录内容
  211. log.info("目录操作", "===== 开始目录列举 =====")
  212. ret, data = io.lsdir(dir_path, 50, 0) -- 50表示最多返回50个文件,0表示从目录开头开始
  213. if ret then
  214. log.info("fs", "lsdir", json.encode(data))
  215. else
  216. log.info("fs", "lsdir", "fail", ret, data)
  217. goto resource_cleanup
  218. end
  219. -- 11. 删除文件测试
  220. -- 测试删除renamed_file.txt文件
  221. if os.remove(new_path) then
  222. log.info("os.remove", "文件删除成功", "路径:" .. new_path)
  223. -- 验证renamed_file.txt删除结果
  224. if not io.exists(new_path) then
  225. log.info("验证结果", "renamed_file.txt文件删除验证成功")
  226. else
  227. log.error("验证结果", "renamed_file.txt文件删除验证失败")
  228. end
  229. else
  230. log.error("io.remove", "renamed_file.txt文件删除失败", "路径:" .. new_path)
  231. goto resource_cleanup
  232. end
  233. -- 测试删除testline文件
  234. if os.remove(line_file) then
  235. log.info("os.remove", "testline文件删除成功", "路径:" .. line_file)
  236. -- 验证删除结果
  237. if not io.exists(line_file) then
  238. log.info("验证结果", "testline文件删除验证成功")
  239. else
  240. log.error("验证结果", "testline文件删除验证失败")
  241. end
  242. else
  243. log.error("io.remove", "testline文件删除失败", "路径:" .. line_file)
  244. goto resource_cleanup
  245. end
  246. if os.remove(file_path) then
  247. log.info("os.remove", "文件删除成功", "路径:" .. file_path)
  248. -- 验证删除结果
  249. if not io.exists(file_path) then
  250. log.info("验证结果", "boottime文件删除验证成功")
  251. else
  252. log.error("验证结果", "boottime文件删除验证失败")
  253. end
  254. else
  255. log.error("io.remove", "boottime文件删除失败", "路径:" .. file_path)
  256. goto resource_cleanup
  257. end
  258. -- 12. 删除目录(不能删除非空目录,所以在删除目录前要确保目录内没有文件或子目录)
  259. if io.rmdir(dir_path) then
  260. log.info("io.rmdir", "目录删除成功", "路径:" .. dir_path)
  261. -- 验证删除结果
  262. if not io.exists(dir_path) then
  263. log.info("验证结果", "目录删除验证成功")
  264. else
  265. log.error("验证结果", "目录删除验证失败")
  266. end
  267. else
  268. log.error("io.rmdir", "目录删除失败", "路径:" .. dir_path)
  269. goto resource_cleanup
  270. end
  271. log.info("文件操作", "===== 文件操作完成 =====")
  272. -- ########## 功能: 收尾功能演示##########
  273. -- 卸载文件系统和关闭SPI
  274. ::resource_cleanup::
  275. log.info("结束", "开始执行关闭操作...")
  276. -- 如已挂载需先卸载文件系统,未挂载直接关闭SPI
  277. if mount_ok then
  278. if fatfs.unmount("/sd") then
  279. log.info("文件系统", "卸载成功")
  280. else
  281. log.error("文件系统", "卸载失败")
  282. end
  283. end
  284. -- 2. 关闭SPI接口
  285. spi.close(spi_id)
  286. log.info("SPI接口", "已关闭")
  287. end
  288. sys.taskInit(tfcard_main_task)