shuichan_old/V1.1/STM32F103_App1/HardWare/SYSINIT/app_loop.c

168 lines
4.9 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.

/* app_loop.c - 主循环业务调度封装
*
* 将 main() 中 while(1) 的业务逻辑封装到本模块,
* 使 main.c 只保留初始化和 app_loop_process() 调用。
*/
#include "app_loop.h"
#include "app_common.h"
#include "user_cmd.h"
#include "relay.h"
#include "network.h"
#include "led.h"
#include "adc.h"
#include "feed_scale.h"
#include "iic.h"
#include "24c02.h"
#include "uart.h"
#include "../W25Q64/w25q64.h"
/* 主循环状态变量 */
static uint8_t ota_confirmed = 0;
static uint8_t ota_simulate_fail = 0; /* =1测试模拟 OTA 确认失败 */
static uint8_t ota_fail_logged = 0;
static uint32_t ota_confirm_tick = 0;
static uint32_t mqtt_ready_tick = 0;
static uint8_t mqtt_ready_recorded = 0;
static uint8_t mqtt_first_status_reported = 0;
/**
* @brief 业务模块初始化:横幅 → 配置/存储 → 外设 → 网络 → 串口接收
* @note 基础硬件(时钟/GPIO/UART/看门狗)由 Board_Init() 完成
*/
void app_init(void)
{
log_info("");
log_info("* * * * * * * * * * * * * * * * * *");
log_info("* Version: 1.1.0 *");
log_info("* * * * * * * By Helei * * * *");
/* EEPROM 中的 MQTT/版本配置 */
iicInit();
eepromReadInfo();
log_info("> Server: %s:%d", MqttInfoStr.ServerIP, MqttInfoStr.ServerPort);
log_info("> Client: %s", MqttInfoStr.ClientID);
log_info("> User : %s", MqttInfoStr.Username);
log_info("> Firmware Ver: %u", MqttInfoStr.Ver);
/* W25Q64 外部 Flash用于 OTA 固件暂存 */
W25Q64_Init();
/* 继电器 GPIO控制输出 + 反馈输入) */
relayInit();
/* RS485 喂料秤控制模块 */
feedScaleInit();
/* LEDLED2 心跳同时兼任外部看门狗 TPL5010 喂狗) */
ledInit();
/* ADC 电量检测 */
adcInit();
update_batter();
/* 网络模块初始化:仅使用 4G Air780E 模块 */
NET_init();
/* 启动各路串口接收 */
USART2_StartRx(); /* RS485 喂料秤 */
USART3_StartRx(); /* 4G MQTT 消息DMA+IDLE */
USART1_StartRx(); /* 蓝牙调试命令 */
}
void app_loop_init(void)
{
/* 网络连接成功后,才从 EEPROM 恢复继电器上次状态,防止模块离线时误动作 */
if (g_net_mqtt_ready) {
relayRestoreState();
}
}
void app_loop_process(void)
{
/* 记录 MQTT 首次就绪时刻 */
if (!mqtt_ready_recorded && g_net_mqtt_ready) {
mqtt_ready_recorded = 1;
mqtt_ready_tick = HAL_GetTick();
}
/* MQTT 首次就绪后上报一次完整状态 */
if (g_net_mqtt_ready && !mqtt_first_status_reported) {
mqtt_first_status_reported = 1;
relayStatueUpdata();
log_info("> Main: first status report after MQTT ready");
ota_confirm_tick = HAL_GetTick();
}
/* 更新联网指示灯 */
g_net_led_connected = g_net_mqtt_ready ? 1 : 0;
/* 首次发布成功后延迟 3s 再 OTA 确认 */
if (!ota_confirmed && g_net_mqtt_ready && g_net_first_publish_ok &&
(HAL_GetTick() - ota_confirm_tick) > 3000) {
if (ota_simulate_fail) {
if (!ota_fail_logged) {
ota_fail_logged = 1;
log_info("> OTA confirm skipped (simulate fail for rollback test)");
}
/* 不置位 ota_confirmed让 1 分钟健康超时触发复位 */
} else {
ota_confirmed = 1;
NET_ota_confirm();
log_info("> OTA confirmed (MQTT ready + first publish ok + 3s delay)");
}
}
/* MQTT 就绪后 1 分钟仍未首次 MPUB主动复位 */
if (!ota_confirmed && mqtt_ready_recorded &&
(HAL_GetTick() - mqtt_ready_tick) > OTA_HEALTH_TIMEOUT_MS) {
log_warn("> OTA health timeout: MQTT ready but no MPUB in 1min, reset");
W25Q64_OTA_IncTrial(); /* 软件复位 BL 不计次,这里自行消耗一次试错 */
HAL_Delay(100);
NVIC_SystemReset();
}
/* 蓝牙调试命令 */
process_usart1_command();
/* 继电器命令响应状态机 */
relayCmdProcess();
/* 延迟状态上报 */
if (relay_report_pending && (HAL_GetTick() - relay_report_tick) > 100) {
relay_report_pending = 0;
relayStatueUpdata();
}
/* 各模块轮询 */
NET_process();
update_batter();
feedScaleProcess();
activeEvents();
}
/* 后台任务切片:供长时间阻塞的 AT/OTA 流程在等待间隙调用。
* 只包含轮询式、可重入安全的任务;不调用 NET_process避免递归。 */
void app_bg_service(void)
{
static uint32_t bg_batt_tick = 0;
/* 长阻塞流程AT/OTA 等待)在等待间隙喂狗 */
IWDG_Feed();
/* 蓝牙调试命令 */
process_usart1_command();
/* 喂料秤轮询与投喂保护 */
feedScaleProcess();
/* LED 心跳/联网指示 */
activeEvents();
/* 电量 1s 节流更新 */
if (HAL_GetTick() - bg_batt_tick >= 1000) {
bg_batt_tick = HAL_GetTick();
update_batter();
}
}