@@ -64,6 +64,8 @@ bool g_reset_factory_flag = false;
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
// PWM参数更新调试标志引脚是否已初始化
static bool g_pwm_update_flag_inited = false ;
void save_device_data ( void ) ;
void read_device_data ( void ) ;
@@ -112,6 +114,7 @@ static struct fade_ctx_t {
uint16_t fade_time ; //s
uint32_t smooth_time_us ; // 渐变总时长(us)
uint32_t update_interval ; // 更新间隔(us)
volatile bool timer_active ; // 渐变定时器是否允许自重启(竞态保护)
// 打印限制器
print_limiter_t print_limiter ;
} ;
@@ -208,7 +211,7 @@ static void *fade_task(const char *arg)
fade_ctx . current_cct , fade_ctx . target_cct , fade_ctx . step_cct , fade_ctx . is_closing_fade ) ;
}
// 检查是否达到目标值(恢复原始逻辑)
// 检查是否达到目标值
bool brightness_reached = ( fade_ctx . step_brightness > 0 ) ?
( fade_ctx . current_brightness > = fade_ctx . target_brightness ) :
( fade_ctx . current_brightness < = fade_ctx . target_brightness ) ;
@@ -216,14 +219,14 @@ static void *fade_task(const char *arg)
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, closing_fade: %d \r \n " ,
fade_ctx . target_brightness , fade_ctx . target_cct , fade_ctx . is_closing_fade ) ;
@@ -231,6 +234,7 @@ static void *fade_task(const char *arg)
fade_ctx . fade_completed = true ;
fade_ctx . current_brightness = fade_ctx . target_brightness ;
fade_ctx . current_cct = fade_ctx . target_cct ;
fade_ctx . timer_active = false ; // 防止回调自重启
uapi_timer_stop ( fade_ctx . timer_handle ) ;
}
@@ -335,6 +339,10 @@ static void *breath_task(const char *arg)
// 渐变定时器回调函数
static void fade_timer_callback ( uintptr_t data )
{
// 若已被取消或未处于渐变态,禁止回调重入自重启,避免双定时器抖动
if ( ! fade_ctx . timer_active | | ! fade_ctx . is_fading ) {
return ;
}
osal_sem_up ( & fade_ctx . sem ) ; // 唤醒渐变任务 fade_task
uapi_timer_start ( fade_ctx . timer_handle , fade_ctx . update_interval , fade_timer_callback , 0 ) ;
}
@@ -364,6 +372,27 @@ static void init_fade_ctx(void)
// 初始化打印限制器
init_print_limiter ( & fade_ctx . print_limiter , " [fade_task] " ) ;
// 🔧 智能初始化:根据设备状态决定初始值
if ( g_device_control . read_done ) {
// 数据已读取完成(正常启动)
if ( g_device_control . on ) {
// 开机渐变: 从0开始渐变到目标亮度
fade_ctx . current_brightness = 0 ;
fade_ctx . current_cct = g_device_control . cct_local ; // 色温保持目标值
e_printf ( " [init_fade_ctx] 开机渐变模式: brightness=0->%d, cct=%d \n " ,
g_device_control . brightness_local , fade_ctx . current_cct ) ;
} else {
// 设备关闭状态
fade_ctx . current_brightness = 0 ;
fade_ctx . current_cct = g_device_control . cct_local ;
}
} else {
// 数据尚未读取(初始化阶段)- 保持原有逻辑
fade_ctx . current_brightness = 0 ;
fade_ctx . current_cct = 0 ;
e_printf ( " [init_fade_ctx] 初始化阶段: brightness=0, cct=0 \n " ) ;
}
// 创建渐变任务
osal_kthread_lock ( ) ;
fade_ctx . task_handle = osal_kthread_create ( ( osal_kthread_handler ) fade_task , NULL , " FadeTask " ,
@@ -380,8 +409,7 @@ static void init_fade_ctx(void)
// 设置默认更新间隔
fade_ctx . update_interval = FADE_INTERVAL_MIN ;
// fade_ctx.current_brightness = g_device_control.brightness_local;
// fade_ctx.current_cct = g_device_control.cct_local;
fade_ctx. timer_active = false ; // 默认禁用,只有开始渐变时启用
}
// 初始化呼吸灯控制
@@ -491,8 +519,12 @@ void calculate_pwm_duty(device_control_t* pdevice_control)
// 更新PWM输出
void update_pwm_output ( bool on_state , uint16_t duty_cw_val , uint16_t duty_ww_val )
{
pwm_config_t cfg_repeat = { 0 } ;
cfg_repeat . repeat = true ;
// 说明:为了避免每步“重相位 + 动态拼接”导致的低亮抖动,
// 这里改为固定相位( offset_time=0) , 并避免每次重复start_group。
// 若平台支持 uapi_pwm_update_duty_ratio, 可切换为更新接口; 否则退回 open 配置。
pwm_config_t cfg = { 0 } ;
cfg . repeat = true ;
uint16_t current_duty_cw = duty_cw_val ;
uint16_t current_duty_ww = duty_ww_val ;
@@ -512,29 +544,53 @@ void update_pwm_output(bool on_state, uint16_t duty_cw_val, uint16_t duty_ww_val
if ( ! on_state ) {
high_cnt_cw = 0 ;
low_cnt_cw = pwm_period_cnt ; // Ensure low_cnt is full period if off
low_cnt_cw = pwm_period_cnt ; // 关灯时保持低电平整周期
high_cnt_ww = 0 ;
low_cnt_ww = pwm_period_cnt ; // Ensure low_cnt is full period if off
low_cnt_ww = pwm_period_cnt ;
}
// uapi_pwm_stop_group(CONFIG_PWM_GROUP_ID);
cfg_repeat . high_time = high_cnt_cw ;
cfg_repeat . low_time = low_cnt_cw ;
uapi_pwm_open ( channel_id_cw , & cfg_repeat ) ;
// uapi_pwm_update_duty_ratio(channel_id_cw, cfg_repeat.low_time, cfg_repeat.high_time);
# if defined(CONFIG_PWM_USING_V150)
// V150: 先更新占空,再通过 start_group 触发加载
( void ) uapi_pwm_update_duty_ratio ( channel_id_cw , low_cnt_cw , high_cnt_cw ) ;
( void ) uapi_pwm_update_duty_ratio ( channel_id_ww , low_cnt_ww , high_cnt_ww ) ;
// 需要显式触发加载
( void ) uapi_pwm_start_group ( CONFIG_PWM_GROUP_ID ) ;
# else
// V151 场景
cfg . offset_time = 0 ; // 固定相位,避免相位不断重置造成抖动
# if defined(CONFIG_PWM_PRELOAD)
// 使用预加载:配置写入影子寄存器,等当前周期结束后自动无缝切换。
cfg . high_time = high_cnt_cw ;
cfg . low_time = low_cnt_cw ;
( void ) uapi_pwm_config_preload ( CONFIG_PWM_GROUP_ID , channel_id_cw , & cfg ) ;
cfg_repeat . high_time = high_cnt_ww ;
cfg_repeat . low_time = low_cnt_ww ;
cf g_repeat . offset_time = high_cnt_c w; // WW PWM starts after CW PWM high time
cfg . high_time = high_cnt_ww ;
cfg . low_time = low_cnt_ww ;
( void ) uapi_pwm_confi g_p reload ( CONFIG_PWM_GROUP_ID , channel_id_w w, & cfg ) ;
// 预加载模式下不重复调用 start_group, 避免打乱当前计数器与周期
# else
// 无预加载能力时的回退:直接 open + start_group( 可能导致轻微周期扰动)
cfg . high_time = high_cnt_cw ;
cfg . low_time = low_cnt_cw ;
( void ) uapi_pwm_open ( channel_id_cw , & cfg ) ;
uapi_pwm_open ( channel_id_ww , & cfg_repeat ) ;
// uapi_pwm_update_duty_ratio(channel_id_ww, cfg_repeat.low_time, cfg_repeat.high_time);
uapi_pwm_start_group ( CONFIG_PWM_GROUP_ID ) ;
cfg . high_time = high_cnt_ww ;
cfg . low_time = low_cnt_ww ;
( void ) uapi_pwm_open ( channel_id_ww , & cfg ) ;
( void ) uapi_pwm_start_group ( CONFIG_PWM_GROUP_ID ) ;
# endif
# endif
if ( should_print ( & pwm_limiter ) ) {
e_printf ( " on:%d, cw:high:%u, low: %u, duty:%u/%u , ww:high:%u, low:%u, duty:%u/%u, offset_time :%u \r \n " ,
on_state , high_cnt_cw , low_cnt_cw , current_duty_cw , PWM_DUTY_RATIO_MAX , high_cnt_ww , low_cnt_ww , current_duty_ww , PWM_DUTY_RATIO_MAX , cfg_repeat . offset_time ) ;
e_printf ( " on:%d, cw(H/L):%u/ %u, duty:%u, ww(H/L):%u/%u, duty :%u \r \n " ,
on_state , high_cnt_cw , low_cnt_cw , current_duty_cw ,
high_cnt_ww , low_cnt_ww , current_duty_ww ) ;
}
// 调试: 每次更新PWM参数后, 翻转一次 GPIO10( PWM_UPDATE_FLAG_PIN)
// 便于使用逻辑分析仪观察控制发生的时间点
if ( g_pwm_update_flag_inited ) {
( void ) uapi_gpio_toggle ( PWM_UPDATE_FLAG_PIN ) ;
}
}
@@ -608,6 +664,8 @@ lab_exit:
static void cancel_current_light_fade ( void )
{
// 竞态保护:先拉低标志再停计时器,避免回调自重启
fade_ctx . timer_active = false ;
uapi_timer_stop ( fade_ctx . timer_handle ) ;
// 如果我打断了渐变,则将当前值更新到目标值不然下次计算会异常
// g_device_control.cct_local = fade_ctx.current_cct;
@@ -887,10 +945,17 @@ int set_light(light_ctrl_source_e source,
// 如果打开灯,则需要手动将前置状态设置为关闭的样子,这样子后面计算渐变才能正常计算
if ( APP_OPEN_LIGHT = = source | | DEV_POWER_ON = = source ) {
g_device_control . on = true ;
// fade_ctx.current_brightness = 0;
if ( DEV_POWER_ON = = source ) {
// 🔧 开机渐变: 明确设置从0开始
fade_ctx . current_brightness = 0 ; // 从0开始渐变
fade_ctx . current_cct = g_device_control . cct_local ; // 色温保持目标值
e_printf ( " [set_light] 开机渐变设置: brightness=0->%d, cct=%d \n " ,
g_device_control . brightness_local , fade_ctx . current_cct ) ;
}
brightness_local_target = g_device_control . brightness_local ;
// 色温不进行变化,只改变亮度
fade_ctx . current_cct = g_device_control . cct_local ;
cct_local_target = g_device_control . cct_local ;
if ( g_device_control . colourMode ! = COLOUR_MODE_DUAL ) {
@@ -930,6 +995,7 @@ int set_light(light_ctrl_source_e source,
calculate_fade_steps ( & tmp_fade_ctx ) ; // 复用原有计算流程
memcpy ( & fade_ctx , & tmp_fade_ctx , FADE_CTRL_DATA_SIZE ( tmp_fade_ctx ) ) ;
e_printf ( " start close light fade \r \n " ) ;
fade_ctx . timer_active = true ;
uapi_timer_start ( fade_ctx . timer_handle , fade_ctx . update_interval , fade_timer_callback , 0 ) ;
start_report_task ( REPORT_SWITCH | REPORT_LIGHT_MODE ) ;
req_save_device_data ( ) ;
@@ -953,6 +1019,7 @@ int set_light(light_ctrl_source_e source,
calculate_fade_steps ( & tmp_fade_ctx ) ;
memcpy ( & fade_ctx , & tmp_fade_ctx , FADE_CTRL_DATA_SIZE ( tmp_fade_ctx ) ) ;
e_printf ( " start fade \r \n " ) ;
fade_ctx . timer_active = true ;
uapi_timer_start ( fade_ctx . timer_handle , fade_ctx . update_interval , fade_timer_callback , 0 ) ;
start_report_task ( REPORT_SWITCH | REPORT_BRIGHTNESS | REPORT_CCT | REPORT_LIGHT_MODE | REPORT_COLOUR_MODE ) ;
req_save_device_data ( ) ;
@@ -972,6 +1039,7 @@ int set_light(light_ctrl_source_e source,
calculate_fade_steps ( & tmp_fade_ctx ) ;
memcpy ( & fade_ctx , & tmp_fade_ctx , FADE_CTRL_DATA_SIZE ( tmp_fade_ctx ) ) ;
e_printf ( " start fade \r \n " ) ;
fade_ctx . timer_active = true ;
uapi_timer_start ( fade_ctx . timer_handle , fade_ctx . update_interval , fade_timer_callback , 0 ) ;
start_report_task ( REPORT_BRIGHTNESS | REPORT_CCT | REPORT_LIGHT_MODE | REPORT_COLOUR_MODE ) ;
req_save_device_data ( ) ;
@@ -1025,27 +1093,34 @@ static void pwm_init(pin_t pin, pin_t pin1)
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 ) ;
// 基准时钟固定 80MHz( 客户指定) 。不要使用 uapi_pwm_get_frequency 返回值。
channel_id_cw = pin % 8 ;
channel_id_ww = pin1 % 8 ;
const uint32_t base_clk = 80 * 1000 * 1000 ; // 80MHz 固定
pwm_period_cnt = ( base_clk / PWM_FREQUENCY ) ;
// 初始为关灯: 高电平0, 低电平整周期; 固定相位
cfg_repeat . high_time = 0 ;
cfg_repeat . low_time = pwm_period_cnt ;
// 设置PWM组
channel_id_cw = pin % 8 ;
channel_id_ww = pin1 % 8 ;
cfg_repeat . offset_time = 0 ;
// 先打开两个通道
( void ) uapi_pwm_open ( channel_id_cw , & cfg_repeat ) ;
( void ) uapi_pwm_open ( channel_id_ww , & cfg_repeat ) ;
// 设置分组并启动(分组只需启动一次)
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 ) ;
( void ) uapi_pwm_set_group ( CONFIG_PWM_GROUP_ID , channel_ids , sizeof ( channel_ids ) ) ;
( void ) uapi_pwm_start_group ( CONFIG_PWM_GROUP_ID ) ;
e_printf ( " PWM基础时钟频率(固定): %uHz, 目标时钟频率: %dHz, 周期计数: %u \r \n " , base_clk , PWM_FREQUENCY , pwm_period_cnt ) ;
}
extern int start_hilink_ble_net_config ( int32_t net_cfg_time_s ) ;
void start_net_config ( void ) {
e_printf ( " 进入配网状态,上电次数:%d, is_new_device :%d \r \n " , g_device_control . power_on_cnt , ! g_device_control . is_net_configured ) ;
g_device_control . power_on_cnt = 0 ; //
e_printf ( " 进入配网状态,上电次数:%d, is_new设备 :%d \r \n " , g_device_control . power_on_cnt , ! g_device_control . is_net_configured ) ;
// 按新规则: 上电计数仅能在上电超过5秒后自然清零,
// 配网流程不再主动清除 power_on_cnt。
int ret = start_hilink_ble_net_config ( NET_CFG_TOTAL_TIMEOUT / 1000 ) ;
if ( ret ) {
// FIXME: 这里简单恢复之前等待配网的灯效即可
@@ -1075,23 +1150,16 @@ static int handle_network_status(void)
// 检查是否需要进入配网状态或恢复出厂设置
if ( g_device_control . power_on_cnt > = NET_CFG_ENTRY_CNT ) {
// 任何状态下达到阈值都强制解绑并恢复出厂设置
e_printf ( " 快速上电达到 %d 次,强制恢复出厂设置(解绑) \r \n " , NET_CFG_ENTRY_CNT ) ;
g_reset_factory_flag = true ;
g_device_control . power_on_cnt = 0 ;
if ( g_device_control . is_net_configure d) {
// 已出厂设备: 上下电6次后恢复出厂设置并重启
e_printf ( " 已到达出厂设备上电次,执行恢复出厂设置 \r \n " ) ;
g_reset_factory_flag = true ;
extern int HILINK_RestoreFactorySettings ( void ) ;
while ( ! hf_hilink_main_is_runing ( ) ) {
msleep ( 10 ) ;
}
HILINK_RestoreFactorySettings ( ) ;
return start_net_cfg ;
} else {
// 未出厂设备:进入配网模式
e_printf ( " 未出厂设备上电6次, 进入配网模式 \r \n " ) ;
start_net_config ( ) ;
start_net_cfg = 1 ;
extern int HILINK_RestoreFactorySettings ( voi d) ;
while ( ! hf_hilink_main_is_runing ( ) ) {
msleep ( 10 ) ;
}
HILINK_RestoreFactorySettings ( ) ;
return start_net_cfg ;
} else if ( ! g_device_control . is_net_configured ) {
// 未出厂设备直接进入配网
start_net_config ( ) ;
@@ -1274,18 +1342,17 @@ void handle_device_offline(void)
// 处理设备解绑
void handle_device_unbind ( void )
{
e_printf ( " 设备被解绑,重置配网状态 \r \n " ) ;
e_printf ( " 设备被解绑,重置配网状态:%d \r \n " , g_device_control . is_bound );
if ( g_device_control . is_bound ) {
g_device_control . is_bound = false ;
g_device_control . power_on_cnt = 0 ; // 重置上电计数
// stop_spotlight_main_task();
device_control_t tmp = DEFAULT_DEVICE_DATA ; //恢复默认
// if (!g_reset_factory_flag) {
// tmp.is_net_configured = g_device_control.is_net_configured;
// }
g_device_control = tmp ;
save_device_data ( ) ;
g_device_control = tmp ;
}
save_device_data ( ) ;
}
uint64_t startup_time = 0 ;
@@ -1312,10 +1379,27 @@ 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();
// 自愈: 在HiLink Main运行后做一次绑定状态一致性检查
static bool s_bind_consistency_checked = false ;
while ( spotlight_main_task_running ) {
// 检查配网超时
check_net_cfg_timeout ( ) ;
check_net_cfg_power_on_keep_time ( ) ;
if ( ! s_bind_consistency_checked & & hf_hilink_main_is_runing ( ) ) {
// 仅执行一次: 检查应用层与HiLink SDK的绑定状态是否一致
extern int HILINK_IsRegister ( void ) ;
extern int HILINK_RestoreFactorySettings ( void ) ;
int reg = HILINK_IsRegister ( ) ;
bool sdk_bound = ( reg ! = 0 ) ;
bool app_bound = g_device_control . is_bound ;
if ( sdk_bound ! = app_bound ) {
e_printf ( " [consistency] app_bound=%d, sdk_bound=%d, do factory reset \r \n " , app_bound , sdk_bound ) ;
// 触发完整流程: 由HiLink框架内部清理持久化并按注册的重启回调执行
HILINK_RestoreFactorySettings ( ) ;
}
s_bind_consistency_checked = true ;
}
osal_msleep ( 20 ) ;
}
@@ -1402,6 +1486,10 @@ int spotlight_main(void) {
read_device_data ( ) ;
// 初始化GPIO并将灯关闭
gpio_init ( SWITCH_PIN ) ;
// 初始化 PWM 更新标志引脚( GPIO10) 为普通GPIO输出, 默认拉低
gpio_init ( PWM_UPDATE_FLAG_PIN ) ;
g_pwm_update_flag_inited = true ;
// 初始化PWM系统
pwm_sys_init ( ) ;
pwm_init ( BRIGHTNESS_PIN , CCT_PIN ) ;
@@ -1476,12 +1564,23 @@ static void set_light2net_cfg_done(void)
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 ;
// 🔧 关键修复: 配网完成后直接使用目标色温, 不从PWM反推
// PWM反推逻辑是错误的, 因为呼吸灯PWM状态不代表用户期望的色温
fade_ctx . current_brightness = g_device_control . brightness_local ;
fade_ctx . current_cct = g_device_control . cct_local ;
fade_ctx . current_cct = g_device_control . cct_local ; // 直接使用目标色温
e_printf ( " [set_light2net_cfg_done] 配网完成,同步色温: brightness=%d, cct=%d \n " ,
fade_ctx . current_brightness , fade_ctx . current_cct ) ;
// 设置目标值(与当前值一致,避免不必要的渐变)
fade_ctx . target_brightness = g_device_control . brightness_local ;
fade_ctx . target_cct = g_device_control . cct_local ;
calculate_pwm_duty ( & g_device_control ) ;
update_pwm_output ( g_device_control . on , g_device_control . duty_cw , g_device_control . duty_ww ) ;
e_printf ( " [set_light2net_cfg_done] 配网完成状态同步: current_cct=%d, target_cct=%d \n " ,
fade_ctx . current_cct , fade_ctx . target_cct ) ;
}
// 启动呼吸灯
@@ -1502,4 +1601,3 @@ lightMode_e convert_mode_for_report(lightMode_e current_mode)
// 否则上报基础模式
return LIGHT_MODE_GET_BASE ( current_mode ) ;
}