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

187 lines
5.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.10 *");
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 优先,无 SIM 卡时自动切换到 WiFi(ESP-01S) */
NET_init();
/* 启动各路串口接收 */
USART2_StartRx(); /* RS485 喂料秤 */
USART3_StartRx(); /* 4G MQTT 消息DMA+IDLE */
USART1_StartRx(); /* 蓝牙调试命令 */
}
void app_loop_init(void)
{
/* 继电器断电记忆恢复挪到 app_loop_process 的"MQTT 首次就绪"分支执行:
* 无 SIM 走 WiFi 兜底时联网要等约 2 分钟,这里若按开机瞬时状态判断会永远等不到 */
}
void app_loop_process(void)
{
/* 记录 MQTT 首次就绪时刻 */
if (!mqtt_ready_recorded && g_net_mqtt_ready) {
mqtt_ready_recorded = 1;
mqtt_ready_tick = HAL_GetTick();
}
/* MQTT 首次就绪后:先按 EEPROM 恢复继电器上次状态(断电记忆),
* 再上报一次完整状态,让平台刷新为真实状态 */
if (g_net_mqtt_ready && !mqtt_first_status_reported) {
mqtt_first_status_reported = 1;
relayRestoreState();
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();
/* 运行时长心跳:每 30s 串口输出一次(天/时/分),
* 64 位累计HAL_GetTick 约 49 天回绕也不受影响 */
{
static uint32_t up_last = 0;
static uint32_t up_print = 0;
static uint64_t up_ms = 0;
uint32_t now = HAL_GetTick();
up_ms += (uint32_t)(now - up_last); /* 32位差值天然容忍回绕 */
up_last = now;
if (now - up_print >= 30000) {
up_print = now;
uint32_t mins = (uint32_t)(up_ms / 60000);
log_info("> Uptime: %uday--%02uh--%02um\r\n",
(unsigned)(mins / 1440),
(unsigned)((mins % 1440) / 60),
(unsigned)(mins % 60));
}
}
}
/* 后台任务切片:供长时间阻塞的 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();
}
}