增加文件系统

This commit is contained in:
2026-07-21 00:30:59 +08:00
parent e06d849007
commit fbe0726991
50 changed files with 12921 additions and 893 deletions

View File

@@ -22,12 +22,6 @@ extern "C" {
*/
#define APP_SYS_TIME_SRC 0
/*
* 时间戳输出使能
* 定义后在日志行首自动追加 [T ssssss.uuuuuu] 微秒时间戳
*/
#define APP_TIMESTAMP_ENABLE
/*
* 功能模块使能开关
*/

View File

@@ -10,7 +10,6 @@
#include "app_main.h"
#include "app_cfg.h"
#include "sys_time.h"
#define DBG_TAG "[APP]"
#include "dbg_log.h"
@@ -24,10 +23,6 @@
*/
int app_main_init(void)
{
if (sys_time_init() != 0) {
DBG_ERROR("sys_time_init failed");
return -1;
}
DBG_INFO("App init OK");
return 0;
}

199
App/sys_clock.c Normal file
View File

@@ -0,0 +1,199 @@
/*
* 模块名称System Clock — Wall Clock Time Maintenance
* 模块功能:实现系统墙钟时间维护,包括 RTC 初始读取、HAL Tick 漂移维持
* 适用平台STM32F407ZGTx (Cortex-M4 FPU, 168MHz)
* 作者:王建锋
* 创建日期2026-07-19
* 修改记录:
* v1.0 2026-07-19 王建锋 创建初始版本
*/
#include "sys_clock.h"
#include "main.h"
#include <string.h>
#include <stdio.h>
#define DBG_TAG "[CLK]"
#include "dbg_log.h"
/* ============================================================
* 内部状态:系统墙钟
* ============================================================ */
static volatile uint32_t s_base_tick = 0; /* HAL_GetTick() 基准 */
static volatile uint32_t s_base_unix_secs = UINT32_MAX;
/* ============================================================
* 内部辅助函数Unix time ↔ sd2506_time_t 转换
* ============================================================ */
static void unix_to_sd2506(uint32_t unix_secs, sd2506_time_t *p_sd_time)
{
uint32_t y, m, d;
uint8_t h, mi, s;
int is_leap;
/* 时分秒 */
{
uint64_t total = (uint64_t)unix_secs;
s = (uint8_t)(total % 60uLL);
total /= 60uLL;
mi = (uint8_t)(total % 60uLL);
total /= 60uLL;
h = (uint8_t)(total % 24uL);
}
/* 年月日 */
{
uint64_t day_count = ((uint64_t)unix_secs / 86400uL);
y = 1970u;
while (day_count >= 365uLL) {
uint64_t diy = 365uLL;
if ((y % 4 == 0 && y % 100 != 0) || (y % 400 == 0)) {
diy = 366uLL;
}
if (day_count < diy) break;
day_count -= diy;
y++;
}
is_leap = ((y % 4 == 0 && y % 100 != 0) || (y % 400 == 0));
uint8_t mdays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
if (is_leap) mdays[1] = 29;
m = 0;
while (m < 12u) {
if (day_count < (uint64_t)mdays[m]) break;
day_count -= mdays[m];
m++;
}
d = (uint32_t)(day_count + 1uL);
/* 星期Zeller's congruence0=Sunday */
uint64_t wy = y;
uint64_t wm = m;
if (wm <= 2) {
wy--;
wm += 12uL;
}
uint8_t week = ((uint32_t)(wy % 100uLL + wy / 100uLL / 4uLL - wy / 100uLL / 15uLL) +
(uint32_t)(((uint64_t)26 * (wm + 1uL)) / 10uLL) +
(uint32_t)(d % 100uLL)) % 7uLL;
/* SD2506 year 字段为 0~99+2000 */
uint16_t sd_year = y >= 2000 ? (y - 2000) : (y + 2000);
p_sd_time->year = sd_year;
p_sd_time->month = m + 1uL; /* 月份从 0 → 1 */
p_sd_time->day = d;
p_sd_time->hour = h;
p_sd_time->minute = mi;
p_sd_time->second = s;
p_sd_time->week = week;
}
}
/* ============================================================
* 系统墙钟时间维护
* ============================================================ */
int sys_clock_init(void)
{
sd2506_time_t sd_time;
uint32_t year, month, day, hour, minute, second;
int64_t unix_secs = 0;
int i;
/* Step 1: 从 SD2506 RTC 读取初始时间 */
sd2506_get_time(&sd_time);
year = (uint32_t)sd_time.year + 2000uL;
month = (uint32_t)sd_time.month;
day = (uint32_t)sd_time.day;
hour = (uint32_t)sd_time.hour;
minute = (uint32_t)sd_time.minute;
second = (uint32_t)sd_time.second;
DBG_INFO("sys_clock_init: RTC initial time %04d-%02d-%02d %02d:%02d:%02d",
year, month, day, hour, minute, second);
/* Step 2: Unix epoch → seconds简化算法适用于 1970~2038 */
{
uint64_t total_days = 0;
for (i = 1970; i < year; i++) {
if ((i % 4 == 0 && i % 100 != 0) || (i % 400 == 0)) {
total_days += 366uLL;
} else {
total_days += 365uLL;
}
}
int is_leap = ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0));
uint8_t mdays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
if (is_leap) mdays[1] = 29;
for (i = 0; i < month - 1; i++) {
total_days += mdays[i];
}
total_days += day - 1uL;
unix_secs = (int64_t)(total_days * 86400LL) + hour * 3600LL + minute * 60LL + second;
}
/* Step 3: 设置系统墙钟基准 */
s_base_tick = HAL_GetTick();
s_base_unix_secs = (uint32_t)unix_secs;
DBG_INFO("sys_clock_init: wall clock base = unix %lu, base_tick=%lu",
(unsigned long)s_base_unix_secs, (unsigned long)s_base_tick);
return 0;
}
uint32_t sys_clock_get(void)
{
uint32_t now_tick = HAL_GetTick();
int64_t unix_secs = (int64_t)s_base_unix_secs + (int64_t)((uint32_t)(now_tick - s_base_tick) / 1000uL);
if (unix_secs < 0) {
return UINT32_MAX; /* 未初始化 */
}
return (uint32_t)unix_secs;
}
char *sys_clock_get_str(char *buf, size_t buf_size)
{
uint32_t unix_secs = sys_clock_get();
if (unix_secs == UINT32_MAX) {
snprintf(buf, buf_size, "----/--/-- --:--:--");
return buf;
}
sd2506_time_t sd;
unix_to_sd2506(unix_secs, &sd);
snprintf(buf, buf_size, "%04d-%02d-%02d %02d:%02d:%02d",
sd.year + 2000uL, sd.month, sd.day,
sd.hour, sd.minute, sd.second);
return buf;
}
int sys_clock_set(uint32_t unix_secs, const sd2506_time_t *sd_time)
{
/* Step 1: 更新墙钟基准 */
s_base_tick = HAL_GetTick();
s_base_unix_secs = unix_secs;
DBG_INFO("sys_clock_set: wall clock updated to %lu", (unsigned long)unix_secs);
/* Step 2: 写回 SD2506 RTC若提供了 sd_time */
if (sd_time != NULL) {
sd2506_set_time(sd_time);
DBG_INFO("sys_clock_set: SD2506 RTC written");
}
return 0;
}

