#include "app_init/app_test.h" #include "app_init/app_init.h" #include #include #include #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 */