LPT26x-HSF-4MB-Hilink_14.2..../application/ws63/user_main/spotlight/spotlight_main.c

1267 lines
42 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.

#include "hsf.h"
#include "hfconfig.h"
#if defined(CONFIG_PWM_SUPPORT_LPM)
#include "pm_veto.h"
#endif
#include "pinctrl.h"
#include "gpio.h"
#include "pinctrl.h"
#include "pwm.h"
#include "timer.h"
#include "soc_osal.h"
#include "systick.h"
// #include "tcxo.h"
#include "spotlight.h"
// 函数前向声明
static void init_timer_system(void);
static void init_fade_ctx(void);
static void init_breath_ctx(void);
static void stop_fade_task(void);
static void stop_breath_task(void);
static void stop_breath_timer(void);
static void stop_spotlight_main_task(void);
static void check_net_cfg_timeout(void);
static void check_net_cfg_power_on_keep_time(void);
static void set_light2breathtimeout(void);
static void set_light2net_cfg_done(void);
static void start_breath_timer(void);
void calculate_pwm_duty(void);
void update_pwm_output(void);
// 定义上报函数类型
typedef void (*report_func_t)(void);
static void start_report_task(report_func_t report_func);
static void report_fade_complete_status(void);
static uint32_t calculate_checksum(const device_data_t* data);
static bool write_device_data_to_addr(uint32_t addr, const device_data_t* data);;
static void report_device_online_status(void);
#define BRIGHTNESS_PIN GPIO_04 // 冷白LED (CW)
#define CCT_PIN GPIO_00 // 暖白LED (WW)
#define SWITCH_PIN GPIO_13
#define CONFIG_PWM_GROUP_ID 2
#define OPEN_LIGHT GPIO_LEVEL_HIGH
#define CLOSE_LIGHT GPIO_LEVEL_LOW
// 状态上报任务相关变量
#define REPORT_TASK_PRIO 80
#define REPORT_TASK_STACK_SIZE 0x1000
static osal_task *report_task_handle = NULL;
static bool report_task_running = false; // 添加任务运行状态标志
// 灯渐变任务相关定义
#define FADE_TASK_PRIO 80
#define FADE_TASK_STACK_SIZE 0x1000
// 呼吸灯任务相关定义
#define BREATH_TASK_PRIO 80
#define BREATH_TASK_STACK_SIZE 0x1000
// PWM频率和周期定义
#define PWM_FREQUENCY 2000 // PWM频率 2KHz
static uint32_t pwm_period_cnt = 0; // PWM周期 40us
static uint8_t channel_id_cw = 0; // 冷白LED通道ID
static uint8_t channel_id_ww = 0; // 暖白LED通道ID
void save_device_data(void);
void read_device_data(void);
void req_save_device_data(void);
static void stop_breath_timer(void);
device_control_t g_device_control = DEFAULT_DEVICE_DATA;
// 配网状态定义
typedef enum {
NET_CFG_IDLE = 0, // 空闲状态
NET_CFG_BREATHING, // 呼吸灯状态,配网中
NET_CFG_TIMEOUT, // 超时状态
} net_cfg_state_e;
// 配网状态相关变量
static net_cfg_state_e g_net_breath_state = NET_CFG_IDLE; // 配网状态
static uint64_t g_net_cfg_start_time = 0; // 配网开始时间
// 保存任务相关变量
static osal_task *save_task_handle = NULL;
static bool save_task_running = false;
static osal_semaphore save_data_sem;
// 打印频率限制相关定义
#define PRINT_INTERVAL_MS 1000 // 最小打印间隔(ms)
typedef struct {
uint64_t last_print_time; // 上次打印时间
const char *prefix; // 打印前缀
} print_limiter_t;
// 渐变控制相关变量
static struct {
// 渐变控制参数
int32_t target_brightness;
int32_t target_cct;
int32_t current_brightness;
int32_t current_cct;
int32_t step_brightness;
int32_t step_cct;
bool is_fading;
bool fade_completed;
uint32_t smooth_time_us; // 渐变总时长(us)
uint32_t update_interval; // 更新间隔(us)
// 任务相关
osal_task *task_handle;
bool task_running;
osal_semaphore sem;
timer_handle_t timer_handle;
// 打印限制器
print_limiter_t print_limiter;
} fade_ctx = {0};
// 呼吸灯控制相关变量
static struct {
// 呼吸灯控制参数
int32_t duty;
int32_t step;
uint32_t update_interval; // 更新间隔(us)
bool is_initial_breath; // 是否是初始3秒呼吸
// 任务相关
osal_task *task_handle;
bool task_running;
osal_semaphore sem;
timer_handle_t timer_handle;
uint32_t start_time_ms;
uint32_t breath_cnt;
// 打印限制器
print_limiter_t print_limiter;
} breath_ctx = {0};
print_limiter_t pwm_limiter = {
.last_print_time = 0,
.prefix = "[pwm]",
};
// 定时器初始化标志
static bool timer_initialized = false;
// 初始化定时器系统
static void init_timer_system(void)
{
if (!timer_initialized) {
uapi_timer_init();
int ret = uapi_timer_adapter(TIMER_INDEX_1, TIMER_1_IRQN, 1);
if (ret != 0) {
e_printf("定时器适配器初始化失败\r\n");
return;
}
timer_initialized = true;
}
}
// 初始化打印限制器
static void init_print_limiter(print_limiter_t *limiter, const char *prefix)
{
limiter->last_print_time = 0;
limiter->prefix = prefix;
}
// 带频率限制的打印函数
static bool should_print(print_limiter_t *limiter)
{
uint64_t current_time = uapi_systick_get_ms();
if (current_time - limiter->last_print_time >= PRINT_INTERVAL_MS) {
limiter->last_print_time = current_time;
return true;
}
return false;
}
// 渐变灯任务函数
static void *fade_task(const char *arg)
{
unused(arg);
e_printf("[fade_task] Task started\r\n");
while (fade_ctx.task_running) {
// 等待渐变信号
if (osal_sem_down_timeout(&fade_ctx.sem, 100*1000) != OSAL_SUCCESS) {
continue;
}
if (!fade_ctx.is_fading) {
continue;
}
// 使用打印限制器控制打印频率
if (should_print(&fade_ctx.print_limiter)) {
e_printf("%s Brightness: curr:%d, target:%d, step:%d, cct:curr:%d, target:%d, step:%d\r\n",
fade_ctx.print_limiter.prefix,
fade_ctx.current_brightness, fade_ctx.target_brightness, fade_ctx.step_brightness,
fade_ctx.current_cct, fade_ctx.target_cct,fade_ctx.step_cct);
}
// 检查是否达到目标值
bool brightness_reached = (fade_ctx.step_brightness > 0) ?
(fade_ctx.current_brightness >= fade_ctx.target_brightness) :
(fade_ctx.current_brightness <= fade_ctx.target_brightness);
bool cct_reached = (fade_ctx.step_cct > 0) ?
(fade_ctx.current_cct >= fade_ctx.target_cct) :
(fade_ctx.current_cct <= fade_ctx.target_cct);
// 更新当前值
if (!brightness_reached)
{
fade_ctx.current_brightness += fade_ctx.step_brightness;
}
if (!cct_reached)
{
fade_ctx.current_cct += fade_ctx.step_cct;
}
// 如果达到目标值,停止渐变
if (brightness_reached && cct_reached) {
e_printf("[fade_task] Fade completed, Final brightness: %d, CCT: %d\r\n",
fade_ctx.target_brightness,
fade_ctx.target_cct);
fade_ctx.is_fading = false;
fade_ctx.fade_completed = true;
fade_ctx.current_brightness = fade_ctx.target_brightness;
fade_ctx.current_cct = fade_ctx.target_cct;
uapi_timer_stop(fade_ctx.timer_handle);
}
BRIGHTNESS_LITME_RANGE(fade_ctx.current_brightness);
CCT_LITME_RANGE(fade_ctx.current_cct);
// 更新PWM输出
g_device_control.brightness_local = fade_ctx.current_brightness;
g_device_control.cct_local = fade_ctx.current_cct;
calculate_pwm_duty();
update_pwm_output();
if (fade_ctx.fade_completed) {
fade_ctx.fade_completed = false;
e_printf("[fade_task] Status report: local brightness=%d, CCT=%d\r\n",
g_device_control.brightness_local,
g_device_control.cct_local);
// 启动状态上报任务,使用渐变完成状态上报函数
start_report_task(report_device_online_status);
req_save_device_data();
}
}
e_printf("[fade_task] Task exited\r\n");
return NULL;
}
// 呼吸灯任务函数
static void *breath_task(const char *arg)
{
unused(arg);
e_printf("[breath_task] Task started\r\n");
while (breath_ctx.task_running) {
// 等待呼吸信号
if (osal_sem_down_timeout(&breath_ctx.sem, 100*1000) != OSAL_SUCCESS) {
continue;
}
if (g_net_breath_state != NET_CFG_BREATHING) {
continue;
}
// 检查是否超过呼吸灯持续时间
uint32_t current_time = uapi_systick_get_ms();
uint32_t elapsed_time = current_time - g_net_cfg_start_time;
if (elapsed_time >= NET_CFG_BREATH_DURATION) {
set_light2breathtimeout();
stop_breath_timer();
continue;
}
// 检查是否需要改变方向
if (breath_ctx.duty >= BRIGHTNESS_LOCAL_MAX) {
breath_ctx.duty = BRIGHTNESS_LOCAL_MAX;
breath_ctx.step = -1 * breath_ctx.step;
e_printf("%s breathing %d, down %dms\n", breath_ctx.print_limiter.prefix, breath_ctx.breath_cnt, uapi_systick_get_ms() - breath_ctx.start_time_ms);
} else if (breath_ctx.duty <= 0) {
breath_ctx.duty = 0;
breath_ctx.step = -1 * breath_ctx.step;
e_printf("%s breathing %d, up %dms\n", breath_ctx.print_limiter.prefix, breath_ctx.breath_cnt, uapi_systick_get_ms() - breath_ctx.start_time_ms);
}
// 更新亮度
breath_ctx.duty += breath_ctx.step;
int32_t brightness_pwm = breath_ctx.duty;
// 设置黄白灯交替呼吸
g_device_control.duty_ww = brightness_pwm;
g_device_control.duty_cw = PWM_DUTY_RATIO_MAX - brightness_pwm;
update_pwm_output();
}
e_printf("[breath_task] Task exited\r\n");
return NULL;
}
// 渐变定时器回调函数
static void fade_timer_callback(uintptr_t data)
{
osal_sem_up(&fade_ctx.sem);
uapi_timer_start(fade_ctx.timer_handle, fade_ctx.update_interval, fade_timer_callback, 0);
}
// 呼吸灯定时器回调函数
static void breath_timer_callback(uintptr_t data)
{
osal_sem_up(&breath_ctx.sem);
uapi_timer_start(breath_ctx.timer_handle, breath_ctx.update_interval, breath_timer_callback, 0);
}
// 初始化渐变控制
static void init_fade_ctx(void)
{
init_timer_system();
int ret = uapi_timer_create(TIMER_INDEX_1, &fade_ctx.timer_handle);
if (ret != 0) {
e_printf("渐变定时器创建失败\r\n");
}
// 初始化信号量
if (osal_sem_init(&fade_ctx.sem, 0) != OSAL_SUCCESS) {
e_printf("[init_fade_ctx] Failed to init semaphore\n");
return;
}
// 初始化打印限制器
init_print_limiter(&fade_ctx.print_limiter, "[fade_task]");
// 创建渐变任务
osal_kthread_lock();
fade_ctx.task_handle = osal_kthread_create((osal_kthread_handler)fade_task, NULL, "FadeTask",
FADE_TASK_STACK_SIZE);
if (fade_ctx.task_handle != NULL) {
fade_ctx.task_running = true;
osal_kthread_set_priority(fade_ctx.task_handle, FADE_TASK_PRIO);
e_printf("[init_fade_ctx] Fade task created successfully\n");
} else {
e_printf("[init_fade_ctx] Failed to create fade task\n");
osal_sem_destroy(&fade_ctx.sem);
}
osal_kthread_unlock();
// 设置默认更新间隔
fade_ctx.update_interval = FADE_INTERVAL_MIN;
}
// 初始化呼吸灯控制
static void init_breath_ctx(void)
{
init_timer_system();
int ret = uapi_timer_create(TIMER_INDEX_1, &breath_ctx.timer_handle);
if (ret != 0) {
e_printf("呼吸灯定时器创建失败\r\n");
}
// 初始化信号量
if (osal_sem_init(&breath_ctx.sem, 0) != OSAL_SUCCESS) {
e_printf("[init_breath_ctx] Failed to init semaphore\n");
return;
}
// 初始化打印限制器
init_print_limiter(&breath_ctx.print_limiter, "[breath_task]");
breath_ctx.duty = g_device_control.brightness_local;
breath_ctx.step = BREARTH_STEP == 0 ? 1 : BREARTH_STEP;
breath_ctx.update_interval = BREARTH_INTERVAL;
breath_ctx.is_initial_breath = true;
breath_ctx.start_time_ms = uapi_systick_get_ms();
e_printf("Breath task: brightness=%d, step=%d, update_interval=%d, is_initial_breath=%d\n",
breath_ctx.duty, breath_ctx.step, breath_ctx.update_interval, breath_ctx.is_initial_breath);
// 创建呼吸灯任务
osal_kthread_lock();
breath_ctx.task_handle = osal_kthread_create((osal_kthread_handler)breath_task, NULL, "BreathTask",
BREATH_TASK_STACK_SIZE);
if (breath_ctx.task_handle != NULL) {
breath_ctx.task_running = true;
osal_kthread_set_priority(breath_ctx.task_handle, BREATH_TASK_PRIO);
e_printf("[init_breath_ctx] Breath task created successfully\n");
} else {
e_printf("[init_breath_ctx] Failed to create breath task\n");
osal_sem_destroy(&breath_ctx.sem);
}
osal_kthread_unlock();
}
// 停止渐变任务
static void stop_fade_task(void)
{
if (fade_ctx.task_handle == NULL) {
return;
}
fade_ctx.task_running = false;
osal_sem_up(&fade_ctx.sem); // 唤醒任务以使其退出
osal_kthread_lock();
osal_kthread_destroy(fade_ctx.task_handle, 0);
fade_ctx.task_handle = NULL;
osal_kthread_unlock();
osal_sem_destroy(&fade_ctx.sem);
e_printf("[stop_fade_task] Fade task stopped\n");
}
// 停止呼吸灯任务
static void stop_breath_task(void)
{
if (breath_ctx.task_handle == NULL) {
return;
}
breath_ctx.task_running = false;
osal_sem_up(&breath_ctx.sem); // 唤醒任务以使其退出
osal_kthread_lock();
osal_kthread_destroy(breath_ctx.task_handle, 0);
breath_ctx.task_handle = NULL;
osal_kthread_unlock();
osal_sem_destroy(&breath_ctx.sem);
e_printf("[stop_breath_task] Breath task stopped\n");
}
// 修改stop_breath_timer函数
static void stop_breath_timer(void)
{
uapi_timer_stop(breath_ctx.timer_handle);
uapi_timer_delete(breath_ctx.timer_handle);
stop_breath_task();
}
// 计算PWM占空比
void calculate_pwm_duty(void)
{ // 如果开关关闭则占空比为0
uint32_t total_brightness_pwm = g_device_control.brightness_local;
// 计算色温比例 (0-10000)
uint16_t cct_ratio = ((g_device_control.cct_local - CCT_LOCAL_MIN) * 10000) / CCT_RANGE;
// 根据色温比例计算CW和WW的占空比
// 总亮度保持不变只调整CW和WW的比例
g_device_control.duty_cw = (total_brightness_pwm * cct_ratio) / 10000;
g_device_control.duty_ww = total_brightness_pwm - g_device_control.duty_cw;
}
// 更新PWM输出
void update_pwm_output(void)
{
pwm_config_t cfg_repeat = {0};
cfg_repeat.repeat = true;
if (g_device_control.duty_cw > PWM_DUTY_RATIO_MAX) {
g_device_control.duty_cw = PWM_DUTY_RATIO_MAX;
}
if (g_device_control.duty_ww > PWM_DUTY_RATIO_MAX) {
g_device_control.duty_ww = PWM_DUTY_RATIO_MAX;
}
uint32_t high_cnt_cw = (pwm_period_cnt * g_device_control.duty_cw) / PWM_DUTY_RATIO_MAX;
uint32_t low_cnt_cw = pwm_period_cnt - high_cnt_cw;
uint32_t high_cnt_ww = (pwm_period_cnt * g_device_control.duty_ww) / PWM_DUTY_RATIO_MAX;
uint32_t low_cnt_ww = pwm_period_cnt - high_cnt_ww;
// uapi_pwm_stop_group(CONFIG_PWM_GROUP_ID);
// uapi_pwm_clear_group(CONFIG_PWM_GROUP_ID);
if (!g_device_control.on) { // 如果开关关闭则占空比为0
e_printf("spotlight off\r\n");
high_cnt_cw = 0;
low_cnt_cw = 0;
high_cnt_ww = 0;
low_cnt_ww = 0;
}
cfg_repeat.high_time = high_cnt_cw;
cfg_repeat.low_time = low_cnt_cw;
uapi_pwm_open(channel_id_cw, &cfg_repeat);
// 配置第二个通道
cfg_repeat.high_time = high_cnt_ww;
cfg_repeat.low_time = low_cnt_ww;
cfg_repeat.offset_time = high_cnt_cw;//配置互补形成相位
uapi_pwm_open(channel_id_ww, &cfg_repeat);
// 设置PWM组
uint8_t channel_ids[2] = {channel_id_cw, channel_id_ww};
// uapi_pwm_set_group(CONFIG_PWM_GROUP_ID, channel_ids, 2);
// // 更新PWM占空比
// uapi_pwm_update_duty_ratio(channel_id_cw, low_cnt_cw, high_cnt_cw);
// uapi_pwm_update_duty_ratio(channel_id_ww, low_cnt_ww, high_cnt_ww);
// 启动PWM组
uapi_pwm_start_group(CONFIG_PWM_GROUP_ID);
if (should_print(&pwm_limiter)) {
e_printf("cw:high:%u, low:%u, duty:%u/1000, ww:high:%u, low:%u, duty:%u/1000, offset_time:%u\r\n",
high_cnt_cw, low_cnt_cw, g_device_control.duty_cw, high_cnt_ww, low_cnt_ww, g_device_control.duty_ww, cfg_repeat.offset_time);
}
}
#define ABS(x) ((x) < 0 ? -(x) : (x))
// 计算渐变步长
static void calculate_fade_steps(void)
{
// 从g_device_control获取渐变时间
fade_ctx.smooth_time_us = g_device_control.fade_time * 1000 * 1000;//s->us
e_printf("fade brightness: curr:%d, target:%d, cct: curr:%d, target:%d\r\n",
fade_ctx.current_brightness, fade_ctx.target_brightness, fade_ctx.current_cct, fade_ctx.target_cct);
// 计算亮度渐变步长
int32_t brightness_diff = fade_ctx.target_brightness - fade_ctx.current_brightness;
int32_t cct_diff = fade_ctx.target_cct - fade_ctx.current_cct;
// 计算需要的总步数(取亮度和色温中变化较大的那个)
uint32_t max_diff = (ABS(brightness_diff) > ABS(cct_diff)) ? ABS(brightness_diff) : ABS(cct_diff);
uint32_t min_steps = 0;
uint32_t available_interval = 0;
// 如果变化太小,直接设置目标值 EKKO:这里需要确认是直接设置目标值还是强制等待渐变时长
if (max_diff == 0) {
fade_ctx.step_brightness = 0;
fade_ctx.step_cct = 0;
fade_ctx.update_interval = fade_ctx.smooth_time_us;
goto lab_exit;
}
min_steps = max_diff;
// 计算实际可用的时间间隔
available_interval = fade_ctx.smooth_time_us / min_steps;
// 如果时间间隔太小(小于允许的最小更新间隔),则增加步长
if (available_interval < FADE_INTERVAL_MIN) {
// 重新计算步长,确保在指定时间内完成
fade_ctx.update_interval = FADE_INTERVAL_MIN;
int32_t actual_steps = fade_ctx.smooth_time_us / fade_ctx.update_interval;
// 计算新的步长
fade_ctx.step_brightness = brightness_diff / actual_steps;
fade_ctx.step_cct = cct_diff / actual_steps;
// 确保至少有一个最小步长
if (fade_ctx.step_brightness == 0 && brightness_diff != 0) {
fade_ctx.step_brightness = (brightness_diff > 0) ? 1 : -1;
}
if (fade_ctx.step_cct == 0 && cct_diff != 0) {
fade_ctx.step_cct = (cct_diff > 0) ? 1 : -1;
}
} else {
// 使用计算出的时间间隔
fade_ctx.update_interval = available_interval;
fade_ctx.step_brightness = (brightness_diff > 0) ? 1 : -1;
fade_ctx.step_cct = (cct_diff > 0) ? 1 : -1;
}
// 如果亮度或色温没有变化则步长为0
if (brightness_diff == 0) {
fade_ctx.step_brightness = 0;
}
if (cct_diff == 0) {
fade_ctx.step_cct = 0;
}
lab_exit:
if (should_print(&fade_ctx.print_limiter)) {
e_printf("max_diff:%d, fade time:%uus, Brightness: diff:%d, step:%d, CCT: diff:%d, step:%d, update_interval:%uus\r\n",
max_diff, fade_ctx.smooth_time_us, brightness_diff, fade_ctx.step_brightness, cct_diff, fade_ctx.step_cct, fade_ctx.update_interval);
}
}
static void cancel_current_light_fade(void)
{
uapi_timer_stop(fade_ctx.timer_handle);
}
// 计算校验和
static uint32_t calculate_checksum(const device_data_t* data)
{
uint32_t sum = 0;
const uint32_t* ptr = (const uint32_t*)(((char*)data) + sizeof(data->checksum));
size_t len = sizeof(device_data_t) - sizeof(data->checksum); // 减去checksum字段的大小
for (size_t i = 0; i < len / 4; i++) {
sum ^= ptr[i];
}
return sum;
}
// 验证数据有效性
static bool verify_device_data(const device_data_t* data)
{
if (data->magic != DEVICE_DATA_MAGIC) {
e_printf("magic error:%x\n", data->magic);
return false;
}
if (data->version > DEVICE_DATA_VERSION) {
e_printf("versoin missmatch:%x\n", data->version);
return false;
}
uint32_t checksum = calculate_checksum(data);
if (checksum != data->checksum) {
e_printf("check sum error:%x\n", data->version);
return false;
}
return true;
}
// 从指定地址读取设备数据
static bool read_device_data_from_addr(uint32_t addr, device_data_t* data)
{
int ret = hfuflash_read(addr, (char*)data, sizeof(device_data_t));
if (ret != sizeof(device_data_t)) {
e_printf("从地址0x%x读取设备数据失败实际读取长度%d\r\n", addr, ret);
return false;
}
if (!verify_device_data(data)) {
e_printf("地址0x%x的数据无效\r\n", addr);
return false;
}
return true;
}
// 写入数据到指定地址
static bool write_device_data_to_addr(uint32_t addr, const device_data_t* data)
{
int ret = hfuflash_erase_page(addr, 1);
if (ret != HF_SUCCESS) {
e_printf("擦除地址0x%x的Flash页失败错误码%d\r\n", addr, ret);
return false;
}
ret = hfuflash_write(addr, (char*)data, sizeof(device_data_t));
if (ret != sizeof(device_data_t)) {
e_printf("写入数据到地址0x%x失败实际写入长度%d\r\n", addr, ret);
return false;
}
return true;
}
void read_device_data(void)
{
#if SUPPORT_SAVE_TO_FLASH
device_data_t data;
bool main_valid = false;
bool backup_valid = false;
// 尝试读取主数据区
main_valid = read_device_data_from_addr(DEVICE_DATA_FLASH_ADDR, &data);
// 如果主数据区无效,尝试读取备份区
if (!main_valid) {
backup_valid = read_device_data_from_addr(DEVICE_DATA_BACKUP_ADDR, &data);
}
if (!main_valid && backup_valid) { // 如果主数据区无效但备份区有效,从备份区恢复
e_printf("从备份区恢复数据\r\n");
write_device_data_to_addr(DEVICE_DATA_FLASH_ADDR, &data);
} else if (!main_valid && !backup_valid) { // 如果两个区域都无效,使用默认值
e_printf("主数据和备份数据都无效,使用默认值\r\n");
// 只打印g_device_control的当前值不打印data.control
// e_printf("读取完成状态: %d\r\n", g_device_control.read_done);
e_printf("上电次数: %d\r\n", g_device_control.power_on_cnt);
e_printf("配网状态: %d\r\n", g_device_control.is_networked);
e_printf("开关状态: %d\r\n", g_device_control.on);
e_printf("灯光模式: %d\r\n", g_device_control.elightMode);
e_printf("亮度: %d\r\n", g_device_control.brightness_local);
e_printf("色温: %d\r\n", g_device_control.cct_local);
e_printf("冷白LED: %d\r\n", g_device_control.duty_cw);
e_printf("暖白LED: %d\r\n", g_device_control.duty_ww);
e_printf("渐变时间: %d\r\n", g_device_control.fade_time);
goto lab_exit;
}
// 更新设备控制状态
e_printf("设备状态恢复:\r\n");
// e_printf("读取完成状态: %d => %d\r\n", g_device_control.read_done, data.control.read_done);
e_printf("上电次数: %d => %d\r\n", g_device_control.power_on_cnt, data.control.power_on_cnt);
e_printf("配网状态: %d => %d\r\n", g_device_control.is_networked, data.control.is_networked);
e_printf("开关状态: %d => %d\r\n", g_device_control.on, data.control.on);
e_printf("灯光模式: %d => %d\r\n", g_device_control.elightMode, data.control.elightMode);
e_printf("亮度: %d => %d\r\n", g_device_control.brightness_local, data.control.brightness_local);
e_printf("色温: %d => %d\r\n", g_device_control.cct_local, data.control.cct_local);
e_printf("冷白LED: %d => %d\r\n", g_device_control.duty_cw, data.control.duty_cw);
e_printf("暖白LED: %d => %d\r\n", g_device_control.duty_ww, data.control.duty_ww);
e_printf("渐变时间: %d => %d\r\n", g_device_control.fade_time, data.control.fade_time);
g_device_control = data.control;
lab_exit:
#endif
g_device_control.read_done = true;
e_printf("读取设备数据成功\r\n");
}
void save_device_data(void)
{
e_printf("Starting to save device data\n");
#if SUPPORT_SAVE_TO_FLASH
// 使用静态变量保存上一次的数据状态
static device_control_t last_control = {0};
static bool is_first_save = true;
// 需要比较的字段(根据注释标记的持久化维持部分)
bool need_save = is_first_save ||
last_control.on != g_device_control.on ||
last_control.elightMode != g_device_control.elightMode ||
last_control.brightness_local != g_device_control.brightness_local ||
last_control.fade_time != g_device_control.fade_time ||
last_control.cct_local != g_device_control.cct_local ||
last_control.power_on_cnt != g_device_control.power_on_cnt ||
last_control.is_networked != g_device_control.is_networked;
if (!need_save) {
e_printf("No changes detected, skip saving\n");
return;
}
device_data_t data;
// 准备要保存的数据
data.magic = DEVICE_DATA_MAGIC;
data.version = DEVICE_DATA_VERSION;
data.control = g_device_control;
data.checksum = calculate_checksum(&data);
// 先写入备份区
if (!write_device_data_to_addr(DEVICE_DATA_BACKUP_ADDR, &data)) {
e_printf("Failed to write backup data\n");
return;
}
// 再写入主数据区
if (!write_device_data_to_addr(DEVICE_DATA_FLASH_ADDR, &data)) {
e_printf("Failed to write main data, but backup data saved\n");
}
// 更新上一次的数据状态
last_control = g_device_control;
is_first_save = false;
e_printf("Device data saved successfully\n");
#endif
e_printf("Save device data done\n");
}
void req_save_device_data(void)
{
osal_sem_up(&save_data_sem);
}
// 保存任务函数
static void *save_data_task(const char *arg)
{
e_printf("[save_data_task] Save task started\n");
while (save_task_running) {
// 等待保存信号
if (osal_sem_down_timeout(&save_data_sem, 100*1000) != OSAL_SUCCESS) {
continue;
}
while(OSAL_SUCCESS == osal_sem_trydown(&save_data_sem));//消耗所有的信号一次性刷入
save_device_data();
}
e_printf("[save_data_task] Save task exited\n");
return NULL;
}
// 初始化保存任务
static void init_save_task(void)
{
if (save_task_handle != NULL) {
return;
}
// 初始化信号量
if (osal_sem_init(&save_data_sem, 0) != OSAL_SUCCESS) {
e_printf("[init_save_task] Failed to init semaphore\n");
return;
}
// 创建保存任务
osal_kthread_lock();
save_task_handle = osal_kthread_create((osal_kthread_handler)save_data_task, NULL, "SaveDataTask",
SAVE_TASK_STACK_SIZE);
if (save_task_handle != NULL) {
save_task_running = true;
osal_kthread_set_priority(save_task_handle, SAVE_TASK_PRIO);
e_printf("[init_save_task] Save task created successfully\n");
} else {
e_printf("[init_save_task] Failed to create save task\n");
osal_sem_destroy(&save_data_sem);
}
osal_kthread_unlock();
}
// 停止保存任务
static void stop_save_task(void)
{
if (save_task_handle == NULL) {
return;
}
save_task_running = false;
osal_sem_up(&save_data_sem); // 唤醒任务以使其退出
osal_kthread_lock();
osal_kthread_destroy(save_task_handle, 0);
save_task_handle = NULL;
osal_kthread_unlock();
osal_sem_destroy(&save_data_sem);
e_printf("[stop_save_task] Save task stopped\n");
}
// 设置灯光状态(统一控制函数)
int set_light(int32_t brightness_local, int32_t cct_local)
{
// 如果任一参数大于等于0则更新对应值
e_printf("ligMode:%d, local brightness: curr:%d, target:%d, local cct: curr:%d, target:%d\r\n",
g_device_control.elightMode, g_device_control.brightness_local, brightness_local, g_device_control.cct_local, cct_local);
fade_ctx.current_brightness = g_device_control.brightness_local;
fade_ctx.current_cct = g_device_control.cct_local;
fade_ctx.target_brightness = fade_ctx.current_brightness ;
fade_ctx.target_cct = fade_ctx.current_cct;
if (brightness_local >= 0) {
BRIGHTNESS_LITME_RANGE(brightness_local);
if (g_device_control.elightMode == LIGHT_MODE_CUSTOMER) {
fade_ctx.target_brightness = brightness_local;
} else {
g_device_control.brightness_local = brightness_local;
}
}
if (cct_local >= 0) {
CCT_LITME_RANGE(cct_local);
if (g_device_control.elightMode == LIGHT_MODE_CUSTOMER) {
fade_ctx.target_cct = cct_local;
} else {
g_device_control.cct_local = cct_local;
}
}
switch (g_device_control.elightMode)
{
case LIGHT_MODE_CUSTOMER:
if (g_device_control.fade_time) {
fade_ctx.is_fading = true;
fade_ctx.fade_completed = false;
// 计算渐变步长
calculate_fade_steps();
e_printf("start fade\r\n");
// 启动渐变定时器
set_switch(true);
uapi_timer_start(fade_ctx.timer_handle, fade_ctx.update_interval, fade_timer_callback, 0);
#if 0
等待渐变完成
while (!fade_ctx.fade_completed) {
msleep(10);
}
return 0; // 同步上报
#else
return -111; // 异步上报
#endif
}
// no break; // 如果渐变时间是0则直接一步完成
default: //情景模式直接切换到对应的色温和亮度
set_switch(true);
}
start_report_task(report_device_online_status);//直接全量上报
return -111; // 异步上报
}
// 设置开关状态
int set_switch(bool open)
{
g_device_control.on = open;
if (fade_ctx.is_fading) //打断当前的渐变计划
{
cancel_current_light_fade();
}
calculate_pwm_duty();
update_pwm_output();
uapi_gpio_set_val(SWITCH_PIN, open ? OPEN_LIGHT : CLOSE_LIGHT);
// 保存设备状态
req_save_device_data();
return 0;
}
static void gpio_init(pin_t pin)
{
/* PINCTRL init. */
uapi_pin_init();
uapi_pin_set_mode(pin, HAL_PIO_FUNC_GPIO);
uapi_gpio_set_dir(pin, GPIO_DIRECTION_OUTPUT);
uapi_pin_set_ds(pin, PIN_DS_3);
uapi_pin_set_pull(pin, PIN_PULL_TYPE_DOWN);
uapi_gpio_set_val(pin, CLOSE_LIGHT);
}
static void pwm_sys_init(void) {
uapi_pwm_deinit();
}
static void pwm_init(pin_t pin, pin_t pin1)
{
pwm_config_t cfg_repeat = {0};
cfg_repeat.repeat = true;
uapi_pin_set_mode(pin, PIN_MODE_1);
uapi_pin_set_mode(pin1, PIN_MODE_1);
uapi_pwm_init();
uint32_t frequency = uapi_pwm_get_frequency(pin%8);
// uint32_t pwm_base_period_ns = 1000 * 1000 * 1000 / frequency;
// uint32_t pwm_base_period_ns = 1000 * 1000 * 1000 / (80 * 1000 * 1000);// 80MHZ
// uint32_t pwm_target_period_ns = 1000 * 1000 * 1000 / PWM_FREQUENCY;
pwm_period_cnt = ((80 * 1000 * 1000) / PWM_FREQUENCY);
// 设置PWM组
channel_id_cw = pin%8;
channel_id_ww = pin1%8;
uint8_t channel_ids[2] = {channel_id_cw, channel_id_ww};
uapi_pwm_open(channel_id_cw, &cfg_repeat);
uapi_pwm_open(channel_id_ww, &cfg_repeat);
uapi_pwm_set_group(CONFIG_PWM_GROUP_ID, channel_ids, sizeof(channel_ids));
uapi_pwm_start_group(CONFIG_PWM_GROUP_ID);
e_printf("PWM基础时钟频率: %dHz, 目标时钟频率: %dHz, 周期计数: %d\r\n", frequency, PWM_FREQUENCY, pwm_period_cnt);
}
// 配网状态管理相关函数
static void handle_network_status(void)
{
// 如果已经配网,直接返回
if (g_device_control.is_networked) {
return;
}
// 增加上电计数
g_device_control.power_on_cnt++;
e_printf("现在是第 %d 次上电\r\n", g_device_control.power_on_cnt);
// 检查是否需要进入配网状态
if (g_device_control.power_on_cnt >= NET_CFG_ENTRY_CNT) {
e_printf("进入配网状态,上电次数:%d\r\n", g_device_control.power_on_cnt);
g_device_control.power_on_cnt = 0;//
extern int start_hilink_ble_net_config(int32_t net_cfg_time_s);
int ret = start_hilink_ble_net_config(NET_CFG_TOTAL_TIMEOUT/1000);
if (ret) {
// FIXME: 这里简单恢复之前等待配网的灯效即可
e_printf("start net_cfg fail:%n\r\n", ret);
req_save_device_data();
// extern int HILINK_RestoreFactorySettings(void);
// HILINK_RestoreFactorySettings();
return;
}
// 初始化呼吸灯控制
init_breath_ctx();
start_breath_timer();
}
// 保存设备状态
req_save_device_data();
}
// 设备上线时的状态上报
static void report_device_online_status(void)
{
e_printf("[report_task] Starting to report all service status\r\n");
fast_report(SVC_ID_SWITCH);
fast_report(SVC_ID_BRIGHTNESS);
fast_report(SVC_ID_CCT);
fast_report(SVC_ID_LIGHT_MODE);
fast_report(SVC_ID_FADE_TIME);
e_printf("[report_task] Status report completed\r\n");
}
// 渐变结束时的状态上报
static void report_fade_complete_status(void)
{
req_save_device_data();
e_printf("[report_task] Reporting fade complete status\r\n");
fast_report(SVC_ID_LIGHT_MODE);
fast_report(SVC_ID_BRIGHTNESS);
fast_report(SVC_ID_CCT);
e_printf("[report_task] Fade status report completed\r\n");
}
// 状态上报任务函数
static void *report_task(const char *arg)
{
report_func_t report_func = (report_func_t)arg;
e_printf("report_task running...\r\n");
while (!(g_device_control.read_done && hf_hilink_main_is_runing())) {
// 数据已经正确load并且hilink已经运行才开始上报
e_printf("read_done%d, hilink:%d\r\n", g_device_control.read_done, hf_hilink_main_is_runing());
osal_msleep(50);
}
if (report_func)
{
report_func();
}
report_task_running = false;
e_printf("[report_task] exited\r\n");
return NULL;
}
// 启动状态上报任务
static void start_report_task(report_func_t report_func)
{
if (report_task_running) {
e_printf("[report_task] Previous task is still running, skip this report\r\n");
return;
}
if (report_task_handle) {
osal_kthread_destroy(report_task_handle, 0);
report_task_handle = NULL;
}
e_printf("start report_task\r\n");
osal_kthread_lock();
report_task_handle = osal_kthread_create((osal_kthread_handler)report_task, (void*)report_func, "ReportStaTask",
REPORT_TASK_STACK_SIZE);
if (report_task_handle != NULL) {
report_task_running = true; // 设置任务运行标志
osal_kthread_set_priority(report_task_handle, REPORT_TASK_PRIO);
}
osal_kthread_unlock();
}
static int device_online = 0;
// 修改handle_device_online函数
void handle_device_online(void)
{
if(device_online)
{
return;
}
e_printf("device online!\r\n");
if (!g_device_control.is_networked) {
e_printf("设备首次上线,记录配网状态\r\n");
g_device_control.is_networked = true;
g_device_control.power_on_cnt = 0; // 重置上电计数
stop_breath_timer(); // 停止呼吸灯
set_light2net_cfg_done();
req_save_device_data();
}
// 重置配网状态
g_net_breath_state = NET_CFG_IDLE;
g_net_cfg_start_time = 0;
// 启动状态上报任务,使用设备上线状态上报函数
start_report_task(report_device_online_status);
device_online = 1;
}
void handle_device_offline(void)
{
if (!device_online) {
return;
}
device_online = 0;
e_printf("device offline!\r\n");
}
// 处理设备解绑
void handle_device_unbind(void)
{
e_printf("设备被解绑,重置配网状态\r\n");
if (g_device_control.is_networked) {
g_device_control.is_networked = false;
g_device_control.power_on_cnt = 0; // 重置上电计数
stop_spotlight_main_task();
device_control_t tmp = DEFAULT_DEVICE_DATA;//恢复默认
g_device_control = tmp;
save_device_data();
}
}
static void check_net_cfg_power_on_keep_time(void)
{
if (g_device_control.power_on_cnt <= 0) {
return;
}
if (g_device_control.is_networked) {
return;
}
if (uapi_systick_get_ms() > INIT_NET_CFG_PWOER_ON_KEEP_TIME) {
e_printf("power_on keep time is %llums must < %ds, we will reset cnt\r\n", uapi_systick_get_ms(), INIT_NET_CFG_PWOER_ON_KEEP_TIME/1000);
g_device_control.power_on_cnt = 0;
req_save_device_data();
}
}
// spotlight主任务相关变量
#define SPOTLIGHT_MAIN_TASK_PRIO 23
#define SPOTLIGHT_MAIN_TASK_STACK_SIZE 0x1000
static osal_task *spotlight_main_task_handle = NULL;
static bool spotlight_main_task_running = false;
// spotlight主任务函数
static void *spotlight_main_task(const char *arg)
{
unused(arg);
e_printf("[spotlight_main_task] Task started\r\n");
uint32_t current_time = 0; //uapi_systick_get_ms();
while (spotlight_main_task_running) {
// 检查配网超时
check_net_cfg_timeout();
check_net_cfg_power_on_keep_time();
osal_msleep(20);
}
// 停止保存任务
stop_save_task();
e_printf("[spotlight_main_task] Task exited\r\n");
return NULL;
}
// 启动spotlight主任务
static void start_spotlight_main_task(void)
{
if (spotlight_main_task_handle != NULL) {
e_printf("[start spotlight task] Task already running\r\n");
return;
}
e_printf("[start spotlight task] Starting task\r\n");
osal_kthread_lock();
spotlight_main_task_handle = osal_kthread_create((osal_kthread_handler)spotlight_main_task, NULL, "SpotlightMain",
SPOTLIGHT_MAIN_TASK_STACK_SIZE);
if (spotlight_main_task_handle != NULL) {
spotlight_main_task_running = true;
osal_kthread_set_priority(spotlight_main_task_handle, SPOTLIGHT_MAIN_TASK_PRIO);
e_printf("[start spotlight task] Task created successfully\r\n");
} else {
e_printf("[start spotlight task] Failed to create task\r\n");
}
osal_kthread_unlock();
}
// 停止spotlight主任务
static void stop_spotlight_main_task(void)
{
if (spotlight_main_task_handle == NULL) {
return;
}
spotlight_main_task_running = false;
osal_kthread_lock();
osal_kthread_destroy(spotlight_main_task_handle, 0);
spotlight_main_task_handle = NULL;
osal_kthread_unlock();
e_printf("[stop_spotlight_main_task] Task stopped\r\n");
}
// 检查配网超时
static void check_net_cfg_timeout(void)
{
if (g_net_breath_state != NET_CFG_BREATHING) {
return;
}
uint64_t current_time = uapi_systick_get_ms();
uint64_t elapsed_time = current_time - g_net_cfg_start_time;
if (elapsed_time >= NET_CFG_TOTAL_TIMEOUT) {
e_printf("[Net Cfg] 配网超过10分钟退出配网模式\r\n");
g_net_breath_state = NET_CFG_TIMEOUT;
}
}
// 修改spotlight_main函数
int spotlight_main(void) {
uapi_systick_init();
read_device_data();
e_printf("uapi_timer_get_max_us:%uus\r\n", uapi_timer_get_max_us());
// 初始化GPIO并将灯关闭
gpio_init(SWITCH_PIN);
// 初始化PWM系统
pwm_sys_init();
pwm_init(BRIGHTNESS_PIN, CCT_PIN);
// 初始化渐变控制
init_fade_ctx();
// 初始化保存任务
init_save_task();
// 检查配网状态,确定是否需要进入配网状态
handle_network_status();
set_switch(g_device_control.on);//按照当前值更新light
start_spotlight_main_task();
return 0;
}
// 设置渐变时长
int set_smooth_time(uint32_t smooth_time)
{
e_printf("[set_smooth_time] Setting smooth time: %d s\r\n", smooth_time);
if (smooth_time < SMOOTH_TIME_MIN) {
e_printf("[set_smooth_time] Smooth time below minimum, adjusted to: %d s\r\n", SMOOTH_TIME_MIN);
smooth_time = SMOOTH_TIME_MIN;
}
if (smooth_time > SMOOTH_TIME_MAX) {
e_printf("[set_smooth_time] Smooth time above maximum, adjusted to: %d s\r\n", SMOOTH_TIME_MAX);
smooth_time = SMOOTH_TIME_MAX;
}
g_device_control.fade_time = smooth_time;
req_save_device_data();
e_printf("[set_smooth_time] Smooth time setting completed\r\n");
return 0;
}
// 设置灯光到配网超时状态
static void set_light2breathtimeout(void)
{
e_printf("[Net cfg] 配网超过1分钟退出呼吸灯状态\r\n");
// 恢复到自定义模式
g_device_control.brightness_local = BRIGHTNESS_REMOTE2LOCAL(NET_CFG_TIMEOUT_BRIGHTNESS);
g_device_control.cct_local = CCT_REMOTE2LOCAL(NET_CFG_TIMEOUT_CCT);
calculate_pwm_duty();
update_pwm_output();
}
// 设置灯光到配网完成状态
static void set_light2net_cfg_done(void)
{
g_device_control.elightMode = NET_CFG_DEFAULT_LIGHTMODE;
g_device_control.brightness_local = BRIGHTNESS_REMOTE2LOCAL(NET_CFG_DEFAULT_BRIGHTNESS);
g_device_control.cct_local = CCT_REMOTE2LOCAL(NET_CFG_DEFAULT_CCT);
g_device_control.fade_time = NET_CFG_DEFAULT_FADE_TIME;
calculate_pwm_duty();
update_pwm_output();
}
// 启动呼吸灯
static void start_breath_timer(void)
{
g_net_breath_state = NET_CFG_BREATHING;
g_net_cfg_start_time = uapi_systick_get_ms();
breath_ctx.is_initial_breath = true;
uapi_timer_start(breath_ctx.timer_handle, breath_ctx.update_interval, breath_timer_callback, 0);
}