65
App/sys_clock.h Normal file
View File

@@ -0,0 +1,65 @@
/*
* 模块名称System Clock — Wall Clock Time Maintenance
* 模块功能:基于 HAL Tick + SD2506 RTC 的系统墙钟时间维护
* 启动时从 SD2506 RTC 读取初始时间,运行期间以 HAL Tick 计数维持
* 适用平台STM32F407ZGTx (Cortex-M4 FPU, 168MHz)
* 作者:王建锋
* 创建日期2026-07-19
* 修改记录:
* v1.0 2026-07-19 王建锋 创建初始版本
*/
#ifndef __SYS_CLOCK_H
#define __SYS_CLOCK_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include "sd2506.h"
/*
* 函数功能:系统时钟初始化(从 SD2506 RTC 读取初始时间)
* 入口参数:无
* 返回值0 - 成功, -1 - 失败
* 限定条件sd2506_init() 已调用
* 函数说明:读取 SD2506 RTC 当前值转换为 Unix timestamp设为系统墙钟初始时间
*/
int sys_clock_init(void);
/*
* 函数功能获取当前系统墙钟时间Unix epoch seconds
* 入口参数:无
* 返回值Unix time (秒),失败返回 UINT32_MAX
* 限定条件sys_clock_init() 已调用
* 函数说明:基于 HAL Tick 计数 + 上次校准时刻的 Unix 秒数计算当前时间,
* 精度为毫秒级
*/
uint32_t sys_clock_get(void);
/*
* 函数功能:格式化系统墙钟时间为字符串
* 入口参数buf - 输出缓冲区(至少 20 字节)
* buf_size - 缓冲区大小
* 返回值buf 指针,失败返回 NULL
* 限定条件sys_clock_init() 已调用
* 函数说明:格式 "YYYY-MM-DD HH:MM:SS"
*/
char *sys_clock_get_str(char *buf, size_t buf_size);
/*
* 函数功能:设置系统墙钟时间
* 入口参数unix_secs - Unix epoch time (秒)
* sd_time - SD2506 RTC 时间结构体(可选,非 NULL 时同时写入 RTC
* 返回值0 - 成功, -1 - 失败
* 限定条件sys_clock_init() 已调用
* 函数说明:更新系统墙钟基准 + 写回 SD2506 RTC 保持长期准确性
*/
int sys_clock_set(uint32_t unix_secs, const sd2506_time_t *sd_time);
#ifdef __cplusplus
}
#endif
#endif /* __SYS_CLOCK_H */

View File

