Skip to main content Link Menu Expand (external link) Document Search Copy Copied

尝试使用Rust为ESP系列控制器开发软件(续)

前言

上一篇文章介绍了如何通过复用Rust组件包,以及一点少量代码在ESP32-S3上运行一个WebDAV服务。但是简单测试后我发现服务有一点问题。现象是当我想上传一个像 rust-logo-blk.svg 这样的文件时,WebDAV服务会返回 500 Internal Server Error 的错误,见下面Wireshark截图的最后两条消息包,而使用hello.txt这样的文件名就没有问题。 img

问题原因

这个问题有点蹊跷,感觉是不是 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.txtrust-logo-blk.svghello.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格式的文件名实在太不方便了。