#include "auto_ctrl_thresholds.h" #include "freertos/FreeRTOS.h" #include "esp_check.h" // 默认土壤湿度低于此百分比时启动水泵(单位:%) #define DEFAULT_PUMP_ON_SOIL_BELOW_PCT 35.0f // 默认土壤湿度高于此百分比时关闭水泵(单位:%) #define DEFAULT_PUMP_OFF_SOIL_ABOVE_PCT 45.0f // 默认光照强度低于此值时开启补光灯(单位:lux) #define DEFAULT_LIGHT_ON_LUX_BELOW 200.0f // 默认光照强度高于此值时关闭补光灯(单位:lux) #define DEFAULT_LIGHT_OFF_LUX_ABOVE 350.0f // 用于保护阈值数据的自旋锁(临界区) static portMUX_TYPE s_thresholds_lock = portMUX_INITIALIZER_UNLOCKED; // 全局阈值配置结构体,初始化为默认值 static auto_ctrl_thresholds_t s_thresholds = { .pump_on_soil_below_pct = DEFAULT_PUMP_ON_SOIL_BELOW_PCT, .pump_off_soil_above_pct = DEFAULT_PUMP_OFF_SOIL_ABOVE_PCT, .light_on_lux_below = DEFAULT_LIGHT_ON_LUX_BELOW, .light_off_lux_above = DEFAULT_LIGHT_OFF_LUX_ABOVE, }; /** * @brief 验证自动控制阈值配置的有效性 * * 检查指针非空、数值范围合法、启停阈值满足 on < off 等条件。 * * @param cfg 待验证的阈值配置指针 * @return esp_err_t 验证结果,ESP_OK 表示有效 */ static esp_err_t auto_ctrl_thresholds_validate(const auto_ctrl_thresholds_t *cfg) { ESP_RETURN_ON_FALSE(cfg != NULL, ESP_ERR_INVALID_ARG, "auto_ctrl_thresholds", "cfg is null"); ESP_RETURN_ON_FALSE(cfg->pump_on_soil_below_pct >= 0.0f && cfg->pump_on_soil_below_pct <= 100.0f, ESP_ERR_INVALID_ARG, "auto_ctrl_thresholds", "pump_on_soil_below_pct out of range"); ESP_RETURN_ON_FALSE(cfg->pump_off_soil_above_pct >= 0.0f && cfg->pump_off_soil_above_pct <= 100.0f, ESP_ERR_INVALID_ARG, "auto_ctrl_thresholds", "pump_off_soil_above_pct out of range"); ESP_RETURN_ON_FALSE(cfg->pump_on_soil_below_pct < cfg->pump_off_soil_above_pct, ESP_ERR_INVALID_ARG, "auto_ctrl_thresholds", "pump thresholds must satisfy on < off"); ESP_RETURN_ON_FALSE(cfg->light_on_lux_below >= 0.0f, ESP_ERR_INVALID_ARG, "auto_ctrl_thresholds", "light_on_lux_below out of range"); ESP_RETURN_ON_FALSE(cfg->light_off_lux_above >= 0.0f, ESP_ERR_INVALID_ARG, "auto_ctrl_thresholds", "light_off_lux_above out of range"); ESP_RETURN_ON_FALSE(cfg->light_on_lux_below < cfg->light_off_lux_above, ESP_ERR_INVALID_ARG, "auto_ctrl_thresholds", "light thresholds must satisfy on < off"); return ESP_OK; } /** * @brief 初始化阈值为默认值 * * 将全局阈值结构体重置为预设的默认配置。 */ void auto_ctrl_thresholds_init_defaults(void) { const auto_ctrl_thresholds_t defaults = { .pump_on_soil_below_pct = DEFAULT_PUMP_ON_SOIL_BELOW_PCT, .pump_off_soil_above_pct = DEFAULT_PUMP_OFF_SOIL_ABOVE_PCT, .light_on_lux_below = DEFAULT_LIGHT_ON_LUX_BELOW, .light_off_lux_above = DEFAULT_LIGHT_OFF_LUX_ABOVE, }; taskENTER_CRITICAL(&s_thresholds_lock); s_thresholds = defaults; taskEXIT_CRITICAL(&s_thresholds_lock); } /** * @brief 获取当前阈值配置 * * 安全地复制当前阈值到输出参数中。 * * @param out 输出参数,指向接收阈值的结构体 */ void auto_ctrl_thresholds_get(auto_ctrl_thresholds_t *out) { if (out == NULL) { return; } taskENTER_CRITICAL(&s_thresholds_lock); *out = s_thresholds; taskEXIT_CRITICAL(&s_thresholds_lock); } /** * @brief 设置新的阈值配置 * * 验证输入配置有效性后,安全更新全局阈值。 * * @param cfg 新的阈值配置指针 * @return esp_err_t 设置结果,ESP_OK 表示成功 */ esp_err_t auto_ctrl_thresholds_set(const auto_ctrl_thresholds_t *cfg) { ESP_RETURN_ON_ERROR(auto_ctrl_thresholds_validate(cfg), "auto_ctrl_thresholds", "invalid thresholds"); taskENTER_CRITICAL(&s_thresholds_lock); s_thresholds = *cfg; taskEXIT_CRITICAL(&s_thresholds_lock); return ESP_OK; } /** * @brief 通过独立参数设置阈值 * * 提供一种更便捷的阈值设置方式,内部封装为结构体后调用 set 接口。 * * @param pump_on_soil_below_pct 水泵启动土壤湿度阈值(%) * @param pump_off_soil_above_pct 水泵关闭土壤湿度阈值(%) * @param light_on_lux_below 补光灯开启光照阈值(lux) * @param light_off_lux_above 补光灯关闭光照阈值(lux) * @return esp_err_t 设置结果 */ esp_err_t auto_ctrl_thresholds_set_values(float pump_on_soil_below_pct, float pump_off_soil_above_pct, float light_on_lux_below, float light_off_lux_above) { const auto_ctrl_thresholds_t cfg = { .pump_on_soil_below_pct = pump_on_soil_below_pct, .pump_off_soil_above_pct = pump_off_soil_above_pct, .light_on_lux_below = light_on_lux_below, .light_off_lux_above = light_off_lux_above, }; return auto_ctrl_thresholds_set(&cfg); }