328 lines
9.4 KiB
C
328 lines
9.4 KiB
C
/* USER CODE BEGIN Header */
|
||
/**
|
||
******************************************************************************
|
||
* File Name : freertos.c
|
||
* Description : Code for freertos applications
|
||
******************************************************************************
|
||
* @attention
|
||
*
|
||
* Copyright (c) 2026 STMicroelectronics.
|
||
* All rights reserved.
|
||
*
|
||
* This software is licensed under terms that can be found in the LICENSE file
|
||
* in the root directory of this software component.
|
||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||
*
|
||
******************************************************************************
|
||
*/
|
||
/* USER CODE END Header */
|
||
|
||
/* Includes ------------------------------------------------------------------*/
|
||
#include "FreeRTOS.h"
|
||
#include "task.h"
|
||
#include "main.h"
|
||
#include "cmsis_os.h"
|
||
|
||
/* Private includes ----------------------------------------------------------*/
|
||
/* USER CODE BEGIN Includes */
|
||
#include <string.h>
|
||
#include "net_task.h"
|
||
#include "ch395f.h"
|
||
#include "dbg_log.h"
|
||
#include "net_socket.h"
|
||
#include "usart.h"
|
||
#include "ff.h"
|
||
#include "flashdb.h"
|
||
#include "gd5f2gq5ue.h"
|
||
/* USER CODE END Includes */
|
||
|
||
/* Private typedef -----------------------------------------------------------*/
|
||
/* USER CODE BEGIN PTD */
|
||
|
||
/* USER CODE END PTD */
|
||
|
||
/* Private define ------------------------------------------------------------*/
|
||
/* USER CODE BEGIN PD */
|
||
|
||
/* 存储测试统计 */
|
||
typedef struct {
|
||
uint16_t total;
|
||
uint16_t passed;
|
||
uint16_t failed;
|
||
} storage_test_stats_t;
|
||
|
||
#define STORAGE_TEST_CHECK(cond, fmt, ...) do { \
|
||
g_storage_stats.total++; \
|
||
if (cond) { \
|
||
g_storage_stats.passed++; \
|
||
DBG_INFO(" [PASS] " fmt, ##__VA_ARGS__); \
|
||
} else { \
|
||
g_storage_stats.failed++; \
|
||
DBG_ERROR(" [FAIL] " fmt, ##__VA_ARGS__); \
|
||
} \
|
||
} while (0)
|
||
|
||
#define STORAGE_TEST_REPORT(name) do { \
|
||
DBG_INFO("=== %s: %d/%d PASSED (failed=%d) ===", \
|
||
name, g_storage_stats.passed, g_storage_stats.total, g_storage_stats.failed); \
|
||
} while (0)
|
||
|
||
/* USER CODE END PD */
|
||
|
||
/* Private macro -------------------------------------------------------------*/
|
||
/* USER CODE BEGIN PM */
|
||
|
||
/* USER CODE END PM */
|
||
|
||
/* Private variables ---------------------------------------------------------*/
|
||
/* USER CODE BEGIN Variables */
|
||
static struct fdb_kvdb s_kvdb;
|
||
static storage_test_stats_t g_storage_stats;
|
||
static uint8_t s_perf_buf[4096];
|
||
/* USER CODE END Variables */
|
||
/* Definitions for defaultTask */
|
||
osThreadId_t defaultTaskHandle;
|
||
const osThreadAttr_t defaultTask_attributes = {
|
||
.name = "defaultTask",
|
||
.stack_size = 512 * 4,
|
||
.priority = (osPriority_t) osPriorityNormal,
|
||
};
|
||
/* Definitions for netTask */
|
||
osThreadId_t netTaskHandle;
|
||
const osThreadAttr_t netTask_attributes = {
|
||
.name = "netTask",
|
||
.stack_size = 1024 * 4,
|
||
.priority = (osPriority_t) osPriorityNormal,
|
||
};
|
||
/* Definitions for netMsgQueue */
|
||
osMessageQueueId_t netMsgQueueHandle;
|
||
const osMessageQueueAttr_t netMsgQueue_attributes = {
|
||
.name = "netMsgQueue"
|
||
};
|
||
|
||
/* Private function prototypes -----------------------------------------------*/
|
||
/* USER CODE BEGIN FunctionPrototypes */
|
||
|
||
/* USER CODE END FunctionPrototypes */
|
||
|
||
void StartDefaultTask(void *argument);
|
||
void StartNetTask(void *argument);
|
||
|
||
void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */
|
||
|
||
/**
|
||
* @brief FreeRTOS initialization
|
||
* @param None
|
||
* @retval None
|
||
*/
|
||
void MX_FREERTOS_Init(void) {
|
||
/* USER CODE BEGIN Init */
|
||
|
||
/* USER CODE END Init */
|
||
|
||
/* USER CODE BEGIN RTOS_MUTEX */
|
||
/* add mutexes, ... */
|
||
/* USER CODE END RTOS_MUTEX */
|
||
|
||
/* USER CODE BEGIN RTOS_SEMAPHORES */
|
||
/* add semaphores, ... */
|
||
/* USER CODE END RTOS_SEMAPHORES */
|
||
|
||
/* USER CODE BEGIN RTOS_TIMERS */
|
||
/* start timers, add new ones, ... */
|
||
/* USER CODE END RTOS_TIMERS */
|
||
|
||
/* Create the queue(s) */
|
||
/* creation of netMsgQueue */
|
||
netMsgQueueHandle = osMessageQueueNew (8, sizeof(net_msg_t), &netMsgQueue_attributes);
|
||
|
||
/* USER CODE BEGIN RTOS_QUEUES */
|
||
/* add queues, ... */
|
||
/* USER CODE END RTOS_QUEUES */
|
||
|
||
/* Create the thread(s) */
|
||
/* creation of defaultTask */
|
||
defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);
|
||
|
||
/* creation of netTask */
|
||
netTaskHandle = osThreadNew(StartNetTask, NULL, &netTask_attributes);
|
||
|
||
/* USER CODE BEGIN RTOS_THREADS */
|
||
/* add threads, ... */
|
||
/* USER CODE END RTOS_THREADS */
|
||
|
||
/* USER CODE BEGIN RTOS_EVENTS */
|
||
/* add events, ... */
|
||
/* USER CODE END RTOS_EVENTS */
|
||
|
||
}
|
||
|
||
/* USER CODE BEGIN Header_StartDefaultTask */
|
||
/**
|
||
* @brief Function implementing the defaultTask thread.
|
||
* @param argument: Not used
|
||
* @retval None
|
||
*/
|
||
/* USER CODE END Header_StartDefaultTask */
|
||
void StartDefaultTask(void *argument)
|
||
{
|
||
/* USER CODE BEGIN StartDefaultTask */
|
||
|
||
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!";
|
||
fdb_err_t fdb_ret;
|
||
|
||
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, strlen(test_str), &bw);
|
||
STORAGE_TEST_CHECK(bw == 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, sizeof(read_buf) - 1, &br);
|
||
f_close(&fil);
|
||
read_buf[br] = '\0';
|
||
STORAGE_TEST_CHECK(br == strlen(test_str) && memcmp(test_str, read_buf, br) == 0,
|
||
"data verify \"%s\"", read_buf);
|
||
}
|
||
}
|
||
f_unlink("test.txt");
|
||
}
|
||
|
||
/* ==================== FlashDB KVDB 测试 ==================== */
|
||
|
||
DBG_INFO("=== Storage Test: FlashDB KVDB ===");
|
||
|
||
/* 第一次 init(会触发 FAL 初始化,报告错误但成功) */
|
||
fdb_ret = fdb_kvdb_init(&s_kvdb, "kvdb1", "fdb_kvdb1", NULL, NULL);
|
||
|
||
/* 清除旧验证数据:格式化所有 sector */
|
||
fdb_kv_set_default(&s_kvdb);
|
||
/* 重新初始化干净的数据库 */
|
||
fdb_ret = fdb_kvdb_init(&s_kvdb, "kvdb1", "fdb_kvdb1", NULL, NULL);
|
||
STORAGE_TEST_CHECK(fdb_ret == FDB_NO_ERR, "fdb_kvdb_init");
|
||
|
||
if (fdb_ret == FDB_NO_ERR) {
|
||
fdb_ret = fdb_kv_set(&s_kvdb, "hello", "FlashDB KVDB!");
|
||
STORAGE_TEST_CHECK(fdb_ret == FDB_NO_ERR, "fdb_kv_set(hello)");
|
||
|
||
char *val = fdb_kv_get(&s_kvdb, "hello");
|
||
STORAGE_TEST_CHECK(val != NULL && strcmp(val, "FlashDB KVDB!") == 0,
|
||
"fdb_kv_get(hello) -> \"%s\"", val ? val : "NULL");
|
||
|
||
uint32_t blob_data = 0xDEADBEEF;
|
||
struct fdb_blob blob;
|
||
fdb_blob_make(&blob, &blob_data, sizeof(blob_data));
|
||
fdb_ret = fdb_kv_set_blob(&s_kvdb, "counter", &blob);
|
||
STORAGE_TEST_CHECK(fdb_ret == FDB_NO_ERR, "fdb_kv_set_blob(counter)");
|
||
|
||
uint32_t read_data = 0;
|
||
struct fdb_blob read_blob;
|
||
fdb_blob_make(&read_blob, &read_data, sizeof(read_data));
|
||
size_t len = fdb_kv_get_blob(&s_kvdb, "counter", &read_blob);
|
||
STORAGE_TEST_CHECK(len == sizeof(read_data) && read_data == 0xDEADBEEF,
|
||
"fdb_kv_get_blob(counter) -> 0x%08lX", (unsigned long)read_data);
|
||
|
||
fdb_kv_del(&s_kvdb, "hello");
|
||
fdb_kv_del(&s_kvdb, "counter");
|
||
}
|
||
|
||
/* ==================== 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);
|
||
}
|
||
}
|
||
|
||
/* ==================== 汇总报告 ==================== */
|
||
|
||
STORAGE_TEST_REPORT("Storage Tests");
|
||
|
||
for (;;) {
|
||
osDelay(1000);
|
||
}
|
||
/* USER CODE END StartDefaultTask */
|
||
}
|
||
|
||
/* USER CODE BEGIN Header_StartNetTask */
|
||
/**
|
||
* @brief Function implementing the netTask thread.
|
||
* @param argument: Not used
|
||
* @retval None
|
||
*/
|
||
/* USER CODE END Header_StartNetTask */
|
||
void StartNetTask(void *argument)
|
||
{
|
||
/* USER CODE BEGIN StartNetTask */
|
||
net_task_func(argument);
|
||
/* USER CODE END StartNetTask */
|
||
}
|
||
|
||
/* Private application code --------------------------------------------------*/
|
||
/* USER CODE BEGIN Application */
|
||
|
||
/* USER CODE END Application */
|
||
|