@@ -1,107 +0,0 @@
/*
* 模块名称System Timer
* 模块功能DWT CYCCNT 实现 64-bit 微秒级时间戳
* 在 SysTick 中断中检测 CYCCNT 溢出以扩展至 64-bit
* 适用平台STM32F407ZGTx (168MHz)
* 作者:王建锋
* 创建日期2026-07-19
*
* 限定条件:
* - CPU 主频 168MHz若更改须同步 SYS_TIME_CYCLE_PER_US 宏)
* - 须在 FreeRTOS 启动前调用 sys_time_init()
* - sys_time_systick_hook() 须在 SysTick 中断中调用
*
* 修改记录:
* v1.0 2026-07-19 王建锋 创建初始版本
*/
#include "sys_time.h"
#include "app_cfg.h"
#include "stm32f4xx.h"
/*
* 每微秒 CPU 周期数168MHz → 168 cycles/µs
*/
#define SYS_TIME_CYCLE_PER_US 168UL
/*
* CYCCNT 每溢出一次代表的微秒数2^32 / 168 ≈ 25,564,904 µs ≈ 25.56s
*/
#define SYS_TIME_OVERFLOW_US (uint64_t)(((uint64_t)1 << 32) / SYS_TIME_CYCLE_PER_US)
static volatile uint32_t s_overflow_cnt;
/*
* 函数功能:初始化 DWT CYCCNT
* 入口参数:无
* 返 回 值0 - 成功
* 限定条件:须在 FreeRTOS 启动前调用
* 函数说明:启用 DWT 和 CYCCNT 计数器,计数器从 0 开始
*/
int sys_time_init(void)
{
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
DWT->CYCCNT = 0;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
s_overflow_cnt = 0;
return 0;
}
/*
* 函数功能:获取微秒级时间戳
* 入口参数:无
* 返 回 值64 位微秒时间戳
* 函数说明:由当前 CYCCNT 值与溢出计数合成 64-bit 周期数再转换
*/
uint64_t sys_time_us(void)
{
uint32_t cyccnt = 0;
uint64_t ticks = 0;
uint32_t ov = 0;
uint32_t ov2 = 0;
/*
* 原子读取溢出计数与 CYCCNT处理潜在的读取竞争
* 若两次读取溢出计数不一致则重读 CYCCNT
*/
do {
ov = s_overflow_cnt;
cyccnt = DWT->CYCCNT;
ov2 = s_overflow_cnt;
} while (ov != ov2);
ticks = ((uint64_t)ov << 32) | cyccnt;
return ticks / SYS_TIME_CYCLE_PER_US;
}
/*
* 函数功能:获取毫秒级时间戳
* 入口参数:无
* 返 回 值64 位毫秒时间戳
* 限定条件sys_time_init() 已成功调用
* 函数说明:通过对 sys_time_us() 取整实现
*/
uint64_t sys_time_ms(void)
{
return sys_time_us() / 1000;
}
/*
* 函数功能SysTick 中断钩子,检测 CYCCNT 溢出
* 入口参数:无
* 返 回 值:无
* 函数说明:必须在 SysTick_Handler() 中调用
* 每 1ms 检查一次 CYCCNT 是否已回绕
*/
void sys_time_systick_hook(void)
{
static uint32_t s_last_cyccnt = 0;
uint32_t cyccnt = DWT->CYCCNT;
if (cyccnt < s_last_cyccnt) {
s_overflow_cnt++;
}
s_last_cyccnt = cyccnt;
}

View File

@@ -1,29 +0,0 @@
/*
* 模块名称System Timer
* 模块功能:基于 DWT CYCCNT + SysTick 溢出的 64 位微秒级时间戳
* 适用平台STM32F407ZGTx (Cortex-M4 FPU)
* 作者:王建锋
* 创建日期2026-07-19
* 修改记录:
* v1.0 2026-07-19 王建锋 创建初始版本
*/
#ifndef __SYS_TIME_H
#define __SYS_TIME_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
int sys_time_init(void);
uint64_t sys_time_us(void);
uint64_t sys_time_ms(void);
void sys_time_systick_hook(void);
#ifdef __cplusplus
}
#endif
#endif /* __SYS_TIME_H */

View File

@@ -46,10 +46,11 @@ void net_task_func(void const *arg)
(void)arg;
osDelay(2000);
DBG_INFO("netTask: started");
DBG_INFO("netTask: started, processing messages");
for (;;) {
net_poll();
net_process_messages();
#ifdef ENABLE_PHASE4_TESTS
for (int i = 1; i < 8; i++) {
@@ -58,9 +59,9 @@ void net_task_func(void const *arg)
continue;
}
int n = net_recv(i, s_net_buf, sizeof(s_net_buf), NET_MSG_DONTWAIT);
int n = net_recv_sock(p_sk, s_net_buf, sizeof(s_net_buf), NET_MSG_DONTWAIT);
if (n > 0) {
net_send(i, s_net_buf, n, 0);
net_send_sock(p_sk, s_net_buf, n);
}
}
#endif