P0/P1/P2功能实现:接入业务组合根(按键/LED/过零/配网/OTA),联动、11B定时、运行记录、灯泡寿命(DP3/DP4/DP25)、CBR0 VM、512分包
This commit is contained in:
@@ -0,0 +1,207 @@
|
||||
/******************************************************************************
|
||||
* @file app_light_life.c
|
||||
* @brief 灯泡剩余寿命(规格书 13.2 节):实际吸合扣秒 / DP4 复位 /
|
||||
* 到期告警 / DP3 60s 节流上报 / 边沿立刻落盘
|
||||
* @author cyWu <1917507415@qq.com>
|
||||
* @date 2026.09.08
|
||||
* @version V1.0.0
|
||||
*
|
||||
* @note 扣秒与运行记录同口径:只看 app_relay_get_actual()==1(过零后已吸合)。
|
||||
* 上下文分工(避免 ISR 写 VM / 切 BLE):
|
||||
* - tick(20ms ISR):只折秒到 s_life.remain,标记 need_sync /
|
||||
* need_edge(到期),不碰 gDevData / flash。
|
||||
* - loop(500ms 任务):60s 节流同步 gDevData.lighe_remain_time;
|
||||
* 边沿立刻同步 + 推导 gDevData.alarm_code + 立刻落盘。
|
||||
* BOARD_LIGHT_LIFE_ENABLE=0:不扣秒、不置到期告警;DP3 走 VM/默认
|
||||
* 值原样上报(规格书 0.4 条)。
|
||||
******************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "system/includes.h" /* local_irq_disable / local_irq_enable */
|
||||
#include "app_light_life.h"
|
||||
#include "app_relay.h"
|
||||
#include "app_nvm.h"
|
||||
#include "jb_product.h"
|
||||
#include "board_pin.h"
|
||||
|
||||
#define LOG_TAG_CONST APP
|
||||
#define LOG_TAG "[LIGHT]"
|
||||
#define LOG_INFO_ENABLE
|
||||
#include "debug.h"
|
||||
|
||||
/** 剩余寿命运行上下文 */
|
||||
typedef struct {
|
||||
volatile uint32_t remain; /**< 权威剩余寿命秒(ISR 扣减,任务读) */
|
||||
volatile uint16_t ms; /**< 不足 1 秒的毫秒零头(仅 ISR) */
|
||||
volatile uint16_t since_sync; /**< 距上次同步 gDevData 的秒数(60s 节流) */
|
||||
volatile uint32_t since_save; /**< 距上次落盘的累计运行秒(600s 节奏) */
|
||||
volatile uint8_t need_sync; /**< 1=ISR 要求任务同步 gDevData(60s 到点) */
|
||||
volatile uint8_t need_edge; /**< 1=边沿(到期)需立刻同步 + 落盘 */
|
||||
} LightLifeCtx_t;
|
||||
|
||||
static LightLifeCtx_t s_life;
|
||||
|
||||
#if BOARD_LIGHT_LIFE_ENABLE
|
||||
/**
|
||||
* @brief 按当前 remain 推导告警并同步 gDevData(任务上下文)
|
||||
* @param immediate 1=边沿立刻落盘;0=仅同步(60s 节流点,落盘随 600s)
|
||||
* @return 无
|
||||
*/
|
||||
static void life_sync_gdata(uint8_t immediate)
|
||||
{
|
||||
gDevData.lighe_remain_time = s_life.remain;
|
||||
gDevData.alarm_code = (s_life.remain == 0) ? 1 : 0;
|
||||
|
||||
if (immediate) {
|
||||
app_nvm_save_runrec(); /* 寿命随 runrec item 落盘(规格书 13.2 边沿) */
|
||||
s_life.since_save = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief 初始化剩余寿命:默认额定值(VM 有效时 app_nvm_load 会覆盖)
|
||||
* @return 无
|
||||
*/
|
||||
void app_light_life_init(void)
|
||||
{
|
||||
#if !BOARD_LIGHT_LIFE_ENABLE
|
||||
log_info("light life disabled\n");
|
||||
return;
|
||||
#else
|
||||
memset(&s_life, 0, sizeof(s_life));
|
||||
s_life.remain = BOARD_LIGHT_RATED_SEC;
|
||||
/* 首上电(VM 无效)DP3 即额定值、DP25=0(规格书 17 章 P1 末条);
|
||||
* VM 有效时 app_nvm_load 会再调 set_remain 覆盖 */
|
||||
gDevData.lighe_remain_time = BOARD_LIGHT_RATED_SEC;
|
||||
gDevData.alarm_code = 0;
|
||||
log_info("light life init, remain=%lu\n", (unsigned long)s_life.remain);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 20ms 业务节拍:实际吸合才扣秒(与运行记录同口径)
|
||||
* @param dt 距上次调用的毫秒数
|
||||
* @return 无
|
||||
*/
|
||||
void app_light_life_tick(uint16_t dt)
|
||||
{
|
||||
#if !BOARD_LIGHT_LIFE_ENABLE
|
||||
(void)dt;
|
||||
return;
|
||||
#else
|
||||
if (!app_relay_get_actual()) {
|
||||
s_life.ms = 0; /* 没在点灯:丢弃不足 1 秒的零头(13.2 同口径) */
|
||||
return;
|
||||
}
|
||||
if (s_life.remain == 0) {
|
||||
return; /* 已到期:停在 0,不回绕 */
|
||||
}
|
||||
|
||||
s_life.ms = (uint16_t)(s_life.ms + dt);
|
||||
while (s_life.ms >= 1000u) {
|
||||
s_life.ms = (uint16_t)(s_life.ms - 1000u);
|
||||
s_life.remain--;
|
||||
s_life.since_sync++;
|
||||
s_life.since_save++;
|
||||
if (s_life.remain == 0) {
|
||||
s_life.need_edge = 1; /* 到期边沿:任务立刻同步 + 落盘 + 上报 */
|
||||
}
|
||||
}
|
||||
|
||||
/* 60s 节流:点灯且未到期时满 60s 才允许同步一次 DP3(规格书 13.2) */
|
||||
if ((s_life.since_sync >= BOARD_LIGHT_REPORT_MS / 1000u) && !s_life.need_edge) {
|
||||
s_life.since_sync = 0;
|
||||
s_life.need_sync = 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 500ms 任务上下文:节流同步 / 边沿立刻同步 + 落盘
|
||||
* @return 无
|
||||
*/
|
||||
void app_light_life_loop(void)
|
||||
{
|
||||
#if !BOARD_LIGHT_LIFE_ENABLE
|
||||
return;
|
||||
#else
|
||||
uint8_t edge;
|
||||
uint8_t sync;
|
||||
|
||||
local_irq_disable();
|
||||
edge = s_life.need_edge;
|
||||
sync = s_life.need_sync;
|
||||
s_life.need_edge = 0;
|
||||
s_life.need_sync = 0;
|
||||
local_irq_enable();
|
||||
|
||||
if (edge) {
|
||||
life_sync_gdata(1);
|
||||
log_info("life expired, remain=0 alarm=1\n");
|
||||
return;
|
||||
}
|
||||
if (sync) {
|
||||
life_sync_gdata(0); /* 60s 节流点:只同步,flash 随 600s */
|
||||
}
|
||||
|
||||
/* 平时落盘节奏:累计点灯满 600s 写一次(与运行记录同次可接受误差) */
|
||||
if (s_life.since_save >= BOARD_RUN_RECORD_SAVE_SEC) {
|
||||
s_life.since_save = 0;
|
||||
app_nvm_save_runrec();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置剩余寿命(APP 写 DP3 / VM 恢复 / 出厂复位,任务上下文)
|
||||
* @param remain 剩余寿命秒,0~0xFFFFFFFF 不封顶
|
||||
* @return 无
|
||||
*/
|
||||
void app_light_life_set_remain(uint32_t remain)
|
||||
{
|
||||
#if BOARD_LIGHT_LIFE_ENABLE
|
||||
local_irq_disable();
|
||||
s_life.remain = remain;
|
||||
s_life.since_sync = 0;
|
||||
s_life.ms = 0;
|
||||
local_irq_enable();
|
||||
|
||||
/* 边沿立刻生效:同步 gDevData + 推导告警 + 立刻落盘 */
|
||||
gDevData.lighe_remain_time = remain;
|
||||
gDevData.alarm_code = (remain == 0) ? 1 : 0;
|
||||
app_nvm_save_runrec();
|
||||
s_life.since_save = 0;
|
||||
log_info("life set remain=%lu alarm=%d\n", (unsigned long)remain, gDevData.alarm_code);
|
||||
#else
|
||||
/* 模块关闭:仅按值回填(VM/默认原样上报,不扣秒不置告警,规格书 0.4) */
|
||||
gDevData.lighe_remain_time = remain;
|
||||
if (remain == 0) {
|
||||
gDevData.alarm_code = 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 灯泡复位(DP4 写 1 / 出厂复位):回额定值、告警清 0
|
||||
* @return 无
|
||||
*/
|
||||
void app_light_life_reset(void)
|
||||
{
|
||||
app_light_life_set_remain(BOARD_LIGHT_RATED_SEC);
|
||||
log_info("light reset to rated %lu\n", (unsigned long)BOARD_LIGHT_RATED_SEC);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 查询剩余寿命
|
||||
* @return 剩余寿命秒
|
||||
*/
|
||||
uint32_t app_light_life_get_remain(void)
|
||||
{
|
||||
#if !BOARD_LIGHT_LIFE_ENABLE
|
||||
return gDevData.lighe_remain_time; /* 关闭时按上报值原样返回 */
|
||||
#else
|
||||
return s_life.remain;
|
||||
#endif
|
||||
}
|
||||
Reference in New Issue
Block a user