P0/P1/P2功能实现:接入业务组合根(按键/LED/过零/配网/OTA),联动、11B定时、运行记录、灯泡寿命(DP3/DP4/DP25)、CBR0 VM、512分包

This commit is contained in:
2026-09-08 11:44:20 +08:00
parent 61821de0f8
commit 426bb8dab6
52 changed files with 6042 additions and 313 deletions
+156
View File
@@ -0,0 +1,156 @@
/******************************************************************************
* @file app_relay.c
* @brief 继电器:请求等过零执行;超时则关强断、开放弃
* @author cyWu <1917507415@qq.com>
* @date 2026.09.04
* @version V1.1.0
* @history
* - V1.1.0, 2026.09.04, cyWu, 去掉未使用计数,精简注释
* - V1.0.0, 2026.09.04, cyWu, 首次发布
******************************************************************************/
#include "system/includes.h"
#include "app_relay.h"
#include "bsp_hw.h"
#include "board_pin.h"
#include "jb_product.h"
#define LOG_TAG_CONST APP
#define LOG_TAG "[RELAY]"
#define LOG_INFO_ENABLE
#include "debug.h"
typedef struct {
uint8_t request; /**< 上层意图:0=关 1=开 */
uint8_t actual; /**< 过零后的 GPIO 真值 */
} AppRelayCtx_t;
static AppRelayCtx_t s_relay;
/**
* @brief 写继电器 GPIO 并更新 actual(过零 ISR / 超时路径)
* @param on 1=吸合 0=断开
* @return 无
*/
static void relay_apply(uint8_t on)
{
bsp_relay_set(on);
s_relay.actual = on;
}
/**
* @brief 初始化继电器:GPIO 上电默认关;P0 无 VM,请求=实际=关
* @return 无
*/
void app_relay_init(void)
{
s_relay.request = 0;
s_relay.actual = 0;
bsp_relay_set(0);
log_info("relay init, request=off actual=off\n");
}
/**
* @brief 请求加热开/关(手动/APP 写 DP0/定时/联动统一入口)
* @param on 1=开 0=关
* @return 无
*/
void app_relay_request(uint8_t on)
{
on = on ? 1 : 0;
if (on == s_relay.request) {
return; /* 意图没变:不重复发起(避免连续同向请求反复计超时) */
}
s_relay.request = on;
#if BOARD_ZC_ENABLE
if (on == s_relay.actual) {
/* 例如 PC3 已因超时强关(actual=0),收到关请求:无需等沿,直接同步 */
log_info("request %s but actual already %d, sync\n", on ? "ON" : "OFF",
s_relay.actual);
return;
}
log_info("request %s, wait zc edge\n", on ? "ON" : "OFF");
/* 等 app_zc_poll 计数 / bsp_zc 沿回调执行 */
#else
/* 无过零(调试):开不吸合,关立即强断(规格书 7.2 / 4 章) */
if (on) {
gDevData.fault_code = 2;
log_info("zc disabled: open request rejected, stay off\n");
s_relay.request = 0; /* 放弃开请求,回落到实际(不吸合) */
} else {
log_info("zc disabled: force relay off\n");
relay_apply(0);
}
#endif
}
/**
* @brief 过零沿:有 pending 则切 GPIO
* @note FPIN ISR 上下文,禁止 printf / 写 VM / 切 BLE
* @return 无
*/
void app_relay_zc_edge(void)
{
if (s_relay.request == s_relay.actual) {
return; /* 无 pending,仅记录过零(由 app_zc 管超时) */
}
relay_apply(s_relay.request);
/* 7.2:下一次成功过零切变后清设备故障(RAM 写,ISR 安全) */
gDevData.fault_code = 0;
}
/**
* @brief 过零超时:关则强断,开则放弃并保持关,fault_code=2
* @note 20ms 节拍调用;与 FPIN ISR 抢状态,关中断后复检
* @return 无
*/
void app_relay_zc_timeout(void)
{
local_irq_disable();
if (s_relay.request == s_relay.actual) {
local_irq_enable();
return;
}
gDevData.fault_code = 2;
if (s_relay.request) {
/* 开请求超时:禁止无过零吸合,放弃本次开请求,保持关 */
s_relay.request = 0;
s_relay.actual = 0;
bsp_relay_set(0);
} else {
/* 关请求超时:强制断开(安全路径,规格书 7.2) */
bsp_relay_set(0);
s_relay.actual = 0;
}
local_irq_enable();
}
/**
* @brief 当前请求态
* @return 1=请求开,0=请求关
*/
uint8_t app_relay_get_request(void)
{
return s_relay.request;
}
/**
* @brief 当前实际吸合态
* @return 1=已吸合,0=已断开
*/
uint8_t app_relay_get_actual(void)
{
return s_relay.actual;
}
/**
* @brief 是否已同步(无 pending
* @return 1=request==actual
*/
uint8_t app_relay_synced(void)
{
return (s_relay.request == s_relay.actual) ? 1 : 0;
}