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

1267 lines
42 KiB
C
Raw Normal View History

2025-05-13 22:00:58 +08:00
#include "hsf.h"
#include "hfconfig.h"
2025-05-13 22:00:58 +08:00
#if defined(CONFIG_PWM_SUPPORT_LPM)
#include "pm_veto.h"
#endif
#include "pinctrl.h"
#include "gpio.h"
#include "pinctrl.h"
2025-05-13 22:00:58 +08:00
#include "pwm.h"
#include "timer.h"
#include "soc_osal.h"
#include "systick.h"
2025-05-13 22:00:58 +08:00
// #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)
2025-05-13 22:00:58 +08:00
#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;
}
2025-05-13 22:00:58 +08:00
// 渐变定时器回调函数
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);
}
2025-05-13 22:00:58 +08:00
// 呼吸灯定时器回调函数
static void breath_timer_callback(uintptr_t data)
2025-05-13 22:00:58 +08:00
{
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;
2025-05-13 22:00:58 +08:00
}
static void gpio_init(pin_t pin)
{
/* PINCTRL init. */
2025-05-13 22:00:58 +08:00
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);
2025-05-13 22:00:58 +08:00
}
static void pwm_sys_init(void) {
2025-05-13 22:00:58 +08:00
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);
2025-05-13 22:00:58 +08:00
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();
2025-05-13 22:00:58 +08:00
}
// 设备上线时的状态上报
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");
2025-05-13 22:00:58 +08:00
}
// 渐变结束时的状态上报
static void report_fade_complete_status(void)
2025-05-13 22:00:58 +08:00
{
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");
2025-05-13 22:00:58 +08:00
}
// 状态上报任务函数
static void *report_task(const char *arg)
2025-05-13 22:00:58 +08:00
{
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;
}
2025-05-13 22:00:58 +08:00
// 启动状态上报任务
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();
2025-05-13 22:00:58 +08:00
}
static int device_online = 0;
// 修改handle_device_online函数
void handle_device_online(void)
2025-05-13 22:00:58 +08:00
{
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;
2025-05-13 22:00:58 +08:00
}
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();
}
}
2025-05-13 22:00:58 +08:00
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函数
2025-05-13 22:00:58 +08:00
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并将灯关闭
2025-05-13 22:00:58 +08:00
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;
}
2025-05-13 22:00:58 +08:00
// 设置渐变时长
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;
2025-05-13 22:00:58 +08:00
}
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");
2025-05-13 22:00:58 +08:00
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);
}