diff --git a/application/samples/wifi/ohos_connect/hilink_adapt/product/device_profile.h b/application/samples/wifi/ohos_connect/hilink_adapt/product/device_profile.h index 0a27380..25b0278 100755 --- a/application/samples/wifi/ohos_connect/hilink_adapt/product/device_profile.h +++ b/application/samples/wifi/ohos_connect/hilink_adapt/product/device_profile.h @@ -30,7 +30,7 @@ extern "C" { #define DEVICE_HIVERSION "1.0.0" /* 设备固件版本号 */ -#define FIRMWARE_VER "1.0.4" +#define FIRMWARE_VER "1.0.5" /* 设备硬件版本号 */ #define HARDWARE_VER "1.0.0" /* 设备软件版本号 */ diff --git a/application/ws63/user_main/switch_panel/switch_panel.h b/application/ws63/user_main/switch_panel/switch_panel.h index 8d05a09..40efd3e 100644 --- a/application/ws63/user_main/switch_panel/switch_panel.h +++ b/application/ws63/user_main/switch_panel/switch_panel.h @@ -43,6 +43,9 @@ #define CONFIG_BLINK_MS (3*60*1000) // 配网前3分钟闪烁时间 #define PANEL_BLINK_MS 1000 // 面板背光快闪时间(1秒) #define LED_BLINK_FREQ_HZ 1 // 配网时LED闪烁频率(1Hz) +#define CONSECUTIVE_PRESS_COUNT 4 // 强制解绑需要的连续按键次数 +#define CONSECUTIVE_PRESS_TIMEOUT_MS 2000 // 连续按键超时时间(2秒) +#define FORCE_UNBIND_WAIT_TIMEOUT_MS 3000 // 等待长按超时时间(3秒) //====================== 设备状态定义 ====================== // 开关状态 @@ -96,7 +99,7 @@ typedef struct { bool long_press_handled; // 长按处理标志 } switch_runtime_info_t; -// 持久化设备状态(需要保存到Flash) +// V1版本的持久化设备状态(老版本兼容) typedef struct { switch_persistent_info_t switches[SWITCH_COUNT]; // 4个开关的持久化状态 bool master_switch; // 总开关状态 - 持久化 @@ -106,7 +109,24 @@ typedef struct { uint32_t magic; // 魔数标识 uint32_t version; // 版本号 uint32_t reserved[8]; // 保留字段 -} device_persistent_state_t; +} device_persistent_state_v1_t; + +// V2版本的持久化设备状态(新版本,当前使用) +typedef struct { + switch_persistent_info_t switches[SWITCH_COUNT]; // 4个开关的持久化状态 + bool master_switch; // 总开关状态 - 持久化 + bool panel_led; // 面板背光状态 - 持久化 + bool is_bound; // 设备绑定状态 - 持久化 + bool is_first_boot; // 是否第一次上电 - 持久化 + bool memory_switches[SWITCH_COUNT]; // APP关闭总开关时记忆的子开关状态 - 持久化 + bool has_memory_state; // 是否有记忆状态 - 持久化 + uint32_t magic; // 魔数标识 + uint32_t version; // 版本号 + uint32_t reserved[6]; // 保留字段(减少2个给新字段使用) +} device_persistent_state_v2_t; + +// 当前使用的持久化状态结构(V2) +typedef device_persistent_state_v2_t device_persistent_state_t; // 运行时设备状态(不需要持久化,断电丢失) typedef struct { @@ -119,7 +139,13 @@ typedef struct { bool factory_test_running; // 产测是否运行中 uint32_t last_save_time; // 上次保存时间 bool is_online; - uint32_t reserved[16]; // 保留字段 + // 强制解绑连续按键检测状态 + uint32_t consecutive_press_count; // 连续按键计数 + uint32_t first_press_time; // 第一次按键时间 + uint32_t last_press_time; // 最后一次按键时间 + bool waiting_long_press; // 等待长按标志 + uint32_t wait_long_press_start_time; // 开始等待长按的时间 + uint32_t reserved[11]; // 保留字段(减少5个给新字段使用) } device_runtime_state_t; @@ -142,7 +168,9 @@ typedef struct { } device_data_t; #define DEVICE_DATA_MAGIC 0x4C505426 // "LPT&"的ASCII码 -#define DEVICE_DATA_VERSION 1 // 数据版本号 +#define DEVICE_DATA_VERSION_V1 1 // 数据版本号V1(老版本,无记忆功能) +#define DEVICE_DATA_VERSION_V2 2 // 数据版本号V2(新版本,支持记忆功能) +#define DEVICE_DATA_VERSION DEVICE_DATA_VERSION_V2 // 当前版本 //====================== 配网相关定义 ====================== #define FACTORY_TEST_SSID "ShuorongSelfTest" // 产测热点名称 @@ -202,6 +230,18 @@ void fast_report_switch(int switch_id); void fast_report_master_switch(void); void set_device_mode(system_mode_t mode); +// 恢复出厂设置相关函数 +void perform_factory_reset_and_reboot(void); + +// 记忆状态管理函数 +void save_memory_switches(void); +void restore_memory_switches(void); +void clear_memory_switches(void); + +// 强制解绑检测函数 +bool check_consecutive_press(int key_id); +void check_force_unbind_timeout(void); + // 状态访问便利函数 bool get_switch_state(int switch_id); bool get_master_switch_state(void); @@ -289,4 +329,4 @@ bool switch_panel_ble_is_enabled(void); int switch_panel_ble_fast_report(const char *svc_id); int start_hilink_ble_net_config(int32_t net_cfg_time_s); -#endif // __SWITCH_PANEL_H__ \ No newline at end of file +#endif // __SWITCH_PANEL_H__ diff --git a/application/ws63/user_main/switch_panel/switch_panel_hilink.c b/application/ws63/user_main/switch_panel/switch_panel_hilink.c index 17539f8..e6bc257 100644 --- a/application/ws63/user_main/switch_panel/switch_panel_hilink.c +++ b/application/ws63/user_main/switch_panel/switch_panel_hilink.c @@ -5,6 +5,7 @@ #include "securec.h" #include "cJSON.h" #include "switch_panel.h" +#include "hfsys.h" static int handle_get_switch_common(int switch_id, const char* svc_id, const char* in, unsigned int in_len, @@ -79,16 +80,15 @@ void handle_device_unbind(void) { // 重置为出厂默认状态 reset_persistent_state(); g_persistent_state.is_bound = false; // 保持未绑定状态 - g_persistent_state.is_first_boot = false; // 标记为非出厂模式 + g_persistent_state.is_first_boot = true; // 标记为出厂模式,重启后自动配网 // 同步硬件状态 sync_hardware_state(); // 保存状态 - save_persistent_state(); - // HILINK_RestoreFactorySettings(); + save_persistent_state_sync(); // 使用同步保存确保立即写入 - e_printf("设备已重置为出厂默认状态\r\n"); + e_printf("设备已重置为出厂默认状态,重启后将自动进入配网模式\r\n"); } // 同步所有状态到云端 @@ -253,4 +253,100 @@ static int handle_get_switch_common(int switch_id, const char* svc_id, // 获取设备当前模式 system_mode_t get_current_mode(void) { return g_runtime_state.mode; +} + +//====================== 恢复出厂设置函数 ====================== + +// 执行恢复出厂设置并重启 +void perform_factory_reset_and_reboot(void) { + e_printf("开始执行恢复出厂设置...\r\n"); + + // 调用HiLink恢复出厂设置API,该API内部会: + // 1. 清除HiLink相关的所有绑定信息和云端数据 + // 2. 调用handle_device_unbind函数进行本地状态清除 + // 3. 自动重启设备 + int ret = HILINK_RestoreFactorySettings(); + if (ret != 0) { + e_printf("HiLink恢复出厂设置失败,错误码: %d\r\n", ret); + return; + } + + e_printf("HiLink恢复出厂设置API调用成功,等待系统重启...\r\n"); + + // 注意:这里代码可能不会执行到很多,因为HILINK_RestoreFactorySettings会触发重启 +} + +//====================== 记忆状态管理函数 ====================== + +// 保存当前子开关状态到记忆区 +void save_memory_switches(void) { + e_printf("保存当前子开关状态到记忆区\r\n"); + + for (int i = 0; i < SWITCH_COUNT; i++) { + g_persistent_state.memory_switches[i] = g_persistent_state.switches[i].switch_on; + e_printf("记忆开关%d状态: %s\r\n", i + 1, + g_persistent_state.memory_switches[i] ? "开" : "关"); + } + + g_persistent_state.has_memory_state = true; + + // 立即保存到Flash + save_persistent_state(); + + e_printf("子开关状态记忆保存完成\r\n"); +} + +// 从记忆区恢复子开关状态 +void restore_memory_switches(void) { + if (!g_persistent_state.has_memory_state) { + e_printf("没有记忆状态,无法恢复\r\n"); + return; + } + + e_printf("从记忆区恢复子开关状态\r\n"); + + bool any_switch_changed = false; + for (int i = 0; i < SWITCH_COUNT; i++) { + bool new_state = g_persistent_state.memory_switches[i]; + if (g_persistent_state.switches[i].switch_on != new_state) { + g_persistent_state.switches[i].switch_on = new_state; + g_persistent_state.switches[i].led_state = new_state; + + // 同步硬件状态 + set_switch_output(i, new_state); + set_led_output(i, new_state ? LED_WHITE : LED_YELLOW); + + e_printf("恢复开关%d状态: %s\r\n", i + 1, new_state ? "开" : "关"); + any_switch_changed = true; + } + } + + if (any_switch_changed) { + // 保存状态变化 + save_persistent_state(); + + // 同步到云端 + if (g_persistent_state.is_bound) { + fast_report_all_switches_async(); + } + } + + e_printf("子开关状态恢复完成\r\n"); +} + +// 清除记忆状态 +void clear_memory_switches(void) { + if (!g_persistent_state.has_memory_state) { + return; + } + + e_printf("清除记忆状态\r\n"); + + g_persistent_state.has_memory_state = false; + memset(g_persistent_state.memory_switches, 0, sizeof(g_persistent_state.memory_switches)); + + // 立即保存到Flash + save_persistent_state(); + + e_printf("记忆状态已清除\r\n"); } \ No newline at end of file diff --git a/application/ws63/user_main/switch_panel/switch_panel_keys.c b/application/ws63/user_main/switch_panel/switch_panel_keys.c index 5206ee2..bb78477 100644 --- a/application/ws63/user_main/switch_panel/switch_panel_keys.c +++ b/application/ws63/user_main/switch_panel/switch_panel_keys.c @@ -14,11 +14,14 @@ void update_switch_state(int switch_id, bool state) { } // 新逻辑:移除总开关限制,允许本地按键自由控制子开关 - // 本地按键控制子开关时,如果要开启子开关且总开关关闭,则自动打开总开关 + // 本地按键控制子开关时,如果要开启子开关且总开关关闭,则自动打开总开关并清除记忆状态 bool need_auto_master_on = false; + bool need_clear_memory = false; + if (state && !g_persistent_state.master_switch) { need_auto_master_on = true; - e_printf("子开关%d激活,将自动打开总开关\r\n", switch_id + 1); + need_clear_memory = true; // 物理按键操作时清除记忆状态 + e_printf("子开关%d激活,将自动打开总开关并清除记忆状态\r\n", switch_id + 1); } // 更新开关状态 @@ -35,6 +38,11 @@ void update_switch_state(int switch_id, bool state) { e_printf("开关%d 状态更新: %s\r\n", switch_id + 1, state ? "开" : "关"); + // 如果需要清除记忆状态 + if (need_clear_memory) { + clear_memory_switches(); + } + // 如果需要自动打开总开关 if (need_auto_master_on) { g_persistent_state.master_switch = true; @@ -78,16 +86,16 @@ void update_master_switch(bool state) { void apply_master_switch_control(void) { if (!g_persistent_state.master_switch) { - // 总开关关闭时,强制关闭所有子开关 - e_printf("总开关关闭,强制关闭所有子开关\r\n"); + // 总开关关闭时,先保存当前子开关状态到记忆区,再强制关闭所有子开关 + e_printf("总开关关闭,保存当前状态并强制关闭所有子开关\r\n"); + + // 保存当前子开关状态到记忆区 + save_memory_switches(); for (int i = 0; i < SWITCH_COUNT; i++) { - // 如果子开关之前是开着的,需要同步状态 - if (g_persistent_state.switches[i].switch_on) { - g_persistent_state.switches[i].switch_on = false; - g_persistent_state.switches[i].led_state = false; - e_printf("强制关闭子开关%d\r\n", i + 1); - } + // 强制关闭所有子开关 + g_persistent_state.switches[i].switch_on = false; + g_persistent_state.switches[i].led_state = false; // 更新硬件状态 set_switch_output(i, false); @@ -99,27 +107,16 @@ void apply_master_switch_control(void) { fast_report_all_switches_async(); } } else { - // 总开关开启时,自动开启所有子开关 - e_printf("总开关开启,自动开启所有子开关\r\n"); + // 总开关开启时,尝试恢复记忆状态,如果没有记忆状态则不操控子开关 + e_printf("总开关开启\r\n"); - bool any_switch_changed = false; - for (int i = 0; i < SWITCH_COUNT; i++) { - if (!g_persistent_state.switches[i].switch_on) { - g_persistent_state.switches[i].switch_on = true; - g_persistent_state.switches[i].led_state = true; // true表示白灯 - - // 同步硬件状态 - set_switch_output(i, true); - set_led_output(i, LED_WHITE); - - e_printf("自动开启子开关%d\r\n", i + 1); - any_switch_changed = true; - } - } - - // 如果有子开关状态变化,同步到云端 - if (any_switch_changed && g_persistent_state.is_bound) { - fast_report_all_switches_async(); + if (g_persistent_state.has_memory_state) { + // 恢复记忆的子开关状态 + e_printf("恢复记忆的子开关状态\r\n"); + restore_memory_switches(); + } else { + // 没有记忆状态,不操控子开关(保持当前状态) + e_printf("没有记忆状态,保持子开关当前状态不变\r\n"); } } @@ -152,6 +149,9 @@ int key_scan_task(void *arg) { while (1) { uint32_t current_time = hfsys_get_time(); + // 检查强制解绑超时 + check_force_unbind_timeout(); + // 扫描所有按键 for (int i = 0; i < SWITCH_COUNT; i++) { bool new_raw_state = get_key_input(i); @@ -178,6 +178,21 @@ int key_scan_task(void *arg) { press_start_time[i] = current_time; is_long_press_handled[i] = false; e_printf("按键%d 按下\r\n", i + 1); + + // 如果正在等待长按强制解绑 + if (g_runtime_state.waiting_long_press) { + if (i == 0) { + // 第一个按键:停止超时检测,等待长按处理 + e_printf("检测到第一个按键按下,停止强制解绑超时检测\r\n"); + g_runtime_state.wait_long_press_start_time = 0; // 停止超时检测 + } else { + // 其他按键:取消等待状态 + e_printf("检测到其他按键按下,取消强制解绑等待\r\n"); + g_runtime_state.waiting_long_press = false; + g_runtime_state.wait_long_press_start_time = 0; + g_runtime_state.consecutive_press_count = 0; + } + } } else { // 按键松开 uint32_t press_duration = current_time - press_start_time[i]; @@ -238,6 +253,15 @@ void handle_key_press(int key_id) { return; } + // 如果是第一个按键且设备已绑定,检测连续按键(用于强制解绑) + if (key_id == 0 && g_persistent_state.is_bound) { + if (check_consecutive_press(key_id)) { + e_printf("检测到连续4次按键,等待长按10秒执行强制解绑\r\n"); + // 不执行正常的开关切换操作,等待长按 + return; + } + } + // 正常模式下切换开关状态 bool current_state = g_persistent_state.switches[key_id].switch_on; update_switch_state(key_id, !current_state); @@ -251,21 +275,35 @@ void handle_key_long_press(int key_id) { e_printf("处理按键%d 长按事件\r\n", key_id + 1); - // 只有第一个按键支持长按进入配网模式 + // 只有第一个按键支持长按进入配网模式或强制解绑 if (key_id == 0) { - e_printf("长按第一个按键,检查配网条件\r\n"); + e_printf("长按第一个按键,检查操作条件\r\n"); - // 只有在正常模式下且设备未绑定时才能进入配网模式 - if (g_runtime_state.mode == MODE_NORMAL && !g_persistent_state.is_bound) { - extern int g_config_key_id; - g_config_key_id = key_id; // 设置触发配网的按键ID - enter_config_mode(); - } else { - if (g_persistent_state.is_bound) { - e_printf("设备已绑定,不能进入配网模式\r\n"); + // 检查设备状态并执行相应操作 + if (g_runtime_state.mode == MODE_NORMAL) { + if (!g_persistent_state.is_bound) { + // 未绑定设备:直接进入配网模式 + e_printf("设备未绑定,进入配网模式\r\n"); + extern int g_config_key_id; + g_config_key_id = key_id; // 设置触发配网的按键ID + enter_config_mode(); } else { - e_printf("非正常模式,不能进入配网模式\r\n"); + // 已绑定设备:检查是否在等待长按状态(强制解绑) + if (g_runtime_state.waiting_long_press) { + // 执行强制解绑 + e_printf("检测到强制解绑条件:连续4次短按+长按10秒,执行强制解绑\r\n"); + // 清除等待状态 + g_runtime_state.waiting_long_press = false; + g_runtime_state.wait_long_press_start_time = 0; + g_runtime_state.consecutive_press_count = 0; + perform_factory_reset_and_reboot(); + } else { + // 普通长按:只有未绑定设备才能配网,已绑定设备需要连续4次短按后长按 + e_printf("设备已绑定,需要先连续按4次再长按10秒才能强制解绑\r\n"); + } } + } else { + e_printf("非正常模式,不能进入配网模式或执行解绑\r\n"); } } else { e_printf("非第一个按键的长按,忽略\r\n"); @@ -311,4 +349,75 @@ void fast_report_switch(int switch_id) { // 快速上报总开关状态(兼容旧接口,内部使用异步上报) void fast_report_master_switch(void) { fast_report_master_switch_async(); +} + +//====================== 强制解绑连续按键检测 ====================== + +// 检测连续按键(返回true表示达到连续按键条件,可以等待长按) +bool check_consecutive_press(int key_id) { + // 只有第一个按键支持强制解绑 + if (key_id != 0) { + return false; + } + + uint32_t current_time = hfsys_get_time(); + + // 如果是首次按键或者超时,重置计数 + if (g_runtime_state.consecutive_press_count == 0 || + (current_time - g_runtime_state.last_press_time) > CONSECUTIVE_PRESS_TIMEOUT_MS) { + + g_runtime_state.consecutive_press_count = 1; + g_runtime_state.first_press_time = current_time; + g_runtime_state.last_press_time = current_time; + g_runtime_state.waiting_long_press = false; + + e_printf("连续按键检测:第1次按键\r\n"); + return false; + } + + // 增加按键计数 + g_runtime_state.consecutive_press_count++; + g_runtime_state.last_press_time = current_time; + + e_printf("连续按键检测:第%d次按键\r\n", g_runtime_state.consecutive_press_count); + + // 检查是否达到连续按键次数 + if (g_runtime_state.consecutive_press_count >= CONSECUTIVE_PRESS_COUNT) { + uint32_t total_time = current_time - g_runtime_state.first_press_time; + e_printf("连续按键检测完成:%d次按键在%ums内完成\r\n", + g_runtime_state.consecutive_press_count, total_time); + + // 设置等待长按标志和开始时间 + g_runtime_state.waiting_long_press = true; + g_runtime_state.wait_long_press_start_time = current_time; + + // 重置连续按键计数,为下次检测做准备 + g_runtime_state.consecutive_press_count = 0; + + e_printf("开始等待长按,3秒内必须开始长按否则超时\r\n"); + return true; // 可以等待长按了 + } + + return false; +} + +// 检查强制解绑超时 +void check_force_unbind_timeout(void) { + // 只有在等待长按状态下且设置了超时开始时间才检查超时 + if (!g_runtime_state.waiting_long_press || g_runtime_state.wait_long_press_start_time == 0) { + return; + } + + uint32_t current_time = hfsys_get_time(); + uint32_t wait_time = current_time - g_runtime_state.wait_long_press_start_time; + + // 检查是否超时(3秒) + if (wait_time >= FORCE_UNBIND_WAIT_TIMEOUT_MS) { + e_printf("强制解绑超时:等待长按超过3秒,退出检测流程\r\n"); + + // 清除等待状态 + g_runtime_state.waiting_long_press = false; + g_runtime_state.wait_long_press_start_time = 0; + g_runtime_state.consecutive_press_count = 0; // 完全重置 + } } \ No newline at end of file diff --git a/application/ws63/user_main/switch_panel/switch_panel_main.c b/application/ws63/user_main/switch_panel/switch_panel_main.c index 8ed546b..d9df274 100644 --- a/application/ws63/user_main/switch_panel/switch_panel_main.c +++ b/application/ws63/user_main/switch_panel/switch_panel_main.c @@ -359,21 +359,76 @@ static bool write_device_data_to_addr(uint32_t addr, uint8_t* data, uint32_t len } +// 从V1版本数据升级到V2版本 +static void upgrade_from_v1_to_v2(device_persistent_state_v1_t* v1_state, device_persistent_state_t* v2_state) { + e_printf("检测到V1版本数据,升级到V2版本\r\n"); + + // 复制V1的所有字段到V2 + memcpy(v2_state->switches, v1_state->switches, sizeof(v1_state->switches)); + v2_state->master_switch = v1_state->master_switch; + v2_state->panel_led = v1_state->panel_led; + v2_state->is_bound = v1_state->is_bound; + v2_state->is_first_boot = v1_state->is_first_boot; + + // 初始化V2新增的记忆功能字段 + v2_state->has_memory_state = false; + memset(v2_state->memory_switches, 0, sizeof(v2_state->memory_switches)); + + // 更新版本信息 + v2_state->magic = DEVICE_DATA_MAGIC; + v2_state->version = DEVICE_DATA_VERSION_V2; + memset(v2_state->reserved, 0, sizeof(v2_state->reserved)); + + e_printf("V1数据升级完成\r\n"); +} + // 从 Flash 加载持久化状态 int load_persistent_state(void) { int ret = 0; device_persistent_state_t state; + device_persistent_state_v1_t v1_state; bool valid = false; + bool is_v1_data = false; - // 尝试读取主数据区 + // 先尝试读取V2版本数据 valid = read_device_data_from_addr(DEVICE_DATA_FLASH_ADDR, (uint8_t*)&state, sizeof(state)); - - // 如果主数据区无效,尝试读取备份区 if (!valid) { valid = read_device_data_from_addr(DEVICE_DATA_BACKUP_ADDR, (uint8_t*)&state, sizeof(state)); } - // 两个存储区都失败,使用默认状态 + // 如果V2读取失败,尝试读取V1版本数据 + if (!valid) { + e_printf("V2数据读取失败,尝试读取V1版本数据\r\n"); + valid = read_device_data_from_addr(DEVICE_DATA_FLASH_ADDR, (uint8_t*)&v1_state, sizeof(v1_state)); + if (!valid) { + valid = read_device_data_from_addr(DEVICE_DATA_BACKUP_ADDR, (uint8_t*)&v1_state, sizeof(v1_state)); + } + + if (valid) { + // 检查是否确实是V1版本数据 + if (v1_state.magic == DEVICE_DATA_MAGIC && v1_state.version == DEVICE_DATA_VERSION_V1) { + is_v1_data = true; + e_printf("检测到V1版本数据\r\n"); + } else { + valid = false; + } + } + } else { + // 检查V2数据版本 + if (state.version != DEVICE_DATA_VERSION_V2) { + if (state.version == DEVICE_DATA_VERSION_V1) { + e_printf("读取到的数据是V1版本格式,需要升级\r\n"); + // 将读取的数据重新解释为V1格式 + memcpy(&v1_state, &state, sizeof(v1_state)); + is_v1_data = true; + } else { + e_printf("未知的数据版本: %d,使用默认状态\r\n", state.version); + valid = false; + } + } + } + + // 所有存储区都失败,使用默认状态 if (!valid) { e_printf("存储区数据损坏,使用默认状态\r\n"); reset_persistent_state(); @@ -381,21 +436,29 @@ int load_persistent_state(void) { return 0; } - // 更新持久化状态 - e_printf("持久化状态恢复:\r\n"); - e_printf("首次启动: %d => %d\r\n", g_persistent_state.is_first_boot, state.is_first_boot); - e_printf("配网状态: %d => %d\r\n", g_persistent_state.is_bound, state.is_bound); - e_printf("总开关: %d => %d\r\n", g_persistent_state.master_switch, state.master_switch); - e_printf("面板背光: %d => %d\r\n", g_persistent_state.panel_led, state.panel_led); - - for (int i = 0; i < SWITCH_COUNT; i++) { - e_printf("开关%d(%s): %d => %d, LED%d: %d => %d\r\n", - i + 1, state.switches[i].name, - g_persistent_state.switches[i].switch_on, state.switches[i].switch_on, - i + 1, g_persistent_state.switches[i].led_state, state.switches[i].led_state); + // 如果是V1数据,需要升级到V2 + if (is_v1_data) { + upgrade_from_v1_to_v2(&v1_state, &state); + // 升级后立即保存新版本数据 + memcpy(&g_persistent_state, &state, sizeof(device_persistent_state_t)); + save_persistent_state(); + } else { + // 直接使用V2数据 + memcpy(&g_persistent_state, &state, sizeof(device_persistent_state_t)); } - memcpy(&g_persistent_state, &state, sizeof(device_persistent_state_t)); + // 打印恢复的状态信息 + e_printf("持久化状态恢复 (版本%s):\r\n", is_v1_data ? "V1->V2" : "V2"); + e_printf("首次启动: %d, 配网状态: %d\r\n", g_persistent_state.is_first_boot, g_persistent_state.is_bound); + e_printf("总开关: %d, 面板背光: %d\r\n", g_persistent_state.master_switch, g_persistent_state.panel_led); + e_printf("记忆功能: %s\r\n", g_persistent_state.has_memory_state ? "有记忆" : "无记忆"); + + for (int i = 0; i < SWITCH_COUNT; i++) { + e_printf("开关%d(%s): %s, LED: %s\r\n", + i + 1, g_persistent_state.switches[i].name, + g_persistent_state.switches[i].switch_on ? "开" : "关", + g_persistent_state.switches[i].led_state ? "白灯" : "黄灯"); + } return 0; } @@ -581,6 +644,10 @@ void reset_persistent_state(void) { g_persistent_state.is_bound = false; // 设备未绑定 g_persistent_state.is_first_boot = true; // 标记为首次启动 + // 清除记忆状态 + g_persistent_state.has_memory_state = false; + memset(g_persistent_state.memory_switches, 0, sizeof(g_persistent_state.memory_switches)); + // 所有开关默认关闭,所有LED默认黄灯,初始化默认名字 for (int i = 0; i < SWITCH_COUNT; i++) { g_persistent_state.switches[i].switch_on = false; // 开关关闭 @@ -604,6 +671,13 @@ void init_runtime_state(void) { g_runtime_state.factory_test_running = false; g_runtime_state.last_save_time = 0; + // 初始化强制解绑连续按键检测状态 + g_runtime_state.consecutive_press_count = 0; + g_runtime_state.first_press_time = 0; + g_runtime_state.last_press_time = 0; + g_runtime_state.waiting_long_press = false; + g_runtime_state.wait_long_press_start_time = 0; + // 初始化所有开关的运行时状态 for (int i = 0; i < SWITCH_COUNT; i++) { g_runtime_state.switches[i].physical_key = true; // 按键松开 diff --git a/output/LPT262_hilink-SR_Switch-20250807-1.0.5.fwpkg b/output/LPT262_hilink-SR_Switch-20250807-1.0.5.fwpkg new file mode 100644 index 0000000..22c54d3 Binary files /dev/null and b/output/LPT262_hilink-SR_Switch-20250807-1.0.5.fwpkg differ diff --git a/output/package(SR_Switch-LPT262_hilink-20250807-1.0.5).zip b/output/package(SR_Switch-LPT262_hilink-20250807-1.0.5).zip new file mode 100644 index 0000000..f06e89e Binary files /dev/null and b/output/package(SR_Switch-LPT262_hilink-20250807-1.0.5).zip differ