From 10468736615f65447aa6360ff0d77a9aa508ee9b Mon Sep 17 00:00:00 2001 From: "ekko.bao" Date: Sun, 6 Jul 2025 19:21:42 +0800 Subject: [PATCH] =?UTF-8?q?claude=20=E7=94=9F=E6=88=90=E5=88=9D=E6=AD=A5?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../samples/wifi/ohos_connect/CMakeLists.txt | 1 + .../hilink_adapt/entry/hilink_ble_main.c | 32 +- .../hilink_adapt/product/device_profile.h | 12 +- .../hilink_adapt/product/hilink_device.c | 192 ++------ application/ws63/hsf/hfuart.h | 7 +- application/ws63/user_main/CMakeLists.txt | 6 + application/ws63/user_main/app_main.c | 30 +- .../ws63/user_main/spotlight/factory_test.h | 4 + .../user_main/switch_panel/switch_panel.h | 209 +++++++++ .../switch_panel/switch_panel_config.c | 335 ++++++++++++++ .../switch_panel/switch_panel_hilink.c | 255 +++++++++++ .../switch_panel/switch_panel_keys.c | 293 ++++++++++++ .../switch_panel/switch_panel_main.c | 432 ++++++++++++++++++ build/config/target_config/ws63/config.py | 13 +- readme.md | 47 +- 15 files changed, 1656 insertions(+), 212 deletions(-) create mode 100644 application/ws63/user_main/spotlight/factory_test.h create mode 100644 application/ws63/user_main/switch_panel/switch_panel.h create mode 100644 application/ws63/user_main/switch_panel/switch_panel_config.c create mode 100644 application/ws63/user_main/switch_panel/switch_panel_hilink.c create mode 100644 application/ws63/user_main/switch_panel/switch_panel_keys.c create mode 100644 application/ws63/user_main/switch_panel/switch_panel_main.c diff --git a/application/samples/wifi/ohos_connect/CMakeLists.txt b/application/samples/wifi/ohos_connect/CMakeLists.txt index 2842656..a251c8d 100755 --- a/application/samples/wifi/ohos_connect/CMakeLists.txt +++ b/application/samples/wifi/ohos_connect/CMakeLists.txt @@ -94,6 +94,7 @@ set(PRIVATE_HEADER ${ROOT_DIR}/protocol/wifi/source/host/inc/liteOS ${ROOT_DIR}/open_source/mbedtls/mbedtls_v3.1.0/harden/src/internal_include ${ROOT_DIR}/include + ${ROOT_DIR}/application/ws63/user_main/ ) # use this when you want to add ccflags like -include xxx diff --git a/application/samples/wifi/ohos_connect/hilink_adapt/entry/hilink_ble_main.c b/application/samples/wifi/ohos_connect/hilink_adapt/entry/hilink_ble_main.c index e478b75..37486b3 100755 --- a/application/samples/wifi/ohos_connect/hilink_adapt/entry/hilink_ble_main.c +++ b/application/samples/wifi/ohos_connect/hilink_adapt/entry/hilink_ble_main.c @@ -42,7 +42,7 @@ //static bool g_switch = 0; int sid_switch; static bool g_autoUpdate = 0; - +static int ble_adv_time = 0; static HILINK_BT_DevInfo g_btDevInfo = {0}; extern int set_get_ble_mac(void); extern int HILINK_Printf(const char *format, ...); @@ -258,6 +258,7 @@ static void ReporFwvCheckSum(void) } #endif +static int ble_sdk_running = 0; static void HILINK_BT_StateChangeHandler(HILINK_BT_SdkStatus event, const void *param) { (void)param; @@ -275,7 +276,8 @@ static void HILINK_BT_StateChangeHandler(HILINK_BT_SdkStatus event, const void * BLE_SetAdvType(BLE_ADV_LOCAL_NAME); /* BLE配网广播控制:参数代表广播时间,0:停止;0xFFFFFFFF:一直广播,其他:广播指定时间后停止,单位秒 */ - (void)BLE_CfgNetAdvCtrl(BLE_ADV_TIME); + (void)BLE_CfgNetAdvCtrl(ble_adv_time); + ble_sdk_running = 1; } } @@ -430,12 +432,20 @@ unsigned int GetWifiRecoveryType(void) { return (0x01 | 0x02); } +int start_hilink_ble_net_config(int32_t net_cfg_time_s) +{ + ble_adv_time = net_cfg_time_s; + if (ble_sdk_running) { + e_printf("set ble adv time: %ds\n", ble_adv_time); + BLE_CfgNetAdvCtrl(ble_adv_time); + } + return 0; +} int hilink_ble_main(void) { int ret = 0; - hfdbg_set_level(1); - hfset_hilink_mode(2); + hfset_hilink_mode(SMTLK_BLE_FAST_CONNECT); int hilink_entry_mode=hfget_hilink_mode(); printf("hilink_entry_mode:%d\r\n",hilink_entry_mode); if(hilink_entry_mode != SMTLK_SOFTAP) @@ -454,6 +464,7 @@ int hilink_ble_main(void) HILINK_EnableSle(); HILINK_EnablePrescan(); HILINK_SetProtType(17); + e_printf("SMTLK_BLE_FAST_CONNECT\r\n"); } ret = HILINK_SetNetConfigMode(HILINK_NETCONFIG_OTHER); @@ -482,6 +493,7 @@ int hilink_ble_main(void) HILINK_SAL_NOTICE("ble sdk init fail\r\n"); return -1; } + e_printf("ble sdk init success\r\n"); //set_get_ble_mac(); } else if(hilink_entry_mode == SMTLK_SOFTAP) @@ -528,6 +540,16 @@ int hilink_ble_main(void) HILINK_SAL_NOTICE("HILINK_Main start error"); return -1; } + e_printf("HILINK_Main start success\r\n"); hf_set_hilink_main_runing(); + // HILINK_RestoreFactorySettings(); return 0; -} \ No newline at end of file +} + +#ifndef CONFIG_SUPPORT_HILINK_INDIE_UPGRADE +// EKKO remove indie upgrade +int hilink_indie_upgrade_main(void) +{ + return 0; +} +#endif \ No newline at end of file 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 f367490..67def20 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 @@ -17,17 +17,17 @@ extern "C" { */ -#define ProductId "2Q4G" -#define deviceTypeId "201" +#define ProductId "2Q4S" +#define deviceTypeId "21S" #define manufacturerID "gub" -#define deviceModel "S15" +#define deviceModel "SR-SW-020-10S" #define configName "SR_S" #define configType "witch" #define enterpriseEnglishName "SORONTEK" #define brandEn "SORONTEK" -#define deviceName "SORONTEK智能面板" +#define deviceName "SORONTEK智能开关面板" #define productSeries "" - + #define DEVICE_HIVERSION "1.0.0" /* 设备固件版本号 */ #define FIRMWARE_VER "1.0.0" @@ -51,4 +51,4 @@ extern "C" { #endif #endif -#endif /* DEVICE_PROFILE_H */ \ No newline at end of file +#endif /* DEVICE_PROFILE_H */ diff --git a/application/samples/wifi/ohos_connect/hilink_adapt/product/hilink_device.c b/application/samples/wifi/ohos_connect/hilink_adapt/product/hilink_device.c index 03fe4b7..125ee69 100755 --- a/application/samples/wifi/ohos_connect/hilink_adapt/product/hilink_device.c +++ b/application/samples/wifi/ohos_connect/hilink_adapt/product/hilink_device.c @@ -15,12 +15,20 @@ #include "hsf.h" #include "hilink_entry.h" +extern void handle_device_online(void); +extern void handle_device_unbind(void); +extern void handle_device_offline(void); + +// 声明外部函数 +#include "switch_panel/switch_panel.h" + /* * * 服务信息定义 * 注意:(1)适配格式{svcType, svcId} * (2)与devicepartner平台物模型定义必须保持一致 */ +// 四开关面板服务信息定义 static const HILINK_SvcInfo SVC_INFO[] = { { "switch", "switch3" }, { "switch", "switch2" }, @@ -31,6 +39,7 @@ static const HILINK_SvcInfo SVC_INFO[] = { // { "checkSum", "checkSum" }, #endif }; + int HILINK_GetDevInfo(HILINK_DevInfo *devinfo) { if (devinfo == NULL) { @@ -126,9 +135,9 @@ int HILINK_GetSvcInfo(HILINK_SvcInfo *svcInfo[], unsigned int size) return -1; } } + e_printf("HILINK_GetSvcInfo svcNum:%d\r\n", svcNum); return svcNum; } - /* AC参数 */ unsigned char A_C[48] = { 0x66, 0x22, 0x33, 0x5F, 0x75, 0x31, 0x29, 0x6A, 0x27, 0x34, 0x57, 0x44, 0x32, 0x42, 0x27, 0x59, 0xE1, \ @@ -145,21 +154,6 @@ unsigned char *HILINK_GetAutoAc(void) extern int HILINK_HILINK_Printf(const char *format, ...); -// 设备状态定义 -typedef struct{ - int switch3_on; - int switch3_name; - int switch2_on; - int switch2_name; - int switch1_on; - int switch1_name; - int switch_on; - int switch4_on; - int switch4_name; -}t_device_info; -// 分配一个对象记录设备状态 -static t_device_info g_device_info = {0}; - // 服务处理函数定义 typedef int (*handle_put_func)(const char* svc_id, const char* payload, unsigned int len); typedef int (*handle_get_func)(const char* svc_id, const char* in, unsigned int in_len, char** out, unsigned int* out_len); @@ -178,148 +172,13 @@ int not_support_put(const char* svc_id, const char* payload, unsigned int len) HILINK_Printf("sid:%s NOT SUPPORT PUT function \r\n", svc_id); return 0; } -// 处理从 HILINK_PutCharState 传递过来的信息 -int handle_put_switch(const char* svc_id, const char* payload, unsigned int len) -{ - cJSON* pJson = cJSON_Parse(payload); - if (pJson == NULL){ - HILINK_Printf("JSON parse failed in PUT cmd: ID-%s \r\n", svc_id); - return -1; - } - cJSON* item = cJSON_GetObjectItem(pJson, "on"); - if (item != NULL) - g_device_info.switch_on = item->valueint; - if (pJson != NULL) - cJSON_Delete(pJson); - HILINK_Printf("handle func:%s, sid:%s \r\n", __FUNCTION__, svc_id); - return 0; -} -// 处理从 HILINK_GetCharState 传递过来的信息 -int handle_get_switch(const char* svc_id, const char* in, unsigned int in_len,char** out, unsigned int* out_len) -{ - *out_len = 20; - *out = (char*)malloc(*out_len); - if (NULL == *out) - return -1; - *out_len = sprintf_s(*out, *out_len, "{\"on\":%d}", g_device_info.switch_on); - HILINK_Printf("%s:%d svcId:%s, *out:%s\r\n",__FUNCTION__ , __LINE__,svc_id, *out); - return 0; -} -// 服务处理信息注册 - -int handle_put_switch3(const char* svc_id, const char* payload, unsigned int len) -{ - cJSON* pJson = cJSON_Parse(payload); - if (!pJson) - return -1; - cJSON* on_item = cJSON_GetObjectItem(pJson, "on"); - if (on_item) - g_device_info.switch3_on = on_item->valueint; - cJSON* name_item = cJSON_GetObjectItem(pJson, "name"); - if (name_item) - g_device_info.switch3_name = name_item->valueint; - HILINK_Printf("%s:%d svcId:%s, payload:%s\r\n", __FUNCTION__, __LINE__, svc_id, payload); - cJSON_Delete(pJson); - return 0; -} - -int handle_get_switch3(const char* svc_id, const char* in, unsigned int in_len, char** out, unsigned int* out_len) -{ - *out_len = 64; - *out = (char*)malloc(*out_len); - if (*out == NULL) - return -1; - *out_len = sprintf_s(*out, *out_len, "{\"on\":%d, \"name\":%d}", g_device_info.switch3_on, g_device_info.switch3_name); - HILINK_Printf("%s:%d svcId:%s, *out:%s\r\n", __FUNCTION__, __LINE__, svc_id, *out); - return 0; -} - -int handle_put_switch2(const char* svc_id, const char* payload, unsigned int len) -{ - cJSON* pJson = cJSON_Parse(payload); - if (!pJson) - return -1; - cJSON* on_item = cJSON_GetObjectItem(pJson, "on"); - if (on_item) - g_device_info.switch2_on = on_item->valueint; - cJSON* name_item = cJSON_GetObjectItem(pJson, "name"); - if (name_item) - g_device_info.switch2_name = name_item->valueint; - HILINK_Printf("%s:%d svcId:%s, payload:%s\r\n", __FUNCTION__, __LINE__, svc_id, payload); - cJSON_Delete(pJson); - return 0; -} - -int handle_get_switch2(const char* svc_id, const char* in, unsigned int in_len, char** out, unsigned int* out_len) -{ - *out_len = 64; - *out = (char*)malloc(*out_len); - if (*out == NULL) - return -1; - *out_len = sprintf_s(*out, *out_len, "{\"on\":%d, \"name\":%d}", g_device_info.switch2_on, g_device_info.switch2_name); - HILINK_Printf("%s:%d svcId:%s, *out:%s\r\n", __FUNCTION__, __LINE__, svc_id, *out); - return 0; -} - -int handle_put_switch1(const char* svc_id, const char* payload, unsigned int len) -{ - cJSON* pJson = cJSON_Parse(payload); - if (!pJson) - return -1; - cJSON* on_item = cJSON_GetObjectItem(pJson, "on"); - if (on_item) - g_device_info.switch1_on = on_item->valueint; - cJSON* name_item = cJSON_GetObjectItem(pJson, "name"); - if (name_item) - g_device_info.switch1_name = name_item->valueint; - HILINK_Printf("%s:%d svcId:%s, payload:%s\r\n", __FUNCTION__, __LINE__, svc_id, payload); - cJSON_Delete(pJson); - return 0; -} - -int handle_get_switch1(const char* svc_id, const char* in, unsigned int in_len, char** out, unsigned int* out_len) -{ - *out_len = 64; - *out = (char*)malloc(*out_len); - if (*out == NULL) - return -1; - *out_len = sprintf_s(*out, *out_len, "{\"on\":%d, \"name\":%d}", g_device_info.switch1_on, g_device_info.switch1_name); - HILINK_Printf("%s:%d svcId:%s, *out:%s\r\n", __FUNCTION__, __LINE__, svc_id, *out); - return 0; -} - -int handle_put_switch4(const char* svc_id, const char* payload, unsigned int len) -{ - cJSON* pJson = cJSON_Parse(payload); - if (!pJson) - return -1; - cJSON* on_item = cJSON_GetObjectItem(pJson, "on"); - if (on_item) - g_device_info.switch4_on = on_item->valueint; - cJSON* name_item = cJSON_GetObjectItem(pJson, "name"); - if (name_item) - g_device_info.switch4_name = name_item->valueint; - HILINK_Printf("%s:%d svcId:%s, payload:%s\r\n", __FUNCTION__, __LINE__, svc_id, payload); - cJSON_Delete(pJson); - return 0; -} - -int handle_get_switch4(const char* svc_id, const char* in, unsigned int in_len, char** out, unsigned int* out_len) -{ - *out_len = 64; - *out = (char*)malloc(*out_len); - if (*out == NULL) - return -1; - *out_len = sprintf_s(*out, *out_len, "{\"on\":%d, \"name\":%d}", g_device_info.switch4_on, g_device_info.switch4_name); - HILINK_Printf("%s:%d svcId:%s, *out:%s\r\n", __FUNCTION__, __LINE__, svc_id, *out); - return 0; -} +// 服务处理函数 HANDLE_SVC_INFO g_device_profile[] = { - {"switch3", handle_put_switch3, handle_get_switch3}, - {"switch2", handle_put_switch2, handle_get_switch2}, - {"switch1", handle_put_switch1, handle_get_switch1}, - {"switch", handle_put_switch, handle_get_switch}, - {"switch4", handle_put_switch4, handle_get_switch4}, + {"switch", handle_put_switch, handle_get_switch}, + {"switch1", handle_put_switch1, handle_get_switch1}, + {"switch2", handle_put_switch2, handle_get_switch2}, + {"switch3", handle_put_switch3, handle_get_switch3}, + {"switch4", handle_put_switch4, handle_get_switch4}, }; // 服务总数量 int g_device_profile_count = sizeof(g_device_profile) / sizeof(HANDLE_SVC_INFO); @@ -366,6 +225,7 @@ int handle_get_cmd(const char* svc_id, const char* in, unsigned int in_len, char } return function(svc_id, in, in_len, out,out_len); } + // 快速上报函数,用于上报服务状态信息 int fast_report(const char* svc_id) { @@ -377,7 +237,7 @@ int fast_report(const char* svc_id) return err; } err = HILINK_ReportCharState(svc_id, payload, len); - HILINK_Printf("report %s result is %d \r\n", svc_id, err); + HILINK_Printf("report %s result is %d, payload:%s \r\n", svc_id, err, payload); return err; } /* @@ -389,7 +249,10 @@ int fast_report(const char* svc_id) */ int HILINK_PutCharState(const char *svcId, const char *payload, unsigned int len) { + e_printf("[HILINK_PutCharState] 收到控制指令: svcId=%s, payload=%s\r\n", svcId, payload); + if ((svcId == NULL) || (payload == NULL)) { + e_printf("[HILINK_PutCharState] 参数无效\r\n"); return -1; } @@ -397,8 +260,11 @@ int HILINK_PutCharState(const char *svcId, const char *payload, unsigned int len if (json == NULL) { return -1; } - int err = handle_put_cmd(svcId, payload, len); - return err; + cJSON_Delete(json); + + int err = handle_put_cmd(svcId, payload, len); + e_printf("[HILINK_PutCharState] 控制指令处理完成,返回值: %d\r\n", err); + return err; } #ifdef CONFIG_SUPPORT_HILINK_INDIE_UPGRADE static int GetFwvCheckSum(char **out, unsigned int *outLen) @@ -498,6 +364,7 @@ void HILINK_NotifyDevStatus(int status) BLE_CfgNetAdvCtrl(0); (void)BLE_CfgNetAdvCtrl(0xFFFFFFFF); #endif + handle_device_offline(); break; case HILINK_M2M_CLOUD_ONLINE: /* 设备连接云端成功,请在此处添加实现 */ @@ -506,6 +373,8 @@ void HILINK_NotifyDevStatus(int status) BLE_CfgNetAdvCtrl(0); (void)BLE_CfgNetAdvCtrl(0xFFFFFFFF); #endif + /* 设备连接云端成功,请在此处添加实现 */ + handle_device_online(); // 处理设备上线 break; case HILINK_M2M_LONG_OFFLINE: /* 设备与云端连接长时间断开,请在此处添加实现 */ @@ -542,9 +411,11 @@ void HILINK_NotifyDevStatus(int status) break; case HILINK_DEVICE_UNREGISTER: /* 设备被解绑,请在此处添加实现 */ + handle_device_unbind(); break; case HILINK_REVOKE_FLAG_SET: /* 设备被复位标记置位,请在此处添加实现 */ + handle_device_unbind(); break; case HILINK_NEGO_REG_INFO_FAIL: /* 设备协商配网信息失败 */ @@ -589,6 +460,7 @@ int HILINK_ProcessBeforeRestart(int flag) /* APP删除设备触发模组重启 */ if (flag == 1) { /* 实现模组重启前的操作(如:保存系统状态等) */ + handle_device_unbind(); // 处理设备解绑 return 1; } diff --git a/application/ws63/hsf/hfuart.h b/application/ws63/hsf/hfuart.h index 1f19010..a998c75 100755 --- a/application/ws63/hsf/hfuart.h +++ b/application/ws63/hsf/hfuart.h @@ -64,7 +64,12 @@ void HSF_API HF_Debug(int debug_level, const char *format , ... ); #define hfdbg_warn(...) HF_Debug(DEBUG_WARN,"[warnning %d %s %d]",hfsys_get_time(),__FUNCTION__,__LINE__); \ HF_Debug(DEBUG_WARN,__VA_ARGS__) #define u_printf(...) HF_Debug(DEBUG_LEVEL_USER,__VA_ARGS__) - +#define e_printf(...) \ + do { \ + HF_Debug(DEBUG_WARN, "[Ekko]%d %s():%d: ", hfsys_get_time(), \ + __FUNCTION__, __LINE__); \ + HF_Debug(DEBUG_WARN, __VA_ARGS__); \ + } while (0) int hfuart_config(hfuart_handle_t huart, int baudrate, ENCOMPARITY_E parity, ENCOMBITS_E databits, ENCOMSTOPBITS_E stopbits, ENCOMUARTCTL_E fc); diff --git a/application/ws63/user_main/CMakeLists.txt b/application/ws63/user_main/CMakeLists.txt index feab344..84c01d8 100755 --- a/application/ws63/user_main/CMakeLists.txt +++ b/application/ws63/user_main/CMakeLists.txt @@ -6,12 +6,18 @@ set(COMPONENT_NAME "user_main") set(SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/app_main.c + ${CMAKE_CURRENT_SOURCE_DIR}/switch_panel/switch_panel_main.c + ${CMAKE_CURRENT_SOURCE_DIR}/switch_panel/switch_panel_keys.c + ${CMAKE_CURRENT_SOURCE_DIR}/switch_panel/switch_panel_hilink.c + ${CMAKE_CURRENT_SOURCE_DIR}/switch_panel/switch_panel_config.c ) + if (DEFINES MATCHES "HF_MCU_OTA") list(APPEND SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/mcu_update.c) endif() set(PUBLIC_HEADER ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/switch_panel/ ) set(PRIVATE_HEADER diff --git a/application/ws63/user_main/app_main.c b/application/ws63/user_main/app_main.c index 25367f9..6aa57e3 100755 --- a/application/ws63/user_main/app_main.c +++ b/application/ws63/user_main/app_main.c @@ -6,7 +6,10 @@ * */ +#include #include "hsf.h" +#include "hfgpio.h" +#include "switch_panel.h" #ifdef HF_MCU_OTA #include "mcu_update.h" #endif @@ -196,6 +199,15 @@ int hf_atcmd_appver(pat_session_t s,int argc,char *argv[],char *rsp,int len) } return -3; } + +#ifdef CONFIG_SPOTLIGHT_UT + extern int hf_atcmd_pwm(pat_session_t s, int argc, char *argv[], char *rsp, int len); + extern int hf_atcmd_pwm_query(pat_session_t s, int argc, char *argv[], char *rsp, int len); + extern int hf_atcmd_light(pat_session_t s, int argc, char *argv[], char *rsp, int len); + extern int hf_atcmd_light_query(pat_session_t s, int argc, char *argv[], char *rsp, int len); + extern int hf_atcmd_reset(pat_session_t s, int argc, char *argv[], char *rsp, int len); + extern int hf_atcmd_reset_factory(pat_session_t s, int argc, char *argv[], char *rsp, int len); +#endif const hfat_cmd_t user_define_at_cmds_table[]= { {"APPVER", hf_atcmd_appver, "AT+APPVER: get version. \r\n",NULL}, @@ -204,16 +216,32 @@ const hfat_cmd_t user_define_at_cmds_table[]= {"MCUVER", hf_atcmd_mcuver, "AT+MCUVER: get mcu version. \r\n",NULL}, {"OTAWAITTIME", hf_atcmd_ota_wait_time, "AT+OTAWAITTIME: set/get uart send mcu ota time\r\n", NULL}, #endif - {NULL, NULL, NULL, NULL} //the last item must be null +#ifdef CONFIG_SPOTLIGHT_UT + {"RESET", hf_atcmd_reset, "AT+RESET: reset. \r\n",NULL}, + {"FACTORY", hf_atcmd_reset_factory, "AT+FACTORY: factory. \r\n",NULL}, + {"UTPWM", hf_atcmd_pwm, "AT+PWM=,: Set PWM duty cycle (0-1000)\r\n", NULL}, + {"UTLIGHT", hf_atcmd_light, "AT+LIGHT=,: Set brightness(0-1000) and CCT(2700-6000)\r\n", NULL}, + {"UTPWMQ", NULL, "AT+PWMQ=,: Set PWM duty cycle (0-1000)\r\n", hf_atcmd_pwm_query}, + {"UTLIGHTQ", NULL, "AT+LIGHTQ=,: Set brightness(0-1000) and CCT(2700-6000)\r\n", hf_atcmd_light_query}, +#endif + {NULL, NULL, NULL, NULL} //the last item must be null }; int USER_FUNC user_app_main(void) { + hfdbg_set_level(1); //AT+UART uart0 if(hfnet_start_uart(HFTHREAD_PRIORITIES_LOW,(hfnet_callback_t)uart_recv_callback)!=HF_SUCCESS) { HF_Debug(DEBUG_WARN,"start uart fail!\r\n"); } + switch_panel_main(); // 四开关面板主程序 + + // 初始化按键扫描系统 + extern int key_system_init(void); + if(key_system_init() != HF_SUCCESS) { + HF_Debug(DEBUG_WARN,"key system init fail!\r\n"); + } #ifdef HF_MCU_OTA if(hf_mcu_init() != HF_SUCCESS) HF_Debug(DEBUG_WARN,"init mcu ota fail!\r\n"); diff --git a/application/ws63/user_main/spotlight/factory_test.h b/application/ws63/user_main/spotlight/factory_test.h new file mode 100644 index 0000000..81d137e --- /dev/null +++ b/application/ws63/user_main/spotlight/factory_test.h @@ -0,0 +1,4 @@ +#ifndef FACTORY_TEST_H +#define FACTORY_TEST_H +void try_detect_factory_test(void); +#endif // FACTORY_TEST_H diff --git a/application/ws63/user_main/switch_panel/switch_panel.h b/application/ws63/user_main/switch_panel/switch_panel.h new file mode 100644 index 0000000..1559b66 --- /dev/null +++ b/application/ws63/user_main/switch_panel/switch_panel.h @@ -0,0 +1,209 @@ +#ifndef __SWITCH_PANEL_H__ +#define __SWITCH_PANEL_H__ + +#include "hsf.h" +#include "cmsis_os2.h" +#include +#include +#include "driver/gpio.h" +#include "driver/pinctrl.h" +#include "driver/timer.h" +#include "platform_core_rom.h" +#include "schedule/osal_task.h" +#include "hfflash.h" +#include "hfuart.h" + +//====================== 硬件引脚定义 ====================== +// 根据CLAUDE.md中的物理连接定义,使用标准GPIO枚举 +// LED指示灯引脚 (控制按键指示灯颜色: 高电平=白灯, 低电平=黄灯) +#define LED1_GPIO GPIO_00 // GPIO 0 - 按键1指示灯 +#define LED2_GPIO GPIO_02 // GPIO 2 - 按键2指示灯 +#define LED3_GPIO GPIO_05 // GPIO 5 - 按键3指示灯 +#define LED4_GPIO GPIO_10 // GPIO 10 - 按键4指示灯 + +// 开关控制引脚 (控制实际开关: 高电平=开, 低电平=关) +#define SWITCH1_GPIO GPIO_12 // GPIO 12 - 开关1控制 +#define SWITCH2_GPIO GPIO_13 // GPIO 13 - 开关2控制 +#define SWITCH3_GPIO GPIO_14 // GPIO 14 - 开关3控制 +#define SWITCH4_GPIO GPIO_07 // GPIO 7 - 开关4控制 + +// 物理按键输入引脚 (输入检测: 低电平=按下, 高电平=松开) +#define KEY1_GPIO GPIO_09 // GPIO 9 - 按键1输入 +#define KEY2_GPIO GPIO_04 // GPIO 4 - 按键2输入 +#define KEY3_GPIO GPIO_11 // GPIO 11 - 按键3输入 +#define KEY4_GPIO GPIO_08 // GPIO 8 - 按键4输入 + +// 面板背光引脚 (控制面板背光: 高电平=亮黄灯, 低电平=灭灯) +#define PANEL_LED_GPIO GPIO_03 // GPIO 3 - 面板背光 + +//====================== 系统常量定义 ====================== +#define SWITCH_COUNT 4 // 开关数量 +#define KEY_DEBOUNCE_MS 50 // 按键防抖时间(毫秒) +#define KEY_LONG_PRESS_MS 10000 // 长按时间阈值(毫秒) - 用于进入配网 +#define CONFIG_TIMEOUT_MS (10*60*1000) // 配网超时时间(10分钟) +#define CONFIG_BLINK_MS (3*60*1000) // 配网前3分钟闪烁时间 +#define PANEL_BLINK_MS 1000 // 面板背光快闪时间(1秒) +#define LED_BLINK_FREQ_HZ 1 // 配网时LED闪烁频率(1Hz) + +//====================== 设备状态定义 ====================== +// 开关状态 +typedef enum { + SWITCH_OFF = 0, + SWITCH_ON = 1 +} switch_state_t; + +// 按键状态 +typedef enum { + KEY_RELEASED = 1, // 高电平 - 按键松开 + KEY_PRESSED = 0 // 低电平 - 按键按下 +} key_state_t; + +// LED状态 +typedef enum { + LED_YELLOW = 0, // 低电平 - 黄灯 + LED_WHITE = 1 // 高电平 - 白灯 +} led_state_t; + +// 面板背光状态 +typedef enum { + PANEL_LED_OFF = 0, // 低电平 - 背光关闭 + PANEL_LED_ON = 1 // 高电平 - 背光开启(黄色) +} panel_led_state_t; + +// 系统工作模式 +typedef enum { + MODE_NORMAL = 0, // 正常工作模式 + MODE_CONFIG, // 配网模式 + MODE_FACTORY_TEST, // 产测模式 + MODE_UNBIND // 设备解绑模式 +} system_mode_t; + +//====================== 设备状态结构 ====================== +// 单个开关状态信息 +typedef struct { + bool switch_on; // 开关状态 (true=开, false=关) + bool led_state; // LED状态 (true=白灯, false=黄灯) + bool physical_key; // 物理按键状态 (true=松开, false=按下) +} switch_info_t; + + +// 系统设备状态 +typedef struct { + switch_info_t switches[SWITCH_COUNT]; // 4个开关的状态 + bool master_switch; // 总开关状态 + bool panel_led; // 面板背光状态 + bool is_bound; // 设备绑定状态 + bool is_first_boot; // 是否第一次上电 + system_mode_t mode; // 系统工作模式 + uint32_t reserved[10]; // 保留字段 +} device_state_t; + + +//====================== Flash存储相关 ====================== +// Flash存储地址定义 +#define SUPPORT_SAVE_TO_FLASH 1 + +// 定义Flash存储地址和大小 +#define DEVICE_DATA_FLASH_SIZE 0x001000 // 使用一个页的大小 +#define DEVICE_DATA_FLASH_ADDR 0x000000 // 主数据区地址 +#define DEVICE_DATA_BACKUP_ADDR (DEVICE_DATA_FLASH_ADDR + DEVICE_DATA_FLASH_SIZE) // 备份数据区地址 + +// 设备数据结构 +typedef struct { + uint8_t checksum; // 校验和 + uint32_t magic; // 魔数,用于验证数据有效性 + uint32_t version; // 版本号 + uint32_t data_len; // 数据长度 + uint8_t data[0]; // 数据 +} device_data_t; + +#define DEVICE_DATA_MAGIC 0x4C505426 // "LPT&"的ASCII码 +#define DEVICE_DATA_VERSION 1 // 数据版本号 + +//====================== 配网相关定义 ====================== +#define FACTORY_TEST_SSID "ShuorongSelfTest" // 产测热点名称 +#define CONFIG_ENTRY_COUNT 3 // 连续重启次数进入配网 + +//====================== 任务和定时器相关 ====================== +#define TASK_STACK_SIZE 2048 +#define TASK_PRIORITY_HIGH OSAL_TASK_PRIORITY_HIGH +#define TASK_PRIORITY_NORM OSAL_TASK_PRIORITY_MIDDLE +#define TASK_PRIORITY_LOW OSAL_TASK_PRIORITY_LOW + +//====================== 全局变量声明 ====================== +extern device_state_t g_device_state; +extern timer_handle_t g_key_debounce_timer[SWITCH_COUNT]; +extern timer_handle_t g_config_timeout_timer; +extern timer_handle_t g_config_blink_timer; +extern osal_task *g_key_scan_task_handle; +extern osal_task *g_config_task_handle; + +//====================== 函数声明 ====================== + +// 主程序函数 +int switch_panel_main(void); + +// 硬件控制函数 +int switch_panel_gpio_init(void); +void set_switch_output(int switch_id, bool state); +void set_led_output(int led_id, led_state_t state); +void set_panel_led(panel_led_state_t state); +bool get_key_input(int key_id); + +// 设备状态管理函数 +int load_device_state(void); +int save_device_state(void); +void reset_device_state(void); +void sync_hardware_state(void); +void fast_report_switch(int switch_id); + +// 开关控制函数 +void update_switch_state(int switch_id, bool state); +void update_master_switch(bool state); +void apply_master_switch_control(void); + +// 按键处理函数 +int key_scan_task(void *arg); +void handle_key_press(int key_id); +void handle_key_long_press(int key_id); + +// 配网相关函数 +void enter_config_mode(void); +void exit_config_mode(void); +int config_mode_task(void *arg); +void config_led_blink(void); +void panel_led_blink(void); + +// 产测相关函数 +void enter_factory_test_mode(void); +void factory_test_sequence(void); +bool check_factory_test_wifi(void); + +// HiLink设备事件处理 +void handle_device_online(void); +void handle_device_offline(void); +void handle_device_unbind(void); +void sync_cloud_state(void); + +// HiLink服务处理函数 +int handle_put_switch(const char* svc_id, const char* payload, unsigned int len); +int handle_get_switch(const char* svc_id, const char* in, unsigned int in_len, char** out, unsigned int* out_len); +int handle_put_switch1(const char* svc_id, const char* payload, unsigned int len); +int handle_get_switch1(const char* svc_id, const char* in, unsigned int in_len, char** out, unsigned int* out_len); +int handle_put_switch2(const char* svc_id, const char* payload, unsigned int len); +int handle_get_switch2(const char* svc_id, const char* in, unsigned int in_len, char** out, unsigned int* out_len); +int handle_put_switch3(const char* svc_id, const char* payload, unsigned int len); +int handle_get_switch3(const char* svc_id, const char* in, unsigned int in_len, char** out, unsigned int* out_len); +int handle_put_switch4(const char* svc_id, const char* payload, unsigned int len); +int handle_get_switch4(const char* svc_id, const char* in, unsigned int in_len, char** out, unsigned int* out_len); + +// 调试和工具函数 +void print_device_state(void); +const char* get_mode_string(system_mode_t mode); + +// 定时器回调函数 +void key_debounce_timer_callback(uintptr_t data); +void config_timeout_timer_callback(uintptr_t data); +void config_blink_timer_callback(uintptr_t data); + +#endif // __SWITCH_PANEL_H__ \ No newline at end of file diff --git a/application/ws63/user_main/switch_panel/switch_panel_config.c b/application/ws63/user_main/switch_panel/switch_panel_config.c new file mode 100644 index 0000000..c1e059d --- /dev/null +++ b/application/ws63/user_main/switch_panel/switch_panel_config.c @@ -0,0 +1,335 @@ +#include "stdint.h" +#include "hsf.h" +#include "hfsys.h" +#include "hfgpio.h" +#include "switch_panel.h" +#include "hilink.h" +#include "hsf.h" +#include "hfconfig.h" +#include "pinctrl.h" +#include "timer.h" +#include "soc_osal.h" +#include "systick.h" + +//====================== 配网相关变量 ====================== +static bool g_config_led_blink_state = false; +static bool g_panel_led_blink_state = false; +static uint32_t g_config_blink_start_time = 0; +static int g_config_key_id = -1; // 触发配网的按键 + +//====================== 产测相关变量 ====================== +static bool g_factory_test_running = false; +static int g_factory_test_step = 0; +static uint32_t g_factory_test_start_time = 0; + +//====================== 配网模式函数 ====================== + +// 进入配网模式 +void enter_config_mode(void) { + if (g_device_state.mode == MODE_CONFIG) { + e_printf("[CONFIG] 已在配网模式中\r\n"); + return; + } + + e_printf("[CONFIG] 进入配网模式\r\n"); + + // 更新设备模式 + set_device_mode(MODE_CONFIG); + + // 记录配网开始时间 + g_config_start_time = hfsys_get_time(); + g_config_blink_start_time = g_config_start_time; + + // 面板背光快闪1秒表示进入配网模式 + panel_led_blink(); + + // 创建配网任务 + if (!g_config_task_handle) { + g_config_task_handle = osal_kthread_create((osal_kthread_handler)config_mode_task, + NULL, + "config_task", + TASK_STACK_SIZE); + if (!g_config_task_handle) { + e_printf("[CONFIG] 创建配网任务失败\r\n"); + return; + } + + // 设置任务优先级 + osal_kthread_set_priority(g_config_task_handle, TASK_PRIORITY_NORM); + } + + // 创建配网超时定时器 + if (!g_config_timeout_timer) { + int ret = uapi_timer_create(TIMER_INDEX_1, &g_config_timeout_timer); + if (ret != ERRCODE_SUCC) { + e_printf("[CONFIG] 创建配网超时定时器失败: %d\r\n", ret); + } + } + + if (g_config_timeout_timer) { + uapi_timer_start(g_config_timeout_timer, + CONFIG_TIMEOUT_MS * 1000, + config_timeout_timer_callback, + 0); + } + + // 创建闪烁定时器 + if (!g_config_blink_timer) { + int ret = uapi_timer_create(TIMER_INDEX_2, &g_config_blink_timer); + if (ret != ERRCODE_SUCC) { + e_printf("[CONFIG] 创建配网闪烁定时器失败: %d\r\n", ret); + } + } + + if (g_config_blink_timer) { + uint32_t blink_period = 1000000 / (LED_BLINK_FREQ_HZ * 2); // 半周期(微秒) + uapi_timer_start(g_config_blink_timer, + blink_period, + config_blink_timer_callback, + 0); + } + + e_printf("[CONFIG] 配网模式已开启,超时时间: %d分钟\r\n", CONFIG_TIMEOUT_MS / 60000); +} + +// 退出配网模式 +void exit_config_mode(void) { + if (g_device_state.mode != MODE_CONFIG) { + return; + } + + e_printf("[CONFIG] 退出配网模式\r\n"); + + // 停止定时器 + if (g_config_timeout_timer) { + uapi_timer_stop(g_config_timeout_timer); + } + + if (g_config_blink_timer) { + uapi_timer_stop(g_config_blink_timer); + } + + // 终止配网任务 + if (g_config_task_handle) { + osal_kthread_destroy(g_config_task_handle, 1); + g_config_task_handle = NULL; + } + + // 恢复正常LED状态 + for (int i = 0; i < SWITCH_COUNT; i++) { + set_led_output(i, g_device_state.switches[i].led_state ? LED_WHITE : LED_YELLOW); + } + + // 恢复面板背光状态 + set_panel_led(g_device_state.panel_led ? PANEL_LED_ON : PANEL_LED_OFF); + + // 更新设备模式 + set_device_mode(MODE_NORMAL); + + // 重置配网相关变量 + g_key_id = -1; + g_config_led_blink_state = false; + g_panel_led_blink_state = false; + + e_printf("[CONFIG] 已退出配网模式\r\n"); +} + +// 配网模式任务 +int config_mode_task(void *arg) { + (void)arg; + + e_printf("[CONFIG] 配网任务开始\r\n"); + + while (g_device_state.mode == MODE_CONFIG && !osal_kthread_should_stop()) { + // 检查是否有产测热点 + if (check_factory_test_wifi()) { + e_printf("[CONFIG] 检测到产测热点,进入产测模式\r\n"); + exit_config_mode(); + enter_factory_test_mode(); + break; + } + + // 每秒检查一次 + osal_msleep(1000); + } + + e_printf("[CONFIG] 配网任务结束\r\n"); + return 0; +} + +// 配网LED闪烁 +void config_led_blink(void) { + uint32_t current_time = hfsys_get_time(); + uint32_t elapsed_time = current_time - g_config_blink_start_time; + + // 前3分钟闪烁,后7分钟常亮 + if (elapsed_time < CONFIG_BLINK_MS) { + // 只有触发配网的按键LED闪烁,其他LED保持常亮 + for (int i = 0; i < SWITCH_COUNT; i++) { + if (i == g_config_key_id) { + // 触发配网的按键LED闪烁 + g_config_led_blink_state = !g_config_led_blink_state; + set_led_output(i, g_config_led_blink_state ? LED_WHITE : LED_YELLOW); + } else { + // 其他按键LED保持常亮 + set_led_output(i, LED_YELLOW); + } + } + } else { + // 超过3分钟后,所有LED保持常亮 + for (int i = 0; i < SWITCH_COUNT; i++) { + set_led_output(i, LED_YELLOW); + } + } +} + +// 面板背光快闪 +void panel_led_blink(void) { + // 快闪1秒 + for (int i = 0; i < 10; i++) { + set_panel_led(PANEL_LED_ON); + osal_msleep(50); + set_panel_led(PANEL_LED_OFF); + osal_msleep(50); + } + + // 恢复原状态 + set_panel_led(g_device_state.panel_led ? PANEL_LED_ON : PANEL_LED_OFF); +} + +//====================== 产测模式函数 ====================== + +// 进入产测模式 +void enter_factory_test_mode(void) { + e_printf("[FACTORY] 进入产测模式\r\n"); + + // 更新设备模式 + set_device_mode(MODE_FACTORY_TEST); + + // 初始化产测变量 + g_factory_test_running = true; + g_factory_test_step = 0; + g_factory_test_start_time = hfsys_get_time(); + + // 开始产测序列 + factory_test_sequence(); +} + +// 产测序列 +void factory_test_sequence(void) { + e_printf("[FACTORY] 开始产测序列\r\n"); + + // 步骤1: 开始指示 - 交替闪烁白黄灯500ms + for (int i = 0; i < 6; i++) { + for (int j = 0; j < SWITCH_COUNT; j++) { + set_led_output(j, (i % 2) ? LED_WHITE : LED_YELLOW); + } + osal_msleep(500); + } + + // 步骤2-5: 单个开关测试 (开1->4, 每个1.5秒) + for (int switch_id = 0; switch_id < SWITCH_COUNT; switch_id++) { + e_printf("[FACTORY] 测试开关%d\r\n", switch_id + 1); + + // 所有开关关闭,所有LED黄灯 + for (int i = 0; i < SWITCH_COUNT; i++) { + set_switch_output(i, false); + set_led_output(i, LED_YELLOW); + } + + // 当前测试的开关开启且LED白灯 + set_switch_output(switch_id, true); + set_led_output(switch_id, LED_WHITE); + + // 保持1.5秒 + osal_msleep(1500); + } + + // 步骤6: 全关 (1.5秒) + e_printf("[FACTORY] 测试全关\r\n"); + for (int i = 0; i < SWITCH_COUNT; i++) { + set_switch_output(i, false); + set_led_output(i, LED_YELLOW); + } + osal_msleep(1500); + + // 步骤7: 全开 (1.5秒) + e_printf("[FACTORY] 测试全开\r\n"); + for (int i = 0; i < SWITCH_COUNT; i++) { + set_switch_output(i, true); + set_led_output(i, LED_WHITE); + } + osal_msleep(1500); + + // 步骤8: 再次全关 + e_printf("[FACTORY] 结束测试 - 全关\r\n"); + for (int i = 0; i < SWITCH_COUNT; i++) { + set_switch_output(i, false); + set_led_output(i, LED_YELLOW); + } + + // TODO: WiFi信号强度校验 + bool wifi_test_pass = check_factory_test_wifi(); + + // 显示最终结果 + if (wifi_test_pass) { + e_printf("[FACTORY] 产测全部通过\r\n"); + // 所有开关开启表示通过 + for (int i = 0; i < SWITCH_COUNT; i++) { + set_switch_output(i, true); + set_led_output(i, LED_WHITE); + } + } else { + e_printf("[FACTORY] 产测失败\r\n"); + // 所有开关关闭表示失败 + for (int i = 0; i < SWITCH_COUNT; i++) { + set_switch_output(i, false); + set_led_output(i, LED_YELLOW); + } + } + + // 产测完成,返回正常模式 + g_factory_test_running = false; + set_device_mode(MODE_NORMAL); + + // 恢复设备默认状态 + sync_hardware_state(); + + e_printf("[FACTORY] 产测序列完成\r\n"); +} + +// 检查产测热点 +bool check_factory_test_wifi(void) { + // 简化实现:直接返回false,实际应该扫描WiFi热点 + // TODO: 实际实现需要调用WiFi扫描接口查找 "ShuorongSelfTest" 热点 + + static bool test_triggered = false; + + // 模拟产测触发条件(仅作为演示) + if (!test_triggered && g_device_state.power_on_count > 5) { + test_triggered = true; + return false; // 模拟找到产测热点 + } + + return false; // 默认未找到产测热点 +} + +//====================== 定时器回调函数 ====================== + +// 配网超时定时器回调 +void config_timeout_timer_callback(uintptr_t data) { + (void)data; + + e_printf("[CONFIG] 配网超时,退出配网模式\r\n"); + + // 超时退出配网模式 + exit_config_mode(); +} + +// 配网闪烁定时器回调 +void config_blink_timer_callback(uintptr_t data) { + (void)data; + + // 执行闪烁操作 + config_led_blink(); +} \ No newline at end of file diff --git a/application/ws63/user_main/switch_panel/switch_panel_hilink.c b/application/ws63/user_main/switch_panel/switch_panel_hilink.c new file mode 100644 index 0000000..8f9aad0 --- /dev/null +++ b/application/ws63/user_main/switch_panel/switch_panel_hilink.c @@ -0,0 +1,255 @@ +#include +#include "hsf.h" +#include "hfgpio.h" +#include "hilink.h" +#include "securec.h" +#include "cJSON.h" +#include "switch_panel.h" + +//====================== HiLink 设备事件处理 ====================== + +// 处理设备上线事件 +void handle_device_online(void) { + e_printf("[HILINK] 设备上线\r\n"); + + // 更新设备绑定状态 + g_device_state.is_bound = true; + + // 退出配网模式 + if (g_device_state.mode == MODE_CONFIG) { + exit_config_mode(); + } + + // 同步所有状态到云端 + sync_cloud_state(); + + // 保存状态 + save_device_state(); +} + +// 处理设备下线事件 +void handle_device_offline(void) { + e_printf("[HILINK] 设备下线\r\n"); + + // 设备下线时保持现有状态,不做特殊处理 +} + +// 处理设备解绑事件 +void handle_device_unbind(void) { + e_printf("[HILINK] 设备解绑\r\n"); + + // 更新设备绑定状态 + g_device_state.is_bound = false; + g_device_state.mode = MODE_UNBIND; + + // 重置为出厂默认状态 + reset_device_state(); + g_device_state.is_bound = false; // 保持未绑定状态 + + // 同步硬件状态 + sync_hardware_state(); + + // 保存状态 + save_device_state(); + + e_printf("[HILINK] 设备已重置为出厂默认状态\r\n"); +} + +// 同步所有状态到云端 +void sync_cloud_state(void) { + e_printf("[HILINK] 开始同步状态到云端\r\n"); + + // 上报总开关状态 + extern int fast_report(const char* svc_id); + fast_report("switch"); + + // 上报所有子开关状态 + for (int i = 0; i < SWITCH_COUNT; i++) { + char svc_id[16] = {0}; + snprintf(svc_id, sizeof(svc_id), "switch%d", i + 1); + fast_report(svc_id); + // osDelay(pdMS_TO_TICKS(100)); // 防止上报过快 + } + + e_printf("[HILINK] 状态同步完成\r\n"); +} + +//====================== HiLink 服务处理函数 ====================== + +// 处理总开关PUT命令 +int handle_put_switch(const char* svc_id, const char* payload, unsigned int len) { + if (!svc_id || !payload) { + e_printf("[HILINK] handle_put_switch 参数无效\r\n"); + return -1; + } + + e_printf("[HILINK] 收到总开关控制命令: %s\r\n", payload); + + cJSON* json = cJSON_Parse(payload); + if (!json) { + e_printf("[HILINK] JSON解析失败\r\n"); + return -1; + } + + cJSON* on_item = cJSON_GetObjectItem(json, "on"); + if (on_item && cJSON_IsBool(on_item)) { + bool state = cJSON_IsTrue(on_item); + update_master_switch(state); + e_printf("[HILINK] 总开关设置为: %s\r\n", state ? "开" : "关"); + } + + cJSON_Delete(json); + return 0; +} + +// 处理总开关GET命令 +int handle_get_switch(const char* svc_id, const char* in, unsigned int in_len, + char** out, unsigned int* out_len) { + if (!out || !out_len) { + return -1; + } + + *out_len = 32; + *out = (char*)malloc(*out_len); + if (!*out) { + return -1; + } + + *out_len = snprintf(*out, *out_len, "{\"on\":%s}", + g_device_state.master_switch ? "true" : "false"); + + e_printf("[HILINK] 返回总开关状态: %s\r\n", *out); + return 0; +} + +// 处理开关1 PUT命令 +int handle_put_switch1(const char* svc_id, const char* payload, unsigned int len) { + return handle_put_switch_common(0, svc_id, payload, len); +} + +// 处理开关1 GET命令 +int handle_get_switch1(const char* svc_id, const char* in, unsigned int in_len, + char** out, unsigned int* out_len) { + return handle_get_switch_common(0, svc_id, in, in_len, out, out_len); +} + +// 处理开关2 PUT命令 +int handle_put_switch2(const char* svc_id, const char* payload, unsigned int len) { + return handle_put_switch_common(1, svc_id, payload, len); +} + +// 处理开关2 GET命令 +int handle_get_switch2(const char* svc_id, const char* in, unsigned int in_len, + char** out, unsigned int* out_len) { + return handle_get_switch_common(1, svc_id, in, in_len, out, out_len); +} + +// 处理开关3 PUT命令 +int handle_put_switch3(const char* svc_id, const char* payload, unsigned int len) { + return handle_put_switch_common(2, svc_id, payload, len); +} + +// 处理开关3 GET命令 +int handle_get_switch3(const char* svc_id, const char* in, unsigned int in_len, + char** out, unsigned int* out_len) { + return handle_get_switch_common(2, svc_id, in, in_len, out, out_len); +} + +// 处理开关4 PUT命令 +int handle_put_switch4(const char* svc_id, const char* payload, unsigned int len) { + return handle_put_switch_common(3, svc_id, payload, len); +} + +// 处理开关4 GET命令 +int handle_get_switch4(const char* svc_id, const char* in, unsigned int in_len, + char** out, unsigned int* out_len) { + return handle_get_switch_common(3, svc_id, in, in_len, out, out_len); +} + +//====================== 子开关通用处理函数 ====================== + +// 子开关PUT命令通用处理函数 +static int handle_put_switch_common(int switch_id, const char* svc_id, + const char* payload, unsigned int len) { + if (switch_id < 0 || switch_id >= SWITCH_COUNT || !svc_id || !payload) { + e_printf("[HILINK] handle_put_switch%d 参数无效\r\n", switch_id + 1); + return -1; + } + + e_printf("[HILINK] 收到开关%d控制命令: %s\r\n", switch_id + 1, payload); + + cJSON* json = cJSON_Parse(payload); + if (!json) { + e_printf("[HILINK] JSON解析失败\r\n"); + return -1; + } + + cJSON* on_item = cJSON_GetObjectItem(json, "on"); + if (on_item && cJSON_IsBool(on_item)) { + bool state = cJSON_IsTrue(on_item); + update_switch_state(switch_id, state); + e_printf("[HILINK] 开关%d设置为: %s\r\n", + switch_id + 1, state ? "开" : "关"); + } + + // 检查是否有name字段(预留功能) + cJSON* name_item = cJSON_GetObjectItem(json, "name"); + if (name_item && cJSON_IsString(name_item)) { + e_printf("[HILINK] 开关%d名称: %s\r\n", + switch_id + 1, cJSON_GetStringValue(name_item)); + // TODO: 将来可以存储开关名称 + } + + cJSON_Delete(json); + return 0; +} + +// 子开关GET命令通用处理函数 +static int handle_get_switch_common(int switch_id, const char* svc_id, + const char* in, unsigned int in_len, + char** out, unsigned int* out_len) { + if (switch_id < 0 || switch_id >= SWITCH_COUNT || !out || !out_len) { + return -1; + } + + *out_len = 64; + *out = (char*)malloc(*out_len); + if (!*out) { + return -1; + } + + // 返回开关状态和名称 + *out_len = snprintf(*out, *out_len, + "{\"on\":%s,\"name\":\"开关%d\"}", + g_device_state.switches[switch_id].switch_on ? "true" : "false", + switch_id + 1); + + e_printf("[HILINK] 返回开关%d状态: %s\r\n", switch_id + 1, *out); + return 0; +} + +//====================== HiLink 事件扩展函数 ====================== + +// 检查设备是否在线 +bool is_device_online(void) { + return g_device_state.is_bound; +} + +// 获取设备当前模式 +system_mode_t get_current_mode(void) { + return g_device_state.mode; +} + +// 设置设备工作模式 +void set_device_mode(system_mode_t mode) { + if (g_device_state.mode != mode) { + system_mode_t old_mode = g_device_state.mode; + g_device_state.mode = mode; + + e_printf("[MODE] 设备模式切换: %s -> %s\r\n", + get_mode_string(old_mode), get_mode_string(mode)); + + // 保存模式变更 + save_device_state(); + } +} \ 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 new file mode 100644 index 0000000..eca6ce6 --- /dev/null +++ b/application/ws63/user_main/switch_panel/switch_panel_keys.c @@ -0,0 +1,293 @@ +#include "switch_panel.h" +#include "hilink.h" + +//====================== 按键检测相关变量 ====================== +static bool g_key_states[SWITCH_COUNT] = {true, true, true, true}; // 上一次按键状态 +static uint32_t g_key_press_time[SWITCH_COUNT] = {0}; // 按键按下开始时间 +static bool g_key_debounce_flag[SWITCH_COUNT] = {false}; // 防抖标志 +static bool g_is_long_press_handled[SWITCH_COUNT] = {false}; // 长按处理标志 + +// 定时器参数 +typedef struct { + int key_id; +} key_timer_param_t; + +static key_timer_param_t g_timer_params[SWITCH_COUNT]; + +//====================== 开关控制函数 ====================== + +// 更新单个开关状态 +void update_switch_state(int switch_id, bool state) { + if (switch_id < 0 || switch_id >= SWITCH_COUNT) { + e_printf("[SWITCH] 无效的开关ID: %d\r\n", switch_id); + return; + } + + // 检查总开关是否允许操作 + if (!g_device_state.master_switch && state) { + e_printf("[SWITCH] 总开关关闭,不允许开启开关%d\r\n", switch_id + 1); + return; + } + + // 更新开关状态 + if (g_device_state.switches[switch_id].switch_on != state) { + g_device_state.switches[switch_id].switch_on = state; + + // 更新LED指示灯(开关开启时LED白灯,关闭时LED黄灯) + g_device_state.switches[switch_id].led_state = state; + + // 同步硬件状态 + set_switch_output(switch_id, state); + set_led_output(switch_id, state ? LED_WHITE : LED_YELLOW); + + e_printf("[SWITCH] 开关%d 状态更新: %s\r\n", + switch_id + 1, state ? "开" : "关"); + + // 立即保存状态 + save_device_state(); + + // 上报状态给云端 + if (g_device_state.is_bound) { + fast_report_switch(switch_id); + } + } +} + +// 更新总开关状态 +void update_master_switch(bool state) { + if (g_device_state.master_switch != state) { + g_device_state.master_switch = state; + + e_printf("[SWITCH] 总开关状态更新: %s\r\n", state ? "开" : "关"); + + // 应用总开关控制逻辑 + apply_master_switch_control(); + + // 立即保存状态 + save_device_state(); + + // 上报状态给云端 + if (g_device_state.is_bound) { + fast_report_master_switch(); + } + } +} + +// 应用总开关控制逻辑 +void apply_master_switch_control(void) { + for (int i = 0; i < SWITCH_COUNT; i++) { + if (!g_device_state.master_switch) { + // 总开关关闭时,关闭所有开关但保持LED状态 + set_switch_output(i, false); + } else { + // 总开关开启时,恢复各开关的原状态 + set_switch_output(i, g_device_state.switches[i].switch_on); + } + + // LED状态保持不变,始终显示实际的开关状态 + set_led_output(i, g_device_state.switches[i].led_state ? LED_WHITE : LED_YELLOW); + } +} + +//====================== 按键检测与处理 ====================== + +// 按键防抖定时器回调 +void key_debounce_timer_callback(uintptr_t data) { + key_timer_param_t *param = (key_timer_param_t *)data; + if (!param) return; + + int key_id = param->key_id; + if (key_id < 0 || key_id >= SWITCH_COUNT) return; + + // 清除防抖标志 + g_key_debounce_flag[key_id] = false; +} + +// 按键扫描任务 +int key_scan_task(void *arg) { + (void)arg; + + e_printf("[KEY] 按键扫描任务开始\r\n"); + + while (!osal_kthread_should_stop()) { + // 扫描所有按键 + for (int i = 0; i < SWITCH_COUNT; i++) { + bool current_state = get_key_input(i); + uint32_t current_time = hfsys_get_time(); + + // 检测按键状态变化 + if (current_state != g_key_states[i] && !g_key_debounce_flag[i]) { + if (current_state == KEY_PRESSED) { + // 按键按下 + g_key_press_time[i] = current_time; + g_is_long_press_handled[i] = false; + + e_printf("[KEY] 按键%d 按下\r\n", i + 1); + } else { + // 按键松开 + uint32_t press_duration = current_time - g_key_press_time[i]; + + if (press_duration >= KEY_LONG_PRESS_MS && !g_is_long_press_handled[i]) { + // 长按事件(如果在按下期间没有处理) + handle_key_long_press(i); + g_is_long_press_handled[i] = true; + } else if (press_duration < KEY_LONG_PRESS_MS) { + // 短按事件 + handle_key_press(i); + } + + e_printf("[KEY] 按键%d 松开 (持续时间: %ums)\r\n", + i + 1, press_duration); + } + + // 启动防抖定时器 + g_key_debounce_flag[i] = true; + if (g_key_debounce_timer[i]) { + uapi_timer_start(g_key_debounce_timer[i], + KEY_DEBOUNCE_MS * 1000, + key_debounce_timer_callback, + (uintptr_t)&g_timer_params[i]); + } + + g_key_states[i] = current_state; + g_device_state.switches[i].physical_key = current_state; + } + + // 检查是否达到长按时间(在按下期间监测) + if (current_state == KEY_PRESSED && !g_is_long_press_handled[i]) { + uint32_t press_duration = current_time - g_key_press_time[i]; + if (press_duration >= KEY_LONG_PRESS_MS) { + handle_key_long_press(i); + g_is_long_press_handled[i] = true; + } + } + } + + // 休眠一段时间再继续扫描 + osal_msleep(10); // 10ms扫描间隔 + } + + return 0; +} + +// 处理按键短按事件 +void handle_key_press(int key_id) { + if (key_id < 0 || key_id >= SWITCH_COUNT) { + return; + } + + e_printf("[KEY] 处理按键%d 短按事件\r\n", key_id + 1); + + // 在配网模式下,忽略短按事件 + if (g_device_state.mode == MODE_CONFIG) { + e_printf("[KEY] 配网模式下,忽略短按事件\r\n"); + return; + } + + // 在产测模式下,忽略短按事件 + if (g_device_state.mode == MODE_FACTORY_TEST) { + e_printf("[KEY] 产测模式下,忽略短按事件\r\n"); + return; + } + + // 正常模式下切换开关状态 + bool current_state = g_device_state.switches[key_id].switch_on; + update_switch_state(key_id, !current_state); +} + +// 处理按键长按事件 +void handle_key_long_press(int key_id) { + if (key_id < 0 || key_id >= SWITCH_COUNT) { + return; + } + + e_printf("[KEY] 处理按键%d 长按事件\r\n", key_id + 1); + + // 只有第一个按键支持长按进入配网模式 + if (key_id == 0) { + e_printf("[KEY] 长按第一个按键,进入配网模式\r\n"); + + // 只有在正常模式下才能进入配网模式 + if (g_device_state.mode == MODE_NORMAL) { + enter_config_mode(); + } else { + e_printf("[KEY] 非正常模式,不能进入配网模式\r\n"); + } + } else { + e_printf("[KEY] 非第一个按键的长按,忽略\r\n"); + } +} + +//====================== 初始化函数 ====================== + +int key_system_init(void) { + int ret = ERRCODE_SUCC; + + // 初始化定时器 + ret = uapi_timer_init(); + if (ret != ERRCODE_SUCC) { + e_printf("[KEY] 定时器初始化失败: %d\r\n", ret); + return HF_FAIL; + } + + // 初始化定时器参数 + for (int i = 0; i < SWITCH_COUNT; i++) { + g_timer_params[i].key_id = i; + + // 创建防抖定时器 + ret = uapi_timer_create(TIMER_INDEX_0, &g_key_debounce_timer[i]); + if (ret != ERRCODE_SUCC) { + e_printf("[KEY] 创建按键%d防抖定时器失败: %d\r\n", i + 1, ret); + return HF_FAIL; + } + + // 初始化按键状态 + g_key_states[i] = get_key_input(i); + g_device_state.switches[i].physical_key = g_key_states[i]; + } + + // 创建按键扫描任务 + g_key_scan_task_handle = osal_kthread_create((osal_kthread_handler)key_scan_task, + NULL, + "key_scan", + TASK_STACK_SIZE); + if (!g_key_scan_task_handle) { + e_printf("[KEY] 创建按键扫描任务失败\r\n"); + return HF_FAIL; + } + + // 设置任务优先级 + ret = osal_kthread_set_priority(g_key_scan_task_handle, TASK_PRIORITY_NORM); + if (ret != 0) { + e_printf("[KEY] 设置按键扫描任务优先级失败: %d\r\n", ret); + } + + e_printf("[KEY] 按键系统初始化完成\r\n"); + return HF_SUCCESS; +} + +//====================== 快速上报函数 ====================== + +// 快速上报单个开关状态 +void fast_report_switch(int switch_id) { + if (switch_id < 0 || switch_id >= SWITCH_COUNT) { + return; + } + + char svc_id[16] = {0}; + snprintf(svc_id, sizeof(svc_id), "switch%d", switch_id + 1); + + // 使用已有的fast_report函数 + extern int fast_report(const char* svc_id); + fast_report(svc_id); + + e_printf("[REPORT] 已上报开关%d状态\r\n", switch_id + 1); +} + +// 快速上报总开关状态 +void fast_report_master_switch(void) { + extern int fast_report(const char* svc_id); + fast_report("switch"); + + e_printf("[REPORT] 已上报总开关状态\r\n"); +} \ 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 new file mode 100644 index 0000000..8c2bd72 --- /dev/null +++ b/application/ws63/user_main/switch_panel/switch_panel_main.c @@ -0,0 +1,432 @@ +#include "switch_panel.h" +#include "hilink.h" +#include "securec.h" +#include "hilink_sal_defines.h" +#include "driver/pinctrl.h" +#include "driver/gpio.h" +#include "platform_core_rom.h" + +//====================== 全局变量 ====================== +device_state_t g_device_state = {0}; +timer_handle_t g_key_debounce_timer[SWITCH_COUNT] = {0}; +timer_handle_t g_config_timeout_timer = 0; +timer_handle_t g_config_blink_timer = 0; +osal_task *g_key_scan_task_handle = NULL; +osal_task *g_config_task_handle = NULL; + +static bool g_initialized = false; +static uint32_t g_config_start_time = 0; +static bool g_config_led_state = false; + +//====================== 存储管理函数 ====================== + +// 计算数据校验码 + +// 计算校验和 +static uint8_t calculate_checksum(const uint8_t* data, int len) +{ + uint8_t sum = 0; + for (int i = 0; i < len; i++) { + sum ^= data[i]; + } + return sum; +} + +// 从指定地址读取设备数据 +static bool read_device_data_from_addr(uint32_t addr, uint8_t* data, uint32_t len) +{ + int total_size = sizeof(device_data_t) + len; + device_data_t *data_all = malloc(total_size); + if (data_all == NULL) { + e_printf("内存分配失败\r\n"); + return false; + } + + int ret = hfuflash_read(addr, (char*)data_all, total_size); + if (ret != total_size) { + e_printf("从地址0x%x读取设备数据失败,实际读取长度:%d\r\n", addr, ret); + goto lab_err; + } + + uint8_t checksum = calculate_checksum(data_all->data, data_all->data_len); + if (checksum != data_all->checksum) { + e_printf("check sum error:%x\n", data_all->version); + goto lab_err; + } + + if (data_all->magic != DEVICE_DATA_MAGIC) { + e_printf("magic error:%x\n", data_all->magic); + goto lab_err; + } + + if (data_all->version > DEVICE_DATA_VERSION) { + e_printf("versoin missmatch:%x\n", data_all->version); + goto lab_err; + } + memcpy_s(data, len, data_all->data, data_all->data_len); + free(data_all); + return true; + +lab_err: + free(data_all); + return false; +} + +// 写入数据到指定地址 +static bool write_device_data_to_addr(uint32_t addr, uint8_t* data, uint32_t len) +{ + int ret = hfuflash_erase_page(addr, 1); + if (ret != HF_SUCCESS) { + e_printf("擦除地址0x%x的Flash页失败,错误码:%d\r\n", addr, ret); + return false; + } + uint32_t total_size = sizeof(device_data_t) + len; + device_data_t *data_all = malloc(total_size); + if (data_all == NULL) { + e_printf("内存分配失败\r\n"); + return false; + } + memset(data_all, 0, total_size); + memcpy_s(data_all->data, len, data, len); + data_all->checksum = calculate_checksum(data_all->data, data_all->data_len); + data_all->magic = DEVICE_DATA_MAGIC; + data_all->version = DEVICE_DATA_VERSION; + ret = hfuflash_write(addr, (char*)data_all, total_size); + if (ret != total_size) { + e_printf("写入数据到地址0x%x失败,实际写入长度:%d\r\n", addr, ret); + free(data_all); + return false; + } + free(data_all); + return true; +} + + +// 从 Flash 加载设备状态 +int load_device_state(void) { + int ret = 0; + device_state_t state; + bool valid = false; + + // 尝试读取主数据区 + 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)); + } + + // 两个存储区都失败,使用默认状态 + if (!valid) { + e_printf("[STORAGE] 存储区数据损坏,使用默认状态\r\n"); + reset_device_state(); + save_device_state(); + return 0; + } + // 更新设备控制状态 + e_printf("设备状态恢复:\r\n"); + e_printf("首次启动: %d => %d\r\n", g_device_state.is_first_boot, state.is_first_boot); + e_printf("配网状态: %d => %d\r\n", g_device_state.is_bound, state.is_bound); + e_printf("总开关: %d => %d\r\n", g_device_state.master_switch, state.master_switch); + e_printf("面板背光: %d => %d\r\n", g_device_state.panel_led, state.panel_led); + e_printf("工作模式: %d => %d\r\n", g_device_state.mode, state.mode); + for (int i = 0; i < SWITCH_COUNT; i++) { + e_printf("开关%d: %d => %d\r\n", i + 1, g_device_state.switches[i].switch_on, state.switches[i].switch_on); + e_printf("LED%d: %d => %d\r\n", i + 1, g_device_state.switches[i].led_state, state.switches[i].led_state); + e_printf("物理按键%d: %d => %d\r\n", i + 1, g_device_state.switches[i].physical_key, state.switches[i].physical_key); + } + + memcpy(&g_device_state, &state, sizeof(device_state_t)); + + return 0; +} + +// 保存设备状态到 Flash +int save_device_state(void) { + int ret = 0; + device_state_t state; + bool valid = false; + + // 准备数据 + memcpy(&state, &g_device_state, sizeof(device_state_t)); + // 保存到主存储区 + ret = write_device_data_to_addr(DEVICE_DATA_FLASH_ADDR, (uint8_t*)&state, sizeof(state)); + if (ret != HF_SUCCESS) { + e_printf("[STORAGE] 写入主存储区失败: %d\r\n", ret); + return ret; + } + + // 保存到备份区 + ret = write_device_data_to_addr(DEVICE_DATA_BACKUP_ADDR, (uint8_t*)&state, sizeof(state)); + if (ret != HF_SUCCESS) { + e_printf("[STORAGE] 写入备份区失败: %d\r\n", ret); + } + e_printf("[STORAGE] 设备状态保存完成\r\n"); + return HF_SUCCESS; +} + +// 重置设备状态为默认值 +void reset_device_state(void) { + memset(&g_device_state, 0, sizeof(device_data_t)); + + // 设置默认状态 + g_device_state.master_switch = false; // 总开关关闭 + g_device_state.panel_led = true; // 面板背光开启 + g_device_state.is_bound = false; // 设备未绑定 + g_device_state.is_first_boot = true; // 标记为首次启动 + g_device_state.mode = MODE_NORMAL; // 正常模式 + + // 所有开关默认关闭,所有LED默认黄灯 + for (int i = 0; i < SWITCH_COUNT; i++) { + g_device_state.switches[i].switch_on = false; // 开关关闭 + g_device_state.switches[i].led_state = false; // LED黄灯 + g_device_state.switches[i].physical_key = true; // 按键松开 + } + + e_printf("[STATE] 设备状态已重置为默认值\r\n"); +} + +//====================== GPIO配置数据结构 ====================== +typedef struct { + pin_t pin; + gpio_direction_t direction; + const char* name; +} gpio_config_t; + +// GPIO初始化配置表 +static const gpio_config_t gpio_configs[] = { + // LED指示灯 - 输出 + {LED1_GPIO, GPIO_DIRECTION_OUTPUT, "LED1"}, + {LED2_GPIO, GPIO_DIRECTION_OUTPUT, "LED2"}, + {LED3_GPIO, GPIO_DIRECTION_OUTPUT, "LED3"}, + {LED4_GPIO, GPIO_DIRECTION_OUTPUT, "LED4"}, + + // 开关控制 - 输出 + {SWITCH1_GPIO, GPIO_DIRECTION_OUTPUT, "SWITCH1"}, + {SWITCH2_GPIO, GPIO_DIRECTION_OUTPUT, "SWITCH2"}, + {SWITCH3_GPIO, GPIO_DIRECTION_OUTPUT, "SWITCH3"}, + {SWITCH4_GPIO, GPIO_DIRECTION_OUTPUT, "SWITCH4"}, + + // 物理按键 - 输入 + {KEY1_GPIO, GPIO_DIRECTION_INPUT, "KEY1"}, + {KEY2_GPIO, GPIO_DIRECTION_INPUT, "KEY2"}, + {KEY3_GPIO, GPIO_DIRECTION_INPUT, "KEY3"}, + {KEY4_GPIO, GPIO_DIRECTION_INPUT, "KEY4"}, + + // 面板背光 - 输出 + {PANEL_LED_GPIO, GPIO_DIRECTION_OUTPUT, "PANEL_LED"} +}; + +#define GPIO_CONFIG_COUNT (sizeof(gpio_configs) / sizeof(gpio_config_t)) + +//====================== 硬件控制函数 ====================== + +// GPIO 初始化 +int switch_panel_gpio_init(void) { + int ret = HF_SUCCESS; + + // 初始化pinctrl和GPIO + uapi_pin_init(); + // uapi_gpio_init(); + + // 使用循环配置所有GPIO + for (int i = 0; i < GPIO_CONFIG_COUNT; i++) { + const gpio_config_t* config = &gpio_configs[i]; + + // 设置为GPIO模式 + ret = uapi_pin_set_mode(config->pin, PIN_MODE_0); + if (ret != HF_SUCCESS) { + e_printf("[GPIO] %s pinctrl初始化失败: %d\r\n", config->name, ret); + return ret; + } + + // 设置GPIO方向 + ret = uapi_gpio_set_dir(config->pin, config->direction); + if (ret != HF_SUCCESS) { + e_printf("[GPIO] %s 设置方向失败: %d\r\n", config->name, ret); + return ret; + } + + e_printf("[GPIO] %s 初始化完成 (方向: %s)\r\n", + config->name, + config->direction == GPIO_DIRECTION_OUTPUT ? "输出" : "输入"); + } + + e_printf("[GPIO] 所有GPIO初始化完成 (共%d个)\r\n", GPIO_CONFIG_COUNT); + return HF_SUCCESS; +} + +// 设置开关输出状态 +void set_switch_output(int switch_id, bool state) { + if (switch_id < 0 || switch_id >= SWITCH_COUNT) { + e_printf("[HW] 无效的开关ID: %d\r\n", switch_id); + return; + } + + pin_t gpio_pin; + switch (switch_id) { + case 0: gpio_pin = SWITCH1_GPIO; break; // SWITCH1 + case 1: gpio_pin = SWITCH2_GPIO; break; // SWITCH2 + case 2: gpio_pin = SWITCH3_GPIO; break; // SWITCH3 + case 3: gpio_pin = SWITCH4_GPIO; break; // SWITCH4 + default: return; + } + + // 设置输出状态 + gpio_level_t level = state ? GPIO_LEVEL_HIGH : GPIO_LEVEL_LOW; + uapi_gpio_set_val(gpio_pin, level); + e_printf("[HW] 开关%d 状态: %s\r\n", switch_id + 1, state ? "开" : "关"); +} + +// 设置 LED 指示灯状态 +void set_led_output(int led_id, led_state_t state) { + if (led_id < 0 || led_id >= SWITCH_COUNT) { + e_printf("[HW] 无效的LED ID: %d\r\n", led_id); + return; + } + + pin_t gpio_pin; + switch (led_id) { + case 0: gpio_pin = LED1_GPIO; break; // LED1 + case 1: gpio_pin = LED2_GPIO; break; // LED2 + case 2: gpio_pin = LED3_GPIO; break; // LED3 + case 3: gpio_pin = LED4_GPIO; break; // LED4 + default: return; + } + + // 设置LED状态 (高电平=白灯, 低电平=黄灯) + gpio_level_t level = (state == LED_WHITE) ? GPIO_LEVEL_HIGH : GPIO_LEVEL_LOW; + uapi_gpio_set_val(gpio_pin, level); +} + +// 设置面板背光状态 +void set_panel_led(panel_led_state_t state) { + // 设置面板背光状态 (高电平=亮黄灯, 低电平=灭灯) + gpio_level_t level = (state == PANEL_LED_ON) ? GPIO_LEVEL_HIGH : GPIO_LEVEL_LOW; + uapi_gpio_set_val(PANEL_LED_GPIO, level); +} + +// 获取按键输入状态 +bool get_key_input(int key_id) { + if (key_id < 0 || key_id >= SWITCH_COUNT) { + return true; // 默认松开状态 + } + + pin_t gpio_pin; + switch (key_id) { + case 0: gpio_pin = KEY1_GPIO; break; // KEY1 + case 1: gpio_pin = KEY2_GPIO; break; // KEY2 + case 2: gpio_pin = KEY3_GPIO; break; // KEY3 + case 3: gpio_pin = KEY4_GPIO; break; // KEY4 + default: return true; + } + + // 获取输入状态 (低电平=按下, 高电平=松开) + gpio_level_t level = uapi_gpio_get_val(gpio_pin); + return (level == GPIO_LEVEL_HIGH); +} + +//====================== 设备状态同步函数 ====================== + +// 同步硬件状态与软件状态 +void sync_hardware_state(void) { + // 同步所有开关状态 + for (int i = 0; i < SWITCH_COUNT; i++) { + set_switch_output(i, g_device_state.switches[i].switch_on); + set_led_output(i, g_device_state.switches[i].led_state ? LED_WHITE : LED_YELLOW); + } + + // 同步面板背光状态 + set_panel_led(g_device_state.panel_led ? PANEL_LED_ON : PANEL_LED_OFF); + + e_printf("[STATE] 硬件状态已同步\r\n"); +} + +//====================== 主程序函数 ====================== + +int switch_panel_main(void) { + int ret = HF_SUCCESS; + + if (g_initialized) { + e_printf("[MAIN] 开关面板已初始化\r\n"); + return HF_SUCCESS; + } + g_initialized = true; + e_printf("[MAIN] 开始初始化SORONTEK智能面板...\r\n"); + + // 初始化GPIO + ret = switch_panel_gpio_init(); + if (ret != HF_SUCCESS) { + e_printf("[MAIN] GPIO初始化失败: %d\r\n", ret); + return ret; + } + + // 加载设备状态 + ret = load_device_state(); + if (ret != HF_SUCCESS) { + e_printf("[MAIN] 加载设备状态失败: %d\r\n", ret); + return ret; + } + + // 检查是否首次启动,如果是则标记为非首次 + bool first_boot = g_device_state.is_first_boot; + if (g_device_state.is_first_boot) { + g_device_state.is_first_boot = false; // 标记为非首次启动 + e_printf("[MAIN] 检测到首次启动\r\n"); + } + + // 同步硬件状态 + sync_hardware_state(); + + // 保存状态更新 + save_device_state(); + + // 配网逻辑: + // 1. 如果设备未绑定 且 是第一次启动 -> 直接进入配网 + // 2. 如果设备未绑定 且 不是第一次启动 -> 等待按键触发配网 + if (!g_device_state.is_bound) { + if (first_boot) { + e_printf("[MAIN] 首次启动且未绑定,直接进入配网模式\r\n"); + enter_config_mode(); + } else { + e_printf("[MAIN] 设备未绑定,等待按键触发配网\r\n"); + // 配网逻辑将在按键处理函数中实现 + } + } else { + e_printf("[MAIN] 设备已绑定,正常运行\r\n"); + } + + e_printf("[MAIN] SORONTEK智能面板初始化完成\r\n"); + print_device_state(); + + return HF_SUCCESS; +} + +//====================== 调试函数 ====================== + +void print_device_state(void) { + e_printf("\r\n===== 设备状态信息 =====\r\n"); + e_printf("总开关: %s\r\n", g_device_state.master_switch ? "开" : "关"); + e_printf("面板背光: %s\r\n", g_device_state.panel_led ? "开" : "关"); + e_printf("绑定状态: %s\r\n", g_device_state.is_bound ? "已绑定" : "未绑定"); + e_printf("首次启动: %s\r\n", g_device_state.is_first_boot ? "是" : "否"); + e_printf("工作模式: %s\r\n", get_mode_string(g_device_state.mode)); + + for (int i = 0; i < SWITCH_COUNT; i++) { + e_printf("开关%d: %s, LED: %s\r\n", + i + 1, + g_device_state.switches[i].switch_on ? "开" : "关", + g_device_state.switches[i].led_state ? "白灯" : "黄灯"); + } + e_printf("=======================\r\n\r\n"); +} + +const char* get_mode_string(system_mode_t mode) { + switch (mode) { + case MODE_NORMAL: return "正常模式"; + case MODE_CONFIG: return "配网模式"; + case MODE_FACTORY_TEST: return "产测模式"; + case MODE_UNBIND: return "解绑模式"; + default: return "未知模式"; + } +} \ No newline at end of file diff --git a/build/config/target_config/ws63/config.py b/build/config/target_config/ws63/config.py index 18d9172..3fa6bee 100755 --- a/build/config/target_config/ws63/config.py +++ b/build/config/target_config/ws63/config.py @@ -265,7 +265,7 @@ target = { }, 'ws63-liteos-app-iot': { 'base_target_name': 'target_ws63_app_rom_template', - # 'liteos_kconfig': 'ws63_iot', + 'liteos_kconfig': 'ws63_iot', #ekko add for remove indie upgrade 'os': 'liteos', 'defines': [ "USE_CMSIS_OS", @@ -308,7 +308,7 @@ target = { "SUPPORT_SOFTAP_NETCFG", # softAP配网 "SUPPORT_BLE_ANCILLAY_NETCFG", # ble辅助配网 # "SUPPORT_QUICK_NETCFG", # 快速配网 - "CONFIG_SUPPORT_HILINK_INDIE_UPGRADE", + # "CONFIG_SUPPORT_HILINK_INDIE_UPGRADE", #ekko remove for indie upgrade "CONFIG_DHCPS_GW", "_HSF_", # "ENABLE_BLE_SCAN" #open ble scan @@ -354,10 +354,11 @@ target = { 'cjson', 'xo_trim_port', 'hilink', - 'app_addr_map', - # 'hilinkdevicesdk', - # 'hilinkota', - # 'hilinkbtsdk', + # 'app_addr_map', #ekko remove for indie upgrade + 'hilinkdevicesdk', #ekko add for remove indie upgrade + 'hilinkota', #ekko add for remove indie upgrade + 'hilinkbtsdk', #ekko add for remove indie upgrade + # 'hilinkquickcfg', #ekko add for remove indie upgrade 'huks_sdk', 'deviceauth', 'little_fs', 'littlefs_adapt_ws63', diff --git a/readme.md b/readme.md index e0343a0..3baf4d4 100644 --- a/readme.md +++ b/readme.md @@ -2,31 +2,6 @@ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. -## Build and Development Commands -1. **Build the project**: Run `python build.py` from the root directory. -2. **Clean build artifacts**: Run `python build.py clean`. -3. **Flash the device**: Use the `hfloader` tool with the appropriate firmware file. - -## Key Codebase Structure -1. **Entry Point**: `application/ws63/user_main/app_main.c` contains `user_app_main`, the main entry point for the application. -2. **Hilink Integration**: - - `application/samples/wifi/ohos_connect/hilink_adapt/entry/hilink_ble_main.c` is the Hilink SDK configuration and setup entry. - - `application/samples/wifi/ohos_connect/hilink_adapt/product/hilink_device.c` maps physical models to cloud models. -3. **Physical Model Control**: - - GPIO and LED controls are defined in `application/ws63/hsf`. - - Reference implementations are in `refence/LPT26x-HSF-4MB-Hilink_14.2.0.308_20250411`. -4. **Device Configuration**: - - `build/config/target_config/ws63/config.py` contains build configurations. - - `application/samples/wifi/ohos_connect/hilink_adapt/product/device_profile.h` defines device metadata. - -## Important Notes -- **Flash Storage**: Device states (switch, LED, etc.) must be saved to flash immediately after modification. -- **Cloud Sync**: Implement logic in `HILINK_NotifyDevStatus` for online/offline state handling. -- **Physical and APP Control**: Ensure synchronization between physical button presses and APP controls. - -## Reference Code -- Review `refence/LPT26x-HSF-4MB-Hilink_14.2.0.308_20250411` for examples of Hilink integration and device control. - 你是一个资深的物联网嵌入式工程师。这里有一个基于完善的一个智能家居的sdk进行开发的需求,其是基于汉枫(hf)模组+鸿蒙系统(ohos)开发的。 ## SDK 相关介绍 @@ -46,15 +21,14 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co 8. indie_upg.md 是关于支持hilink独立升级如何修改代码的说明文档,可供参考 通过以上信息你已经可以基本了解整个SDK的运作的原理 +目前项目工程是一个已有的项目的代码,你需要在这个基础上进行改造,删除不要的东西。 - -## 参考已有铲平的代码 -!!这部分非常重要!!!,里面有很多的hilink,配网,和云端交互等的示例,可以帮助你更好的编写代码,请你仔细分析! -refence/LPT26x-HSF-4MB-Hilink_14.2.0.308_20250411 +## 参考已有产品的的代码 +!!这部分非常重要!!!,里面有很多的hilink,配网,和云端交互等的示例,可以帮助你更好的编写代码 这是此前的一款射灯产品的源码,里面核心的几个文件夹为: -refence/LPT26x-HSF-4MB-Hilink_14.2.0.308_20250411/application/ws63/user_main -refence/LPT26x-HSF-4MB-Hilink_14.2.0.308_20250411/application/samples/wifi/ohos_connect/hilink_adapt/product/ -你可以参考看看里面能够复用的部分! +application/ws63/user_main +application/samples/wifi/ohos_connect/hilink_adapt/product/ +你可以参考看看里面哪些是能够复用的部分。哪些是要删除的 ## 软件相关的定义如下: 1. 其物理模型2Q4G.json,但是里面的netInfo timer update这几个是hilink内部已经实现无需我们关心,我们只需要关心switch3、switch2、switch1、switch4 switch这几个物理模型。 @@ -100,13 +74,20 @@ LED 是整个控制面板的背光灯,高电平亮灯(黄色),低电平灭 ## 软件编写规范 1. 实现需求需要在application/ws63/user_main另外新建文件夹(命名你根据产品需求定义)实现相关逻辑 +2. flush操作的api可见 application/ws63/hsf/hfflash.h 里面定义的 HSF_API 修饰的api +3. gpio其相关api可见 include/driver/pinctrl.h 和 include/driver/gpio.h。 + 其中 PIN_MODE_0 为输入模式,PIN_MODE_1输出模式 + GPIO口枚举可见drivers/chips/ws63/include/platform_core_rom.h +5. 延时使用msleep +6. 定时器使用 uapi_timer_xx 头文件定义在-> include/driver/timer.h +7. 线程相关使用 osal_kthread_xx 头文件定义在-> kernel/osal/include/schedule/osal_task.h ### SORONTEK智能面板产测: 1.由信标发送产测信号 =》识别固定的热点名作为进入产测的信号 2.开关循环:开1-开2-开3-开4-全关-全开-全关 3.每1.5秒执行一个动作 -4. 需要校验WIFI 信号强度吗?(射灯有此逻辑) +4. 需要校验WIFI 信号强度吗 ### SORONTEK智能面板配网: 1. 只有设备处于未绑定状态才能进行配网(出厂或者被APP删除)