喷淋器 P0 功能实现
This commit is contained in:
@@ -0,0 +1,208 @@
|
||||
/******************************************************************************
|
||||
* @file app_spray.c
|
||||
* @brief 喷淋作业引擎:一轮 = 单次时长 × 次数 + 间隔(规格书第 10 章)
|
||||
* @author cyWu <1917507415@qq.com>
|
||||
* @date 2026.09.09
|
||||
* @version V1.0.0
|
||||
* @history
|
||||
* - V1.0.0, 2026.09.09, cyWu, P0 首次发布(默认 10s×3 次+3s,只跑一轮)
|
||||
*
|
||||
* @note 本模块是**唯一切泵者**(规格书 7.2):键/DP/联动/计划都只请求
|
||||
* "开一轮 / 停"。20ms 节拍倒数,禁止阻塞 delay。间隔等待也算作业态
|
||||
* (DP1=1、绿灯继续闪),但泵已关、不记运行秒(P2 由 app_runrec 负责)。
|
||||
******************************************************************************/
|
||||
|
||||
#include "system/includes.h"
|
||||
#include "app_spray.h"
|
||||
#include "app_pump.h"
|
||||
#include "jb_product.h"
|
||||
#include "board_pin.h"
|
||||
|
||||
#define LOG_TAG_CONST APP
|
||||
#define LOG_TAG "[APP_SPRAY]"
|
||||
#define LOG_INFO_ENABLE
|
||||
#include "debug.h"
|
||||
|
||||
/** 作业阶段 */
|
||||
typedef enum {
|
||||
SPRAY_PHASE_PUMP_ON = 0, /**< 泵开段:倒数单次时长 */
|
||||
SPRAY_PHASE_WAIT /**< 间隔段:泵关,倒数间隔(仅 interval>0 出现) */
|
||||
} SprayPhase_t;
|
||||
|
||||
/** 模块状态:全程由 20ms 业务节拍(usr_timer_tick)驱动,无跨上下文竞争 */
|
||||
typedef struct {
|
||||
uint8_t initialized;
|
||||
uint8_t state; /**< 0=空闲,1=作业中 */
|
||||
uint8_t phase; /**< 当前段(SPRAY_PHASE_*) */
|
||||
uint16_t total_count; /**< 本轮总次数(来自 DP7) */
|
||||
uint16_t round; /**< 已完成的次数 */
|
||||
uint32_t dur_ms; /**< 单次时长 ms */
|
||||
uint32_t wait_ms; /**< 间隔 ms(0=中间不停泵) */
|
||||
uint32_t remain_ms; /**< 当前段剩余 ms */
|
||||
} SprayCtx_t;
|
||||
|
||||
static SprayCtx_t s_spray;
|
||||
|
||||
/**
|
||||
* @brief 从 gDevData.spray_config 解析本轮参数(非法回退默认)
|
||||
* @note DP7 布局(规格书 10.2):Byte0-1 时长 uint16 大端、Byte2 次数、
|
||||
* Byte3-4 间隔 uint16 大端。非法 = 时长 0 或次数 0。
|
||||
* @return 无
|
||||
*/
|
||||
static void spray_parse_cfg(void)
|
||||
{
|
||||
const uint8_t *p = gDevData.spray_config;
|
||||
uint16_t dur = (uint16_t)(((uint16_t)p[0] << 8) | p[1]);
|
||||
uint8_t cnt = p[2];
|
||||
uint16_t itv = (uint16_t)(((uint16_t)p[3] << 8) | p[4]);
|
||||
|
||||
if ((dur == 0) || (cnt == 0)) {
|
||||
/* 从未收到合法 DP7(P0 无 VM,理论上 userInit 已写默认,此处兜底) */
|
||||
dur = BOARD_SPRAY_DEFAULT_DUR_S;
|
||||
cnt = BOARD_SPRAY_DEFAULT_COUNT;
|
||||
itv = BOARD_SPRAY_DEFAULT_INTERVAL_S;
|
||||
log_info("dp7 invalid, use default %us x%u + %us\n",
|
||||
(unsigned)dur, (unsigned)cnt, (unsigned)itv);
|
||||
}
|
||||
|
||||
s_spray.dur_ms = (uint32_t)dur * 1000u;
|
||||
s_spray.wait_ms = (uint32_t)itv * 1000u;
|
||||
s_spray.total_count = cnt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 初始化作业引擎(泵保持关,参数待 start 时解析)
|
||||
* @return APP_SPRAY_OK=成功
|
||||
*/
|
||||
AppSpray_Ret_t app_spray_init(void)
|
||||
{
|
||||
if (s_spray.initialized) {
|
||||
return APP_SPRAY_OK;
|
||||
}
|
||||
#if BOARD_SPRAY_ENABLE
|
||||
app_pump_set(0); /* 上电绝不喷 */
|
||||
s_spray.state = 0;
|
||||
s_spray.phase = SPRAY_PHASE_PUMP_ON;
|
||||
s_spray.round = 0;
|
||||
s_spray.remain_ms = 0;
|
||||
s_spray.initialized = 1;
|
||||
#else
|
||||
log_info("spray disabled\n");
|
||||
#endif
|
||||
return APP_SPRAY_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 开一轮(幂等:作业中不重开)
|
||||
* @return 无
|
||||
*/
|
||||
void app_spray_start(void)
|
||||
{
|
||||
if (!s_spray.initialized) {
|
||||
return;
|
||||
}
|
||||
if (s_spray.state != 0) {
|
||||
return; /* 已在作业中:保持当前轮(规格书 10.5 幂等) */
|
||||
}
|
||||
|
||||
spray_parse_cfg();
|
||||
s_spray.round = 0;
|
||||
s_spray.phase = SPRAY_PHASE_PUMP_ON;
|
||||
s_spray.remain_ms = s_spray.dur_ms;
|
||||
s_spray.state = 1;
|
||||
app_pump_set(1); /* 两脚同时高 */
|
||||
log_info("spray start dur=%u ms x%u wait=%u ms\n",
|
||||
(unsigned)s_spray.dur_ms, (unsigned)s_spray.total_count,
|
||||
(unsigned)s_spray.wait_ms);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 停:立刻两脚拉低、结束作业
|
||||
* @return 无
|
||||
*/
|
||||
void app_spray_stop(void)
|
||||
{
|
||||
if (!s_spray.initialized) {
|
||||
return;
|
||||
}
|
||||
if (s_spray.state == 0) {
|
||||
return; /* 已空闲,保持关(幂等) */
|
||||
}
|
||||
app_pump_set(0); /* 两脚同时低 */
|
||||
s_spray.state = 0;
|
||||
s_spray.round = 0;
|
||||
s_spray.remain_ms = 0;
|
||||
log_info("spray stop\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 作业节拍:段倒数与切泵(20ms 调用)
|
||||
* @param dt 距上次调用的毫秒数
|
||||
* @return 无
|
||||
*/
|
||||
void app_spray_poll(uint16_t dt)
|
||||
{
|
||||
if (!s_spray.initialized || (s_spray.state == 0)) {
|
||||
return;
|
||||
}
|
||||
if (dt == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (s_spray.phase == SPRAY_PHASE_PUMP_ON) {
|
||||
/* 泵开段倒数 */
|
||||
if (s_spray.remain_ms <= dt) {
|
||||
s_spray.round++;
|
||||
if (s_spray.round >= s_spray.total_count) {
|
||||
/* 次数用尽:作业自然结束,泵关 */
|
||||
app_pump_set(0);
|
||||
s_spray.state = 0;
|
||||
s_spray.remain_ms = 0;
|
||||
log_info("spray round done, pump off\n");
|
||||
return;
|
||||
}
|
||||
if (s_spray.wait_ms > 0) {
|
||||
/* 进入间隔段:泵关等待 */
|
||||
s_spray.phase = SPRAY_PHASE_WAIT;
|
||||
s_spray.remain_ms = s_spray.wait_ms;
|
||||
app_pump_set(0);
|
||||
} else {
|
||||
/* 间隔=0:不停泵,马上喷下一次 */
|
||||
s_spray.remain_ms = s_spray.dur_ms;
|
||||
}
|
||||
} else {
|
||||
s_spray.remain_ms -= dt;
|
||||
}
|
||||
} else {
|
||||
/* 间隔段倒数 */
|
||||
if (s_spray.remain_ms <= dt) {
|
||||
s_spray.phase = SPRAY_PHASE_PUMP_ON;
|
||||
s_spray.remain_ms = s_spray.dur_ms;
|
||||
app_pump_set(1); /* 两脚同时高 */
|
||||
} else {
|
||||
s_spray.remain_ms -= dt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 查询是否处于作业态(含间隔等待,整轮期间为 1)
|
||||
* @return 1=作业中,0=空闲
|
||||
*/
|
||||
uint8_t app_spray_is_running(void)
|
||||
{
|
||||
#if BOARD_SPRAY_ENABLE
|
||||
return (uint8_t)(s_spray.state != 0);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 查询模块是否已初始化
|
||||
* @return APP_SPRAY_OK=已初始化,APP_SPRAY_ERR_NOT_INIT=未初始化
|
||||
*/
|
||||
AppSpray_Ret_t app_spray_get_status(void)
|
||||
{
|
||||
return s_spray.initialized ? APP_SPRAY_OK : APP_SPRAY_ERR_NOT_INIT;
|
||||
}
|
||||
Reference in New Issue
Block a user