Files
vd_960/vd960Loop/utilities/at32f421_freertos_demo/src/main.c
T
wangfq 40e6648445 feat(vd960Loop): LOOP_MEASURE_BASE 归一化基数上报 (协议 V1.09)
跨产品 MEASUREMENT_BASE 对齐(2026-08-26 DLD110S ×4 事故):variation 是周期域
计数值,归一化必须除设备自身的 MEASUREMENT_BASE。960Loop 此前 0x64 读参响应裸发
参数,第三方平台无从换算(写死 131072 恰好蒙对,写 524288 就 ÷4 失真)。

- docs(DLD960Loop_串口通信协议.md): V1.09 — 0x64 响应尾部追加 3B LE
  LOOP_MEASURE_BASE(响应 34B→37B)+ 换算公式 ΔL/L≈-2×variation/BASE、
  Δf/f≈variation/BASE + 修订记录
- inc/cmcng.h: #define LOOP_MEASURE_BASE 131072L(注释标明与 TaskLoop.h
  MEASUREMENT_BASE 同步)
- src/main.c: CMD_DBN_GET_MCJQ_PARAM (0x64) handler for 循环后追加 3B LE
- docs/devlog.md: 置顶 2026-08-27 条目

设计决策:常量走 0x64 查询响应(低频)不进 0xC0 高频帧(避免分包);
向后兼容老客户端(只读前 34B 不受影响)。
联动待办:DBN 侧对外(BLE/TCP/MQTT)暴露基数未落地。
2026-08-27 08:27:02 +08:00

