尝试使用Rust为ESP系列控制器开发软件(续)
前言
上一篇文章介绍了如何通过复用Rust组件包,以及一点少量代码在ESP32-S3上运行一个WebDAV服务。但是简单测试后我发现服务有一点问题。现象是当我想上传一个像 rust-logo-blk.svg
这样的文件时,WebDAV服务会返回 500 Internal Server Error
的错误,见下面Wireshark截图的最后两条消息包,而使用hello.txt这样的文件名就没有问题。
问题原因
这个问题有点蹊跷,感觉是不是 rust-logo-blk.svg
中是不是有什么特殊的地方。所以我就写了下面的代码用来测试不同的文件名。
info!("Mounting FAT filesystem...");
let fat_config = esp_vfs_fat_mount_config_t {
format_if_mount_failed: true,
max_files: 4,
allocation_unit_size: CONFIG_WL_SECTOR_SIZE as usize,
disk_status_check_enable: false,
use_one_fat: false,
};
let mut wl_handle: wl_handle_t = 0;
let base_path = CString::new("/vfat")?;
let partition_label = CString::new("storage")?;
let ret = unsafe {
esp_vfs_fat_spiflash_mount_rw_wl(
base_path.as_ptr(),
partition_label.as_ptr(),
&fat_config,
&mut wl_handle,
)
};
if ret != ESP_OK {
info!("vfs fat mount failed: ret={}", ret);
return Err(EspError::from_non_zero(NonZero::new(ret).unwrap()).into());
}
...
let info = std::fs::metadata("/vfat/rust-logo-blk.svg");
info!("metadata result: {:?}", info);
出错时日志会打印 Invalid argument
的错误。
...
(477) hello_esp_rust: metadata result: Err(Os { code: 22, kind: InvalidInput, message: "Invalid argument" })
...
经过尝试各个文件名,我发现如果文件名里有两个 .
,如果文件名较长,后缀不是三个字符,比如 .hello.txt
、 rust-logo-blk.svg
、 hello.txt#
都会引起 Invalid argument
的错误。感觉这个问题和文件系统的实现有关,只好去查ESP32-S3的文档。文档告诉我们这里的FAT文件系统其实是叫FatFs的开源文件系统,再去查看FatFs的文档,知道了FatFs支持多个配置选项。其中有几个配置选项可能与我们的问题有关。
- FF_USE_LFN
- FF_MAX_LFN
FF_USE_LFN是控制是否支持长文件名的开关。在关闭的情况下,只支持8.3格式的文件名,意思是文件名前缀部分最多8个字符,文件名后缀只能是3个字符。我想这就是为什么我们会遇到 fs::metadata
函数会返回 Invalid argument
错误的原因了。
解决方法
解决方法是让FatFs支持长文件名。这就需要在编译时打开上面两个宏,但ESP-IDF不支持用户直接设置FatFs的宏,需要我们通过ESP-IDF项目配置来间接控制。我们需要将配置写到sdkconfig.defaults文件中。通过查看文档,我们得到下面两个配置。
CONFIG_FATFS_LFN_HEAP=y
CONFIG_FATFS_MAX_LFN=255
修改配置文件后,重新编译刷写固件。再次尝试上传文件 rust-logo-blk.svg
,这次上传成功了。
总结
在早期版本的DOS和Windows系统中只支持8.3的文件名格式,因为向前兼容的原因,这个格式被保留了下来。而这个格式是ESP-IDF中FatFs文件系统的默认格式,要支持普通的文件名我们需要通过ESP-IDF配置长文件名模式。不过我觉得ESP-IDF应该默认打开这两个配置,使用8.3格式的文件名实在太不方便了。