Files
STM32F4-Base/test/sd2506_test_task.c
T

251 lines
10 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.
/******************************************************************************
* 模块名称:SD2506 RTC Test Suite
* 模块功能:SD2506API-G RTC 驱动功能自测(黑盒,仅用公共 API)。
*
* 历史背景:本驱动曾出现"时间写不进"问题,根因是 sd2506.h 中寄存器宏写成
* "0x0FH"(H 后缀)。KEIL/ARMCC 不识别 H 整数后缀,将其编译为 0,
* 导致 SD2506_REG_CTR1 实际等于 0(秒寄存器),sd2506_write_enable()
* 把 WRTC 写到了错误寄存器,写保护永不解除。修正为 "0x0FU" 后恢复。
* 详见 docs/SD2506_Trap_Records.md。
*
* 当前测试:Phase 1 基本读写(init / 读 / 写 / 回读一致 / 走时),
* 结束后自动恢复板子原始时间。
* 入口:sd2506_test_run()(由 start_test_task 经 TEST_SUITE_RTC 调度)
* 创建日期:2026-08-28
******************************************************************************/
#include <string.h>
#include <stdint.h>
#include "sd2506_test.h"
#include "test_config.h"
#include "cmsis_os.h"
#include "sd2506.h"
#define DBG_TAG "[RTC_TEST]"
#include "dbg_log.h"
#ifdef TEST_SUITE_RTC
/* 全局测试统计(宏自动管理) */
sd2506_test_stats_t g_sd2506_test_stats;
/* ===================== Phase 1:基本读写 ===================== */
#ifdef ENABLE_RTC_BASIC_TESTS
static void sd2506_phase_basic(void)
{
DBG_INFO("=== SD2506 Phase 1: basic read/write (public API) ===");
/* TC-RTC-001: init + 读取当前时间 */
int ret = sd2506_init();
SD2506_TEST_CHECK(ret == SD2506_OK, "sd2506_init() ret=%d (expect 0)", ret);
sd2506_time_t r;
ret = sd2506_get_time(&r);
SD2506_TEST_CHECK(ret == SD2506_OK, "sd2506_get_time() ret=%d (expect 0)", ret);
if (ret == SD2506_OK) {
DBG_INFO(" current RTC: %04u-%02u-%02u %02u:%02u:%02u wk=%u",
(unsigned int)r.year, (unsigned int)r.month, (unsigned int)r.day,
(unsigned int)r.hour, (unsigned int)r.minute,
(unsigned int)r.second, (unsigned int)r.week);
}
/* TC-RTC-002: 写固定时间,立即回读比对(破坏性:改设备 RTC 时间,套件结束会复原)。
* 若 FAIL -> 先查 sd2506.h 寄存器宏后缀是否为 H(曾因 0x0FH 被 KEIL 编译为 0
* 导致 SD2506_REG_CTR1 指向秒寄存器、WRTC 写错地址)。详见 docs/SD2506_Trap_Records.md。 */
#ifdef ENABLE_DESTRUCTIVE_TESTS
{
sd2506_time_t t;
int match;
t.year = 2026; t.month = 8; t.day = 28; t.hour = 12; t.minute = 0; t.second = 0; t.week = 4;
ret = sd2506_set_time(&t);
SD2506_TEST_CHECK(ret == SD2506_OK, "sd2506_set_time() ret=%d (expect 0)", ret);
ret = sd2506_get_time(&r);
SD2506_TEST_CHECK(ret == SD2506_OK, "sd2506_get_time() after set ret=%d (expect 0)", ret);
if (ret == SD2506_OK) {
DBG_INFO(" set : %04u-%02u-%02u %02u:%02u:%02u",
(unsigned int)t.year, (unsigned int)t.month, (unsigned int)t.day,
(unsigned int)t.hour, (unsigned int)t.minute, (unsigned int)t.second);
DBG_INFO(" readback: %04u-%02u-%02u %02u:%02u:%02u",
(unsigned int)r.year, (unsigned int)r.month, (unsigned int)r.day,
(unsigned int)r.hour, (unsigned int)r.minute, (unsigned int)r.second);
}
match = (r.year == t.year && r.month == t.month && r.day == t.day &&
r.hour == t.hour && r.minute == t.minute &&
(r.second == t.second || r.second == ((t.second + 1U) % 60U)));
SD2506_TEST_CHECK(match, "set==readback (in-session write takes effect)");
}
#else
DBG_INFO("TC-RTC-002 skipped: destructive tests disabled (RTC time write)");
#endif
/* TC-RTC-003: 走时。写后等 3s,应前进约 3 秒 */
if (ret == SD2506_OK) {
osDelay(3000);
sd2506_time_t r2;
int ret2 = sd2506_get_time(&r2);
if (ret2 == SD2506_OK) {
int adv = (r2.second + 60 * (r2.minute + 60 * (r2.hour + 24 * r2.day)))
- (r.second + 60 * (r.minute + 60 * (r.hour + 24 * r.day)));
if (adv < 0) adv += 60 * 60 * 24 * 32;
DBG_INFO(" 3s later: %04u-%02u-%02u %02u:%02u:%02u (advanced %d s)",
(unsigned int)r2.year, (unsigned int)r2.month, (unsigned int)r2.day,
(unsigned int)r2.hour, (unsigned int)r2.minute, (unsigned int)r2.second, adv);
SD2506_TEST_CHECK(adv >= 2 && adv <= 5, "RTC ticking forward (~3s)");
}
}
SD2506_TEST_REPORT("Phase 1 basic");
}
#endif /* ENABLE_RTC_BASIC_TESTS */
/* ===================== Phase 2:全功能 API 覆盖 ===================== */
#ifdef ENABLE_RTC_API_TESTS
static void sd2506_phase_api(void)
{
DBG_INFO("=== SD2506 Phase 2: full API coverage ===");
/* TC-RTC-010: BCD<->DEC 互转(纯算法,确定性,无需硬件交互) */
int conv_ok = 1;
uint8_t samples[][2] = {
{0, 0x00U}, {1, 0x01U}, {9, 0x09U}, {10, 0x10U}, {23, 0x23U},
{59, 0x59U}, {60, 0x60U}, {99, 0x99U}, {42, 0x42U}, {88, 0x88U}
};
for (uint32_t i = 0U; i < (sizeof(samples) / sizeof(samples[0])); i++) {
uint8_t dec = samples[i][0];
uint8_t bcd = samples[i][1];
if (sd2506_dec_to_bcd(dec) != bcd) {
conv_ok = 0;
DBG_ERROR(" dec_to_bcd(%u) != 0x%02X", (unsigned int)dec, (unsigned int)bcd);
}
if (sd2506_bcd_to_dec(bcd) != dec) {
conv_ok = 0;
DBG_ERROR(" bcd_to_dec(0x%02X) != %u", (unsigned int)bcd, (unsigned int)dec);
}
}
SD2506_TEST_CHECK(conv_ok, "bcd<->dec round-trip (10 samples)");
/* TC-RTC-011: 内部温度读取 */
int8_t temp = 0;
int ret = sd2506_get_temperature(&temp);
SD2506_TEST_CHECK(ret == SD2506_OK, "sd2506_get_temperature() ret=%d (expect 0)", ret);
if (ret == SD2506_OK) {
DBG_INFO(" temperature: %d C", (int)temp);
SD2506_TEST_CHECK(temp >= -40 && temp <= 85,
"temperature in range [-40,85]: %d", (int)temp);
}
/* TC-RTC-012: 电池电压(毫伏) */
uint16_t volt = 0U;
ret = sd2506_get_battery_voltage(&volt);
SD2506_TEST_CHECK(ret == SD2506_OK, "sd2506_get_battery_voltage() ret=%d (expect 0)", ret);
if (ret == SD2506_OK) {
DBG_INFO(" battery: %u mV", (unsigned int)volt);
SD2506_TEST_CHECK(volt > 2000U && volt < 5000U,
"battery voltage plausible: %u mV", (unsigned int)volt);
}
/* TC-RTC-013: 芯片 8 字节 ID */
uint8_t id[8] = {0};
ret = sd2506_get_id(id);
SD2506_TEST_CHECK(ret == SD2506_OK, "sd2506_get_id() ret=%d (expect 0)", ret);
if (ret == SD2506_OK) {
DBG_INFO(" id: %02X%02X%02X%02X%02X%02X%02X%02X",
id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7]);
}
/* TC-RTC-014: 用户 SRAM 读写回环(addr=0, len=8;破坏性:写芯片 SRAM) */
#ifdef ENABLE_DESTRUCTIVE_TESTS
{
uint8_t wbuf[8] = {0xA1U, 0xB2U, 0xC3U, 0xD4U, 0xE5U, 0xF6U, 0x07U, 0x18U};
uint8_t rbuf[8] = {0};
ret = sd2506_write_sram(0U, wbuf, 8U);
SD2506_TEST_CHECK(ret == SD2506_OK, "sd2506_write_sram() ret=%d (expect 0)", ret);
if (ret == SD2506_OK) {
ret = sd2506_read_sram(0U, rbuf, 8U);
SD2506_TEST_CHECK(ret == SD2506_OK, "sd2506_read_sram() ret=%d (expect 0)", ret);
int sram_ok = (memcmp(wbuf, rbuf, 8U) == 0);
SD2506_TEST_CHECK(sram_ok, "SRAM write==readback");
}
}
#else
DBG_INFO("TC-RTC-014 skipped: destructive tests disabled (RTC SRAM write)");
#endif
/* TC-RTC-015: 报警设置 + 清除(破坏性:写报警寄存器;验证 API 通路,不影响时间寄存器) */
#ifdef ENABLE_DESTRUCTIVE_TESTS
{
sd2506_time_t at;
at.year = 2026; at.month = 8; at.day = 28; at.hour = 12; at.minute = 0; at.second = 30; at.week = 4;
ret = sd2506_set_alarm(&at, (uint8_t)(SD2506_AL_EN_EAS | SD2506_AL_EN_EAMN));
SD2506_TEST_CHECK(ret == SD2506_OK, "sd2506_set_alarm() ret=%d (expect 0)", ret);
ret = sd2506_clear_alarm();
SD2506_TEST_CHECK(ret == SD2506_OK, "sd2506_clear_alarm() ret=%d (expect 0)", ret);
}
#else
DBG_INFO("TC-RTC-015 skipped: destructive tests disabled (RTC alarm write)");
#endif
SD2506_TEST_REPORT("Phase 2 API");
}
#endif /* ENABLE_RTC_API_TESTS */
/* ===================== 套件入口 ===================== */
void sd2506_test_run(void)
{
DBG_INFO("SD2506 test suite started");
#ifdef ENABLE_DESTRUCTIVE_TESTS
DBG_INFO("mode: DESTRUCTIVE (RTC time / SRAM / alarm writes enabled)");
#else
DBG_INFO("mode: READ-ONLY (destructive cases skipped; set "
"ENABLE_DESTRUCTIVE_TESTS in test_config.h to run them)");
#endif
int ret = sd2506_init();
SD2506_TEST_CHECK(ret == SD2506_OK, "sd2506_init() ret=%d (expect 0)", ret);
/* 信息:读取 CTR1 默认状态(确认 WRTC 初始/可写能力,纯诊断) */
uint8_t c1 = 0x00U;
if (sd2506_read_ctr1(&c1) == SD2506_OK) {
DBG_INFO(" CTR1=0x%02X (WRTC2=CTR1.2=%u WRTC3=CTR1.7=%u)",
(unsigned int)c1,
(unsigned int)((c1 >> 2) & 1U),
(unsigned int)((c1 >> 7) & 1U));
}
#ifdef ENABLE_DESTRUCTIVE_TESTS
/* 记录原始时间,测试结束恢复,避免把板子时间留在测试值 */
sd2506_time_t orig;
int have_orig = (sd2506_get_time(&orig) == SD2506_OK);
if (!have_orig) {
DBG_INFO(" WARN: cannot read original time; restore step will be skipped");
}
#endif
memset(&g_sd2506_test_stats, 0, sizeof(g_sd2506_test_stats));
#ifdef ENABLE_RTC_BASIC_TESTS
sd2506_phase_basic();
#endif
#ifdef ENABLE_RTC_API_TESTS
sd2506_phase_api();
#endif
#ifdef ENABLE_DESTRUCTIVE_TESTS
/* 恢复原始时间(用公共 API,写保护逻辑已由 sd2506.c 正确处理) */
if (have_orig) {
int r = sd2506_set_time(&orig);
DBG_INFO(" restored original time (ret=%d)", r);
}
#endif
DBG_INFO("SD2506 test suite done");
for (;;) {
osDelay(1000);
}
}
#endif /* TEST_SUITE_RTC */