1123 lines
37 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.
/**
**************************************************************************
* @file main.c
* @brief main program
**************************************************************************
* Copyright notice & Disclaimer
*
* The software Board Support Package (BSP) that is made available to
* download from Artery official website is the copyrighted work of Artery.
* Artery authorizes customers to use, copy, and distribute the BSP
* software and its related documentation for the purpose of design and
* development in conjunction with Artery microcontrollers. Use of the
* software is governed by this copyright notice and the following disclaimer.
*
* THIS SOFTWARE IS PROVIDED ON "AS IS" BASIS WITHOUT WARRANTIES,
* GUARANTEES OR REPRESENTATIONS OF ANY KIND. ARTERY EXPRESSLY DISCLAIMS,
* TO THE FULLEST EXTENT PERMITTED BY LAW, ALL EXPRESS, IMPLIED OR
* STATUTORY OR OTHER WARRANTIES, GUARANTEES OR REPRESENTATIONS,
* INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
*
**************************************************************************
*/
#include "at32f421_board.h"
#include "at32f421_clock.h"
#include "FreeRTOS.h"
#include "task.h"
#include "cmcng.h"
#include "TaskLoop.h"
#include <string.h>
#include "storage.h"
#include <stdlib.h>
#include "at32f421_wdt.h"
#include "iap.h"
/** @addtogroup UTILITIES_examples
* @{
*/
volatile uint8_t usart1_rx_dma_status = 0;
Pkg_Uart g_pkg_uart_1 = { 0, 0, 0, "", 0};
Pkg_Uart g_pkg_uart_report = { 0, 0, 0, "", 0};
static uint8_t tmp_ble_buf[BUFF_STACK_SIZE];
char usart1_rx_buffer[USART1_RX_BUFFER_SIZE];
TaskHandle_t usart_task_handler = NULL;
/** @addtogroup FreeRTOS_demo
* @{
*/
crm_clocks_freq_type g_crm_clocks_freq_struct = {0};
tmr_input_config_type g_tmr_input_config_struct;
__IO uint32_t sys_counter = 0;
__IO uint64_t TimingDelayInc;
__IO uint32_t TimingDelayDec;
TaskHandle_t loop_task_handler;
// 看门狗相关
#define WDT_TIMEOUT_MS 3000 // 看门狗超时时间 3秒
void wdt_init(void);
void wdt_feed(void);
tmr_output_config_type tmr_oc_init_structure;
/*
pb1 output pwm waveform, use Tmr14.
tmr3 channel1 duty cycle = (tmr3_c1dt/ tmr3_pr)* 100 = 50%
tmr3 channel2 duty cycle = (tmr3_c2dt/ tmr3_pr)* 100 = 37.5%
tmr3 channel3 duty cycle = (tmr3_c3dt/ tmr3_pr)* 100 = 25%
tmr3 channel4 duty cycle = (tmr3_c4dt/ tmr3_pr)* 100 = 12.5%
*/
uint16_t c1dt_val = 333;
//uint16_t c2dt_val = 249;
//uint16_t c3dt_val = 166;
//uint16_t c4dt_val = 83;
uint16_t prescaler_value = 0;
__IO uint16_t pulse=0;//55; //
uint8_t g_pulse_counter = 0;
uint8_t g_flag_pulse = 1;
uint64_t mstick(void){
return TimingDelayInc;
}
void InitPkgUart(Pkg_Uart * pkg){
memset(pkg->pkg, 0, BUFF_STACK_SIZE);
pkg->flag = 0;
pkg->tick = 0;
pkg->len = 0;
pkg->offset = 0;
}
/**
* @brief 初始化独立看门狗
* @param none
* @retval none
* @note 超时时间 = (预分频系数 × 重载值) / LSI频率
* LSI频率约 40kHz,预分频64,重载值=4687,超时≈ 3秒
*/
void wdt_init(void)
{
// 使能看门狗寄存器写访问
wdt_register_write_enable(TRUE);
// 设置预分频系数为 64
wdt_divider_set(WDT_CLK_DIV_64);
// 设置重载值
// 超时时间 = (64 × 4687) / 40000 ≈ 7.5秒
// 如果需要 3秒: (64 × 1875) / 40000 = 3秒
wdt_reload_value_set(1875);
// 重载计数器
wdt_counter_reload();
// 使能看门狗
wdt_enable();
PRINT("Watchdog initialized, timeout: %d ms\n", WDT_TIMEOUT_MS);
}
/**
* @brief 喂狗(重载看门狗计数器)
* @param none
* @retval none
*/
void wdt_feed(void)
{
wdt_counter_reload();
}
uint16_t timer_period = 0;
uint16_t channel1_pulse = 0;
void Timr_msic_Init_Pwm(void)
{
gpio_init_type gpio_init_struct = {0};
tmr_output_config_type tmr_output_struct;
/* enable tmr1/gpioa/gpiob clock */
crm_periph_clock_enable(CRM_TMR1_PERIPH_CLOCK, TRUE);
crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
/* timer1 output pin Configuration */
gpio_init_struct.gpio_pins = GPIO_PINS_8 ;
gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init(GPIOA, &gpio_init_struct);
gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE8, GPIO_MUX_2);
/* tmr1 configuration generate 7 pwm signals with 4 different duty cycles:
prescaler = 0, tmr1 counter clock = system_core_clock
the objective is to generate 7 pwm signal at 17.57 khz:
- tim1_period = (system_core_clock / 17570) - 1
the channel 1 and channel 1c duty cycle is set to 50%
the channel 2 and channel 2c duty cycle is set to 37.5%
the channel 3 and channel 3c duty cycle is set to 25%
the channel 4 duty cycle is set to 12.5%
the timer pulse is calculated as follows:
- channelxpulse = duty_cycle * (tim1_period - 1) / 100 */
/* compute the value to be set in arr regiter to generate signal frequency at 17.57 khz */
timer_period = (g_crm_clocks_freq_struct.sclk_freq / 17570 ) - 1;
/* compute c1dt value to generate a duty cycle at 50% for channel 1 and 1c */
// channel1_pulse = (uint16_t)(((uint32_t) 5 * (timer_period - 1)) / 10);
/* compute c2dt value to generate a duty cycle at 37.5% for channel 2 and 2c */
channel1_pulse = (uint16_t)(((uint32_t) 375 * (timer_period - 1)) / 1000);
/* compute c3dt value to generate a duty cycle at 25% for channel 3 and 3c */
// channel1_pulse = (uint16_t)(((uint32_t) 25 * (timer_period - 1)) / 100);
/* compute c4dt value to generate a duty cycle at 12.5% for channel 4 */
// channel1_pulse = (uint16_t)(((uint32_t) 125 * (timer_period- 1)) / 1000);
channel1_pulse = (uint16_t)(((uint32_t) 999 * (timer_period - 1)) / 1000);
tmr_base_init(TMR1, timer_period, 0);
tmr_cnt_dir_set(TMR1, TMR_COUNT_UP);
/* channel 1, 2, 3 and 4 configuration in output mode */
tmr_output_default_para_init(&tmr_output_struct);
tmr_output_struct.oc_mode = TMR_OUTPUT_CONTROL_PWM_MODE_B;
tmr_output_struct.oc_output_state = TRUE;
tmr_output_struct.oc_polarity = TMR_OUTPUT_ACTIVE_LOW;
tmr_output_struct.oc_idle_state = TRUE;
tmr_output_struct.occ_output_state = TRUE;
tmr_output_struct.occ_polarity = TMR_OUTPUT_ACTIVE_HIGH;
tmr_output_struct.occ_idle_state = FALSE;
/* channel 1 */
tmr_output_channel_config(TMR1, TMR_SELECT_CHANNEL_1, &tmr_output_struct);
tmr_channel_value_set(TMR1, TMR_SELECT_CHANNEL_1, channel1_pulse);
/* output enable */
tmr_output_enable(TMR1, TRUE);
/* enable tmr1 */
tmr_counter_enable(TMR1, TRUE);
}
/* Basic timr msic, other timer init */
void Timr_msic_Init(void)
{
crm_periph_clock_enable(CRM_TMR6_PERIPH_CLOCK, TRUE);
//TODO: ʱļ
// tmr_base_init(TMR6, 9999, (g_crm_clocks_freq_struct.ahb_freq / 10000) - 1); // 1s
tmr_base_init(TMR6, 999, (g_crm_clocks_freq_struct.ahb_freq / 1000000) - 1); // 1ms
tmr_cnt_dir_set(TMR6, TMR_COUNT_UP);
tmr_interrupt_enable(TMR6, TMR_OVF_INT, TRUE);
nvic_irq_enable(TMR6_GLOBAL_IRQn, 2, 0); // 较低:系统节拍,上报计时、一般计数器
tmr_counter_enable(TMR6, TRUE);
crm_periph_clock_enable(CRM_TMR15_PERIPH_CLOCK, TRUE);
//TODO: ʱļ
// tmr_base_init(TMR6, 9999, (g_crm_clocks_freq_struct.ahb_freq / 10000) - 1); // 1s
tmr_base_init(TMR15, (5000-1), (g_crm_clocks_freq_struct.ahb_freq / 1000000) - 1); // 5ms
// tmr_base_init(TMR14, 9999, (g_crm_clocks_freq_struct.ahb_freq / 1000000) - 1); // 10ms
tmr_cnt_dir_set(TMR15, TMR_COUNT_UP);
tmr_interrupt_enable(TMR15, TMR_OVF_INT, TRUE);
nvic_irq_enable(TMR15_GLOBAL_IRQn, 2, 0); // 较低:定时任务,线圈任务定时器,5ms
tmr_counter_enable(TMR15, TRUE);
Timr_msic_Init_Pwm();
}
uint8_t g_cnt_pwm_red_low_timeout = 0;
void poll_red_pwm(void)
{
g_pulse_counter++;
if(g_pulse_counter >= 12){
g_pulse_counter = 0;
if(g_flag_pulse){
if(pulse < 6000){
pulse += 400;
}
else{
pulse += 100;
}
if(pulse >= 6800)
{
if(g_cnt_pwm_red_low_timeout < 3){
pulse = 6800;
g_cnt_pwm_red_low_timeout++;
}
else{
g_flag_pulse = 0;
g_cnt_pwm_red_low_timeout = 0;
pulse = 6800;
}
}
}
else{
if(pulse <= 6800)
{
pulse -= 400;
}
// else{
// pulse -= 20;
// }
if(pulse < 500){
g_flag_pulse = 1;
}
}
tmr_channel_value_set(TMR1, TMR_SELECT_CHANNEL_1, pulse);
}
}
void usart1_sendstring(uint8_t *buf, uint16_t len)
{
uint16_t _len = len;
while(_len){
while(usart_flag_get(USART1, USART_TDBE_FLAG) == RESET);
usart_data_transmit(USART1, *buf++);
_len--;
}
}
/**
* @brief main function.
* @param none
* @retval none
*/
int main(void)
{
nvic_vector_table_set(NVIC_VECTTAB_FLASH, APP_START_ADDR - FLASH_BASE);
nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
system_clock_config();
/* get system clock */
crm_clocks_freq_get(&g_crm_clocks_freq_struct);
at32_board_init();
/* init usart1 */
//2250000
// 115200
#ifdef DEBUG
// uart_print_init(230400); //115200
// uart_print_init(115200); //115200
usart_configuration();
PRINT("sys_clock:%d, ahb_freq:%d, sclk_freq:%d\n", system_core_clock, g_crm_clocks_freq_struct.ahb_freq, g_crm_clocks_freq_struct.sclk_freq);
#else
usart_configuration();
#endif
para_store_init();
loop_timer_io_init();
Timr_msic_Init();
// 初始化看门狗
wdt_init();
/* enter critical */
taskENTER_CRITICAL();
/* create loop task */
if(xTaskCreate((TaskFunction_t )loop_task_function,
(const char* )"Loop_task",
(uint16_t )512,
(void* )NULL,
(UBaseType_t )2,
(TaskHandle_t* )&loop_task_handler) != pdPASS)
{
PRINT("loop task could not be created as there was insufficient heap memory remaining.\r\n");
}
else
{
PRINT("loop task was created successfully.\r\n");
}
/* create usart task */
if(xTaskCreate((TaskFunction_t )usart_task_function,
(const char* )"Usart_task",
(uint16_t )256,
(void* )NULL,
(UBaseType_t )3,
(TaskHandle_t* )&usart_task_handler) != pdPASS)
{
PRINT("usart task could not be created as there was insufficient heap memory remaining.\r\n");
}
else
{
PRINT("usart task was created successfully.\r\n");
}
/* create led indicator task */
if(xTaskCreate((TaskFunction_t )led_indicator_task_function,
(const char* )"LED_Task",
(uint16_t )256,
(void* )NULL,
(UBaseType_t )1,
(TaskHandle_t* )NULL) != pdPASS)
{
PRINT("led task could not be created as there was insufficient heap memory remaining.\r\n");
}
else
{
PRINT("led task was created successfully.\r\n");
}
/* exit critical */
taskEXIT_CRITICAL();
/* start scheduler */
vTaskStartScheduler();
}
void uart_report_packet_loop_acs(uint8_t flag)
{
uint8_t i, j, _flag_event = 0, _len = 0, _ckb = 0, _sum = 0;
uint8_t _misc = 0;
uint32_t _misc_val[LOOP_CAPTURE_MAX] = {0};
uint16_t _interval;
/*--- 0. 上电抑制: 3秒内不上报, 等线圈稳定 ---*/
if (g_loop_states.misc_counter < 60) { // 60 × 50ms = 3s
g_loop_states.report_counter = 0; // 抑制期清零, 防止出抑制后立即上报
return;
}
/*--- 1. 检查是否有进场/离开事件 ---*/
for (i = 0; i < LOOP_CAPTURE_MAX; i++) {
Loop154_Unit *unit = &g_loop_states.loop_unit[i];
if (unit->loop_FLAG_IN || unit->loop_FLAG_OUT) _flag_event = 1;
}
/*--- 2. 确定上报间隔 ---*/
if (_flag_event) {
_interval = REPORT_EVENT_TICKS; // 3×50ms = 150ms
} else {
_interval = REPORT_IDLE_TICKS; // 12×50ms = 600ms
}
if (g_loop_states.report_counter < _interval) return;
/*--- 3. 确定本轮杂项类型 ---*/
if (_flag_event) {
_misc = MISC_TYPE_TIME; // 事件优先级最高
} else {
_misc = g_loop_states.report_misc_round;
g_loop_states.report_misc_round++;
if (g_loop_states.report_misc_round >= MISC_TYPE_COUNT)
g_loop_states.report_misc_round = 0;
}
/*--- 4. 准备各通道杂项值 ---*/
for (i = 0; i < LOOP_CAPTURE_MAX; i++) {
Loop154_Unit *unit = &g_loop_states.loop_unit[i];
switch (_misc) {
case MISC_TYPE_TIME:
if (_flag_event) {
_misc_val[i] = unit->misc_value; // 已在上层计算
} else {
_misc_val[i] = 0; // 空闲时为0
}
break;
case MISC_TYPE_CUT:
_misc_val[i] = unit->disconnect_count;
break;
case MISC_TYPE_FLOW:
_misc_val[i] = unit->flow_count;
break;
case MISC_TYPE_RELAY:
_misc_val[i] = unit->relay_count;
break;
}
}
/*--- 5. 组包 ---*/
InitPkgUart(&g_pkg_uart_report);
i = 0;
g_pkg_uart_report.pkg[i++] = 0x7F;
g_pkg_uart_report.pkg[i++] = 0;
g_pkg_uart_report.pkg[i++] = _len; // placeholder
g_pkg_uart_report.pkg[i++] = CMD_SUB_SENS_REPORT;
g_pkg_uart_report.pkg[i++] = SENS_MULTI_LOOP_DYNAMIC;
g_pkg_uart_report.pkg[i++] = 0x00; // SubPkgFlag: 无分包
for (j = 0; j < LOOP_CAPTURE_MAX; j++) {
Loop154_Unit *unit = &g_loop_states.loop_unit[j];
// 配置1: freq_level(2) | direction(1) | freq_type(1=实时) | sens(4)
g_pkg_uart_report.pkg[i++] =
(g_loop_cng_info.loop_cng[j].loopFreq_Level << 6)
| (1 << 4) // freq_type=实时
| (unit->loop_SensLevel & 0x03);
// 评估条件: condition(4) | loop_state(1) | car_state(1) | misc_type(2)
g_pkg_uart_report.pkg[i++] =
((!unit->loop_LOOP_OK) << 3) // loop_state
| (unit->loop_VD_FLAG << 2) // car_state
| (_misc & 0x03); // misc_type
// 频率 (3B, LE)
uint32_t _frequent = 0;
if (unit->loop_LPCNT > 0 && unit->loop_CAPVD > 0) {
_frequent = (uint32_t)((uint64_t)g_crm_clocks_freq_struct.sclk_freq
* g_input_div * unit->loop_LPCNT / unit->loop_CAPVD);
}
g_pkg_uart_report.pkg[i++] = (uint8_t)(_frequent & 0xFF);
g_pkg_uart_report.pkg[i++] = (uint8_t)((_frequent >> 8) & 0xFF);
g_pkg_uart_report.pkg[i++] = (uint8_t)((_frequent >> 16) & 0xFF);
// 变化量 (3B, LE, 有符号补码) — V1.05
// 定义: variation = Origin - CAPVD
// 正值 = 当前值低于基线(车辆/金属进入, 检测裕量方向)
// 负值 = 当前值高于基线(反向漂移/异常抬升)
int32_t variation = (int32_t)unit->loop_Origin - (int32_t)unit->loop_CAPVD;
if (variation > 8388607) variation = 8388607; // +2^23-1 饱和, 防回绕
if (variation < -8388608) variation = -8388608; // -2^23 饱和
g_pkg_uart_report.pkg[i++] = (uint8_t)(variation & 0xFF);
g_pkg_uart_report.pkg[i++] = (uint8_t)((variation >> 8) & 0xFF);
g_pkg_uart_report.pkg[i++] = (uint8_t)((variation >> 16) & 0xFF);
// 杂项值 (4B, LE)
g_pkg_uart_report.pkg[i++] = (uint8_t)(_misc_val[j] & 0xFF);
g_pkg_uart_report.pkg[i++] = (uint8_t)((_misc_val[j] >> 8) & 0xFF);
g_pkg_uart_report.pkg[i++] = (uint8_t)((_misc_val[j] >> 16) & 0xFF);
g_pkg_uart_report.pkg[i++] = (uint8_t)((_misc_val[j] >> 24) & 0xFF);
}
/*--- 6. 回填 LEN + 校验 ---*/
g_pkg_uart_report.pkg[2] = i - 3;
for (j = 1; j < i; j++) {
_ckb ^= g_pkg_uart_report.pkg[j];
_sum += g_pkg_uart_report.pkg[j];
}
g_pkg_uart_report.pkg[i++] = _ckb;
g_pkg_uart_report.pkg[i++] = _sum & 0xFF;
usart1_sendstring(g_pkg_uart_report.pkg, i);
g_loop_states.report_counter = 0;
}
// 7F
void response_uart_pkg(uint8_t cmd, uint8_t *dat, uint8_t dat_len)
{
uint8_t i,j, _ckb = 0, _sum = 0;
uint8_t *sBuf = (uint8_t *)malloc(BUFF_STACK_SIZE);
if(sBuf == NULL){
PRINT("Not enough memory!!");
}
memset(sBuf, 0, BUFF_STACK_SIZE);
i = 0;
sBuf[i++] = 0x7F;
sBuf[i++] = 0x80;
sBuf[i++] = 1 + dat_len;
sBuf[i++] = cmd;
memcpy(&sBuf[i], dat, dat_len);
i += dat_len;
for(j = 1; j < i; j++)
{
_ckb ^= sBuf[j];
_sum += sBuf[j];
}
sBuf[i++] = _ckb;
sBuf[i++] = _sum & 0xFF;
usart1_sendstring(sBuf, i);
free(sBuf);
}
// multip loop cjq param
static void unpack_pkg_set_mcjq_param(uint8_t *pkg, uint8_t len)
{
uint8_t i = 4, j, k = 0;
uint8_t _amount = 0;
g_loop_cng_info.smart_mode = pkg[i++];
_amount = pkg[i++];
Loop_Cng_Unit *unit = g_loop_cng_info.loop_cng;
for(j = 0; j < _amount; j++)
{
k = pkg[i++];
unit->sensitvity = k & 0x0F; // 低4位: 灵敏度序号 (4级制 0~3)
unit->loopFreq_Level = k >> 4; // 高4位: 频率档
unit->delay_time = pkg[i++];
k = pkg[i++];
unit->output_mode = k & 0x03;
unit->loopSafe_Timeout = k >> 3;
unit->exist_mode = pkg[i++];
unit->direction_mode = pkg[i++];
// 同步灵敏度到检测单元 (修复: 运行中配置必须立即生效, 不依赖重启)
g_loop_states.loop_unit[j].loop_SensLevel = sens_level_from_config(unit->sensitvity);
unit++;
}
storage_dev();
}
/**
* @brief USART1 串口数据包校验函数
* @param pkg: 接收到的数据包指针
* @param len: 数据包实际长度
* @retval 0: 校验成功;其他:校验失败
*/
uint8_t usart_packet_validate(uint8_t *pkg, uint8_t len)
{
uint8_t _len = pkg[2];
uint8_t _cmd = pkg[3];
uint8_t _addr = pkg[1];
uint8_t j;
// ===== 数据包校验 =====
// 1. 检查起始字节 STX (0x7F)
// if(pkg[0] != 0x7F && pkg[0] != 0x8F)
// {
// PRINT("Error: Invalid STX 0x%02X\n", pkg[0]);
// return 1; // 校验失败
// }
// 2. 检查长度字段
// LEN = CMD(1) + Data(LEN-1), 总长度应该是 LEN+3(STX+ADDR+LEN+XOR+SUM)
if(_len < 1) // 至少要有 CMD
{
PRINT("Error: Invalid length %d\n", _len);
return 2; // 校验失败
}
// 3. 检查接收到的数据长度是否匹配
if(len < (_len + 3)) // STX(1) + ADDR(1) + LEN(1) + LEN bytes + XOR(1) + SUM(1) = LEN+4,但 pkg 从 0 开始,所以是 len >= _len + 3
{
PRINT("Error: Received length %d doesn't match declared length %d\n", len, _len);
return 3; // 校验失败
}
// 4. 提取并验证 XOR 校验
uint8_t received_xor = pkg[3 + _len]; // XOR 位置:STX+ADDR+LEN+CMD+Data
uint8_t calculated_xor = _addr; // ADDR
calculated_xor ^= _len; // LEN
calculated_xor ^= _cmd; // CMD
for(j = 0; j < (_len - 1); j++) // Data (LEN-1 bytes)
{
calculated_xor ^= pkg[4 + j];
}
if(received_xor != calculated_xor)
{
PRINT("Error: XOR check failed! Received: 0x%02X, Calculated: 0x%02X\n", received_xor, calculated_xor);
return 4; // 校验失败
}
// 5. 提取并验证 SUM 校验
uint8_t received_sum = pkg[3 + _len + 1]; // SUM 位置:XOR 后一个字节
uint8_t calculated_sum = _addr; // ADDR
calculated_sum += _len; // LEN
calculated_sum += _cmd; // CMD
for(j = 0; j < (_len - 1); j++) // Data (LEN-1 bytes)
{
calculated_sum += pkg[4 + j];
}
if(received_sum != calculated_sum)
{
PRINT("Error: SUM check failed! Received: 0x%02X, Calculated: 0x%02X\n", received_sum, calculated_sum);
return 5; // 校验失败
}
// ===== 所有校验通过 =====
return 0; // 校验成功
}
uint8_t usart_packet_9F_validate(uint8_t *pkg, uint8_t len)
{
uint8_t _sub1 = pkg[1];
uint8_t _sub2 = pkg[2];
uint8_t _len = pkg[3];
uint8_t _cmd = pkg[4];
uint8_t j;
// ===== 数据包校验 =====
// 1. 检查起始字节 STX (0x7F)
if(pkg[0] != 0x9F)
{
PRINT("Error: Invalid STX 0x%02X\n", pkg[0]);
return 1; // 校验失败
}
// // 2. 检查长度字段
// // LEN = CMD(1) + Data(LEN-1), 总长度应该是 LEN+3(STX+ADDR+LEN+XOR+SUM)
// if(_len < 1) // 至少要有 CMD
// {
// PRINT("Error: Invalid length %d\n", _len);
// return 2; // 校验失败
// }
//
// // 3. 检查接收到的数据长度是否匹配
// if(len < (_len + 2)) // STX(1) + ADDR(1) + LEN(1) + LEN bytes + SUM(1) = LEN+3,但 pkg 从 0 开始,所以是 len >= _len + 2
// {
// PRINT("Error: Received length %d doesn't match declared length %d\n", len, _len);
// return 3; // 校验失败
// }
//
// // 5. 提取并验证 SUM 校验
// uint8_t received_sum = pkg[4 + _len]; // SUM 位置:XOR 后一个字节
// uint8_t calculated_sum = _sub1 + _sub2; // ADDR
// calculated_sum += _len; // LEN
// calculated_sum += _cmd; // CMD
// for(j = 0; j < (_len - 1); j++) // Data (LEN-1 bytes)
// {
// calculated_sum += pkg[4 + j];
// }
//
// if(received_sum != calculated_sum)
// {
// PRINT("Error: SUM check failed! Received: 0x%02X, Calculated: 0x%02X\n", received_sum, calculated_sum);
// return 5; // 校验失败
// }
// ===== 所有校验通过 =====
return 0; // 校验成功
}
void iap_command_handle(void)
{
// IAP_REV_FLAG_DONE
flash_unlock();
flash_sector_erase(IAP_UPGRADE_FLAG_ADDR);
flash_word_program(IAP_UPGRADE_FLAG_ADDR, IAP_UPGRADE_FLAG_9F);
flash_lock();
nvic_system_reset();
}
void manage_dbn_ble_default(uint8_t *pkg, uint8_t len)
{
uint8_t _header_0 = pkg[1];
uint8_t _header_0_high = 0;
uint8_t _header_0_low = _header_0 % 0x10;
uint8_t _len = pkg[2];
uint8_t _cmd = pkg[3];
uint8_t _tmp = 0;
uint8_t i = 0, j,k = 0;
uint8_t _ota_pre_flag = 0;
if(pkg[0] == 0x7F || pkg[0] == 0x8F)
{
// ===== 调用校验函数进行数据包校验 =====
if(usart_packet_validate(pkg, len) != 0)
{
// 校验失败,直接返回
return;
}
}
else if(pkg[0] == 0x9F)
{
// ===== 调用校验函数进行数据包校验 =====
if(usart_packet_9F_validate(pkg, len) != 0)
{
// 校验失败,直接返回
return;
}
_ota_pre_flag = 1;
}
else{
PRINT("Error: Invalid STX 0x%02X\n", pkg[0]);
return;
}
if(_ota_pre_flag){
PRINT("OTA Pre Flag: %d\n", _ota_pre_flag);
if(pkg[1] == 0x01 && pkg[2] == 0x00 && pkg[3] == 0x01 && pkg[4] == 0xA5 && pkg[5] == 0xA7){
PRINT("OTA Pre Flag: %d\n", _ota_pre_flag);
iap_command_handle();
}
return;
}
switch(_cmd)
{
case CMD_DBN_DEV_RESET:
{
//Restart Dev
nvic_system_reset();
} break;
case CMD_DEV_Ver:
{
i = 0;
tmp_ble_buf[i++] = 0x00;
tmp_ble_buf[i++] = HARDWARE_VER_MAIN;
tmp_ble_buf[i++] = HARDWARE_VER_SUB;
tmp_ble_buf[i++] = HARDWARE_VER_SSUB;
tmp_ble_buf[i++] = FIRMWARE_VER_MAIN;
tmp_ble_buf[i++] = FIRMWARE_VER_SUB;
tmp_ble_buf[i++] = FIRMWARE_VER_SSUB;
response_uart_pkg(_cmd, tmp_ble_buf, i);
} break;
case CMD_DBN_SET_MCJQ_PARAM:
{
unpack_pkg_set_mcjq_param(pkg, len);
tmp_ble_buf[0] = 0;
// set_response_buf(&g_buf_ble_response, MAGIC_BYTE_DBN_DEFAULT, _cmd, tmp_ble_buf, 1);
response_uart_pkg(_cmd, tmp_ble_buf, 1);
delay_ms(30);
NVIC_SystemReset(); // 自动复位
// para_store_init();
} break;
case CMD_DBN_GET_MCJQ_PARAM:
{
i = 0;
tmp_ble_buf[i++] = g_loop_cng_info.smart_mode;
tmp_ble_buf[i++] = LOOP_CAPTURE_MAX;
Loop_Cng_Unit *_cng = g_loop_cng_info.loop_cng;
for(j = 0; j < LOOP_CAPTURE_MAX; j++)
{
tmp_ble_buf[i++] = (_cng->sensitvity) | (_cng->loopFreq_Level << 4);
tmp_ble_buf[i++] = _cng->delay_time;
tmp_ble_buf[i++] = (_cng->output_mode) | (_cng->loopSafe_Timeout << 3);
tmp_ble_buf[i++] = _cng->exist_mode;
tmp_ble_buf[i++] = _cng->direction_mode;
// 上报频率 = sclk_freq * input_div * LPCNT / CAPVD (先乘后除避免精度损失)
uint32_t _freq = 0;
if (g_loop_states.loop_unit[j].loop_LPCNT > 0 && g_loop_states.loop_unit[j].loop_CAPVD > 0) {
_freq = (uint32_t)((uint64_t)g_crm_clocks_freq_struct.sclk_freq * g_input_div
* g_loop_states.loop_unit[j].loop_LPCNT / g_loop_states.loop_unit[j].loop_CAPVD);
}
tmp_ble_buf[i++] = (uint8_t)(_freq & 0xFF);
tmp_ble_buf[i++] = (uint8_t)((_freq >> 8) & 0xFF);
tmp_ble_buf[i++] = (uint8_t)((_freq >> 16) & 0xFF);
_cng++;
}
// LOOP_MEASURE_BASE: variation 归一化基数 (3B LE, 与 TaskLoop.h MEASUREMENT_BASE 同步)
tmp_ble_buf[i++] = (uint8_t)(LOOP_MEASURE_BASE & 0xFF);
tmp_ble_buf[i++] = (uint8_t)((LOOP_MEASURE_BASE >> 8) & 0xFF);
tmp_ble_buf[i++] = (uint8_t)((LOOP_MEASURE_BASE >> 16) & 0xFF);
response_uart_pkg(_cmd, tmp_ble_buf, i);
} break;
// case CMD_DBN_LOOP_SAMPLE_PARAM:{
// // 获取/设置 地感采样参数
//// PRINT("SAMPLE_CNG: %02X\n", pkg[4]);
// if(pkg[4] == 0){
// // get param
// i = 0;
// tmp_ble_buf[i++] = 0x10;
// tmp_ble_buf[i++] = g_loop_balance_planB.sample_cng.flag;
// tmp_ble_buf[i++] = g_loop_balance_planB.sample_cng.max_amplitude;
// tmp_ble_buf[i++] = (g_loop_balance_planB.sample_cng.max_amplitude >> 8) & 0xFF;
// set_response_buf(&g_buf_ble_response, MAGIC_BYTE_DBN_DEFAULT, _cmd, tmp_ble_buf, i);
// }
// else {
// // set param
// i = 0;
// k = 4;
// tmp_ble_buf[i++] = 0x11;
// tmp_ble_buf[i++] = pkg[k++];
// tmp_ble_buf[i++] = pkg[k++];
// tmp_ble_buf[i++] = pkg[k++];
//
// g_loop_balance_planB.sample_cng.flag = tmp_ble_buf[1];
// g_loop_balance_planB.sample_cng.max_amplitude = tmp_ble_buf[2] | ((tmp_ble_buf[3] << 8 ) & 0xFF00);
//
// write_cfg_to_store(Addr_Loop_PlanB_Cng_Offset, &tmp_ble_buf[1], sizeof(Loop_Sample_Cng));
//
// set_response_buf(&g_buf_ble_response, MAGIC_BYTE_DBN_DEFAULT, _cmd, tmp_ble_buf, i);
//
// //TODO: 不整个设备复位,复位除了蓝牙的部分,即蓝牙正常,其他部分重新初始化
// para_store_init();
// }
//
// } break;
// case CMD_DBN_LOOP_BALANCE_PARAM: {
// // 获取/设置 漂移补偿参数
//// PRINT("Balance_CNG: %02X\n", pkg[4]);
// if(pkg[4] == 0){
// // get param
// i = 0;
// tmp_ble_buf[i++] = 0x10;
// tmp_ble_buf[i++] = g_loop_balance_planB.balance_ori_cng.flag;
// tmp_ble_buf[i++] = g_loop_balance_planB.balance_ori_cng.max_cnt;
// tmp_ble_buf[i++] = (g_loop_balance_planB.balance_ori_cng.max_cnt >> 8) & 0xFF;
//
// set_response_buf(&g_buf_ble_response, MAGIC_BYTE_DBN_DEFAULT, _cmd, tmp_ble_buf, i);
// }
// else{
// // set param
// i = 0;
// k = 4;
// tmp_ble_buf[i++] = 0x11;
// tmp_ble_buf[i++] = pkg[k++];
// tmp_ble_buf[i++] = pkg[k++];
// tmp_ble_buf[i++] = pkg[k++];
//
// g_loop_balance_planB.balance_ori_cng.flag = tmp_ble_buf[1];
// g_loop_balance_planB.balance_ori_cng.max_cnt = tmp_ble_buf[2] | ((tmp_ble_buf[3] << 8 ) & 0xFF00);
//
// write_cfg_to_store(Addr_Loop_PlanB_Cng_Offset + sizeof(Loop_Sample_Cng), &tmp_ble_buf[1], sizeof(Loop_Balance_Ori_Cng));
//
// set_response_buf(&g_buf_ble_response, MAGIC_BYTE_DBN_DEFAULT, _cmd, tmp_ble_buf, i);
//
// //TODO: 不整个设备复位,复位除了蓝牙的部分,即蓝牙正常,其他部分重新初始化
// para_store_init();
//
// }
//
// } break;
// case CMD_DBN_LOOP_RELEASE_PLANB: {
// // 获取/设置 释放去抖动算法参数
//// PRINT("Release2_CNG: %02X\n", pkg[4]);
// if(pkg[4] == 0){
// // get param
// i = 0;
// tmp_ble_buf[i++] = 0x10;
// tmp_ble_buf[i++] = g_loop_balance_planB.release_ori_planB.flag_weight;
// tmp_ble_buf[i++] = g_loop_balance_planB.release_ori_planB.max_amplitude;
// tmp_ble_buf[i++] = (g_loop_balance_planB.release_ori_planB.max_amplitude >> 8) & 0xFF;
// tmp_ble_buf[i++] = g_loop_balance_planB.release_ori_planB.timeout;
// tmp_ble_buf[i++] = g_loop_balance_planB.release_change_rate.flag_weight;
// tmp_ble_buf[i++] = g_loop_balance_planB.release_change_rate.rate_first;
// tmp_ble_buf[i++] = g_loop_balance_planB.release_change_rate.rate_second;
// tmp_ble_buf[i++] = g_loop_balance_planB.release_change_rate.mode;
//
// set_response_buf(&g_buf_ble_response, MAGIC_BYTE_DBN_DEFAULT, _cmd, tmp_ble_buf, i);
// }
// else{
// // set param
// i = 0; k = 0;
// tmp_ble_buf[i++] = 0x11;
// memcpy(&tmp_ble_buf[1], &pkg[4], 8);
// i += 8;
//
// write_cfg_to_store(Addr_Loop_PlanB_Cng_Offset + sizeof(Loop_Sample_Cng) + sizeof(Loop_Balance_Ori_Cng), &tmp_ble_buf[1], 8);
//
// set_response_buf(&g_buf_ble_response, MAGIC_BYTE_DBN_DEFAULT, _cmd, tmp_ble_buf, i);
//
// //TODO: 不整个设备复位,复位除了蓝牙的部分,即蓝牙正常,其他部分重新初始化
// para_store_init();
// }
// } break;
case CMD_DBN_LOOP_SENS_LIST: {
PRINT("SENS_CNG: %02X\n", pkg[4]);
if(pkg[4] == 0x00){
// get param
i = 0;
tmp_ble_buf[i++] = 0x10;
tmp_ble_buf[i++] = g_loop_sens_list.total;
for(k = 0; k < g_loop_sens_list.total; k++){
tmp_ble_buf[i++] = g_loop_sens_list.sens[k].sens_in;
tmp_ble_buf[i++] = g_loop_sens_list.sens[k].sens_in >> 8;
tmp_ble_buf[i++] = g_loop_sens_list.sens[k].sens_out;
tmp_ble_buf[i++] = g_loop_sens_list.sens[k].sens_out >> 8;
}
response_uart_pkg(_cmd, tmp_ble_buf, i);
}
else {
// set param
i = 0; k = 5;
tmp_ble_buf[i++] = 0x11;
g_loop_sens_list.total = pkg[k];
if(g_loop_sens_list.total > MAX_LOOP_SENS_AMOUNT){
g_loop_sens_list.total = MAX_LOOP_SENS_AMOUNT;
}
k = 1+ g_loop_sens_list.total * 4;
memcpy(&tmp_ble_buf[i], &pkg[5], k);
memcpy(&g_loop_sens_list.sens, &pkg[6], k - 1);
i += ( k );
storage_dev();
response_uart_pkg(_cmd, tmp_ble_buf, i);
//TODO: 不整个设备复位,复位除了蓝牙的部分,即蓝牙正常,其他部分重新初始化
para_store_init();
}
} break;
case CMD_DBN_SET_CJQ_FACTORY: {
// 出厂初始化
tmp_ble_buf[0] = 0;
set_factory_param();
storage_dev();
response_uart_pkg(_cmd, tmp_ble_buf, 1);
//TODO: 不整个设备复位,复位除了蓝牙的部分,即蓝牙正常,其他部分重新初始化
para_store_init();
} break;
case CMD_SENS_ACS_ENABLE: {
// 线圈动态上报使能(简化版:仅处理 enable flag
// g_dbn_ble_state_acs_enable.enable = pkg[5];
} break;
default:
{
} break;
}
}
/**
* @brief USART1串口接收任务
* @param pvParameters: 任务参数
* @retval None
*/
void usart_task_function(void *pvParameters)
{
uint8_t received_data;
while(1)
{
if(g_pkg_uart_1.flag){
// PRINT("Rcv_uart:%s\n", g_pkg_uart_1.pkg);
manage_dbn_ble_default(g_pkg_uart_1.pkg, g_pkg_uart_1.offset);
InitPkgUart(&g_pkg_uart_1);
}
uart_report_packet_loop_acs(0);
#ifdef DEBUG
if(g_flag_output)
{
g_flag_output = 0;
PRINT("LPCNT:%d,%d,%d,%d CAPVD:%d,%d,%d,%d Origin:%d,%d,%d,%d VD:%d,%d,%d,%d\n",
g_loop_states.loop_unit[0].loop_LPCNT, g_loop_states.loop_unit[1].loop_LPCNT,
g_loop_states.loop_unit[2].loop_LPCNT, g_loop_states.loop_unit[3].loop_LPCNT,
g_loop_states.loop_unit[0].loop_CAPVD, g_loop_states.loop_unit[1].loop_CAPVD,
g_loop_states.loop_unit[2].loop_CAPVD, g_loop_states.loop_unit[3].loop_CAPVD,
g_loop_states.loop_unit[0].loop_Origin, g_loop_states.loop_unit[1].loop_Origin,
g_loop_states.loop_unit[2].loop_Origin, g_loop_states.loop_unit[3].loop_Origin,
g_loop_states.loop_unit[0].loop_VD_FLAG, g_loop_states.loop_unit[1].loop_VD_FLAG,
g_loop_states.loop_unit[2].loop_VD_FLAG, g_loop_states.loop_unit[3].loop_VD_FLAG);
}
#endif
// 短暂延迟,避免过度占用CPU
vTaskDelay(10);
}
}
uint8_t g_flag_output = 0;
uint8_t g_flag_output2 = 0;
// 1ms interval
void TMR6_GLOBAL_IRQHandler(void)
{
static uint16_t _cnt_5ms = 0;
static uint32_t _cnt = 0;
if(tmr_interrupt_flag_get(TMR6, TMR_OVF_FLAG) != RESET)
{
#ifdef DEBUG
_cnt++;
if(_cnt >= 2000){
g_flag_output = 1;
_cnt = 0;
}
#endif
TimingDelayInc++;
if(g_pkg_uart_1.offset){
if(g_pkg_uart_1.flag == 0){
g_pkg_uart_1.tick++;
if(g_pkg_uart_1.tick > 8){
g_pkg_uart_1.flag = 1;
}
}
g_loop_states.report_counter = 0;
}
tmr_flag_clear(TMR6, TMR_OVF_FLAG);
}
}
/**
* @brief this function handles usart1 handler.
* @param none
* @retval none
*/
void USART1_IRQHandler(void)
{
if(usart_interrupt_flag_get(USART1, USART_RDBF_FLAG) != RESET)
{
/* read one byte from the receive data register */
g_pkg_uart_1.pkg[g_pkg_uart_1.offset++] = usart_data_receive(USART1);
g_pkg_uart_1.tick = 0;
// if(usart1_rx_counter == usart2_tx_buffer_size)
// {
// /* disable the usart1 receive interrupt */
// usart_interrupt_enable(USART1, USART_RDBF_INT, FALSE);
// }
}
}
/**
* @}
*/
/**
* @}
*/