Files
STM32F4-Base/test/storage_test_task.c
2026-08-27 18:22:44 +08:00

385 lines
12 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/******************************************************************************
* 模块名称Storage Test Task
* 模块功能FTL + FatFS 存储测试,从 defaultTask 迁入,统一由 ch395fTestTask
* 调度运行。正常产品构建下由 defaultTask 调用,行为与原内联逻辑一致。
* 作者:王建锋
* 创建日期2026-08-26
******************************************************************************/
#include <string.h>
#include "main.h"
#include "ff.h"
#define DBG_TAG "[STORAGE-TEST]"
#include "dbg_log.h"
#include "storage_test.h"
#include "nand_ftl.h"
#include "diskio.h"
#include "gd5f2gq5ue.h"
storage_test_stats_t g_storage_stats;
static uint8_t s_perf_buf[4096];
/* TC-STO-01: FTL 掉电恢复journal 持久化)
* 写文件并同步落盘,随后模拟掉电(卸载 + 复位 FTL + 重新 resume再挂载校验内容一致。
*/
static void storage_test_powerloss(void)
{
static FATFS fs;
static FIL fil;
const uint32_t len = 4096;
uint8_t wbuf[512];
uint8_t rbuf[512];
UINT bw, br;
uint32_t i;
int ok = 0;
DBG_INFO("=== Storage Test: TC-STO-01 Power-loss recovery ===");
if (f_mount(&fs, "", 1) != FR_OK) {
STORAGE_TEST_CHECK(0, "TC-STO-01 mount");
return;
}
/* Phase 1: 写已知内容文件并同步 */
for (i = 0; i < sizeof(wbuf); i++) {
wbuf[i] = (uint8_t)((i * 31 + 7) & 0xFF);
}
if (f_open(&fil, "pl.dat", FA_CREATE_ALWAYS | FA_WRITE) == FR_OK) {
for (i = 0; i < len; i += sizeof(wbuf)) {
f_write(&fil, wbuf, sizeof(wbuf), &bw);
}
f_sync(&fil);
f_close(&fil);
} else {
STORAGE_TEST_CHECK(0, "TC-STO-01 f_open(write)");
return;
}
/* 模拟掉电:卸载 + 复位 FTL + 重新 resume */
f_mount(&fs, "", 0);
nand_ftl_deinit();
nand_ftl_init();
if (f_mount(&fs, "", 1) != FR_OK) {
STORAGE_TEST_CHECK(0, "TC-STO-01 remount after resume");
return;
}
/* Phase 2: 重新打开校验 */
if (f_open(&fil, "pl.dat", FA_READ) == FR_OK) {
ok = 1;
for (i = 0; i < len; i += sizeof(rbuf)) {
f_read(&fil, rbuf, sizeof(rbuf), &br);
for (uint32_t j = 0; j < br; j++) {
if (rbuf[j] != (uint8_t)(((i + j) * 31 + 7) & 0xFF)) {
ok = 0;
break;
}
}
if (!ok) break;
}
f_close(&fil);
} else {
ok = 0;
}
STORAGE_TEST_CHECK(ok, "TC-STO-01 content survived power-loss (resume)");
f_unlink("pl.dat");
}
/* TC-STO-02: 大文件 / 多扇区 / 随机 seek
* 写 256KB 位置相关模式文件,顺序读回比对 + 随机偏移 seek 读比对。
*/
static void storage_test_largefile(void)
{
static FATFS fs;
static FIL fil;
const uint32_t total = 256 * 1024;
const uint32_t chunk = 4096;
uint8_t buf[4096];
UINT bw, br;
uint32_t off, i;
int ok = 1;
DBG_INFO("=== Storage Test: TC-STO-02 Large file / random seek ===");
if (f_mount(&fs, "", 1) != FR_OK) {
STORAGE_TEST_CHECK(0, "TC-STO-02 mount");
return;
}
/* 写:位置相关模式 */
if (f_open(&fil, "big.dat", FA_CREATE_ALWAYS | FA_WRITE) != FR_OK) {
STORAGE_TEST_CHECK(0, "TC-STO-02 f_open(write)");
return;
}
for (off = 0; off < total; off += chunk) {
for (i = 0; i < chunk; i++) {
buf[i] = (uint8_t)(((off + i) * 31 + 7) & 0xFF);
}
f_write(&fil, buf, chunk, &bw);
}
f_close(&fil);
/* 顺序读回 */
if (f_open(&fil, "big.dat", FA_READ) != FR_OK) {
STORAGE_TEST_CHECK(0, "TC-STO-02 f_open(read)");
return;
}
for (off = 0; off < total; off += chunk) {
f_read(&fil, buf, chunk, &br);
if (br != chunk) { ok = 0; break; }
for (i = 0; i < chunk; i++) {
if (buf[i] != (uint8_t)(((off + i) * 31 + 7) & 0xFF)) { ok = 0; break; }
}
if (!ok) break;
}
STORAGE_TEST_CHECK(ok, "TC-STO-02 sequential 256KB read consistent");
/* 随机 seek 读 */
if (ok) {
uint32_t seek_offs[] = { 0, 33333, 131072, 200000, total - 200 };
int seek_ok = 1;
for (int s = 0; s < 5; s++) {
uint32_t so = seek_offs[s];
uint32_t sc = 200;
if (f_lseek(&fil, so) != FR_OK) { seek_ok = 0; break; }
f_read(&fil, buf, sc, &br);
for (i = 0; i < sc; i++) {
if (buf[i] != (uint8_t)(((so + i) * 31 + 7) & 0xFF)) { seek_ok = 0; break; }
}
if (!seek_ok) break;
}
STORAGE_TEST_CHECK(seek_ok, "TC-STO-02 random seek read consistent");
}
f_close(&fil);
f_unlink("big.dat");
}
/* TC-STO-03: 坏块注入下存储写入
* 清空旧 map → 注入若干好块为坏(持久化) → 重建文件系统 → 正常写读 → 校验坏块仍被报告。
*/
static void storage_test_badblock(void)
{
static FATFS fs;
static FIL fil;
uint8_t wbuf[512], rbuf[512];
UINT bw, br;
uint32_t bad[3];
int nbad = 0;
int ok = 1;
DBG_INFO("=== Storage Test: TC-STO-03 Bad-block injection during storage ===");
/* 清空旧 dhara map避免后续注入的坏块被旧映射引用 */
nand_ftl_format();
/* 注入:挑出厂好块标记为坏(更新并持久化 BBT */
for (uint32_t b = 100; b < gd5f_get_usable_blocks() && nbad < 3; b++) {
if (gd5f2gq5ue_is_block_bad(b) == 0) {
gd5f2gq5ue_mark_block_bad(b);
bad[nbad++] = b;
}
}
if (nbad < 3) {
STORAGE_TEST_CHECK(0, "TC-STO-03 could not find 3 good blocks (got %d)", nbad);
return;
}
STORAGE_TEST_CHECK(nbad == 3, "TC-STO-03 injected %d bad blocks", nbad);
/* 复位 FTL 使 dhara 经 is_block_bad 看到新坏块 */
f_mount(&fs, "", 0);
nand_ftl_deinit();
nand_ftl_init();
/* 重建文件系统dhara 仍会跳过坏块) */
{
MKFS_PARM opts = { FM_FAT32, 0, 0, 0, 0 };
uint8_t work[FF_MAX_SS];
if (f_mkfs("", &opts, work, sizeof(work)) != FR_OK) {
STORAGE_TEST_CHECK(0, "TC-STO-03 f_mkfs");
return;
}
}
if (f_mount(&fs, "", 1) != FR_OK) {
STORAGE_TEST_CHECK(0, "TC-STO-03 mount");
return;
}
/* 正常文件写读 */
for (uint32_t i = 0; i < sizeof(wbuf); i++) {
wbuf[i] = (uint8_t)((i * 17 + 3) & 0xFF);
}
if (f_open(&fil, "bbt.dat", FA_CREATE_ALWAYS | FA_WRITE) == FR_OK) {
f_write(&fil, wbuf, sizeof(wbuf), &bw);
f_close(&fil);
} else {
STORAGE_TEST_CHECK(0, "TC-STO-03 f_open(write)");
return;
}
if (f_open(&fil, "bbt.dat", FA_READ) == FR_OK) {
f_read(&fil, rbuf, sizeof(rbuf), &br);
f_close(&fil);
if (br == sizeof(wbuf)) {
for (uint32_t i = 0; i < sizeof(rbuf); i++) {
if (rbuf[i] != wbuf[i]) { ok = 0; break; }
}
} else {
ok = 0;
}
} else {
ok = 0;
}
STORAGE_TEST_CHECK(ok, "TC-STO-03 file intact with injected bad blocks");
/* 校验注入坏块仍被报告为坏(未被 dhara 占用) */
int badok = 1;
for (int k = 0; k < nbad; k++) {
if (gd5f2gq5ue_is_block_bad(bad[k]) != 1) { badok = 0; }
}
STORAGE_TEST_CHECK(badok, "TC-STO-03 injected blocks still reported bad");
f_unlink("bbt.dat");
/* 注意:注入的坏块已持久化,测试设备专用;如需恢复需重建 BBT / 重新格式化 */
}
#ifdef ENABLE_STORAGE_RECOVERY_TESTS
static void storage_test_recover(void);
#endif
void storage_test_run(void)
{
static FATFS fs;
static FIL fil;
static uint8_t work[FF_MAX_SS];
char read_buf[64];
const char *test_str = "Hello FatFS + dhara FTL!";
memset(&g_storage_stats, 0, sizeof(g_storage_stats));
/* ==================== FTL + FatFS 文件系统测试 ==================== */
FRESULT res = f_mount(&fs, "", 1);
if (res == FR_NO_FILESYSTEM) {
MKFS_PARM opts = { FM_FAT32, 0, 0, 0, 0 };
res = f_mkfs("", &opts, work, sizeof(work));
STORAGE_TEST_CHECK(res == FR_OK, "f_mkfs");
res = f_mount(&fs, "", 1);
}
STORAGE_TEST_CHECK(res == FR_OK, "f_mount");
if (res == FR_OK) {
UINT bw, br;
res = f_open(&fil, "test.txt", FA_CREATE_ALWAYS | FA_WRITE);
STORAGE_TEST_CHECK(res == FR_OK, "f_open(write)");
if (res == FR_OK) {
f_write(&fil, test_str, (UINT)strlen(test_str), &bw);
STORAGE_TEST_CHECK(bw == (UINT)strlen(test_str), "f_write (%u bytes)", bw);
f_close(&fil);
res = f_open(&fil, "test.txt", FA_READ);
STORAGE_TEST_CHECK(res == FR_OK, "f_open(read)");
if (res == FR_OK) {
f_read(&fil, read_buf, (UINT)(sizeof(read_buf) - 1), &br);
f_close(&fil);
read_buf[br] = '\0';
STORAGE_TEST_CHECK(br == (UINT)strlen(test_str) &&
memcmp(test_str, read_buf, br) == 0,
"data verify \"%s\"", read_buf);
}
}
f_unlink("test.txt");
}
/* ==================== FTL + FatFS 性能测试 ==================== */
DBG_INFO("=== Storage Test: Performance ===");
{
FIL pfile;
UINT pw, pr;
uint32_t t0, tw, tr;
uint32_t i;
uint32_t total_kb = 128;
uint32_t chunk = sizeof(s_perf_buf);
uint32_t count = (total_kb * 1024) / chunk;
memset(s_perf_buf, 0xA5, sizeof(s_perf_buf));
/* 写入 */
t0 = HAL_GetTick();
if (f_open(&pfile, "perf.dat", FA_CREATE_ALWAYS | FA_WRITE) == FR_OK) {
for (i = 0; i < count; i++) {
f_write(&pfile, s_perf_buf, chunk, &pw);
}
f_close(&pfile);
}
tw = HAL_GetTick() - t0;
/* 读取 */
t0 = HAL_GetTick();
if (f_open(&pfile, "perf.dat", FA_READ) == FR_OK) {
for (i = 0; i < count; i++) {
f_read(&pfile, s_perf_buf, chunk, &pr);
}
f_close(&pfile);
}
tr = HAL_GetTick() - t0;
f_unlink("perf.dat");
if (tw > 0) {
DBG_INFO(" Write: %lu KB in %lu ms = %lu KB/s",
total_kb, tw, (total_kb * 1000) / tw);
}
if (tr > 0) {
DBG_INFO(" Read: %lu KB in %lu ms = %lu KB/s",
total_kb, tr, (total_kb * 1000) / tr);
}
}
/* ==================== 存储集成测试TC-STO-01~03 ==================== */
storage_test_powerloss();
storage_test_largefile();
storage_test_badblock();
#ifdef ENABLE_STORAGE_RECOVERY_TESTS
storage_test_recover();
#endif
/* ==================== 汇总报告 ==================== */
STORAGE_TEST_REPORT("Storage Tests");
}
#ifdef ENABLE_STORAGE_RECOVERY_TESTS
/* TC-STO-04: 重建 BBT + 重新格式化(恢复 TC-STO-03 注入的坏块)
* 仅在启用 ENABLE_STORAGE_RECOVERY_TESTS 时编译运行;运行一次即可把设备
* 恢复到干净出厂态(清除运行时注入坏块并清空 dhara map
*/
static void storage_test_recover(void)
{
DBG_INFO("=== Storage Test: TC-STO-04 BBT rebuild + format (recovery) ===");
int r = gd5f2gq5ue_bbt_rebuild();
STORAGE_TEST_CHECK(r == GD5F_OK, "TC-STO-04 bbt rebuild");
nand_ftl_format();
STORAGE_TEST_CHECK(1, "TC-STO-04 nand_ftl_format done");
uint8_t fb[GD5F_TOTAL_BLOCKS / 8];
uint32_t ver = 0;
if (gd5f_bbt_dump_flash(fb, &ver) == GD5F_OK) {
STORAGE_TEST_CHECK(ver >= 1, "TC-STO-04 persisted BBT version=%lu", ver);
} else {
STORAGE_TEST_CHECK(0, "TC-STO-04 dump_flash failed");
}
DBG_INFO("TC-STO-04 recovery complete; recommend power-cycle to re-init cleanly");
}
#endif