Files
CCU621M/app/app_init/app_test.c
T

906 lines
33 KiB
C

#include "app_init/app_test.h"
#include "app_init/app_init.h"
#include <string.h>
#include <stdint.h>
#include <stdio.h>
#include "FreeRTOS.h"
#include "portable.h"
#include "flash_external_data.h"
#include "fm24cl16.h"
#include "app_rtc/app_rtc.h"
#include "usart.h"
#include "can.h"
#include "publicdata/publicdata.h"
#include "mylog/mylog.h"
#include "collect_ctrl/collect_task.h"
#include "sys_drv_init.h"
#define APP_TEST_LOG(fmt, ...) MYLOG_MSG(TASK_ID_MyLog, (fmt), ##__VA_ARGS__)
#ifndef APP_TEST_ENABLE
#define APP_TEST_ENABLE (0U)
#endif
#define APP_TEST_FLASH_ADDR (0x00010000U)
#define APP_TEST_FLASH_RW_SIZE (1024U)
#define APP_TEST_FLASH_PERIOD_S (10U)
#define APP_TEST_MIN_TEST_MS (1U)
#define APP_TEST_ALIGN (32U)
#define APP_TEST_GUARD_SIZE (32U)
#define APP_TEST_FLASH_TOTAL_32M (0x02000000U)
#define APP_TEST_FLASH_STEP_1M (0x00100000U)
#define APP_TEST_ENABLE_FLASH_SPEED (0U)
#define APP_TEST_EEPROM_ADDR (0x0600U)
#define APP_TEST_EEPROM_SIZE (32U)
#define APP_TEST_EEPROM_MULTI_SIZE (64U)
#define APP_TEST_EEPROM_SPEED_SIZE (64U)
#define APP_TEST_EEPROM_SPEED_LOOP (10U)
#define APP_TEST_EEPROM_SPEED_RETRY (3U)
/* Use dedicated test window, avoid business hot partitions (e.g. 0x0100/0x0400). */
#define APP_TEST_EEPROM_TEST_ADDR_BASE (0x0600U)
typedef enum
{
APP_TEST_STEP_RTC = 0,
APP_TEST_STEP_EEPROM_BASIC,
APP_TEST_STEP_EEPROM_MULTI,
APP_TEST_STEP_EEPROM_SPEED,
APP_TEST_STEP_CAN,
APP_TEST_STEP_UART,
#if (APP_TEST_ENABLE_FLASH_SPEED)
APP_TEST_STEP_FLASH_SPEED,
#endif
APP_TEST_STEP_FLASH_STRIDE,
APP_TEST_STEP_DONE
} APP_TEST_STEP_T;
#if (APP_TEST_ENABLE)
/**
* @brief 将指针向上对齐到指定字节边界。
* @param p 原始指针。
* @param align 对齐值(2 的幂)。
* @return 对齐后的指针。
*/
static uint8_t *align_up_u8(uint8_t *p, uint32_t align)
{
uintptr_t v = (uintptr_t)p;
v = (v + (align - 1U)) & ~(uintptr_t)(align - 1U);
return (uint8_t *)v;
}
/**
* @brief 为 Flash DMA 测试申请对齐缓冲。
* @param tx_raw 输出:TX 原始指针(用于释放)。
* @param rx_raw 输出:RX 原始指针(用于释放)。
* @param tx_buf 输出:对齐后的 TX 指针(用于读写)。
* @param rx_buf 输出:对齐后的 RX 指针(用于读写)。
* @return 1 成功,0 失败。
*/
static uint8_t app_test_alloc_aligned_buffers(uint8_t **tx_raw, uint8_t **rx_raw, uint8_t **tx_buf, uint8_t **rx_buf)
{
uint32_t alloc_size = APP_TEST_FLASH_RW_SIZE + APP_TEST_ALIGN + APP_TEST_GUARD_SIZE;
*tx_raw = (uint8_t *)pvPortMalloc(alloc_size);
*rx_raw = (uint8_t *)pvPortMalloc(alloc_size);
if ((*tx_raw == NULL) || (*rx_raw == NULL)) {
if (*tx_raw != NULL) {
vPortFree(*tx_raw);
}
if (*rx_raw != NULL) {
vPortFree(*rx_raw);
}
*tx_raw = NULL;
*rx_raw = NULL;
*tx_buf = NULL;
*rx_buf = NULL;
return 0U;
}
*tx_buf = align_up_u8(*tx_raw, APP_TEST_ALIGN);
*rx_buf = align_up_u8(*rx_raw, APP_TEST_ALIGN);
return 1U;
}
/**
* @brief 释放由 app_test_alloc_aligned_buffers 申请的原始缓冲。
* @param tx_raw TX 原始指针。
* @param rx_raw RX 原始指针。
*/
static void app_test_free_aligned_buffers(uint8_t *tx_raw, uint8_t *rx_raw)
{
if (tx_raw != NULL) {
vPortFree(tx_raw);
}
if (rx_raw != NULL) {
vPortFree(rx_raw);
}
}
#if (APP_TEST_ENABLE_FLASH_SPEED)
/**
* @brief 单次 Flash 擦写读回测速与校验。
* @details
* - 使用 1KB 数据块在固定地址做擦除/写入/读取;
* - 打印 erase/write/read 耗时与吞吐;
* - 读回校验失败会打印 seed 便于复现。
*/
static void v_app_test_flash_rw_speed_once(void)
{
uint32_t i;
uint64_t t0;
uint64_t t1;
uint32_t seed;
uint32_t erase_ms;
uint32_t write_ms;
uint32_t read_ms;
uint32_t write_kbs;
uint32_t read_kbs;
uint8_t *tx_raw;
uint8_t *rx_raw;
uint8_t *tx_buf;
uint8_t *rx_buf;
if (app_test_alloc_aligned_buffers(&tx_raw, &rx_raw, &tx_buf, &rx_buf) == 0U) {
APP_TEST_LOG("[APP_TEST] exflash malloc fail, size=%u\r\n", (unsigned int)APP_TEST_FLASH_RW_SIZE);
return;
}
seed = (uint32_t)u64_get_current_millis();
for (i = 0U; i < APP_TEST_FLASH_RW_SIZE; i++) {
tx_buf[i] = (uint8_t)((seed + i) & 0xFFU);
}
(void)memset(rx_buf, 0, APP_TEST_FLASH_RW_SIZE);
t0 = u64_get_current_millis();
(void)s32_flash_dataflash_erase_sector(APP_TEST_FLASH_ADDR);
t1 = u64_get_current_millis();
erase_ms = (uint32_t)(t1 - t0);
t0 = u64_get_current_millis();
(void)s32_flash_dataflash_write(APP_TEST_FLASH_ADDR, tx_buf, APP_TEST_FLASH_RW_SIZE);
t1 = u64_get_current_millis();
write_ms = (uint32_t)(t1 - t0);
if (write_ms < APP_TEST_MIN_TEST_MS) {
write_ms = APP_TEST_MIN_TEST_MS;
}
t0 = u64_get_current_millis();
(void)s32_flash_dataflash_read(APP_TEST_FLASH_ADDR, rx_buf, APP_TEST_FLASH_RW_SIZE);
t1 = u64_get_current_millis();
read_ms = (uint32_t)(t1 - t0);
if (read_ms < APP_TEST_MIN_TEST_MS) {
read_ms = APP_TEST_MIN_TEST_MS;
}
if (memcmp(tx_buf, rx_buf, APP_TEST_FLASH_RW_SIZE) != 0) {
APP_TEST_LOG("[APP_TEST] exflash rw verify fail, seed=%lu\r\n", (unsigned long)seed);
app_test_free_aligned_buffers(tx_raw, rx_raw);
return;
}
write_kbs = (APP_TEST_FLASH_RW_SIZE * 1000U) / (write_ms * 1024U);
read_kbs = (APP_TEST_FLASH_RW_SIZE * 1000U) / (read_ms * 1024U);
APP_TEST_LOG("[APP_TEST] exflash speed seed=%lu, erase=%lums, write=%lums(%luKB/s), read=%lums(%luKB/s)\r\n",
(unsigned long)seed,
(unsigned long)erase_ms,
(unsigned long)write_ms,
(unsigned long)write_kbs,
(unsigned long)read_ms,
(unsigned long)read_kbs);
app_test_free_aligned_buffers(tx_raw, rx_raw);
}
#endif
void v_app_test_rtc_rw_once(void)
{
Comm_Time backup_time;
Comm_Time write_time;
Comm_Time read_time;
GetCurrentTime(&backup_time);
write_time = backup_time;
write_time.ucSec = (uint8_t)((write_time.ucSec + 1U) % 60U);
if ((write_time.ucSec == 0U) && (write_time.ucMin < 59U)) {
write_time.ucMin++;
}
v_rtc_set_time(&write_time);
GetCurrentTime(&read_time);
APP_TEST_LOG("[APP_TEST] rtc rw test, write=%04u-%02u-%02u %02u:%02u:%02u, read=%04u-%02u-%02u %02u:%02u:%02u\r\n",
write_time.iYear, write_time.ucMonth, write_time.ucDay,
write_time.ucHour, write_time.ucMin, write_time.ucSec,
read_time.iYear, read_time.ucMonth, read_time.ucDay,
read_time.ucHour, read_time.ucMin, read_time.ucSec);
v_rtc_set_time(&backup_time);
}
#if defined(__CC_ARM)
#pragma diag_suppress 177
#endif
/**
* @brief EEPROM(FM24CL16) 单次读写校验测试。
* @return 1 通过,0 失败。
*/
uint8_t u8_app_test_eeprom_rw_once(void)
{
uint8_t tx[APP_TEST_EEPROM_SIZE];
uint8_t rx[APP_TEST_EEPROM_SIZE];
uint32_t i;
int32_t first_mismatch = -1;
uint8_t probe_ret;
uint32_t err_after_write;
uint32_t err_after_read;
uint8_t pr;
APP_TEST_LOG("[APP_TEST] eeprom rw test start, addr=0x%02X size=%u\r\n",
(unsigned int)APP_TEST_EEPROM_ADDR,
(unsigned int)APP_TEST_EEPROM_SIZE);
for (i = 0U; i < APP_TEST_EEPROM_SIZE; i++) {
tx[i] = (uint8_t)(0xA0U + i);
}
(void)memset(rx, 0, sizeof(rx));
probe_ret = eeprom_probe((uint16_t)APP_TEST_EEPROM_ADDR);
APP_TEST_LOG("[APP_TEST] eeprom probe ret=%u last_err=%lu\r\n",
(unsigned int)probe_ret,
(unsigned long)eeprom_get_last_error());
/* quick probe different blocks to verify dev-addr mapping */
pr = eeprom_probe(0x0000U);
APP_TEST_LOG("[APP_TEST] eeprom probe @0x0000 ret=%u err=%lu\r\n",
(unsigned int)pr, (unsigned long)eeprom_get_last_error());
pr = eeprom_probe(0x0100U);
APP_TEST_LOG("[APP_TEST] eeprom probe @0x0100 ret=%u err=%lu\r\n",
(unsigned int)pr, (unsigned long)eeprom_get_last_error());
pr = eeprom_probe(0x0200U);
APP_TEST_LOG("[APP_TEST] eeprom probe @0x0200 ret=%u err=%lu\r\n",
(unsigned int)pr, (unsigned long)eeprom_get_last_error());
pr = eeprom_probe(0x0700U);
APP_TEST_LOG("[APP_TEST] eeprom probe @0x0700 ret=%u err=%lu\r\n",
(unsigned int)pr, (unsigned long)eeprom_get_last_error());
eeprom_buffer_write(tx, (uint16_t)APP_TEST_EEPROM_ADDR, (uint16_t)APP_TEST_EEPROM_SIZE);
err_after_write = eeprom_get_last_error();
eeprom_buffer_read(rx, (uint16_t)APP_TEST_EEPROM_ADDR, (uint16_t)APP_TEST_EEPROM_SIZE);
err_after_read = eeprom_get_last_error();
if (memcmp(tx, rx, APP_TEST_EEPROM_SIZE) != 0) {
for (i = 0U; i < APP_TEST_EEPROM_SIZE; i++) {
if (tx[i] != rx[i]) {
first_mismatch = (int32_t)i;
break;
}
}
APP_TEST_LOG("[APP_TEST] eeprom rw verify fail, addr=0x%02X size=%u\r\n",
(unsigned int)APP_TEST_EEPROM_ADDR,
(unsigned int)APP_TEST_EEPROM_SIZE);
APP_TEST_LOG("[APP_TEST] eeprom err write=%lu read=%lu\r\n",
(unsigned long)err_after_write,
(unsigned long)err_after_read);
APP_TEST_LOG("[APP_TEST] eeprom dump first16 @0x%02X:\r\n",
(unsigned int)APP_TEST_EEPROM_ADDR);
for (i = 0U; i < 16U; i++) {
APP_TEST_LOG(" [%02u] wr=0x%02X rd=0x%02X\r\n",
(unsigned int)i,
(unsigned int)tx[i],
(unsigned int)rx[i]);
}
if (first_mismatch >= 0) {
APP_TEST_LOG("[APP_TEST] eeprom mismatch idx=%ld wr=0x%02X rd=0x%02X\r\n",
(long)first_mismatch,
(unsigned int)tx[(uint32_t)first_mismatch],
(unsigned int)rx[(uint32_t)first_mismatch]);
}
return 0U;
}
APP_TEST_LOG("[APP_TEST] eeprom rw verify pass, addr=0x%02X size=%u\r\n",
(unsigned int)APP_TEST_EEPROM_ADDR,
(unsigned int)APP_TEST_EEPROM_SIZE);
return 1U;
}
/**
* @brief EEPROM 多地址点读写校验(覆盖关键分区起点与页边界)。
* @return 1 通过,0 失败。
*/
uint8_t u8_app_test_eeprom_multi_addr_rw_once(void)
{
static const uint16_t rw_addrs[] = {
0x0000U,
0x0040U,
0x0070U,
0x0080U,
0x00C0U,
0x00E0U,
0x00F0U,
0x0580U,
0x0600U,
0x0680U,
0x07C0U
};
static const uint16_t observe_addrs[] = {
(uint16_t)EEPROM_ADDR_HISALARM_MNG,
(uint16_t)EEPROM_ADDR_CARD_MNG,
(uint16_t)EEPROM_ADDR_A_LOG_DATA,
(uint16_t)EEPROM_ADDR_B_LOG_DATA
};
uint8_t tx[APP_TEST_EEPROM_MULTI_SIZE];
uint8_t rx[APP_TEST_EEPROM_MULTI_SIZE];
uint8_t bk[APP_TEST_EEPROM_MULTI_SIZE];
uint32_t i;
uint32_t a;
uint16_t addr;
for (i = 0U; i < APP_TEST_EEPROM_MULTI_SIZE; i++) {
tx[i] = (uint8_t)(0x55U ^ (uint8_t)i);
}
APP_TEST_LOG("[APP_TEST] eeprom multi-addr rw test start, size=%u, points=%u\r\n",
(unsigned int)APP_TEST_EEPROM_MULTI_SIZE,
(unsigned int)(sizeof(rw_addrs) / sizeof(rw_addrs[0])));
for (a = 0U; a < (uint32_t)(sizeof(rw_addrs) / sizeof(rw_addrs[0])); a++) {
addr = rw_addrs[a];
if (!EEPROM_ADDR_IN_RANGE(addr) || !EEPROM_ADDR_IN_RANGE((uint16_t)(addr + APP_TEST_EEPROM_MULTI_SIZE - 1U))) {
APP_TEST_LOG("[APP_TEST] eeprom multi-addr skip out-of-range addr=0x%04X\r\n",
(unsigned int)addr);
continue;
}
(void)memset(rx, 0, sizeof(rx));
(void)memset(bk, 0, sizeof(bk));
/* backup original content to avoid corrupting real partitions */
eeprom_buffer_read(bk, addr, (uint16_t)APP_TEST_EEPROM_MULTI_SIZE);
if (eeprom_get_last_error() != 0U) {
APP_TEST_LOG("[APP_TEST] eeprom multi-addr backup read fail addr=0x%04X err=%lu\r\n",
(unsigned int)addr, (unsigned long)eeprom_get_last_error());
return 0U;
}
eeprom_buffer_write(tx, addr, (uint16_t)APP_TEST_EEPROM_MULTI_SIZE);
if (eeprom_get_last_error() != 0U) {
APP_TEST_LOG("[APP_TEST] eeprom multi-addr write fail addr=0x%04X err=%lu\r\n",
(unsigned int)addr, (unsigned long)eeprom_get_last_error());
/* best-effort restore */
eeprom_buffer_write(bk, addr, (uint16_t)APP_TEST_EEPROM_MULTI_SIZE);
return 0U;
}
eeprom_buffer_read(rx, addr, (uint16_t)APP_TEST_EEPROM_MULTI_SIZE);
if (eeprom_get_last_error() != 0U) {
APP_TEST_LOG("[APP_TEST] eeprom multi-addr read fail addr=0x%04X err=%lu\r\n",
(unsigned int)addr, (unsigned long)eeprom_get_last_error());
/* best-effort restore */
eeprom_buffer_write(bk, addr, (uint16_t)APP_TEST_EEPROM_MULTI_SIZE);
return 0U;
}
if (memcmp(tx, rx, APP_TEST_EEPROM_MULTI_SIZE) != 0) {
for (i = 0U; i < APP_TEST_EEPROM_MULTI_SIZE; i++) {
if (tx[i] != rx[i]) {
APP_TEST_LOG("[APP_TEST] eeprom multi-addr mismatch addr=0x%04X idx=%lu wr=0x%02X rd=0x%02X\r\n",
(unsigned int)addr,
(unsigned long)i,
(unsigned int)tx[i],
(unsigned int)rx[i]);
break;
}
}
/* restore original before returning */
eeprom_buffer_write(bk, addr, (uint16_t)APP_TEST_EEPROM_MULTI_SIZE);
return 0U;
}
APP_TEST_LOG("[APP_TEST] eeprom multi-addr pass addr=0x%04X\r\n", (unsigned int)addr);
/* restore original content */
eeprom_buffer_write(bk, addr, (uint16_t)APP_TEST_EEPROM_MULTI_SIZE);
if (eeprom_get_last_error() != 0U) {
APP_TEST_LOG("[APP_TEST] eeprom multi-addr restore fail addr=0x%04X err=%lu\r\n",
(unsigned int)addr, (unsigned long)eeprom_get_last_error());
return 0U;
}
}
/* Observe-only check for business hot partitions (no write/restore). */
for (a = 0U; a < (uint32_t)(sizeof(observe_addrs) / sizeof(observe_addrs[0])); a++) {
addr = observe_addrs[a];
if (!EEPROM_ADDR_IN_RANGE(addr) || !EEPROM_ADDR_IN_RANGE((uint16_t)(addr + APP_TEST_EEPROM_MULTI_SIZE - 1U))) {
continue;
}
(void)memset(bk, 0, sizeof(bk));
eeprom_buffer_read(bk, addr, (uint16_t)APP_TEST_EEPROM_MULTI_SIZE);
if (eeprom_get_last_error() != 0U) {
APP_TEST_LOG("[APP_TEST] eeprom multi-addr observe fail addr=0x%04X err=%lu\r\n",
(unsigned int)addr, (unsigned long)eeprom_get_last_error());
return 0U;
}
APP_TEST_LOG("[APP_TEST] eeprom multi-addr observe pass addr=0x%04X\r\n", (unsigned int)addr);
}
APP_TEST_LOG("[APP_TEST] eeprom multi-addr rw test pass\r\n");
return 1U;
}
/**
* @brief EEPROM 读写速度测试(循环读写固定大小并统计吞吐)。
* @return 1 通过,0 失败。
*/
uint8_t u8_app_test_eeprom_speed_once(void)
{
uint8_t tx[APP_TEST_EEPROM_SPEED_SIZE];
uint8_t rx[APP_TEST_EEPROM_SPEED_SIZE];
uint8_t bk[APP_TEST_EEPROM_SPEED_SIZE];
uint32_t i;
uint32_t j;
uint32_t r;
int32_t first_mismatch;
uint64_t t0;
uint64_t t1;
uint64_t write_ms;
uint64_t read_ms;
uint32_t write_kbs;
uint32_t read_kbs;
uint32_t loops = APP_TEST_EEPROM_SPEED_LOOP;
uint16_t addr = (uint16_t)APP_TEST_EEPROM_TEST_ADDR_BASE;
if (!EEPROM_ADDR_IN_RANGE(addr) || !EEPROM_ADDR_IN_RANGE((uint16_t)(addr + APP_TEST_EEPROM_SPEED_SIZE - 1U))) {
APP_TEST_LOG("[APP_TEST] eeprom speed addr out-of-range\r\n");
return 0U;
}
for (i = 0U; i < APP_TEST_EEPROM_SPEED_SIZE; i++) {
tx[i] = (uint8_t)(i & 0xFFU);
}
APP_TEST_LOG("[APP_TEST] eeprom speed test start, addr=0x%04X size=%u loop=%u\r\n",
(unsigned int)addr,
(unsigned int)APP_TEST_EEPROM_SPEED_SIZE,
(unsigned int)loops);
/* backup original test window and restore at the end */
(void)memset(bk, 0, sizeof(bk));
eeprom_buffer_read(bk, addr, (uint16_t)APP_TEST_EEPROM_SPEED_SIZE);
if (eeprom_get_last_error() != 0U) {
APP_TEST_LOG("[APP_TEST] eeprom speed backup read fail err=%lu\r\n",
(unsigned long)eeprom_get_last_error());
return 0U;
}
t0 = u64_get_current_millis();
for (i = 0U; i < loops; i++) {
for (r = 0U; r < APP_TEST_EEPROM_SPEED_RETRY; r++) {
eeprom_buffer_write(tx, addr, (uint16_t)APP_TEST_EEPROM_SPEED_SIZE);
if (eeprom_get_last_error() == 0U) {
break;
}
vTaskDelay(pdMS_TO_TICKS(2U));
}
if (eeprom_get_last_error() != 0U) {
APP_TEST_LOG("[APP_TEST] eeprom speed write fail loop=%lu retry=%lu err=%lu\r\n",
(unsigned long)i,
(unsigned long)r,
(unsigned long)eeprom_get_last_error());
eeprom_buffer_write(bk, addr, (uint16_t)APP_TEST_EEPROM_SPEED_SIZE);
return 0U;
}
/* Allow write cycle settle time under stress loops. */
vTaskDelay(pdMS_TO_TICKS(2U));
}
t1 = u64_get_current_millis();
write_ms = (t1 >= t0) ? (t1 - t0) : 0U;
if (write_ms < APP_TEST_MIN_TEST_MS) {
write_ms = APP_TEST_MIN_TEST_MS;
}
t0 = u64_get_current_millis();
for (i = 0U; i < loops; i++) {
for (r = 0U; r < APP_TEST_EEPROM_SPEED_RETRY; r++) {
(void)memset(rx, 0, sizeof(rx));
eeprom_buffer_read(rx, addr, (uint16_t)APP_TEST_EEPROM_SPEED_SIZE);
if ((eeprom_get_last_error() == 0U) &&
(memcmp(tx, rx, APP_TEST_EEPROM_SPEED_SIZE) == 0)) {
break;
}
vTaskDelay(pdMS_TO_TICKS(2U));
}
if ((eeprom_get_last_error() != 0U) || (memcmp(tx, rx, APP_TEST_EEPROM_SPEED_SIZE) != 0)) {
first_mismatch = -1;
for (j = 0U; j < APP_TEST_EEPROM_SPEED_SIZE; j++) {
if (tx[j] != rx[j]) {
first_mismatch = (int32_t)j;
break;
}
}
if (first_mismatch >= 0) {
APP_TEST_LOG("[APP_TEST] eeprom speed verify fail loop=%lu retry=%lu idx=%ld wr=0x%02X rd=0x%02X err=%lu\r\n",
(unsigned long)i,
(unsigned long)r,
(long)first_mismatch,
(unsigned int)tx[(uint32_t)first_mismatch],
(unsigned int)rx[(uint32_t)first_mismatch],
(unsigned long)eeprom_get_last_error());
} else {
APP_TEST_LOG("[APP_TEST] eeprom speed verify fail loop=%lu retry=%lu err=%lu\r\n",
(unsigned long)i,
(unsigned long)r,
(unsigned long)eeprom_get_last_error());
}
eeprom_buffer_write(bk, addr, (uint16_t)APP_TEST_EEPROM_SPEED_SIZE);
return 0U;
}
}
t1 = u64_get_current_millis();
read_ms = (t1 >= t0) ? (t1 - t0) : 0U;
if (read_ms < APP_TEST_MIN_TEST_MS) {
read_ms = APP_TEST_MIN_TEST_MS;
}
write_kbs = (uint32_t)(((uint64_t)APP_TEST_EEPROM_SPEED_SIZE * (uint64_t)loops * 1000ULL) / (write_ms * 1024ULL));
read_kbs = (uint32_t)(((uint64_t)APP_TEST_EEPROM_SPEED_SIZE * (uint64_t)loops * 1000ULL) / (read_ms * 1024ULL));
APP_TEST_LOG("[APP_TEST] eeprom speed result: write=%llums(%luKB/s) read=%llums(%luKB/s)\r\n",
(unsigned long long)write_ms,
(unsigned long)write_kbs,
(unsigned long long)read_ms,
(unsigned long)read_kbs);
eeprom_buffer_write(bk, addr, (uint16_t)APP_TEST_EEPROM_SPEED_SIZE);
return 1U;
}
#define APP_TEST_CAN_TX_PERIOD_MS (1000ULL)
#define APP_TEST_CAN_EXT_ID_BASE (0x18FEE000U)
/* ================= USART 单路测试(可改参数) =================
* 简化版:每次执行 UART step 时
* - 发送一次(固定数据,可改)
* - 接收一次并打印(如有数据)
* 每次仅测试一个串口。
*/
static E_USART_ID s_uart_test_port = E_USART_3; /* 可改:E_USART_0/2/3/4/5/6/7 */
static uint8_t s_uart_test_tx_data[16] = { 0x55U, 0xAAU, 0x00U, 0x01U, 0x02U, 0x03U, 0x04U, 0x05U };
static uint16_t s_uart_test_tx_len = 8U;
static void v_app_test_uart_poll(void)
{
uint8_t rx_buf[128];
uint16_t rx_len;
uint16_t send_len = s_uart_test_tx_len;
if (send_len > (uint16_t)sizeof(s_uart_test_tx_data)) {
send_len = (uint16_t)sizeof(s_uart_test_tx_data);
}
if (send_len > 0U) {
(void)u16_usart_send(s_uart_test_port, s_uart_test_tx_data, send_len);
APP_TEST_LOG("[APP_TEST] uart tx port=%u len=%u\r\n",
(unsigned int)s_uart_test_port,
(unsigned int)send_len);
}
rx_len = u16_usart_recv(s_uart_test_port, rx_buf, (uint16_t)sizeof(rx_buf));
if (rx_len > 0U) {
char hex[3U * sizeof(rx_buf) + 4U];
uint32_t pos = 0U;
uint16_t i;
hex[0] = '\0';
for (i = 0U; i < rx_len && pos + 3U < sizeof(hex); i++) {
(void)snprintf(&hex[pos], sizeof(hex) - pos, "%02X ", (unsigned int)rx_buf[i]);
pos = (uint32_t)strlen(hex);
}
APP_TEST_LOG("[APP_TEST] uart rx port=%u len=%u %s\r\n",
(unsigned int)s_uart_test_port,
(unsigned int)rx_len,
hex);
}
}
/**
* @brief 读空三路 CAN 软件缓存并打印(扩展帧由驱动层标记)。
*/
static void v_app_test_can_rx_drain(void)
{
uint8_t port;
CAN_DATA rx[CAN_RX_BUFFER_SIZE];
uint8_t rx_cnt;
uint8_t i;
uint8_t k;
for (port = 0U; port < 3U; port++) {
rx_cnt = u8_can_rx((E_CAN_ID)port, &rx[0]);
for (k = 0U; k < rx_cnt; k++) {
char hex[3U * 8U + 4U] = {0};
uint32_t pos = 0U;
for (i = 0U; i < rx[k].Len && i < 8U && pos + 3U < sizeof(hex); i++) {
(void)snprintf(&hex[pos], sizeof(hex) - pos, "%02X ", (unsigned int)rx[k].Data[i]);
pos = (uint32_t)strlen(hex);
}
APP_TEST_LOG("[APP_TEST] can rx port=%u id=0x%08lX dlc=%u %s\r\n",
(unsigned int)port, (unsigned long)rx[k].ID, (unsigned int)rx[k].Len, hex);
}
}
}
/**
* @brief 三路 CAN 各发一帧扩展数据帧(8 字节,前 4 字节为递增序号)。
*/
static void v_app_test_can_tx_all_ports(uint32_t seq)
{
uint8_t port;
CAN_DATA tx;
for (port = 0U; port < 3U; port++) {
(void)memset(&tx, 0, sizeof(tx));
tx.ID = APP_TEST_CAN_EXT_ID_BASE + (uint32_t)port;
tx.Len = 8U;
tx.Data[0] = (uint8_t)(seq & 0xFFU);
tx.Data[1] = (uint8_t)((seq >> 8) & 0xFFU);
tx.Data[2] = (uint8_t)((seq >> 16) & 0xFFU);
tx.Data[3] = (uint8_t)((seq >> 24) & 0xFFU);
tx.Data[4] = port;
tx.Data[5] = 0xC0U;
tx.Data[6] = 0xAAU;
tx.Data[7] = 0x55U;
v_can_tx((E_CAN_ID)port, &tx);
}
APP_TEST_LOG("[APP_TEST] can tx 3ch ext seq=%lu base_id=0x%08lX\r\n",
(unsigned long)seq, (unsigned long)APP_TEST_CAN_EXT_ID_BASE);
}
/**
* @brief CAN 周期任务:每 1s 三路各发一帧扩展帧;每次调用先收完并打印。
* @note 挂在 v_app_test_periodic 入口,随 MyLog 任务节拍轮询(不受 10s 自检节流影响)。
*/
static void v_app_test_can_poll(void)
{
static uint64_t s_next_tx_ms = 0ULL;
static uint32_t s_tx_seq = 0U;
uint64_t now_ms;
v_app_test_can_rx_drain();
if (u8_can_is_initialized() == 0U) {
v_can_interface_init();
}
now_ms = u64_get_current_millis();
if (s_next_tx_ms == 0ULL) {
s_next_tx_ms = now_ms;
}
if (now_ms < s_next_tx_ms) {
return;
}
s_next_tx_ms = now_ms + APP_TEST_CAN_TX_PERIOD_MS;
v_app_test_can_tx_all_ports(s_tx_seq);
s_tx_seq++;
}
/**
* @brief 通过 u8_get_yxyc_data 读取整桩/枪实时采集结构并打印(与 collect_task 内数据源一致)。
*/
static void v_app_test_collect_yxyc_snapshot_print(void)
{
SYS_RT_DATA pile;
GUN_RT_DATA gun;
U8_T gun_cnt;
U8_T i;
if (u8_get_yxyc_data(&pile, NULL, 0U) == 0U) {
APP_TEST_LOG("[APP_TEST] coll get sys fail (lock/busy)\r\n");
return;
}
APP_TEST_LOG("[APP_TEST] ****************************************************** start ******************************************************\r\n");
APP_TEST_LOG("[APP_TEST] coll SYS yx_raw=0x%08lX\r\n",
(unsigned long)pile.yx_sys_data.u32_yx_sys_data);
APP_TEST_LOG("[APP_TEST] SYS_yx estp=%u door=%u water=%u smoke=%u busKM=%u spd=%u acKM=%u qf=%u\r\n",
(unsigned int)pile.yx_sys_data.bit_yx_sys_data.yx_emergency,
(unsigned int)pile.yx_sys_data.bit_yx_sys_data.yx_door,
(unsigned int)pile.yx_sys_data.bit_yx_sys_data.yx_water,
(unsigned int)pile.yx_sys_data.bit_yx_sys_data.yx_smoke,
(unsigned int)pile.yx_sys_data.bit_yx_sys_data.yx_bus_KM,
(unsigned int)pile.yx_sys_data.bit_yx_sys_data.yx_spd,
(unsigned int)pile.yx_sys_data.bit_yx_sys_data.yx_KM,
(unsigned int)pile.yx_sys_data.bit_yx_sys_data.yx_QF);
APP_TEST_LOG("[APP_TEST] SYS_yc temp1_x1000=%ld temp2_x1000=%ld\r\n",
(long)(pile.f32_yc_sys_temp1 * 1000.0f),
(long)(pile.f32_yc_sys_temp2 * 1000.0f));
APP_TEST_LOG("[APP_TEST] hw_DOgpio(1=H 0=L) K1-K5 : %u %u %u %u %u\r\n",
(unsigned int)DO1_READ(), (unsigned int)DO2_READ(), (unsigned int)DO3_READ(),
(unsigned int)DO4_READ(), (unsigned int)DO5_READ());
APP_TEST_LOG("[APP_TEST] hw_DOgpio(1=H 0=L) K6-K10: %u %u %u %u %u | ELOCK_A=%u ELOCK_B=%u\r\n",
(unsigned int)DO6_READ(), (unsigned int)DO7_READ(), (unsigned int)DO8_READ(),
(unsigned int)DO9_READ(), (unsigned int)DO10_READ(),
(unsigned int)ELOCK_A_READ(), (unsigned int)ELOCK_B_READ());
gun_cnt = (U8_T)GUN_MAX_CNT;
for (i = 0U; i < gun_cnt; i++) {
if (u8_get_yxyc_data(NULL, &gun, i) == 0U) {
APP_TEST_LOG("[APP_TEST] coll get gun%u fail\r\n", (unsigned int)i);
continue;
}
APP_TEST_LOG("[APP_TEST] coll GUN%u link=%u\r\n",
(unsigned int)i,
(unsigned int)gun.u8_gunlink_state);
APP_TEST_LOG("[APP_TEST] GUN_yx raw=0x%08lX lock=%u dcP=%u dcN=%u rlf=%u fuse=%u apw=%u home=%u\r\n",
(unsigned long)gun.yx_gun_data.u32_yx_gun_data,
(unsigned int)gun.yx_gun_data.bit_yx_gun_data.yx_gun_lock,
(unsigned int)gun.yx_gun_data.bit_yx_gun_data.yx_switch_pos,
(unsigned int)gun.yx_gun_data.bit_yx_gun_data.yx_switch_neg,
(unsigned int)gun.yx_gun_data.bit_yx_gun_data.yx_relief_swich,
(unsigned int)gun.yx_gun_data.bit_yx_gun_data.yx_fuse,
(unsigned int)gun.yx_gun_data.bit_yx_gun_data.yx_gun_power,
(unsigned int)gun.yx_gun_data.bit_yx_gun_data.yx_gun_homing);
APP_TEST_LOG("[APP_TEST] GUN_yc bus_mV V+=%ld V-=%ld I_mA=%ld\r\n",
(long)(gun.f32_yc_gun_vol_pos * 1000.0f),
(long)(gun.f32_yc_gun_vol_neg * 1000.0f),
(long)(gun.f32_yc_gun_curr * 1000.0f));
APP_TEST_LOG("[APP_TEST] GUN_yc bat_mV V+=%ld V-=%ld | gunTemp_x1000 Tpos=%ld Tneg=%ld\r\n",
(long)(gun.f32_yc_bat_vol_pos * 1000.0f),
(long)(gun.f32_yc_bat_vol_neg * 1000.0f),
(long)(gun.f32_yc_gun_temp_pos * 1000.0f),
(long)(gun.f32_yc_gun_temp_neg * 1000.0f));
}
APP_TEST_LOG("[APP_TEST] ****************************************************** end ******************************************************\r\n");
}
/**
* @brief 对外:以 1MB 步长扫描 32MB 地址空间读写校验。
* @details
* - 每个步长点执行:扇区擦除 -> 写入 1KB 模式数据 -> 读回校验;
* - 任一点失败立即返回并打印失败地址;
* - 全部通过后打印总耗时。
* @return 1 通过,0 失败。
*/
uint8_t u8_app_test_flash_32m_stride_rw(void)
{
uint32_t addr;
uint32_t i;
uint32_t seed;
uint64_t t0;
uint64_t t1;
uint64_t elapsed_ms;
uint8_t *tx_raw;
uint8_t *rx_raw;
uint8_t *tx_buf;
uint8_t *rx_buf;
if (app_test_alloc_aligned_buffers(&tx_raw, &rx_raw, &tx_buf, &rx_buf) == 0U) {
APP_TEST_LOG("[APP_TEST] 32M stride malloc fail\r\n");
return 0U;
}
APP_TEST_LOG("[APP_TEST] 32M stride test start, step=0x%08X, size=%u\r\n",
(unsigned int)APP_TEST_FLASH_STEP_1M,
(unsigned int)APP_TEST_FLASH_RW_SIZE);
t0 = u64_get_current_millis();
for (addr = 0U; addr < APP_TEST_FLASH_TOTAL_32M; addr += APP_TEST_FLASH_STEP_1M) {
seed = (uint32_t)(addr ^ 0x5A5A0000U);
for (i = 0U; i < APP_TEST_FLASH_RW_SIZE; i++) {
tx_buf[i] = (uint8_t)((seed + i) & 0xFFU);
}
(void)memset(rx_buf, 0, APP_TEST_FLASH_RW_SIZE);
(void)s32_flash_dataflash_erase_sector(addr);
(void)s32_flash_dataflash_write(addr, tx_buf, APP_TEST_FLASH_RW_SIZE);
(void)s32_flash_dataflash_read(addr, rx_buf, APP_TEST_FLASH_RW_SIZE);
if (memcmp(tx_buf, rx_buf, APP_TEST_FLASH_RW_SIZE) != 0) {
APP_TEST_LOG("[APP_TEST] 32M stride verify fail, addr=0x%08lX, seed=0x%08lX\r\n",
(unsigned long)addr,
(unsigned long)seed);
app_test_free_aligned_buffers(tx_raw, rx_raw);
return 0U;
}
}
t1 = u64_get_current_millis();
elapsed_ms = t1 - t0;
APP_TEST_LOG("[APP_TEST] 32M stride test pass, range=0x00000000~0x01FFFFFF, elapsed=%llums\r\n", elapsed_ms);
app_test_free_aligned_buffers(tx_raw, rx_raw);
return 1U;
}
/**
* @brief 周期触发综合测试(RTC/EEPROM/Flash)。
* @details 首次调用仅记录起始时间,不立即执行测试。
*/
void v_app_test_periodic(void)
{
static uint32_t s_last_test_sec = 0U;
static uint8_t s_test_step = (uint8_t)APP_TEST_STEP_RTC;
uint32_t now_sec;
if (s_last_test_sec == 0U) {
s_last_test_sec = get_current_seconds();
return;
}
now_sec = get_current_seconds();
/* 改为 1 秒节拍执行一次 step(按你的要求)。 */
if (u32_safe_seconds_since(s_last_test_sec) < 1U) {
return;
}
// APP_TEST_LOG("[APP_TEST] app test periodic\r\n");
/* 改用“数字递增 step”的方式,避免 bitmask 维护成本。 */
switch ((APP_TEST_STEP_T)s_test_step) {
case APP_TEST_STEP_RTC:
// v_app_test_rtc_rw_once();
test_rtc(); //测试RTC
s_test_step++;
break;
case APP_TEST_STEP_EEPROM_BASIC:
// (void)u8_app_test_eeprom_rw_once();
s_test_step++;
break;
case APP_TEST_STEP_EEPROM_MULTI:
// (void)u8_app_test_eeprom_multi_addr_rw_once();
s_test_step++;
break;
case APP_TEST_STEP_EEPROM_SPEED:
// (void)u8_app_test_eeprom_speed_once();
s_test_step++;
break;
case APP_TEST_STEP_CAN:
/* 每秒发送一次 + 周期接收打印(函数内部有 1s 节拍控制)。 */
// v_app_test_can_poll();
s_test_step++;
break;
case APP_TEST_STEP_UART:
// v_app_test_uart_poll();
v_app_test_collect_yxyc_snapshot_print();
s_test_step++;
break;
#if (APP_TEST_ENABLE_FLASH_SPEED)
case APP_TEST_STEP_FLASH_SPEED:
// v_app_test_flash_rw_speed_once();
s_test_step++;
break;
#endif
case APP_TEST_STEP_FLASH_STRIDE:
// if (u8_app_test_flash_32m_stride_rw() == 0U) {
// APP_TEST_LOG("[APP_TEST] 32M stride test failed in periodic flow\r\n");
// }
s_test_step++;
break;
case APP_TEST_STEP_DONE:
s_test_step = (uint8_t)APP_TEST_STEP_RTC;
break;
default:
break;
}
s_last_test_sec = now_sec;
}
#else
void v_app_test_periodic(void)
{
/* test disabled by APP_TEST_ENABLE */
}
#endif /* APP_TEST_ENABLE */