- peripheral_main.c: snap_init() 恢复 (去 #if 0), offlog_boot() 恢复 (上电复位原因记入事件日志); 删除 sim_snap_spi 模拟写密度实验函数 及主循环调用 (printf 重入修复后 SPI 写无罪已确诊, 实验收尾) - loop_uart_proto.h/c: UART2 波特率注释 115200/19200 -> 192000 (usart_biz.c 硬编码 192000 为实际值; g_storage_uart_baud=19200 为独立配置项不驱动 UART2, BLE 显示 19200 不代表实际速率) - devlog: 新增 2026-08-14 条目, UART2 RX DMA 方案列入待办
434 lines
14 KiB
C
434 lines
14 KiB
C
/********************************** (C) COPYRIGHT *******************************
|
||
* File Name : main.c
|
||
* Author : WCH
|
||
* Version : V1.1
|
||
* Date : 2020/08/06
|
||
* Description : Peripheral slave application main function and task system initialization
|
||
*********************************************************************************
|
||
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
|
||
* Attention: This software (modified or not) and binary are used for
|
||
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
|
||
*******************************************************************************/
|
||
|
||
/******************************************************************************/
|
||
/* Header file contains */
|
||
#include "CONFIG.h"
|
||
#include "HAL.h"
|
||
#include "gattprofile.h"
|
||
#include "peripheral.h"
|
||
#include "cmcng.h"
|
||
#include <string.h>
|
||
#include "dbn_ble_srv.h"
|
||
#include "eth_driver.h"
|
||
#include "net_srv.h"
|
||
#include "storage.h"
|
||
#include "offlog.h"
|
||
#include "snapshot.h"
|
||
#include "tcp_json_srv.h"
|
||
#include "loop_uart_proto.h"
|
||
#include "iot_mqtt_srv.h"
|
||
#include "fault_diag.h"
|
||
|
||
/*********************************************************************
|
||
* GLOBAL TYPEDEFS
|
||
*/
|
||
__attribute__((aligned(4))) uint32_t MEM_BUF[BLE_MEMHEAP_SIZE / 4];
|
||
|
||
#define KEY_GPIO (RCC_APB2Periph_GPIOA)
|
||
#define KEY_BV BV(0)
|
||
#define KEY_IN (GPIO_ReadInputDataBit(KEY_GPIO, KEY_BV)==0)
|
||
#define HAL_PUSH_BUTTON() (KEY1_IN) //Add custom button
|
||
|
||
#if(defined(BLE_MAC)) && (BLE_MAC == TRUE)
|
||
const uint8_t MacAddr[6] = {0x84, 0xC2, 0xE4, 0x03, 0x02, 0x02};
|
||
// #else
|
||
// uint8_t MACAddr[6] = {0x84, 0xC2, 0xE4, 0x03, 0x02, 0x02};
|
||
#endif
|
||
uint8_t gMacAddr[6] = { 0x38, 0x3B, 0x26, 0x11, 0xA4 ,0x35 };
|
||
|
||
/* Used for app judgment file effectiveness */
|
||
const uint32_t Address = 0xFFFFFFFF;
|
||
|
||
__attribute__((aligned(4))) uint32_t Image_Flag __attribute__((section(".ImageFlag"))) = (uint32_t)&Address;
|
||
|
||
uint8_t g_dev_number[6] = ""; // �豸��� ��Ʒ���
|
||
uint8_t g_dev_password[6] = {0x31, 0x32, 0x33, 0x34, 0x35, 0x36};
|
||
uint8_t g_ble_safe_flag = 0;
|
||
uint32_t g_ble_safe_counter_ori = 0;
|
||
uint32_t g_ble_safe_counter_dst = 0;
|
||
|
||
char g_flag_debug = 1;
|
||
|
||
uint8_t g_dg_device_type = DDType_DLD950V4; // ???����?????????????
|
||
uint8_t g_dg_sub_dev_type = DDType_DLD950V4;
|
||
|
||
Sub_Code_Enable g_sub_code_enable = {0,};
|
||
|
||
uint32_t g_activ_counter = 0;
|
||
|
||
uint32_t g_counter_bt_timeout = 0;
|
||
uint8_t g_flag_bt_state = 0;
|
||
uint8_t g_flag_bt_disable = 0;
|
||
|
||
uint8_t g_max_counter_bt_min = 0;
|
||
uint32_t g_max_counter_bt_timeout = 0; //BT_DISABLE_IDLE_TIMEOUT * 60 * 1000; // ms unit
|
||
|
||
|
||
__IO uint32_t TimingDelayInc;
|
||
__IO uint32_t TimingDelayDec;
|
||
|
||
uint8_t trigB;
|
||
Pkg_Uart g_pkg_uart_1 = { 0, 0, 0, "", 0};
|
||
Pkg_Uart g_pkg_uart_2 = { 0, 0, 0, "", 0};
|
||
|
||
Flag_Counter g_flag_counter_key = {0, 0, 0};
|
||
Flag_Counter g_flag_counter_ota = {0, 0, 0};
|
||
|
||
uint8_t g_storage_uart_num = 0;
|
||
uint32_t g_storage_uart_baud = 19200;//9600;
|
||
uint8_t g_storage_uart_num_2 = 1;
|
||
uint32_t g_storage_uart_baud_2 = 115200; //115200;
|
||
|
||
uint32_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;
|
||
}
|
||
|
||
|
||
|
||
/*********************************************************************
|
||
* @fn TIM2_Init
|
||
*
|
||
* @brief Initializes TIM2.
|
||
*
|
||
* @return none
|
||
*/
|
||
void TIM2_Init( void )
|
||
{
|
||
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure={0};
|
||
|
||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
|
||
|
||
TIM_TimeBaseStructure.TIM_Period = SystemCoreClock / 1000000;
|
||
TIM_TimeBaseStructure.TIM_Prescaler = WCHNETTIMERPERIOD * 1000 - 1;
|
||
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
|
||
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
|
||
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
|
||
TIM_ITConfig(TIM2, TIM_IT_Update ,ENABLE);
|
||
|
||
TIM_Cmd(TIM2, ENABLE);
|
||
TIM_ClearITPendingBit(TIM2, TIM_IT_Update );
|
||
NVIC_EnableIRQ(TIM2_IRQn);
|
||
}
|
||
|
||
/*********************************************************************
|
||
* @fn TIM3_Init
|
||
*
|
||
* @brief Initializes TIM3.
|
||
*
|
||
* @return none
|
||
*/
|
||
void TIM3_Init(void)
|
||
{
|
||
NVIC_InitTypeDef NVIC_InitStructure={0};
|
||
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure = { 0 };
|
||
|
||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
|
||
|
||
////10ms
|
||
// TIM_TimeBaseStructure.TIM_Period = SystemCoreClock / 1000000;
|
||
// TIM_TimeBaseStructure.TIM_Prescaler = 10 * 1000 - 1;
|
||
|
||
//1ms
|
||
TIM_TimeBaseStructure.TIM_Period = SystemCoreClock / 1000000;
|
||
TIM_TimeBaseStructure.TIM_Prescaler = 1 * 1000 - 1;
|
||
|
||
|
||
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
|
||
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
|
||
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
|
||
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
|
||
|
||
TIM_Cmd(TIM3, ENABLE);
|
||
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
|
||
NVIC_EnableIRQ(TIM3_IRQn);
|
||
}
|
||
|
||
|
||
void key_event_srv(void){
|
||
// if(g_flag_counter_key.tick > 1000){
|
||
// PRINT("key_tick_timeup_______: %d\n", GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0));
|
||
// g_flag_counter_key.tick = 0;
|
||
// }
|
||
if(g_flag_counter_key.flag){
|
||
uint8_t _pkg[7] = {0};
|
||
uint8_t i = 0;
|
||
switch (g_flag_counter_key.flag) {
|
||
case KEY_ET_BLE_ENABLE: {
|
||
PRINT("______KEY_ET_BLE_ENABLE\n");
|
||
NVIC_SystemReset();
|
||
} break;
|
||
case KEY_ET_REBOOT: {
|
||
PRINT("__________KEY_ET_REBOOT\n");
|
||
_pkg[i++] = 0x7F;
|
||
_pkg[i++] = 0x00;
|
||
_pkg[i++] = 0x01;
|
||
_pkg[i++] = 0x6D;
|
||
_pkg[i++] = 0x6C;
|
||
_pkg[i++] = 0x6E;
|
||
UART2_SendString(_pkg, i); //1 send loop mcu reboot;
|
||
|
||
Delay_Ms(10);
|
||
// 2 DBN dev reboot
|
||
NVIC_SystemReset();
|
||
} break;
|
||
case KEY_ET_FACTORY: {
|
||
PRINT("_____________KEY_ET_FACTORY\n");
|
||
_pkg[i++] = 0x7F;
|
||
_pkg[i++] = 0x00;
|
||
_pkg[i++] = 0x01;
|
||
_pkg[i++] = 0x92;
|
||
_pkg[i++] = 0x93;
|
||
_pkg[i++] = 0x93;
|
||
UART2_SendString(_pkg, i); //1 send loop mcu factory init
|
||
|
||
|
||
} break;
|
||
case KEY_ET_NETBLE_FACTORY: {
|
||
//2 DBN dev factory init;
|
||
factory_dev_info();
|
||
Delay_Ms(10);
|
||
|
||
NVIC_SystemReset();
|
||
} break;
|
||
|
||
}
|
||
g_flag_counter_key.flag = 0;
|
||
}
|
||
|
||
|
||
}
|
||
|
||
|
||
/*********************************************************************
|
||
* @fn Main_Circulation
|
||
*
|
||
* @brief Main loop
|
||
*
|
||
* @return none
|
||
*/
|
||
__attribute__((section(".highcode")))
|
||
__attribute__((noinline))
|
||
void Main_Circulation(void)
|
||
{
|
||
uint32_t _counter = 0;
|
||
while(1)
|
||
{
|
||
FAULT_MARKER(MK_LOOP_TOP);
|
||
iot_watchdog_kick(); /* 无条件喂狗 (2026-08-13): 原只在 iot_mqtt_poll, tcp_json 分支不喂 */
|
||
TMOS_SystemProcess();
|
||
|
||
if(g_net_state.flag < 2)
|
||
{
|
||
net_srv_init();
|
||
}
|
||
if(g_net_state.flag == 2)
|
||
{
|
||
if(g_sub_code_enable.iot_enable){
|
||
if(iot_net_info.mode == IOT_Addr_IP_Mode){
|
||
if(get_ipstr_to_array(iot_net_info.remote_addr, RemoteIP) == 0){
|
||
WCHNET_CreateTcpMqttSocket();
|
||
}
|
||
}
|
||
else{
|
||
//DNS
|
||
}
|
||
|
||
}
|
||
else
|
||
{
|
||
WCHNET_CreateTcpSocket();
|
||
}
|
||
}
|
||
|
||
|
||
/*Ethernet library main task function,
|
||
* which needs to be called cyclically*/
|
||
WCHNET_MainTask();
|
||
/*Query the Ethernet global interrupt,
|
||
* if there is an interrupt, call the global interrupt handler*/
|
||
if(WCHNET_QueryGlobalInt())
|
||
{
|
||
WCHNET_HandleGlobalInt();
|
||
}
|
||
|
||
FAULT_MARKER(MK_UART_SRV_IN);
|
||
uart_srv();
|
||
FAULT_MARKER(MK_UART_SRV_OUT);
|
||
snap_flush(); /* 快照落盘: 无条件挂主循环 (原在 iot_enable 分支, TCP 模式不落盘) */
|
||
FAULT_MARKER(MK_POLL_BLE_IN);
|
||
poll_dbn_ble();
|
||
|
||
if (g_sub_code_enable.iot_enable) {
|
||
iot_mqtt_publish_sensor(); // Push 0xC0 sensor data to MQTT broker
|
||
iot_mqtt_poll(); // IoT MQTT state machine + PINGREQ keepalive
|
||
} else {
|
||
tcp_json_push_sensor(); // Push 0xC0 sensor data to TCP JSON client
|
||
tcp_json_poll();
|
||
}
|
||
|
||
key_event_srv();
|
||
}
|
||
}
|
||
|
||
|
||
|
||
/*********************************************************************
|
||
* @fn main
|
||
*
|
||
* @brief Main function
|
||
*
|
||
* @return none
|
||
*/
|
||
int main(void)
|
||
{
|
||
SystemCoreClockUpdate();
|
||
Delay_Init();
|
||
#ifdef DEBUG
|
||
// USART_Printf_Init( 115200 );
|
||
USART_Printf_Init( 256000 );
|
||
#endif
|
||
/* 诊断: 复位原因寄存器 (bit31=IWDG bit30=WWDG bit29=LPWR bit26=NRST bit25=POR bit24=软复位)
|
||
每次上电必打, 区分看门狗死锁 vs 掉电 vs 外部复位 */
|
||
PRINT("RST_REASON: 0x%08lx\n", (unsigned long)OFFLOG_RCC_RSTSCKR);
|
||
fault_diag_init(); /* 打印上次复位现场 (HardFault mcause/mepc + 执行轨迹 marker) */
|
||
iot_watchdog_init(); /* 无条件 IWDG (2026-08-13): iot_enable=0 时 iot_mqtt_init 不调,
|
||
卡死无兜底 → 永久冻结。IWDG 4s 超时 + 主循环喂狗 */
|
||
PRINT("%s\n", VER_LIB);
|
||
PRINT("SystemCoreClock:%d\n", SystemCoreClock);
|
||
/* ===== 实验: 禁用全部 Flash/SPI 操作 (2026-08-12) =====
|
||
结论: 禁用后设备稳定 → SPI 操作触发复位+乱码实锤
|
||
软件缓解: storage.c SPI 时钟降档 + GPIO 缓边沿 (见 SPI_Flash_Init)
|
||
硬件根治: NRST 加 100nF 电容 / SPI 走线远离 NRST / 串阻缓边沿
|
||
#if 0 = 恢复全部 SPI; 保留本块便于回退实验 */
|
||
#if 0
|
||
PRINT("ISOLATE: flash/SPI disabled (flash isolation test)\n");
|
||
#else
|
||
GetMacAddr(gMacAddr);
|
||
storage_init();
|
||
PRINT("INIT: storage ok\n");
|
||
offlog_init();
|
||
PRINT("INIT: offlog ok\n");
|
||
/* 快照区: 上电扫描恢复 (2026-08-14, printf 重入修复后恢复启用) */
|
||
snap_init();
|
||
PRINT("INIT: snap ok\n");
|
||
|
||
/* offlog_boot: 记录本次复位原因到事件日志 (2026-08-14 恢复) */
|
||
{
|
||
uint32_t rcc_rst = OFFLOG_RCC_RSTSCKR;
|
||
offlog_boot(rcc_rst);
|
||
OFFLOG_RCC_RSTSCKR |= OFFLOG_RST_RMVF; /* RMVF (bit24): 清复位标志 */
|
||
}
|
||
|
||
load_cfg_from_flash();
|
||
output_cfg_from_flash();
|
||
#endif
|
||
|
||
PRINT("MAC: %02X %02X %02X %02X %02X %02X\r\n", gMacAddr[0],gMacAddr[1], gMacAddr[2], gMacAddr[3],gMacAddr[4],gMacAddr[5]);
|
||
PRINT("net version:%x\n", WCHNET_GetVer());
|
||
WCHBLE_Init();
|
||
HAL_Init();
|
||
|
||
uart_init();
|
||
|
||
/* ===== 实验: 禁用 UART2 (Loop 口) 隔离测试 (2026-08-12) =====
|
||
结论: UART2 禁用后仍复位 → 与 Loop 数据路径无关 (后定位为 SPI 串扰)
|
||
#if 0 = 恢复 UART2 正常 */
|
||
#if 0
|
||
{
|
||
GPIO_InitTypeDef gpio;
|
||
USART_ITConfig(USART2, USART_IT_RXNE, DISABLE);
|
||
USART_Cmd(USART2, DISABLE);
|
||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
|
||
gpio.GPIO_Pin = GPIO_Pin_3;
|
||
gpio.GPIO_Mode = GPIO_Mode_IPU; /* PA3 脱离 UART2, 上拉输入 */
|
||
gpio.GPIO_Speed = GPIO_Speed_50MHz;
|
||
GPIO_Init(GPIOA, &gpio);
|
||
PRINT("ISOLATE: UART2 disabled (Loop isolation test)\n");
|
||
}
|
||
#endif
|
||
|
||
TIM3_Init();
|
||
TIM2_Init();
|
||
|
||
GAPRole_PeripheralInit();
|
||
Peripheral_Init();
|
||
Main_Circulation();
|
||
}
|
||
|
||
|
||
void TIM3_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
|
||
/*********************************************************************
|
||
* @fn TIM3_IRQHandler, 1ms
|
||
*
|
||
* @brief This function handles TIM2 exception.
|
||
*
|
||
* @return none
|
||
*/
|
||
void TIM3_IRQHandler(void)
|
||
{
|
||
TimingDelayInc++;
|
||
g_activ_counter++;
|
||
|
||
if(g_pkg_uart_2.offset){
|
||
if(g_pkg_uart_2.flag == 0){
|
||
g_pkg_uart_2.tick++;
|
||
if(g_pkg_uart_2.tick > 8){
|
||
g_pkg_uart_2.flag = 1;
|
||
}
|
||
}
|
||
}
|
||
// Safety: reset frame parser if stuck in non-IDLE state too long
|
||
if(g_lup_parser.state != LUP_FRAME_STATE_IDLE){
|
||
if(g_pkg_uart_2.tick > 20){
|
||
lup_frame_reset();
|
||
g_pkg_uart_2.tick = 0;
|
||
}
|
||
}
|
||
|
||
if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == 0){//HAL_PUSH_BUTTON()){
|
||
g_flag_counter_key.tick++;
|
||
}
|
||
else{
|
||
if(g_flag_counter_key.tick){
|
||
if(g_flag_counter_key.tick < 2000){
|
||
g_flag_counter_key.flag = KEY_ET_BLE_ENABLE;
|
||
}
|
||
else if(g_flag_counter_key.tick < 6000){
|
||
g_flag_counter_key.flag = KEY_ET_REBOOT;
|
||
}
|
||
else if(g_flag_counter_key.tick < 10000){
|
||
g_flag_counter_key.flag = KEY_ET_FACTORY;
|
||
}
|
||
else{
|
||
g_flag_counter_key.flag = KEY_ET_NETBLE_FACTORY;
|
||
}
|
||
g_flag_counter_key.tick = 0;
|
||
}
|
||
}
|
||
|
||
|
||
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
|
||
}
|
||
|
||
|
||
/******************************** endfile @ main ******************************/
|