/*
* usbfs/ufs.cpp - part of UniClock, a Clock for the Galactic Unicorn.
*
* UniClock is an enhanced clock/calendar display for the beautiful Galactic
* Unicorn.
*
* usbfs is the subsystem that handles presenting a filesystem to the host
* over USB; in this instance, it is used for managing configuration files.
*
* ufs is the actual filesystem management, which sits on top of the USB and
* storage components.
*
* Copyright (C) 2023 Pete Favelle <ahnlak@ahnlak.com>
* Released under the MIT License; see LICENSE for details.
*/
/* System headers. */
#include <stdio.h>
#include <stdlib.h>
#include "stdlib.h"
/* Local headers. */
#include "flash_diskio.h"
#include "spi_flash.h"
#include "w25qxx.h" /* SPI Flash driver file */
#include "ff.h"
#include "diskio.h"
#include "ufs.h"
extern const Diskio_drvTypeDef Flash_Driver;
/* Disk status */
static volatile DSTATUS Stat = STA_NOINIT;
/* Module variables. */
static char USERPath[4]; /* SD logical drive path */
static FATFS USERFatFS;
#define _MIN_SS FF_MIN_SS
#define _MAX_SS FF_MAX_SS
/* Functions */
// 配置文件系统
void format_disk() {
FATFS fs;
MKFS_PARM opt = {
.fmt = FM_FAT32, // **改成 FAT16**
.n_fat = 1,
.align = 0,
.n_root = 0,
.au_size = 512
};
BYTE work[4096]; // 工作缓冲区
// 簇数量计算(示例)
DWORD n_clst = (16 * 1024 * 1024) / opt.au_size; // 16MB存储大小
// 格式化磁盘
FRESULT res = f_mkfs("", &opt, work, sizeof(work));
if (res == FR_OK) {
printf("Disk formatted successfully.\n");
} else {
printf("Failed to format disk. Error code: %d\n", res);
}
// 装载文件系统
res = f_mount(&fs, "", 1);
if (res == FR_OK) {
printf("File system mounted successfully.\n");
} else {
printf("Failed to mount file system. Error code: %d\n", res);
}
}
void ufs_init(void) {
FRESULT res;
// 注册并链接Flash驱动
FATFS_LinkDriver(&Flash_Driver, USERPath);
}
// Define workspace buffer for formatting
BYTE workBuffer[4 * User_Sector];
/* Mount the FatFs filesystem */
void Mount_FatFs(void) {
//format_disk();
// Mount the filesystem
FRESULT retUSER = f_mount(&User_FatFs, User_SDPath, 1);
// If an error occurs
if (retUSER != FR_OK) {
// If no filesystem exists, format it
if (retUSER == FR_NO_FILESYSTEM) {
printf("\nNo filesystem found, starting format\n");
format_disk();
}
// If another error occurs
else {
printf("An error occurred, error code = %d\n", retUSER);
}
}
// If the filesystem already exists, mount successfully
else {
//format_disk();
printf("Filesystem mounted successfully\n");
}
}
void FatFs_GetDiskInfo(void) {
FATFS *FS;
size_t Total = 0, Used = 0, Free = 0;
DWORD FreeClusters, TotalSectors;
// Step 1: 获取磁盘信息
int Ret = f_getfree("0:", &FreeClusters, &FS);
if (Ret != FR_OK) {
printf("Error: f_getfree() failed! Code: %d\n", Ret);
return;
}
// Step 2: 通过 GET_SECTOR_COUNT 获取实际的总扇区数
if (disk_ioctl(0, GET_SECTOR_COUNT, &TotalSectors) != RES_OK) {
printf("Error: GET_SECTOR_COUNT failed!\n");
return;
}
// Step 3: 确保 FS->ssize 有效
if (FS->ssize == 0) {
printf("Error: Sector size is 0!\n");
return;
}
// Step 4: 计算 FAT 结构占用的空间 (估算)
DWORD ReservedSectors = FS->csize * 32; // 估算 FAT 表占用的空间
size_t SystemUsed = ReservedSectors * FS->ssize;
// Step 5: 计算存储大小
size_t FreeSectors = FreeClusters * FS->csize; // 空闲扇区数
size_t UsedSectors = TotalSectors - FreeSectors; // 已用扇区数
Total = TotalSectors * FS->ssize; // 总容量 (字节)
Free = FreeSectors * FS->ssize; // 空闲容量 (字节)
Used = UsedSectors * FS->ssize; // 已用容量 (字节)
// Step 6: 转换为 KB / MB
size_t Total_KB = Total / 1024;
size_t Free_KB = Free / 1024;
size_t Used_KB = Used / 1024;
size_t Total_MB = Total_KB / 1024;
size_t Free_MB = Free_KB / 1024;
size_t Used_MB = Used_KB / 1024;
// Step 7: 打印容量信息
printf("\n=== FAT File System Info ===\n");
printf("Total Space: %lu B (%lu KB, %lu MB)\n", Total, Total_KB, Total_MB);
printf("Used Space: %lu B (%lu KB, %lu MB)\n", Used, Used_KB, Used_MB);
printf("Free Space: %lu B (%lu KB, %lu MB)\n", Free, Free_KB, Free_MB);
printf("System Used (FAT Table + Root Dir): %lu B\n", SystemUsed);
}
/* 写入 TXT 文件 */
void FatFs_WriteTXTFile(TCHAR *filename) {
FIL file;
FATFS *fs;
FRESULT res;
printf("\n*** Creating TXT file: %s ***\n", filename);
// Step 1: 检查是否已经挂载
f_getfree("0:", NULL, &fs);
if (fs == NULL) { // 如果未挂载,执行挂载
static FATFS fatfs;
res = f_mount(&fatfs, "0:", 1);
if (res != FR_OK) {
printf("Error: f_mount() failed! Code: %d\n", res);
return;
}
}
// Step 2: 打开/创建文件
res = f_open(&file, filename, FA_CREATE_ALWAYS | FA_WRITE);
if (res != FR_OK) {
printf("Open file error, error code: %d\n", res);
return;
}
// Step 3: 写入内容
TCHAR str[] = "Line1: Hello, FatFs with fixed date (2025/02/06)\n";
UINT bw;
res = f_write(&file, str, sizeof(str) - 1, &bw);
if (res == FR_OK) {
printf("Write file successful: %s (%d bytes written)\n", filename, bw);
} else {
printf("Write file failed, error code: %d\n", res);
}
// Step 4: 关闭文件
f_close(&file);
}
/* 判断文件是否存在 */
int FatFs_FileExists(const TCHAR *filename) {
FILINFO fno;
FRESULT res = f_stat(filename, &fno);
if (res == FR_OK) {
return 1; // 文件存在
} else if (res == FR_NO_FILE) {
return 0; // 文件不存在
} else {
return -1; // 发生错误
}
}
/*读取一个文本文件的内容*/
void FatFs_ReadTXTFile(TCHAR *filename)
{
printf("\r\n*** Reading TXT file: %s ***\r\n", filename);
FIL file;
//以只读方式打开文件
FRESULT res = f_open(&file, filename, FA_READ);
//打开成功
if(res == FR_OK)
{
//读取缓存
TCHAR str[100];
//没有读到文件内容末尾
while(!f_eof(&file))
{
//读取1个字符串,自动加上结束符”\0”
//f_gets(str,100, &file);
//printf("%s", str);
}
printf("\r\n");
}
//如果没有该文件
else if(res == FR_NO_FILE)
printf("File does not exist\r\n");
//打开失败
else
printf("f_open() error,error code: %d\r\n", res);
//关闭文件
f_close(&file);
}
#include "ff.h"
#include <stdio.h>
/* 扫描和显示指定目录下的文件和目录 */
void FatFs_ScanDir(const TCHAR* PathName)
{
FATFS fs; // FAT 文件系统对象
DIR dir; // 目录对象
FILINFO fno; // 文件信息
FRESULT res;
// // Step 1: 先挂载文件系统
// FRESULT res = f_mount(&fs, "0:", 1);
// if (res != FR_OK) {
// printf("Error: f_mount() failed! Code: %d\n", res);
// return;
// }
// Step 2: 打开目录
res = f_opendir(&dir, PathName);
if (res != FR_OK) {
printf("Error: f_opendir() failed! Code: %d\n", res);
f_mount(NULL, "0:", 0); // 卸载文件系统(可选)
return;
}
printf("\n*** All entries in dir: %s ***\n", PathName);
// Step 3: 读取目录中的文件
while (1)
{
res = f_readdir(&dir, &fno);
if (res != FR_OK || fno.fname[0] == 0) {
break; // 读取错误或到达目录末尾
}
// Step 4: 判断是文件还是目录
if (fno.fattrib & AM_DIR) {
printf("[DIR] %s\n", fno.fname);
} else {
printf("[FILE] %s (%lu bytes)\n", fno.fname, fno.fsize);
}
}
// Step 5: 关闭目录
f_closedir(&dir);
// Step 6: 卸载文件系统(可选)
//f_mount(NULL, "0:", 0);
}
/*获取一个文件的文件信息*/
void FatFs_GetFileInfo(TCHAR *filename)
{
printf("\r\n*** File info of: %s ***\r\n", filename);
FILINFO fno;
//检查文件或子目录是否存在
FRESULT fr = f_stat(filename, &fno);
//如果存在从fno中读取文件信息
if(fr == FR_OK)
{
printf("File size(bytes) = %ld\r\n", fno.fsize);
printf("File attribute = 0x%x\r\n", fno.fattrib);
printf("File Name = %s\r\n", fno.fname);
//输出创建/修改文件时的时间戳
FatFs_PrintfFileDate(fno.fdate, fno.ftime);
}
//如果没有该文件
else if (fr == FR_NO_FILE)
printf("File does not exist\r\n");
//发生其他错误
else
printf("f_stat() error,error code: %d\r\n", fr);
}
/*删除文件*/
void FatFs_DeleteFile(TCHAR *filename)
{
printf("\r\n*** Delete File: %s ***\r\n", filename);
FIL file;
//打开文件
FRESULT res = f_open(&file, filename, FA_OPEN_EXISTING);
if(res == FR_OK)
{
//关闭文件
f_close(&file);
printf("open successfully!\r\n");
}
//删除文件
res = f_unlink(filename);
//删除成功
if(res == FR_OK)
{
printf("The file was deleted successfully!\r\n");
}
//删除失败
else
{
printf("File deletion failed, error code:%d\r\n", res);
}
}
/*打印输出文件日期*/
void FatFs_PrintfFileDate(WORD date, WORD time)
{
printf("File data = %d/%d/%d\r\n", ((date>>9)&0x7F)+1980, (date>>5)&0xF, date&0x1F);
printf("File time = %d:%d:%d\r\n", (time>>11)&0x1F, (time>>5)&0x3F, time&0x1F);
}