1. 增加本地离线控制功能
2. 优化代码逻辑加入很多异步操作 3. 适配switch相关物模型
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@ -27,3 +27,6 @@ application/samples/radar/
|
|||||||
application/samples/peripheral/
|
application/samples/peripheral/
|
||||||
application/samples/bt
|
application/samples/bt
|
||||||
CMakeLists.txt
|
CMakeLists.txt
|
||||||
|
|
||||||
|
# YoYo AI version control directory
|
||||||
|
.yoyo/
|
||||||
|
@ -42,6 +42,7 @@
|
|||||||
//static bool g_switch = 0;
|
//static bool g_switch = 0;
|
||||||
int sid_switch;
|
int sid_switch;
|
||||||
static bool g_autoUpdate = 0;
|
static bool g_autoUpdate = 0;
|
||||||
|
static int ble_adv_time = 0;
|
||||||
static HILINK_BT_DevInfo g_btDevInfo = {0};
|
static HILINK_BT_DevInfo g_btDevInfo = {0};
|
||||||
extern int set_get_ble_mac(void);
|
extern int set_get_ble_mac(void);
|
||||||
extern int HILINK_Printf(const char *format, ...);
|
extern int HILINK_Printf(const char *format, ...);
|
||||||
@ -255,6 +256,7 @@ static void ReporFwvCheckSum(void)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static int ble_sdk_running = 0;
|
||||||
static void HILINK_BT_StateChangeHandler(HILINK_BT_SdkStatus event, const void *param)
|
static void HILINK_BT_StateChangeHandler(HILINK_BT_SdkStatus event, const void *param)
|
||||||
{
|
{
|
||||||
(void)param;
|
(void)param;
|
||||||
@ -269,10 +271,12 @@ static void HILINK_BT_StateChangeHandler(HILINK_BT_SdkStatus event, const void *
|
|||||||
HILINK_SAL_ERROR("set addr err\n");
|
HILINK_SAL_ERROR("set addr err\n");
|
||||||
}
|
}
|
||||||
/* 设置蓝牙广播格式,包括靠近发现、碰一碰等,下一次发送广播生效 */
|
/* 设置蓝牙广播格式,包括靠近发现、碰一碰等,下一次发送广播生效 */
|
||||||
BLE_SetAdvType(BLE_ADV_NEARBY_V0);
|
BLE_SetAdvType(BLE_ADV_LOCAL_NAME);
|
||||||
|
|
||||||
/* BLE配网广播控制:参数代表广播时间,0:停止;0xFFFFFFFF:一直广播,其他:广播指定时间后停止,单位秒 */
|
/* BLE配网广播控制:参数代表广播时间,0:停止;0xFFFFFFFF:一直广播,其他:广播指定时间后停止,单位秒 */
|
||||||
(void)BLE_CfgNetAdvCtrl(BLE_ADV_TIME);
|
(void)BLE_CfgNetAdvCtrl(ble_adv_time);
|
||||||
|
ble_sdk_running = 1;
|
||||||
|
e_printf("callback set ble adv time: %ds\n", ble_adv_time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -308,6 +312,18 @@ static int BleHandleCustomDataGet(const char *sid)
|
|||||||
// 参考链接 https://device.harmonyos.com/cn/docs/devicepartner/DevicePartner-Guides/device-development-ble-specifications-control-0000001482432154
|
// 参考链接 https://device.harmonyos.com/cn/docs/devicepartner/DevicePartner-Guides/device-development-ble-specifications-control-0000001482432154
|
||||||
static int BleHandleCustomData(const char *buff, unsigned int len)
|
static int BleHandleCustomData(const char *buff, unsigned int len)
|
||||||
{
|
{
|
||||||
|
// 添加四开关面板的蓝牙处理
|
||||||
|
extern int switch_panel_ble_handle_custom_data(const char *buff, unsigned int len);
|
||||||
|
|
||||||
|
// 优先使用四开关面板的蓝牙处理逻辑
|
||||||
|
int panel_result = switch_panel_ble_handle_custom_data(buff, len);
|
||||||
|
if (panel_result == 0) {
|
||||||
|
// 四开关面板成功处理了该指令
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果面板处理失败,回退到原有的处理逻辑
|
||||||
|
HILINK_SAL_NOTICE("开关面板处理失败,使用默认处理逻辑\r\n");
|
||||||
if (strcmp((char *)buff, "{}") == 0) {
|
if (strcmp((char *)buff, "{}") == 0) {
|
||||||
/* 上报全量数据 */
|
/* 上报全量数据 */
|
||||||
ReporSwitchStatus();
|
ReporSwitchStatus();
|
||||||
@ -424,10 +440,20 @@ unsigned int GetWifiRecoveryType(void)
|
|||||||
{
|
{
|
||||||
return (0x01 | 0x02);
|
return (0x01 | 0x02);
|
||||||
}
|
}
|
||||||
|
int start_hilink_ble_net_config(int32_t net_cfg_time_s)
|
||||||
|
{
|
||||||
|
ble_adv_time = net_cfg_time_s;
|
||||||
|
e_printf("set ble adv time: %ds\n", ble_adv_time);
|
||||||
|
if (ble_sdk_running) {
|
||||||
|
BLE_CfgNetAdvCtrl(ble_adv_time);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int hilink_ble_main(void)
|
int hilink_ble_main(void)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
hfset_hilink_mode(SMTLK_BLE_FAST_CONNECT);
|
||||||
int hilink_entry_mode=hfget_hilink_mode();
|
int hilink_entry_mode=hfget_hilink_mode();
|
||||||
printf("hilink_entry_mode:%d\r\n",hilink_entry_mode);
|
printf("hilink_entry_mode:%d\r\n",hilink_entry_mode);
|
||||||
if(hilink_entry_mode != SMTLK_SOFTAP)
|
if(hilink_entry_mode != SMTLK_SOFTAP)
|
||||||
@ -448,6 +474,7 @@ int hilink_ble_main(void)
|
|||||||
HILINK_EnableSle();
|
HILINK_EnableSle();
|
||||||
HILINK_EnablePrescan();
|
HILINK_EnablePrescan();
|
||||||
HILINK_SetProtType(17);
|
HILINK_SetProtType(17);
|
||||||
|
e_printf("SMTLK_BLE_FAST_CONNECT\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = HILINK_SetNetConfigMode(HILINK_NETCONFIG_OTHER);
|
ret = HILINK_SetNetConfigMode(HILINK_NETCONFIG_OTHER);
|
||||||
@ -457,25 +484,27 @@ int hilink_ble_main(void)
|
|||||||
ret = BLE_SetAdvNameMpp(mpp, sizeof(mpp));
|
ret = BLE_SetAdvNameMpp(mpp, sizeof(mpp));
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
HILINK_SAL_NOTICE("set adv name mpp failed\r\n");
|
HILINK_SAL_NOTICE("set adv name mpp failed\r\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 注册SDK状态接收函数,可在初始化完成后发送广播 */
|
/* 注册SDK状态接收函数,可在初始化完成后发送广播 */
|
||||||
ret = HILINK_BT_SetSdkEventCallback(HILINK_BT_StateChangeHandler);
|
ret = HILINK_BT_SetSdkEventCallback(HILINK_BT_StateChangeHandler);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
HILINK_SAL_NOTICE("set event callback failed\r\n");
|
HILINK_SAL_NOTICE("set event callback failed\r\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 设置广播方式为靠近发现 */
|
/* 设置广播方式为靠近发现 */
|
||||||
BLE_SetAdvType(BLE_ADV_NEARBY_V0);
|
BLE_SetAdvType(BLE_ADV_LOCAL_NAME);
|
||||||
|
|
||||||
/* 初始化ble sdk */
|
/* 初始化ble sdk */
|
||||||
ret = BLE_CfgNetInit(&g_bleInitParam, &g_bleCfgNetCb);
|
ret = BLE_CfgNetInit(&g_bleInitParam, &g_bleCfgNetCb);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
HILINK_SAL_NOTICE("ble sdk init fail\r\n");
|
HILINK_SAL_NOTICE("ble sdk init fail\r\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
e_printf("ble sdk init success\r\n");
|
||||||
|
//set_get_ble_mac();
|
||||||
}
|
}
|
||||||
else if(hilink_entry_mode == SMTLK_SOFTAP)
|
else if(hilink_entry_mode == SMTLK_SOFTAP)
|
||||||
{
|
{
|
||||||
@ -520,6 +549,16 @@ int hilink_ble_main(void)
|
|||||||
HILINK_SAL_NOTICE("HILINK_Main start error");
|
HILINK_SAL_NOTICE("HILINK_Main start error");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
e_printf("HILINK_Main start success\r\n");
|
||||||
hf_set_hilink_main_runing();
|
hf_set_hilink_main_runing();
|
||||||
|
// HILINK_RestoreFactorySettings();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef CONFIG_SUPPORT_HILINK_INDIE_UPGRADE
|
||||||
|
// EKKO remove indie upgrade
|
||||||
|
int hilink_indie_upgrade_main(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
@ -17,15 +17,15 @@ extern "C" {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#define ProductId "2Q4S"
|
#define ProductId "2Q4G"
|
||||||
#define deviceTypeId "21S"
|
#define deviceTypeId "201"
|
||||||
#define manufacturerID "gub"
|
#define manufacturerID "gub"
|
||||||
#define deviceModel "SR-SW-020-10S"
|
#define deviceModel "S15"
|
||||||
#define configName "SR_S"
|
#define configName "SR_S"
|
||||||
#define configType "witch"
|
#define configType "witch"
|
||||||
#define enterpriseEnglishName "SORONTEK"
|
#define enterpriseEnglishName "SORONTEK"
|
||||||
#define brandEn "SORONTEK"
|
#define brandEn "SORONTEK"
|
||||||
#define deviceName "SORONTEK智能开关面板"
|
#define deviceName "SORONTEK智能面板"
|
||||||
#define productSeries ""
|
#define productSeries ""
|
||||||
|
|
||||||
#define DEVICE_HIVERSION "1.0.0"
|
#define DEVICE_HIVERSION "1.0.0"
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
#include "hilink_device.h"
|
#include "hilink_device.h"
|
||||||
#ifdef CONFIG_SUPPORT_HILINK_INDIE_UPGRADE
|
#ifdef CONFIG_SUPPORT_HILINK_INDIE_UPGRADE
|
||||||
#include "hilink_entry.h"
|
#include "hilink_entry.h"
|
||||||
|
#endif
|
||||||
extern void handle_device_online(void);
|
extern void handle_device_online(void);
|
||||||
extern void handle_device_unbind(void);
|
extern void handle_device_unbind(void);
|
||||||
extern void handle_device_offline(void);
|
extern void handle_device_offline(void);
|
||||||
@ -40,7 +40,7 @@ static const HILINK_SvcInfo SVC_INFO[] = {
|
|||||||
{ "switch", "switch" },
|
{ "switch", "switch" },
|
||||||
{ "switch", "switch4" },
|
{ "switch", "switch4" },
|
||||||
#ifdef CONFIG_SUPPORT_HILINK_INDIE_UPGRADE
|
#ifdef CONFIG_SUPPORT_HILINK_INDIE_UPGRADE
|
||||||
//{ "checkSum", "checkSum" },
|
{ "checkSum", "checkSum" },
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -177,14 +177,124 @@ 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);
|
HILINK_Printf("sid:%s NOT SUPPORT PUT function \r\n", svc_id);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#if 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;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
HANDLE_SVC_INFO g_device_profile[] = {
|
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},
|
{"switch", handle_put_switch, handle_get_switch},
|
||||||
{"switch1", handle_put_switch1, handle_get_switch1},
|
{"switch4", handle_put_switch4, handle_get_switch4},
|
||||||
{"switch2", handle_put_switch2, handle_get_switch2},
|
|
||||||
{"switch3", handle_put_switch3, handle_get_switch3},
|
|
||||||
{"switch4", handle_put_switch4, handle_get_switch4},
|
|
||||||
// 故障不支持 HILINK_PutCharState,配置 not_support_put
|
|
||||||
};
|
};
|
||||||
// 服务总数量
|
// 服务总数量
|
||||||
int g_device_profile_count = sizeof(g_device_profile) / sizeof(HANDLE_SVC_INFO);
|
int g_device_profile_count = sizeof(g_device_profile) / sizeof(HANDLE_SVC_INFO);
|
||||||
@ -233,14 +343,29 @@ int handle_get_cmd(const char* svc_id, const char* in, unsigned int in_len, char
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 快速上报函数,用于上报服务状态信息
|
// 快速上报函数,用于上报服务状态信息
|
||||||
|
// 支持蓝牙和云端双模式上报
|
||||||
int fast_report(const char* svc_id)
|
int fast_report(const char* svc_id)
|
||||||
{
|
{
|
||||||
|
// 引入外部的蓝牙控制函数
|
||||||
|
extern bool switch_panel_ble_is_enabled(void);
|
||||||
|
extern int switch_panel_ble_fast_report(const char *svc_id);
|
||||||
|
|
||||||
|
// 检查当前是否处于蓝牙控制模式
|
||||||
|
if (switch_panel_ble_is_enabled()) {
|
||||||
|
// 蓝牙模式下通过蓝牙上报
|
||||||
|
e_printf("[FAST_REPORT] 蓝牙模式上报: %s\r\n", svc_id);
|
||||||
|
return switch_panel_ble_fast_report(svc_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 云端模式下通过HiLink上报
|
||||||
|
e_printf("[FAST_REPORT] 云端模式上报: %s\r\n", svc_id);
|
||||||
|
|
||||||
char* payload = NULL;
|
char* payload = NULL;
|
||||||
int len;
|
int len;
|
||||||
int err = handle_get_cmd(svc_id, NULL, 0, &payload, (unsigned int *)&len);
|
int err = handle_get_cmd(svc_id, NULL, 0, &payload, (unsigned int *)&len);
|
||||||
if(err != 0) {
|
if(err != 0) {
|
||||||
HILINK_Printf("get msg from %s failed \r\n", svc_id);
|
HILINK_Printf("get msg from %s failed \r\n", svc_id);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
err = HILINK_ReportCharState(svc_id, payload, len);
|
err = HILINK_ReportCharState(svc_id, payload, len);
|
||||||
HILINK_Printf("report %s result is %d, payload:%s \r\n", svc_id, err, payload);
|
HILINK_Printf("report %s result is %d, payload:%s \r\n", svc_id, err, payload);
|
||||||
@ -255,9 +380,10 @@ int fast_report(const char* svc_id)
|
|||||||
*/
|
*/
|
||||||
int HILINK_PutCharState(const char *svcId, const char *payload, unsigned int len)
|
int HILINK_PutCharState(const char *svcId, const char *payload, unsigned int len)
|
||||||
{
|
{
|
||||||
e_printf("[HILINK_PutCharState] 收到控制指令: svcId=%s, payload=%s\r\n", svcId, payload);
|
e_printf("收到控制指令: svcId=%s, payload=%s\r\n", svcId, payload);
|
||||||
|
|
||||||
if ((svcId == NULL) || (payload == NULL)) {
|
if ((svcId == NULL) || (payload == NULL)) {
|
||||||
|
e_printf("参数无效\r\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,7 +394,7 @@ int HILINK_PutCharState(const char *svcId, const char *payload, unsigned int len
|
|||||||
cJSON_Delete(json);
|
cJSON_Delete(json);
|
||||||
|
|
||||||
int err = handle_put_cmd(svcId, payload, len);
|
int err = handle_put_cmd(svcId, payload, len);
|
||||||
e_printf("[HILINK_PutCharState] 控制指令处理完成,返回值: %d\r\n", err);
|
e_printf("控制指令处理完成,返回值: %d\r\n", err);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
#ifdef CONFIG_SUPPORT_HILINK_INDIE_UPGRADE
|
#ifdef CONFIG_SUPPORT_HILINK_INDIE_UPGRADE
|
||||||
|
@ -69,7 +69,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__); \
|
#define hfdbg_warn(...) HF_Debug(DEBUG_WARN,"[warnning %d %s %d]",hfsys_get_time(),__FUNCTION__,__LINE__); \
|
||||||
HF_Debug(DEBUG_WARN,__VA_ARGS__)
|
HF_Debug(DEBUG_WARN,__VA_ARGS__)
|
||||||
#define u_printf(...) HF_Debug(DEBUG_LEVEL_USER,__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);
|
int hfuart_config(hfuart_handle_t huart, int baudrate, ENCOMPARITY_E parity, ENCOMBITS_E databits, ENCOMSTOPBITS_E stopbits, ENCOMUARTCTL_E fc);
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ set(SOURCES
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/switch_panel/switch_panel_keys.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_hilink.c
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/switch_panel/switch_panel_config.c
|
${CMAKE_CURRENT_SOURCE_DIR}/switch_panel/switch_panel_config.c
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/switch_panel/switch_panel_ble.c
|
||||||
)
|
)
|
||||||
|
|
||||||
if (DEFINES MATCHES "HF_MCU_OTA")
|
if (DEFINES MATCHES "HF_MCU_OTA")
|
||||||
|
@ -78,24 +78,48 @@ typedef enum {
|
|||||||
} system_mode_t;
|
} system_mode_t;
|
||||||
|
|
||||||
//====================== 设备状态结构 ======================
|
//====================== 设备状态结构 ======================
|
||||||
// 单个开关状态信息
|
// 开关名字最大长度
|
||||||
|
#define SWITCH_NAME_MAX_LEN 32
|
||||||
|
|
||||||
|
// 单个开关的持久化状态信息(需要保存到Flash)
|
||||||
|
typedef struct {
|
||||||
|
bool switch_on; // 开关状态 (true=开, false=关) - 持久化
|
||||||
|
bool led_state; // LED状态 (true=白灯, false=黄灯) - 持久化
|
||||||
|
char name[SWITCH_NAME_MAX_LEN]; // 开关名字 - 持久化
|
||||||
|
} switch_persistent_info_t;
|
||||||
|
|
||||||
|
// 单个开关的运行时状态信息(不需要持久化)
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool switch_on; // 开关状态 (true=开, false=关)
|
|
||||||
bool led_state; // LED状态 (true=白灯, false=黄灯)
|
|
||||||
bool physical_key; // 物理按键状态 (true=松开, false=按下)
|
bool physical_key; // 物理按键状态 (true=松开, false=按下)
|
||||||
} switch_info_t;
|
uint32_t press_time; // 按键按下时间戳
|
||||||
|
bool debounce_flag; // 防抖标志
|
||||||
|
bool long_press_handled; // 长按处理标志
|
||||||
|
} switch_runtime_info_t;
|
||||||
|
|
||||||
|
// 持久化设备状态(需要保存到Flash)
|
||||||
// 系统设备状态
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
switch_info_t switches[SWITCH_COUNT]; // 4个开关的状态
|
switch_persistent_info_t switches[SWITCH_COUNT]; // 4个开关的持久化状态
|
||||||
bool master_switch; // 总开关状态
|
bool master_switch; // 总开关状态 - 持久化
|
||||||
bool panel_led; // 面板背光状态
|
bool panel_led; // 面板背光状态 - 持久化
|
||||||
bool is_bound; // 设备绑定状态
|
bool is_bound; // 设备绑定状态 - 持久化
|
||||||
bool is_first_boot; // 是否第一次上电
|
bool is_first_boot; // 是否第一次上电 - 持久化
|
||||||
system_mode_t mode; // 系统工作模式
|
uint32_t magic; // 魔数标识
|
||||||
uint32_t reserved[10]; // 保留字段
|
uint32_t version; // 版本号
|
||||||
} device_state_t;
|
uint32_t reserved[8]; // 保留字段
|
||||||
|
} device_persistent_state_t;
|
||||||
|
|
||||||
|
// 运行时设备状态(不需要持久化,断电丢失)
|
||||||
|
typedef struct {
|
||||||
|
switch_runtime_info_t switches[SWITCH_COUNT]; // 4个开关的运行时状态
|
||||||
|
system_mode_t mode; // 系统工作模式(运行时状态)
|
||||||
|
bool ble_mode_enabled; // 蓝牙模式是否启用
|
||||||
|
uint32_t config_start_time; // 配网开始时间
|
||||||
|
int config_key_id; // 触发配网的按键ID
|
||||||
|
bool config_led_blink_state; // 配网LED闪烁状态
|
||||||
|
bool factory_test_running; // 产测是否运行中
|
||||||
|
uint32_t last_save_time; // 上次保存时间
|
||||||
|
uint32_t reserved[16]; // 保留字段
|
||||||
|
} device_runtime_state_t;
|
||||||
|
|
||||||
|
|
||||||
//====================== Flash存储相关 ======================
|
//====================== Flash存储相关 ======================
|
||||||
@ -121,21 +145,34 @@ typedef struct {
|
|||||||
|
|
||||||
//====================== 配网相关定义 ======================
|
//====================== 配网相关定义 ======================
|
||||||
#define FACTORY_TEST_SSID "ShuorongSelfTest" // 产测热点名称
|
#define FACTORY_TEST_SSID "ShuorongSelfTest" // 产测热点名称
|
||||||
#define CONFIG_ENTRY_COUNT 3 // 连续重启次数进入配网
|
|
||||||
|
|
||||||
//====================== 任务和定时器相关 ======================
|
//====================== 任务和定时器相关 ======================
|
||||||
#define TASK_STACK_SIZE 2048
|
#define TASK_STACK_SIZE 0x1000
|
||||||
#define TASK_PRIORITY_HIGH OSAL_TASK_PRIORITY_HIGH
|
#define TASK_PRIORITY_HIGH OSAL_TASK_PRIORITY_HIGH
|
||||||
#define TASK_PRIORITY_NORM OSAL_TASK_PRIORITY_MIDDLE
|
#define TASK_PRIORITY_NORM OSAL_TASK_PRIORITY_MIDDLE
|
||||||
#define TASK_PRIORITY_LOW OSAL_TASK_PRIORITY_LOW
|
#define TASK_PRIORITY_LOW OSAL_TASK_PRIORITY_LOW
|
||||||
|
|
||||||
|
//====================== 异步上报系统相关 ======================
|
||||||
|
// 定义服务ID的位掩码
|
||||||
|
#define REPORT_SWITCH_MASK 0x01 // switch (总开关)
|
||||||
|
#define REPORT_SWITCH1_MASK 0x02 // switch1
|
||||||
|
#define REPORT_SWITCH2_MASK 0x04 // switch2
|
||||||
|
#define REPORT_SWITCH3_MASK 0x08 // switch3
|
||||||
|
#define REPORT_SWITCH4_MASK 0x10 // switch4
|
||||||
|
#define REPORT_ALL_MASK 0x1F // 所有开关
|
||||||
|
|
||||||
|
// 异步上报系统相关变量
|
||||||
|
extern osal_task *g_report_task_handle; // 异步上报任务句柄
|
||||||
|
|
||||||
//====================== 全局变量声明 ======================
|
//====================== 全局变量声明 ======================
|
||||||
extern device_state_t g_device_state;
|
extern device_persistent_state_t g_persistent_state;
|
||||||
|
extern device_runtime_state_t g_runtime_state;
|
||||||
extern timer_handle_t g_key_debounce_timer[SWITCH_COUNT];
|
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_key_scan_task_handle;
|
||||||
extern osal_task *g_config_task_handle;
|
extern osal_task *g_config_task_handle;
|
||||||
|
extern osal_task *g_save_task_handle; // 异步保存任务句柄
|
||||||
|
extern osal_task *g_report_task_handle; // 异步上报任务句柄
|
||||||
|
|
||||||
//====================== 函数声明 ======================
|
//====================== 函数声明 ======================
|
||||||
|
|
||||||
@ -151,14 +188,41 @@ void set_panel_led(panel_led_state_t state);
|
|||||||
bool get_key_input(int key_id);
|
bool get_key_input(int key_id);
|
||||||
|
|
||||||
// 设备状态管理函数
|
// 设备状态管理函数
|
||||||
int load_device_state(void);
|
int load_persistent_state(void);
|
||||||
int save_device_state(void);
|
int save_persistent_state(void); // 异步保存(触发保存任务)
|
||||||
void reset_device_state(void);
|
int save_persistent_state_sync(void); // 同步保存(直接写入Flash)
|
||||||
|
int save_system_init(void); // 初始化异步保存系统
|
||||||
|
void save_system_deinit(void); // 清理异步保存系统
|
||||||
|
void reset_persistent_state(void);
|
||||||
|
void init_runtime_state(void);
|
||||||
void sync_hardware_state(void);
|
void sync_hardware_state(void);
|
||||||
void fast_report_switch(int switch_id);
|
void fast_report_switch(int switch_id);
|
||||||
void fast_report_master_switch(void);
|
void fast_report_master_switch(void);
|
||||||
void set_device_mode(system_mode_t mode);
|
void set_device_mode(system_mode_t mode);
|
||||||
|
|
||||||
|
// 状态访问便利函数
|
||||||
|
bool get_switch_state(int switch_id);
|
||||||
|
bool get_master_switch_state(void);
|
||||||
|
bool is_device_bound(void);
|
||||||
|
bool is_first_boot(void);
|
||||||
|
system_mode_t get_device_mode(void);
|
||||||
|
|
||||||
|
// 异步上报系统管理函数
|
||||||
|
int report_system_init(void); // 初始化异步上报系统
|
||||||
|
void report_system_deinit(void); // 清理异步上报系统
|
||||||
|
void trigger_async_report(uint8_t report_mask); // 触发异步上报
|
||||||
|
int async_report_task(void *arg); // 异步上报任务
|
||||||
|
|
||||||
|
// 快速上报函数(新的异步版本)
|
||||||
|
void fast_report_switch_async(int switch_id); // 异步上报单个开关
|
||||||
|
void fast_report_master_switch_async(void); // 异步上报总开关
|
||||||
|
void fast_report_all_switches_async(void); // 异步上报所有开关
|
||||||
|
|
||||||
|
// 开关名字操作函数
|
||||||
|
const char* get_switch_name(int switch_id);
|
||||||
|
int set_switch_name(int switch_id, const char* name);
|
||||||
|
void init_default_switch_names(void);
|
||||||
|
|
||||||
// 开关控制函数
|
// 开关控制函数
|
||||||
void update_switch_state(int switch_id, bool state);
|
void update_switch_state(int switch_id, bool state);
|
||||||
void update_master_switch(bool state);
|
void update_master_switch(bool state);
|
||||||
@ -205,7 +269,19 @@ const char* get_mode_string(system_mode_t mode);
|
|||||||
|
|
||||||
// 定时器回调函数
|
// 定时器回调函数
|
||||||
void key_debounce_timer_callback(uintptr_t data);
|
void key_debounce_timer_callback(uintptr_t data);
|
||||||
void config_timeout_timer_callback(uintptr_t data);
|
// 配网定时器回调函数已移除,配网逻辑现在在config_mode_task中直接处理
|
||||||
void config_blink_timer_callback(uintptr_t data);
|
|
||||||
|
|
||||||
|
//====================== 蓝牙控制相关函数 ======================
|
||||||
|
// 蓝牙数据处理
|
||||||
|
int switch_panel_ble_handle_custom_data(const char *buff, unsigned int len);
|
||||||
|
|
||||||
|
// 蓝牙模式管理
|
||||||
|
void switch_panel_ble_enable(void);
|
||||||
|
void switch_panel_ble_disable(void);
|
||||||
|
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__
|
#endif // __SWITCH_PANEL_H__
|
284
application/ws63/user_main/switch_panel/switch_panel_ble.c
Executable file
284
application/ws63/user_main/switch_panel/switch_panel_ble.c
Executable file
@ -0,0 +1,284 @@
|
|||||||
|
#include "switch_panel.h"
|
||||||
|
#include "hilink_device.h"
|
||||||
|
#include "ble_cfg_net_api.h"
|
||||||
|
#include "cJSON.h"
|
||||||
|
#include "securec.h"
|
||||||
|
|
||||||
|
//====================== 蓝牙控制相关常量 ======================
|
||||||
|
#define SWITCH_BLE_REPORT "{\"data\":{\"on\":%d},\"sid\":\"%s\"}"
|
||||||
|
#define SWITCH_BLE_NAME_REPORT "{\"data\":{\"on\":%d,\"name\":\"%s\"},\"sid\":\"%s\"}"
|
||||||
|
|
||||||
|
//====================== 蓝牙控制状态变量 ======================
|
||||||
|
static bool g_ble_mode_enabled = false; // 蓝牙控制模式是否启用
|
||||||
|
|
||||||
|
//====================== 蓝牙上报函数 ======================
|
||||||
|
|
||||||
|
// 通过蓝牙上报总开关状态
|
||||||
|
static void ble_report_master_switch(void) {
|
||||||
|
char buff[128] = {0};
|
||||||
|
int ret = snprintf_s(buff, sizeof(buff), sizeof(buff) - 1,
|
||||||
|
SWITCH_BLE_REPORT,
|
||||||
|
g_persistent_state.master_switch ? 1 : 0,
|
||||||
|
"switch");
|
||||||
|
if (ret <= 0) {
|
||||||
|
e_printf("[BLE] 总开关状态格式化失败: %d\r\n", ret);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int buffLen = strlen(buff);
|
||||||
|
ret = BLE_SendCustomData(CUSTOM_SEC_DATA, (const unsigned char *)buff, buffLen);
|
||||||
|
e_printf("[BLE] 上报总开关状态: %s, 结果: %d\r\n", buff, ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 通过蓝牙上报单个开关状态
|
||||||
|
static void ble_report_switch_state(int switch_id) {
|
||||||
|
if (switch_id < 0 || switch_id >= SWITCH_COUNT) {
|
||||||
|
e_printf("[BLE] 无效的开关ID: %d\r\n", switch_id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char buff[128] = {0};
|
||||||
|
char svc_id[16] = {0};
|
||||||
|
char switch_name[16] = {0};
|
||||||
|
|
||||||
|
snprintf_s(svc_id, sizeof(svc_id), sizeof(svc_id) - 1, "switch%d", switch_id + 1);
|
||||||
|
snprintf_s(switch_name, sizeof(switch_name), sizeof(switch_name) - 1, "开关%d", switch_id + 1);
|
||||||
|
|
||||||
|
int ret = snprintf_s(buff, sizeof(buff), sizeof(buff) - 1,
|
||||||
|
SWITCH_BLE_NAME_REPORT,
|
||||||
|
g_persistent_state.switches[switch_id].switch_on ? 1 : 0,
|
||||||
|
switch_name,
|
||||||
|
svc_id);
|
||||||
|
if (ret <= 0) {
|
||||||
|
e_printf("[BLE] 开关%d状态格式化失败: %d\r\n", switch_id + 1, ret);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int buffLen = strlen(buff);
|
||||||
|
ret = BLE_SendCustomData(CUSTOM_SEC_DATA, (const unsigned char *)buff, buffLen);
|
||||||
|
e_printf("[BLE] 上报开关%d状态: %s, 结果: %d\r\n", switch_id + 1, buff, ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 通过蓝牙上报所有开关状态
|
||||||
|
static void ble_report_all_switches(void) {
|
||||||
|
e_printf("[BLE] 开始上报所有开关状态\r\n");
|
||||||
|
|
||||||
|
// 上报总开关状态
|
||||||
|
ble_report_master_switch();
|
||||||
|
|
||||||
|
// 上报所有子开关状态
|
||||||
|
for (int i = 0; i < SWITCH_COUNT; i++) {
|
||||||
|
ble_report_switch_state(i);
|
||||||
|
osal_msleep(50); // 避免发送过快
|
||||||
|
}
|
||||||
|
|
||||||
|
e_printf("[BLE] 所有开关状态上报完成\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
//====================== 蓝牙接收数据处理 ======================
|
||||||
|
|
||||||
|
// 处理总开关控制指令
|
||||||
|
static int ble_handle_master_switch(cJSON *dataItem) {
|
||||||
|
cJSON *onItem = cJSON_GetObjectItem(dataItem, "on");
|
||||||
|
if (onItem == NULL || !cJSON_IsNumber(onItem)) {
|
||||||
|
e_printf("[BLE] 总开关控制指令格式错误\r\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool new_state = (onItem->valueint != 0);
|
||||||
|
e_printf("[BLE] 接收到总开关控制指令: %s\r\n", new_state ? "开" : "关");
|
||||||
|
|
||||||
|
// 调用现有的总开关控制函数
|
||||||
|
update_master_switch(new_state);
|
||||||
|
|
||||||
|
// 通过蓝牙上报状态确认
|
||||||
|
ble_report_master_switch();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理子开关控制指令
|
||||||
|
static int ble_handle_switch_control(const char *svc_id, cJSON *dataItem) {
|
||||||
|
// 解析开关ID (switch1 -> 0, switch2 -> 1, etc.)
|
||||||
|
int switch_id = -1;
|
||||||
|
if (strcmp(svc_id, "switch1") == 0) {
|
||||||
|
switch_id = 0;
|
||||||
|
} else if (strcmp(svc_id, "switch2") == 0) {
|
||||||
|
switch_id = 1;
|
||||||
|
} else if (strcmp(svc_id, "switch3") == 0) {
|
||||||
|
switch_id = 2;
|
||||||
|
} else if (strcmp(svc_id, "switch4") == 0) {
|
||||||
|
switch_id = 3;
|
||||||
|
} else {
|
||||||
|
e_printf("[BLE] 未知的开关ID: %s\r\n", svc_id);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cJSON *onItem = cJSON_GetObjectItem(dataItem, "on");
|
||||||
|
if (onItem == NULL || !cJSON_IsNumber(onItem)) {
|
||||||
|
e_printf("[BLE] 开关%d控制指令格式错误\r\n", switch_id + 1);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool new_state = (onItem->valueint != 0);
|
||||||
|
e_printf("[BLE] 接收到开关%d控制指令: %s\r\n", switch_id + 1, new_state ? "开" : "关");
|
||||||
|
|
||||||
|
// 调用现有的开关控制函数
|
||||||
|
update_switch_state(switch_id, new_state);
|
||||||
|
|
||||||
|
// 通过蓝牙上报状态确认
|
||||||
|
ble_report_switch_state(switch_id);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理状态查询指令
|
||||||
|
static int ble_handle_status_query(const char *svc_id) {
|
||||||
|
e_printf("[BLE] 接收到状态查询: %s\r\n", svc_id);
|
||||||
|
|
||||||
|
if (strcmp(svc_id, "switch") == 0) {
|
||||||
|
// 查询总开关状态
|
||||||
|
ble_report_master_switch();
|
||||||
|
} else if (strncmp(svc_id, "switch", 6) == 0 && strlen(svc_id) == 7) {
|
||||||
|
// 查询子开关状态 (switch1, switch2, etc.)
|
||||||
|
int switch_id = svc_id[6] - '1'; // '1' -> 0, '2' -> 1, etc.
|
||||||
|
if (switch_id >= 0 && switch_id < SWITCH_COUNT) {
|
||||||
|
ble_report_switch_state(switch_id);
|
||||||
|
} else {
|
||||||
|
e_printf("[BLE] 无效的开关查询ID: %s\r\n", svc_id);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
e_printf("[BLE] 未知的查询ID: %s\r\n", svc_id);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//====================== 蓝牙数据处理主函数 ======================
|
||||||
|
|
||||||
|
// 处理蓝牙接收的自定义数据
|
||||||
|
int switch_panel_ble_handle_custom_data(const char *buff, unsigned int len) {
|
||||||
|
if (buff == NULL || len == 0) {
|
||||||
|
e_printf("[BLE] 接收数据为空\r\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
e_printf("[BLE] 接收到数据: %s (长度: %u)\r\n", buff, len);
|
||||||
|
|
||||||
|
// 处理空JSON请求 - 上报全量状态
|
||||||
|
if (strcmp(buff, "{}") == 0) {
|
||||||
|
e_printf("[BLE] 收到全量状态请求\r\n");
|
||||||
|
ble_report_all_switches();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析JSON数据
|
||||||
|
cJSON *json = cJSON_Parse(buff);
|
||||||
|
if (json == NULL) {
|
||||||
|
e_printf("[BLE] JSON解析失败\r\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
do {
|
||||||
|
// 获取服务ID
|
||||||
|
cJSON *sidItem = cJSON_GetObjectItem(json, "sid");
|
||||||
|
if (sidItem == NULL || !cJSON_IsString(sidItem) || sidItem->valuestring == NULL) {
|
||||||
|
e_printf("[BLE] 缺少或无效的服务ID\r\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *svc_id = sidItem->valuestring;
|
||||||
|
cJSON *dataItem = cJSON_GetObjectItem(json, "data");
|
||||||
|
|
||||||
|
// 处理特殊服务ID
|
||||||
|
if (strcmp(svc_id, "allservices") == 0) {
|
||||||
|
// H5连接时的状态同步请求
|
||||||
|
e_printf("[BLE] H5连接,同步所有状态\r\n");
|
||||||
|
ble_report_all_switches();
|
||||||
|
ret = 0;
|
||||||
|
break;
|
||||||
|
} else if (strcmp(svc_id, "currentTime") == 0) {
|
||||||
|
// 时间同步(可选实现)
|
||||||
|
e_printf("[BLE] 接收到时间同步请求\r\n");
|
||||||
|
ret = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果没有data字段,表示状态查询
|
||||||
|
if (dataItem == NULL) {
|
||||||
|
ret = ble_handle_status_query(svc_id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理控制指令
|
||||||
|
if (strcmp(svc_id, "switch") == 0) {
|
||||||
|
// 总开关控制
|
||||||
|
ret = ble_handle_master_switch(dataItem);
|
||||||
|
} else if (strncmp(svc_id, "switch", 6) == 0 && strlen(svc_id) == 7) {
|
||||||
|
// 子开关控制 (switch1, switch2, switch3, switch4)
|
||||||
|
ret = ble_handle_switch_control(svc_id, dataItem);
|
||||||
|
} else {
|
||||||
|
e_printf("[BLE] 未知的服务ID: %s\r\n", svc_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
cJSON_Delete(json);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
//====================== 蓝牙模式管理 ======================
|
||||||
|
|
||||||
|
// 启用蓝牙控制模式
|
||||||
|
void switch_panel_ble_enable(void) {
|
||||||
|
g_ble_mode_enabled = true;
|
||||||
|
e_printf("[BLE] 蓝牙控制模式已启用\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 禁用蓝牙控制模式
|
||||||
|
void switch_panel_ble_disable(void) {
|
||||||
|
g_ble_mode_enabled = false;
|
||||||
|
e_printf("[BLE] 蓝牙控制模式已禁用\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查蓝牙控制模式是否启用
|
||||||
|
bool switch_panel_ble_is_enabled(void) {
|
||||||
|
return g_ble_mode_enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
//====================== 蓝牙上报接口 ======================
|
||||||
|
|
||||||
|
// 蓝牙模式下的快速上报函数
|
||||||
|
int switch_panel_ble_fast_report(const char *svc_id) {
|
||||||
|
if (!g_ble_mode_enabled) {
|
||||||
|
return -1; // 蓝牙模式未启用
|
||||||
|
}
|
||||||
|
|
||||||
|
if (svc_id == NULL) {
|
||||||
|
e_printf("[BLE] 服务ID为空\r\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
e_printf("[BLE] 快速上报服务: %s\r\n", svc_id);
|
||||||
|
|
||||||
|
if (strcmp(svc_id, "switch") == 0) {
|
||||||
|
ble_report_master_switch();
|
||||||
|
} else if (strcmp(svc_id, "switch1") == 0) {
|
||||||
|
ble_report_switch_state(0);
|
||||||
|
} else if (strcmp(svc_id, "switch2") == 0) {
|
||||||
|
ble_report_switch_state(1);
|
||||||
|
} else if (strcmp(svc_id, "switch3") == 0) {
|
||||||
|
ble_report_switch_state(2);
|
||||||
|
} else if (strcmp(svc_id, "switch4") == 0) {
|
||||||
|
ble_report_switch_state(3);
|
||||||
|
} else {
|
||||||
|
e_printf("[BLE] 未知的服务ID: %s\r\n", svc_id);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -10,35 +10,190 @@
|
|||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
#include "soc_osal.h"
|
#include "soc_osal.h"
|
||||||
#include "systick.h"
|
#include "systick.h"
|
||||||
|
#include "wifi_hotspot.h"
|
||||||
|
#include "wifi_hotspot_config.h"
|
||||||
|
#include "lwip/netifapi.h"
|
||||||
|
|
||||||
//====================== 配网相关变量 ======================
|
//====================== 配网相关变量 ======================
|
||||||
static bool g_config_led_blink_state = false;
|
int g_config_key_id = -1; // 触发配网的按键 - 移除static使其可被外部访问
|
||||||
static bool g_panel_led_blink_state = false;
|
|
||||||
static uint32_t g_config_blink_start_time = 0;
|
//====================== 产测相关常量定义 ======================
|
||||||
static int g_config_key_id = -1; // 触发配网的按键
|
#define FACTORY_TEST_RSSI_THRESHOLD (-70) // WiFi信号强度阈值 -70dBm
|
||||||
|
#define WIFI_SCAN_AP_LIMIT 64 // 最大扫描AP数量
|
||||||
|
#define WIFI_MAX_SSID_LEN 33 // SSID最大长度
|
||||||
|
#define WIFI_MAC_LEN 6 // MAC地址长度
|
||||||
|
#define WIFI_STA_SAMPLE_LOG "[FACTORY]" // 日志前缀
|
||||||
|
|
||||||
|
//====================== 产测WiFi状态枚举 ======================
|
||||||
|
enum {
|
||||||
|
WIFI_STA_SAMPLE_INIT = 0, // 初始态
|
||||||
|
WIFI_STA_SAMPLE_SCANING, // 扫描中
|
||||||
|
WIFI_STA_SAMPLE_SCAN_DONE, // 扫描完成
|
||||||
|
WIFI_STA_SAMPLE_FOUND_TARGET, // 匹配到目标AP
|
||||||
|
} wifi_state_enum;
|
||||||
|
|
||||||
//====================== 产测相关变量 ======================
|
//====================== 产测相关变量 ======================
|
||||||
static bool g_factory_test_running = false;
|
static bool g_factory_test_running = false;
|
||||||
static int g_factory_test_step = 0;
|
static int g_factory_test_step = 0;
|
||||||
static uint32_t g_factory_test_start_time = 0;
|
static uint32_t g_factory_test_start_time = 0;
|
||||||
|
static uint8_t g_wifi_state = WIFI_STA_SAMPLE_INIT;
|
||||||
|
|
||||||
//====================== 配网模式函数 ======================
|
//====================== WiFi事件回调函数 ======================
|
||||||
|
static void wifi_scan_state_changed(int32_t state, int32_t size) {
|
||||||
|
UNUSED(state);
|
||||||
|
UNUSED(size);
|
||||||
|
e_printf("%s WiFi扫描完成!\r\n", WIFI_STA_SAMPLE_LOG);
|
||||||
|
g_wifi_state = WIFI_STA_SAMPLE_SCAN_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wifi_connection_changed(int32_t state, const wifi_linked_info_stru *info, int32_t reason_code) {
|
||||||
|
UNUSED(info);
|
||||||
|
UNUSED(reason_code);
|
||||||
|
// 产测模式下不需要连接,只需要扫描
|
||||||
|
}
|
||||||
|
|
||||||
|
static wifi_event_stru wifi_event_cb = {
|
||||||
|
.wifi_event_connection_changed = wifi_connection_changed,
|
||||||
|
.wifi_event_scan_state_changed = wifi_scan_state_changed,
|
||||||
|
};
|
||||||
|
|
||||||
|
//====================== WiFi扫描和产测函数 ======================
|
||||||
|
|
||||||
|
// 匹配目标AP并获取信号强度
|
||||||
|
static int32_t get_match_network_rssi(const char* target_ssid, int32_t* rssi) {
|
||||||
|
int32_t ret;
|
||||||
|
uint32_t num = WIFI_SCAN_AP_LIMIT;
|
||||||
|
bool find_ap = false;
|
||||||
|
uint8_t bss_index;
|
||||||
|
|
||||||
|
// 获取扫描结果
|
||||||
|
uint32_t scan_len = sizeof(wifi_scan_info_stru) * WIFI_SCAN_AP_LIMIT;
|
||||||
|
wifi_scan_info_stru *result = osal_kmalloc(scan_len, OSAL_GFP_ATOMIC);
|
||||||
|
if (result == NULL) {
|
||||||
|
e_printf("%s 内存分配失败\r\n", WIFI_STA_SAMPLE_LOG);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset_s(result, scan_len, 0, scan_len);
|
||||||
|
ret = wifi_sta_get_scan_info(result, &num);
|
||||||
|
if (ret != 0) {
|
||||||
|
e_printf("%s 获取扫描信息失败: %d\r\n", WIFI_STA_SAMPLE_LOG, ret);
|
||||||
|
osal_kfree(result);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 筛选扫描到的WiFi网络,查找目标AP
|
||||||
|
for (bss_index = 0; bss_index < num; bss_index++) {
|
||||||
|
if (strlen(target_ssid) == strlen(result[bss_index].ssid)) {
|
||||||
|
if (memcmp(target_ssid, result[bss_index].ssid, strlen(target_ssid)) == 0) {
|
||||||
|
find_ap = true;
|
||||||
|
*rssi = result[bss_index].rssi;
|
||||||
|
e_printf("%s 找到目标AP: %s, 信号强度: %ddBm\r\n",
|
||||||
|
WIFI_STA_SAMPLE_LOG, target_ssid, *rssi);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
osal_kfree(result);
|
||||||
|
|
||||||
|
if (!find_ap) {
|
||||||
|
e_printf("%s 未找到目标AP: %s\r\n", WIFI_STA_SAMPLE_LOG, target_ssid);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// WiFi扫描并检查信号强度
|
||||||
|
static int32_t wifi_scan_and_check(const char* target_ssid, int32_t rssi_threshold) {
|
||||||
|
int32_t rssi = 0;
|
||||||
|
g_wifi_state = WIFI_STA_SAMPLE_INIT;
|
||||||
|
|
||||||
|
do {
|
||||||
|
osal_msleep(10);
|
||||||
|
|
||||||
|
if (g_wifi_state == WIFI_STA_SAMPLE_INIT) {
|
||||||
|
e_printf("%s 开始WiFi扫描...\r\n", WIFI_STA_SAMPLE_LOG);
|
||||||
|
g_wifi_state = WIFI_STA_SAMPLE_SCANING;
|
||||||
|
|
||||||
|
// 启动WiFi扫描
|
||||||
|
if (wifi_sta_scan() != 0) {
|
||||||
|
e_printf("%s WiFi扫描启动失败\r\n", WIFI_STA_SAMPLE_LOG);
|
||||||
|
g_wifi_state = WIFI_STA_SAMPLE_INIT;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else if (g_wifi_state == WIFI_STA_SAMPLE_SCAN_DONE) {
|
||||||
|
// 获取目标网络的信号强度
|
||||||
|
if (get_match_network_rssi(target_ssid, &rssi) != 0) {
|
||||||
|
e_printf("%s 未找到目标AP: %s\r\n", WIFI_STA_SAMPLE_LOG, target_ssid);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (1);
|
||||||
|
|
||||||
|
// 检查信号强度阈值
|
||||||
|
if (rssi_threshold == 0) {
|
||||||
|
// 只检查是否找到目标AP,不检查信号强度
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
e_printf("%s 信号强度测试: 期望 >= %ddBm, 实际 %ddBm\r\n",
|
||||||
|
WIFI_STA_SAMPLE_LOG, rssi_threshold, rssi);
|
||||||
|
|
||||||
|
if (rssi >= rssi_threshold) {
|
||||||
|
return 0; // 测试通过
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1; // 信号强度不足
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化WiFi产测环境
|
||||||
|
static int factory_test_wifi_init(void) {
|
||||||
|
// 注册WiFi事件回调
|
||||||
|
if (wifi_register_event_cb(&wifi_event_cb) != 0) {
|
||||||
|
e_printf("%s WiFi事件回调注册失败\r\n", WIFI_STA_SAMPLE_LOG);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 等待WiFi初始化完成
|
||||||
|
int timeout = 100; // 10秒超时
|
||||||
|
while (wifi_is_wifi_inited() == 0 && timeout-- > 0) {
|
||||||
|
msleep(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeout <= 0) {
|
||||||
|
e_printf("%s WiFi初始化超时\r\n", WIFI_STA_SAMPLE_LOG);
|
||||||
|
goto lab_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建STA接口
|
||||||
|
if (wifi_sta_enable() != 0) {
|
||||||
|
e_printf("%s WiFi STA启动失败\r\n", WIFI_STA_SAMPLE_LOG);
|
||||||
|
goto lab_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
e_printf("%s WiFi产测环境初始化完成\r\n", WIFI_STA_SAMPLE_LOG);
|
||||||
|
return 0;
|
||||||
|
lab_err:
|
||||||
|
wifi_unregister_event_cb(&wifi_event_cb);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
// 进入配网模式
|
// 进入配网模式
|
||||||
void enter_config_mode(void) {
|
void enter_config_mode(void) {
|
||||||
if (g_device_state.mode == MODE_CONFIG) {
|
if (g_runtime_state.mode == MODE_CONFIG) {
|
||||||
e_printf("[CONFIG] 已在配网模式中\r\n");
|
e_printf("[CONFIG] 已在配网模式中\r\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
e_printf("[CONFIG] 进入配网模式\r\n");
|
e_printf("[CONFIG] 进入配网模式\r\n");
|
||||||
|
start_hilink_ble_net_config(CONFIG_TIMEOUT_MS/1000);
|
||||||
|
|
||||||
// 更新设备模式
|
// 更新设备模式
|
||||||
set_device_mode(MODE_CONFIG);
|
set_device_mode(MODE_CONFIG);
|
||||||
|
|
||||||
// 记录配网开始时间
|
|
||||||
g_config_blink_start_time = hfsys_get_time();
|
|
||||||
|
|
||||||
// 面板背光快闪1秒表示进入配网模式
|
// 面板背光快闪1秒表示进入配网模式
|
||||||
panel_led_blink();
|
panel_led_blink();
|
||||||
|
|
||||||
@ -57,57 +212,17 @@ void enter_config_mode(void) {
|
|||||||
osal_kthread_set_priority(g_config_task_handle, TASK_PRIORITY_NORM);
|
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);
|
e_printf("[CONFIG] 配网模式已开启,超时时间: %d分钟\r\n", CONFIG_TIMEOUT_MS / 60000);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 退出配网模式
|
// 退出配网模式
|
||||||
void exit_config_mode(void) {
|
void exit_config_mode(void) {
|
||||||
if (g_device_state.mode != MODE_CONFIG) {
|
if (g_runtime_state.mode != MODE_CONFIG) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
e_printf("[CONFIG] 退出配网模式\r\n");
|
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) {
|
if (g_config_task_handle) {
|
||||||
osal_kthread_destroy(g_config_task_handle, 1);
|
osal_kthread_destroy(g_config_task_handle, 1);
|
||||||
@ -116,19 +231,17 @@ void exit_config_mode(void) {
|
|||||||
|
|
||||||
// 恢复正常LED状态
|
// 恢复正常LED状态
|
||||||
for (int i = 0; i < SWITCH_COUNT; i++) {
|
for (int i = 0; i < SWITCH_COUNT; i++) {
|
||||||
set_led_output(i, g_device_state.switches[i].led_state ? LED_WHITE : LED_YELLOW);
|
set_led_output(i, g_persistent_state.switches[i].led_state ? LED_WHITE : LED_YELLOW);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 恢复面板背光状态
|
// 恢复面板背光状态
|
||||||
set_panel_led(g_device_state.panel_led ? PANEL_LED_ON : PANEL_LED_OFF);
|
set_panel_led(g_persistent_state.panel_led ? PANEL_LED_ON : PANEL_LED_OFF);
|
||||||
|
|
||||||
// 更新设备模式
|
// 更新设备模式
|
||||||
set_device_mode(MODE_NORMAL);
|
set_device_mode(MODE_NORMAL);
|
||||||
|
|
||||||
// 重置配网相关变量
|
// 重置配网相关变量
|
||||||
g_config_key_id = -1;
|
g_config_key_id = -1;
|
||||||
g_config_led_blink_state = false;
|
|
||||||
g_panel_led_blink_state = false;
|
|
||||||
|
|
||||||
e_printf("[CONFIG] 已退出配网模式\r\n");
|
e_printf("[CONFIG] 已退出配网模式\r\n");
|
||||||
}
|
}
|
||||||
@ -139,47 +252,66 @@ int config_mode_task(void *arg) {
|
|||||||
|
|
||||||
e_printf("[CONFIG] 配网任务开始\r\n");
|
e_printf("[CONFIG] 配网任务开始\r\n");
|
||||||
|
|
||||||
while (g_device_state.mode == MODE_CONFIG && !osal_kthread_should_stop()) {
|
// 记录配网开始时间
|
||||||
// 检查是否有产测热点
|
g_runtime_state.config_start_time = hfsys_get_time();
|
||||||
if (check_factory_test_wifi()) {
|
|
||||||
e_printf("[CONFIG] 检测到产测热点,进入产测模式\r\n");
|
// 只有在首次启动时才检查产测热点
|
||||||
exit_config_mode();
|
if (g_persistent_state.is_first_boot && check_factory_test_wifi()) {
|
||||||
enter_factory_test_mode();
|
e_printf("[CONFIG] 检测到产测热点且为首次启动,进入产测模式\r\n");
|
||||||
|
exit_config_mode();
|
||||||
|
enter_factory_test_mode();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t config_start_time = g_runtime_state.config_start_time;
|
||||||
|
bool led_blink_state = false;
|
||||||
|
uint32_t last_blink_time = 0;
|
||||||
|
const uint32_t blink_interval = 500; // 500ms闪烁间隔 (1Hz)
|
||||||
|
|
||||||
|
while (g_runtime_state.mode == MODE_CONFIG && !osal_kthread_should_stop()) {
|
||||||
|
uint32_t current_time = hfsys_get_time();
|
||||||
|
uint32_t elapsed_time = current_time - config_start_time;
|
||||||
|
|
||||||
|
// 检查是否超时 (10分钟)
|
||||||
|
if (elapsed_time >= CONFIG_TIMEOUT_MS) {
|
||||||
|
e_printf("[CONFIG] 配网超时,退出配网模式\r\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 每秒检查一次
|
// LED控制逻辑
|
||||||
osal_msleep(1000);
|
if (elapsed_time < CONFIG_BLINK_MS) { // 前3分钟闪烁
|
||||||
}
|
// 检查是否需要切换LED状态
|
||||||
|
if (current_time - last_blink_time >= blink_interval) {
|
||||||
|
led_blink_state = !led_blink_state;
|
||||||
|
last_blink_time = current_time;
|
||||||
|
|
||||||
e_printf("[CONFIG] 配网任务结束\r\n");
|
// 只有触发配网的按键LED闪烁,其他LED保持黄灯常亮
|
||||||
return 0;
|
for (int i = 0; i < SWITCH_COUNT; i++) {
|
||||||
}
|
if (i == g_config_key_id) {
|
||||||
|
// 触发配网的按键LED闪烁
|
||||||
// 配网LED闪烁
|
set_led_output(i, led_blink_state ? LED_WHITE : LED_YELLOW);
|
||||||
void config_led_blink(void) {
|
} else {
|
||||||
uint32_t current_time = hfsys_get_time();
|
// 其他按键LED保持黄灯常亮
|
||||||
uint32_t elapsed_time = current_time - g_config_blink_start_time;
|
set_led_output(i, LED_YELLOW);
|
||||||
|
}
|
||||||
// 前3分钟闪烁,后7分钟常亮
|
}
|
||||||
if (elapsed_time < CONFIG_BLINK_MS) {
|
}
|
||||||
// 只有触发配网的按键LED闪烁,其他LED保持常亮
|
} else { // 后7分钟常亮
|
||||||
for (int i = 0; i < SWITCH_COUNT; i++) {
|
// 所有LED保持黄灯常亮
|
||||||
if (i == g_config_key_id) {
|
for (int i = 0; i < SWITCH_COUNT; i++) {
|
||||||
// 触发配网的按键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);
|
set_led_output(i, LED_YELLOW);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// 超过3分钟后,所有LED保持常亮
|
// 每100ms检查一次
|
||||||
for (int i = 0; i < SWITCH_COUNT; i++) {
|
osal_msleep(100);
|
||||||
set_led_output(i, LED_YELLOW);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
e_printf("[CONFIG] 配网任务结束\r\n");
|
||||||
|
g_config_task_handle = NULL;
|
||||||
|
// 退出配网模式
|
||||||
|
exit_config_mode();
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 面板背光快闪
|
// 面板背光快闪
|
||||||
@ -193,7 +325,7 @@ void panel_led_blink(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 恢复原状态
|
// 恢复原状态
|
||||||
set_panel_led(g_device_state.panel_led ? PANEL_LED_ON : PANEL_LED_OFF);
|
set_panel_led(g_persistent_state.panel_led ? PANEL_LED_ON : PANEL_LED_OFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
//====================== 产测模式函数 ======================
|
//====================== 产测模式函数 ======================
|
||||||
@ -299,34 +431,30 @@ void factory_test_sequence(void) {
|
|||||||
|
|
||||||
// 检查产测热点
|
// 检查产测热点
|
||||||
bool check_factory_test_wifi(void) {
|
bool check_factory_test_wifi(void) {
|
||||||
// 简化实现:直接返回false,实际应该扫描WiFi热点
|
// 使用WiFi扫描功能检测产测热点 "ShuorongSelfTest"
|
||||||
// TODO: 实际实现需要调用WiFi扫描接口查找 "ShuorongSelfTest" 热点
|
// 并校验信号强度 >= -70dBm
|
||||||
|
|
||||||
return false; // 默认未找到产测热点
|
static bool wifi_initialized = false;
|
||||||
}
|
|
||||||
|
|
||||||
//====================== 定时器回调函数 ======================
|
// 初始化WiFi环境(只初始化一次)
|
||||||
|
if (!wifi_initialized) {
|
||||||
|
if (factory_test_wifi_init() != 0) {
|
||||||
|
e_printf("%s WiFi环境初始化失败\r\n", WIFI_STA_SAMPLE_LOG);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
wifi_initialized = true;
|
||||||
|
|
||||||
// 配网超时定时器回调
|
// 等待WiFi稳定
|
||||||
void config_timeout_timer_callback(uintptr_t data) {
|
// osal_msleep(1000);
|
||||||
(void)data;
|
|
||||||
|
|
||||||
e_printf("[CONFIG] 配网超时,退出配网模式\r\n");
|
|
||||||
|
|
||||||
// 超时退出配网模式
|
|
||||||
exit_config_mode();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 配网闪烁定时器回调
|
|
||||||
void config_blink_timer_callback(uintptr_t data) {
|
|
||||||
(void)data;
|
|
||||||
uint32_t blink_period = 1000000 / (LED_BLINK_FREQ_HZ * 2); // 半周期(微秒)
|
|
||||||
// 执行闪烁操作
|
|
||||||
config_led_blink();
|
|
||||||
if (g_config_blink_timer) {
|
|
||||||
uapi_timer_start(g_config_blink_timer,
|
|
||||||
blink_period,
|
|
||||||
config_blink_timer_callback,
|
|
||||||
0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 扫描并检查目标热点
|
||||||
|
if (wifi_scan_and_check(FACTORY_TEST_SSID, FACTORY_TEST_RSSI_THRESHOLD) == 0) {
|
||||||
|
e_printf("%s 产测热点检测通过: %s, 信号强度满足要求\r\n",
|
||||||
|
WIFI_STA_SAMPLE_LOG, FACTORY_TEST_SSID);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false; // 未找到合格的产测热点
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,68 +15,73 @@ static int handle_put_switch_common(int switch_id, const char* svc_id,
|
|||||||
|
|
||||||
// 处理设备上线事件
|
// 处理设备上线事件
|
||||||
void handle_device_online(void) {
|
void handle_device_online(void) {
|
||||||
e_printf("[HILINK] 设备上线\r\n");
|
e_printf("设备上线\r\n");
|
||||||
|
|
||||||
// 更新设备绑定状态
|
// 更新设备绑定状态
|
||||||
g_device_state.is_bound = true;
|
g_persistent_state.is_bound = true;
|
||||||
|
|
||||||
|
// 如果是首次启动,标记为非首次启动(首次绑定完成)
|
||||||
|
if (g_persistent_state.is_first_boot) {
|
||||||
|
g_persistent_state.is_first_boot = false;
|
||||||
|
e_printf("首次绑定完成,标记为非首次启动\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
// 退出配网模式
|
// 退出配网模式
|
||||||
if (g_device_state.mode == MODE_CONFIG) {
|
if (g_runtime_state.mode == MODE_CONFIG) {
|
||||||
exit_config_mode();
|
exit_config_mode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 设备上线时禁用蓝牙模式,启用云端模式
|
||||||
|
extern void switch_panel_ble_disable(void);
|
||||||
|
switch_panel_ble_disable();
|
||||||
|
|
||||||
// 同步所有状态到云端
|
// 同步所有状态到云端
|
||||||
sync_cloud_state();
|
sync_cloud_state();
|
||||||
|
|
||||||
// 保存状态
|
// 保存状态
|
||||||
save_device_state();
|
save_persistent_state();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理设备下线事件
|
// 处理设备下线事件
|
||||||
void handle_device_offline(void) {
|
void handle_device_offline(void) {
|
||||||
e_printf("[HILINK] 设备下线\r\n");
|
e_printf("设备下线\r\n");
|
||||||
|
|
||||||
|
// 设备下线时启用蓝牙模式,支持本地控制
|
||||||
|
extern void switch_panel_ble_enable(void);
|
||||||
|
switch_panel_ble_enable();
|
||||||
|
|
||||||
// 设备下线时保持现有状态,不做特殊处理
|
// 设备下线时保持现有状态,不做特殊处理
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理设备解绑事件
|
// 处理设备解绑事件
|
||||||
void handle_device_unbind(void) {
|
void handle_device_unbind(void) {
|
||||||
e_printf("[HILINK] 设备解绑\r\n");
|
e_printf("设备解绑\r\n");
|
||||||
|
|
||||||
// 更新设备绑定状态
|
// 更新设备绑定状态
|
||||||
g_device_state.is_bound = false;
|
g_persistent_state.is_bound = false;
|
||||||
g_device_state.mode = MODE_UNBIND;
|
g_runtime_state.mode = MODE_UNBIND;
|
||||||
|
|
||||||
// 重置为出厂默认状态
|
// 重置为出厂默认状态
|
||||||
reset_device_state();
|
reset_persistent_state();
|
||||||
g_device_state.is_bound = false; // 保持未绑定状态
|
g_persistent_state.is_bound = false; // 保持未绑定状态
|
||||||
|
|
||||||
// 同步硬件状态
|
// 同步硬件状态
|
||||||
sync_hardware_state();
|
sync_hardware_state();
|
||||||
|
|
||||||
// 保存状态
|
// 保存状态
|
||||||
save_device_state();
|
save_persistent_state();
|
||||||
|
|
||||||
e_printf("[HILINK] 设备已重置为出厂默认状态\r\n");
|
e_printf("设备已重置为出厂默认状态\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 同步所有状态到云端
|
// 同步所有状态到云端
|
||||||
void sync_cloud_state(void) {
|
void sync_cloud_state(void) {
|
||||||
e_printf("[HILINK] 开始同步状态到云端\r\n");
|
e_printf("开始同步状态到云端\r\n");
|
||||||
|
|
||||||
// 上报总开关状态
|
// 使用批量异步上报所有开关状态
|
||||||
extern int fast_report(const char* svc_id);
|
fast_report_all_switches_async();
|
||||||
fast_report("switch");
|
|
||||||
|
|
||||||
// 上报所有子开关状态
|
e_printf("状态同步完成\r\n");
|
||||||
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 服务处理函数 ======================
|
//====================== HiLink 服务处理函数 ======================
|
||||||
@ -84,24 +89,20 @@ void sync_cloud_state(void) {
|
|||||||
// 处理总开关PUT命令
|
// 处理总开关PUT命令
|
||||||
int handle_put_switch(const char* svc_id, const char* payload, unsigned int len) {
|
int handle_put_switch(const char* svc_id, const char* payload, unsigned int len) {
|
||||||
if (!svc_id || !payload) {
|
if (!svc_id || !payload) {
|
||||||
e_printf("[HILINK] handle_put_switch 参数无效\r\n");
|
e_printf("handle_put_switch 参数无效\r\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
e_printf("[HILINK] 收到总开关控制命令: %s\r\n", payload);
|
e_printf("收到总开关控制命令: %s\r\n", payload);
|
||||||
|
|
||||||
cJSON* json = cJSON_Parse(payload);
|
cJSON* json = cJSON_Parse(payload);
|
||||||
if (!json) {
|
if (!json) {
|
||||||
e_printf("[HILINK] JSON解析失败\r\n");
|
e_printf("JSON解析失败\r\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
cJSON* on_item = cJSON_GetObjectItem(json, "on");
|
cJSON* on_item = cJSON_GetObjectItem(json, "on");
|
||||||
if (on_item && cJSON_IsBool(on_item)) {
|
update_master_switch(cJSON_GetNumberValue(on_item));
|
||||||
bool state = cJSON_IsTrue(on_item);
|
|
||||||
update_master_switch(state);
|
|
||||||
e_printf("[HILINK] 总开关设置为: %s\r\n", state ? "开" : "关");
|
|
||||||
}
|
|
||||||
|
|
||||||
cJSON_Delete(json);
|
cJSON_Delete(json);
|
||||||
return 0;
|
return 0;
|
||||||
@ -120,10 +121,10 @@ int handle_get_switch(const char* svc_id, const char* in, unsigned int in_len,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
*out_len = snprintf(*out, *out_len, "{\"on\":%s}",
|
*out_len = snprintf(*out, *out_len, "{\"on\":%d}",
|
||||||
g_device_state.master_switch ? "true" : "false");
|
g_persistent_state.master_switch ? 1 : 0);
|
||||||
|
|
||||||
e_printf("[HILINK] 返回总开关状态: %s\r\n", *out);
|
e_printf("返回总开关状态: %s\r\n", *out);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,32 +178,25 @@ int handle_get_switch4(const char* svc_id, const char* in, unsigned int in_len,
|
|||||||
static int handle_put_switch_common(int switch_id, const char* svc_id,
|
static int handle_put_switch_common(int switch_id, const char* svc_id,
|
||||||
const char* payload, unsigned int len) {
|
const char* payload, unsigned int len) {
|
||||||
if (switch_id < 0 || switch_id >= SWITCH_COUNT || !svc_id || !payload) {
|
if (switch_id < 0 || switch_id >= SWITCH_COUNT || !svc_id || !payload) {
|
||||||
e_printf("[HILINK] handle_put_switch%d 参数无效\r\n", switch_id + 1);
|
e_printf("handle_put_switch%d 参数无效\r\n", switch_id + 1);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
e_printf("[HILINK] 收到开关%d控制命令: %s\r\n", switch_id + 1, payload);
|
e_printf("收到开关%d控制命令: %s\r\n", switch_id + 1, payload);
|
||||||
|
|
||||||
cJSON* json = cJSON_Parse(payload);
|
cJSON* json = cJSON_Parse(payload);
|
||||||
if (!json) {
|
if (!json) {
|
||||||
e_printf("[HILINK] JSON解析失败\r\n");
|
e_printf("JSON解析失败\r\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
cJSON* on_item = cJSON_GetObjectItem(json, "on");
|
cJSON* on_item = cJSON_GetObjectItem(json, "on");
|
||||||
if (on_item && cJSON_IsBool(on_item)) {
|
if (on_item) {
|
||||||
bool state = cJSON_IsTrue(on_item);
|
update_switch_state(switch_id, cJSON_GetNumberValue(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");
|
cJSON* name_item = cJSON_GetObjectItem(json, "name");
|
||||||
if (name_item && cJSON_IsString(name_item)) {
|
if (name_item) {
|
||||||
e_printf("[HILINK] 开关%d名称: %s\r\n",
|
set_switch_name(switch_id, cJSON_GetStringValue(name_item));
|
||||||
switch_id + 1, cJSON_GetStringValue(name_item));
|
|
||||||
// TODO: 将来可以存储开关名称
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cJSON_Delete(json);
|
cJSON_Delete(json);
|
||||||
@ -223,13 +217,12 @@ static int handle_get_switch_common(int switch_id, const char* svc_id,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 返回开关状态和名称
|
|
||||||
*out_len = snprintf(*out, *out_len,
|
*out_len = snprintf(*out, *out_len,
|
||||||
"{\"on\":%s,\"name\":\"开关%d\"}",
|
"{\"on\":%d,\"name\":\"%s\"}",
|
||||||
g_device_state.switches[switch_id].switch_on ? "true" : "false",
|
g_persistent_state.switches[switch_id].switch_on ? 1 : 0,
|
||||||
switch_id + 1);
|
g_persistent_state.switches[switch_id].name);
|
||||||
|
|
||||||
e_printf("[HILINK] 返回开关%d状态: %s\r\n", switch_id + 1, *out);
|
e_printf("返回开关%d状态: %s\r\n", switch_id + 1, *out);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,24 +230,10 @@ static int handle_get_switch_common(int switch_id, const char* svc_id,
|
|||||||
|
|
||||||
// 检查设备是否在线
|
// 检查设备是否在线
|
||||||
bool is_device_online(void) {
|
bool is_device_online(void) {
|
||||||
return g_device_state.is_bound;
|
return g_persistent_state.is_bound;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取设备当前模式
|
// 获取设备当前模式
|
||||||
system_mode_t get_current_mode(void) {
|
system_mode_t get_current_mode(void) {
|
||||||
return g_device_state.mode;
|
return g_runtime_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();
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -19,35 +19,35 @@ static key_timer_param_t g_timer_params[SWITCH_COUNT];
|
|||||||
// 更新单个开关状态
|
// 更新单个开关状态
|
||||||
void update_switch_state(int switch_id, bool state) {
|
void update_switch_state(int switch_id, bool state) {
|
||||||
if (switch_id < 0 || switch_id >= SWITCH_COUNT) {
|
if (switch_id < 0 || switch_id >= SWITCH_COUNT) {
|
||||||
e_printf("[SWITCH] 无效的开关ID: %d\r\n", switch_id);
|
e_printf("无效的开关ID: %d\r\n", switch_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查总开关是否允许操作
|
// 检查总开关是否允许操作
|
||||||
if (!g_device_state.master_switch && state) {
|
if (!g_persistent_state.master_switch && state) {
|
||||||
e_printf("[SWITCH] 总开关关闭,不允许开启开关%d\r\n", switch_id + 1);
|
e_printf("总开关关闭,不允许开启开关%d\r\n", switch_id + 1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新开关状态
|
// 更新开关状态
|
||||||
if (g_device_state.switches[switch_id].switch_on != state) {
|
if (g_persistent_state.switches[switch_id].switch_on != state) {
|
||||||
g_device_state.switches[switch_id].switch_on = state;
|
g_persistent_state.switches[switch_id].switch_on = state;
|
||||||
|
|
||||||
// 更新LED指示灯(开关开启时LED白灯,关闭时LED黄灯)
|
// 更新LED指示灯(开关开启时LED白灯,关闭时LED黄灯)
|
||||||
g_device_state.switches[switch_id].led_state = state;
|
g_persistent_state.switches[switch_id].led_state = state;
|
||||||
|
|
||||||
// 同步硬件状态
|
// 同步硬件状态
|
||||||
set_switch_output(switch_id, state);
|
set_switch_output(switch_id, state);
|
||||||
set_led_output(switch_id, state ? LED_WHITE : LED_YELLOW);
|
set_led_output(switch_id, state ? LED_WHITE : LED_YELLOW);
|
||||||
|
|
||||||
e_printf("[SWITCH] 开关%d 状态更新: %s\r\n",
|
e_printf("开关%d 状态更新: %s\r\n",
|
||||||
switch_id + 1, state ? "开" : "关");
|
switch_id + 1, state ? "开" : "关");
|
||||||
|
|
||||||
// 立即保存状态
|
// 立即保存状态
|
||||||
save_device_state();
|
save_persistent_state();
|
||||||
|
|
||||||
// 上报状态给云端
|
// 上报状态给云端
|
||||||
if (g_device_state.is_bound) {
|
if (g_persistent_state.is_bound) {
|
||||||
fast_report_switch(switch_id);
|
fast_report_switch(switch_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -55,19 +55,19 @@ void update_switch_state(int switch_id, bool state) {
|
|||||||
|
|
||||||
// 更新总开关状态
|
// 更新总开关状态
|
||||||
void update_master_switch(bool state) {
|
void update_master_switch(bool state) {
|
||||||
if (g_device_state.master_switch != state) {
|
if (g_persistent_state.master_switch != state) {
|
||||||
g_device_state.master_switch = state;
|
g_persistent_state.master_switch = state;
|
||||||
|
|
||||||
e_printf("[SWITCH] 总开关状态更新: %s\r\n", state ? "开" : "关");
|
e_printf("总开关状态更新: %s\r\n", state ? "开" : "关");
|
||||||
|
|
||||||
// 应用总开关控制逻辑
|
// 应用总开关控制逻辑
|
||||||
apply_master_switch_control();
|
apply_master_switch_control();
|
||||||
|
|
||||||
// 立即保存状态
|
// 立即保存状态
|
||||||
save_device_state();
|
save_persistent_state();
|
||||||
|
|
||||||
// 上报状态给云端
|
// 上报状态给云端
|
||||||
if (g_device_state.is_bound) {
|
if (g_persistent_state.is_bound) {
|
||||||
fast_report_master_switch();
|
fast_report_master_switch();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -75,18 +75,42 @@ void update_master_switch(bool state) {
|
|||||||
|
|
||||||
// 应用总开关控制逻辑
|
// 应用总开关控制逻辑
|
||||||
void apply_master_switch_control(void) {
|
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状态保持不变,始终显示实际的开关状态
|
if (!g_persistent_state.master_switch) {
|
||||||
set_led_output(i, g_device_state.switches[i].led_state ? LED_WHITE : LED_YELLOW);
|
// 总开关关闭时,强制关闭所有子开关
|
||||||
|
e_printf("总开关关闭,强制关闭所有子开关\r\n");
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新硬件状态
|
||||||
|
set_switch_output(i, false);
|
||||||
|
set_led_output(i, LED_YELLOW);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 总开关开启时,恢复各开关的原状态(不改变子开关状态)
|
||||||
|
// e_printf("总开关开启,恢复各子开关原有状态\r\n");
|
||||||
|
|
||||||
|
// for (int i = 0; i < SWITCH_COUNT; i++) {
|
||||||
|
// // 硬件状态跟随子开关的实际状态
|
||||||
|
// set_switch_output(i, g_persistent_state.switches[i].switch_on);
|
||||||
|
// set_led_output(i, g_persistent_state.switches[i].led_state ? LED_WHITE : LED_YELLOW);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
// 立即保存状态
|
||||||
|
save_persistent_state();
|
||||||
|
|
||||||
|
// 同步所有子开关状态到云端
|
||||||
|
if (g_persistent_state.is_bound) {
|
||||||
|
fast_report_all_switches_async();
|
||||||
|
}
|
||||||
|
|
||||||
|
e_printf("所有子开关状态已同步\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
//====================== 按键检测与处理 ======================
|
//====================== 按键检测与处理 ======================
|
||||||
@ -149,7 +173,7 @@ int key_scan_task(void *arg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
g_key_states[i] = current_state;
|
g_key_states[i] = current_state;
|
||||||
g_device_state.switches[i].physical_key = current_state;
|
g_runtime_state.switches[i].physical_key = current_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否达到长按时间(在按下期间监测)
|
// 检查是否达到长按时间(在按下期间监测)
|
||||||
@ -178,19 +202,19 @@ void handle_key_press(int key_id) {
|
|||||||
e_printf("[KEY] 处理按键%d 短按事件\r\n", key_id + 1);
|
e_printf("[KEY] 处理按键%d 短按事件\r\n", key_id + 1);
|
||||||
|
|
||||||
// 在配网模式下,忽略短按事件
|
// 在配网模式下,忽略短按事件
|
||||||
if (g_device_state.mode == MODE_CONFIG) {
|
if (g_runtime_state.mode == MODE_CONFIG) {
|
||||||
e_printf("[KEY] 配网模式下,忽略短按事件\r\n");
|
e_printf("[KEY] 配网模式下,忽略短按事件\r\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 在产测模式下,忽略短按事件
|
// 在产测模式下,忽略短按事件
|
||||||
if (g_device_state.mode == MODE_FACTORY_TEST) {
|
if (g_runtime_state.mode == MODE_FACTORY_TEST) {
|
||||||
e_printf("[KEY] 产测模式下,忽略短按事件\r\n");
|
e_printf("[KEY] 产测模式下,忽略短按事件\r\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 正常模式下切换开关状态
|
// 正常模式下切换开关状态
|
||||||
bool current_state = g_device_state.switches[key_id].switch_on;
|
bool current_state = g_persistent_state.switches[key_id].switch_on;
|
||||||
update_switch_state(key_id, !current_state);
|
update_switch_state(key_id, !current_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,13 +228,19 @@ void handle_key_long_press(int key_id) {
|
|||||||
|
|
||||||
// 只有第一个按键支持长按进入配网模式
|
// 只有第一个按键支持长按进入配网模式
|
||||||
if (key_id == 0) {
|
if (key_id == 0) {
|
||||||
e_printf("[KEY] 长按第一个按键,进入配网模式\r\n");
|
e_printf("[KEY] 长按第一个按键,检查配网条件\r\n");
|
||||||
|
|
||||||
// 只有在正常模式下才能进入配网模式
|
// 只有在正常模式下且设备未绑定时才能进入配网模式
|
||||||
if (g_device_state.mode == MODE_NORMAL) {
|
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();
|
enter_config_mode();
|
||||||
} else {
|
} else {
|
||||||
e_printf("[KEY] 非正常模式,不能进入配网模式\r\n");
|
if (g_persistent_state.is_bound) {
|
||||||
|
e_printf("[KEY] 设备已绑定,不能进入配网模式\r\n");
|
||||||
|
} else {
|
||||||
|
e_printf("[KEY] 非正常模式,不能进入配网模式\r\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
e_printf("[KEY] 非第一个按键的长按,忽略\r\n");
|
e_printf("[KEY] 非第一个按键的长按,忽略\r\n");
|
||||||
@ -226,15 +256,19 @@ int key_system_init(void) {
|
|||||||
ret = uapi_timer_init();
|
ret = uapi_timer_init();
|
||||||
if (ret != ERRCODE_SUCC) {
|
if (ret != ERRCODE_SUCC) {
|
||||||
e_printf("[KEY] 定时器初始化失败: %d\r\n", ret);
|
e_printf("[KEY] 定时器初始化失败: %d\r\n", ret);
|
||||||
|
// return HF_FAIL;
|
||||||
|
}
|
||||||
|
ret = uapi_timer_adapter(TIMER_INDEX_1, TIMER_1_IRQN, 1);
|
||||||
|
if (ret != 0) {
|
||||||
|
e_printf("定时器适配器初始化失败\r\n");
|
||||||
return HF_FAIL;
|
return HF_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化定时器参数
|
// 初始化定时器参数
|
||||||
for (int i = 0; i < SWITCH_COUNT; i++) {
|
for (int i = 0; i < SWITCH_COUNT; i++) {
|
||||||
g_timer_params[i].key_id = i;
|
g_timer_params[i].key_id = i;
|
||||||
|
|
||||||
// 创建防抖定时器
|
// 创建防抖定时器
|
||||||
ret = uapi_timer_create(TIMER_INDEX_0, &g_key_debounce_timer[i]);
|
ret = uapi_timer_create(TIMER_INDEX_1, &g_key_debounce_timer[i]);
|
||||||
if (ret != ERRCODE_SUCC) {
|
if (ret != ERRCODE_SUCC) {
|
||||||
e_printf("[KEY] 创建按键%d防抖定时器失败: %d\r\n", i + 1, ret);
|
e_printf("[KEY] 创建按键%d防抖定时器失败: %d\r\n", i + 1, ret);
|
||||||
return HF_FAIL;
|
return HF_FAIL;
|
||||||
@ -242,7 +276,7 @@ int key_system_init(void) {
|
|||||||
|
|
||||||
// 初始化按键状态
|
// 初始化按键状态
|
||||||
g_key_states[i] = get_key_input(i);
|
g_key_states[i] = get_key_input(i);
|
||||||
g_device_state.switches[i].physical_key = g_key_states[i];
|
g_runtime_state.switches[i].physical_key = g_key_states[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建按键扫描任务
|
// 创建按键扫描任务
|
||||||
@ -256,7 +290,7 @@ int key_system_init(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 设置任务优先级
|
// 设置任务优先级
|
||||||
ret = osal_kthread_set_priority(g_key_scan_task_handle, TASK_PRIORITY_NORM);
|
ret = osal_kthread_set_priority(g_key_scan_task_handle, TASK_PRIORITY_HIGH);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
e_printf("[KEY] 设置按键扫描任务优先级失败: %d\r\n", ret);
|
e_printf("[KEY] 设置按键扫描任务优先级失败: %d\r\n", ret);
|
||||||
}
|
}
|
||||||
@ -265,28 +299,12 @@ int key_system_init(void) {
|
|||||||
return HF_SUCCESS;
|
return HF_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
//====================== 快速上报函数 ======================
|
// 快速上报单个开关状态(兼容旧接口,内部使用异步上报)
|
||||||
|
|
||||||
// 快速上报单个开关状态
|
|
||||||
void fast_report_switch(int switch_id) {
|
void fast_report_switch(int switch_id) {
|
||||||
if (switch_id < 0 || switch_id >= SWITCH_COUNT) {
|
fast_report_switch_async(switch_id);
|
||||||
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) {
|
void fast_report_master_switch(void) {
|
||||||
extern int fast_report(const char* svc_id);
|
fast_report_master_switch_async();
|
||||||
fast_report("switch");
|
|
||||||
|
|
||||||
e_printf("[REPORT] 已上报总开关状态\r\n");
|
|
||||||
}
|
}
|
@ -7,29 +7,270 @@
|
|||||||
#include "switch_panel.h"
|
#include "switch_panel.h"
|
||||||
|
|
||||||
//====================== 全局变量 ======================
|
//====================== 全局变量 ======================
|
||||||
device_state_t g_device_state = {
|
device_persistent_state_t g_persistent_state = {
|
||||||
.is_first_boot = true,
|
.is_first_boot = true,
|
||||||
.is_bound = false,
|
.is_bound = false,
|
||||||
.master_switch = false,
|
.master_switch = false,
|
||||||
.panel_led = true,
|
.panel_led = true,
|
||||||
.mode = MODE_NORMAL,
|
|
||||||
.switches = {
|
.switches = {
|
||||||
{.switch_on = false, .led_state = false, .physical_key = true},
|
{.switch_on = false, .led_state = false},
|
||||||
{.switch_on = false, .led_state = false, .physical_key = true},
|
{.switch_on = false, .led_state = false},
|
||||||
{.switch_on = false, .led_state = false, .physical_key = true},
|
{.switch_on = false, .led_state = false},
|
||||||
{.switch_on = false, .led_state = false, .physical_key = true}
|
{.switch_on = false, .led_state = false}
|
||||||
|
},
|
||||||
|
.magic = DEVICE_DATA_MAGIC,
|
||||||
|
.version = DEVICE_DATA_VERSION
|
||||||
|
};
|
||||||
|
|
||||||
|
device_runtime_state_t g_runtime_state = {
|
||||||
|
.mode = MODE_NORMAL,
|
||||||
|
.ble_mode_enabled = false,
|
||||||
|
.config_start_time = 0,
|
||||||
|
.config_key_id = -1,
|
||||||
|
.config_led_blink_state = false,
|
||||||
|
.factory_test_running = false,
|
||||||
|
.last_save_time = 0,
|
||||||
|
.switches = {
|
||||||
|
{.physical_key = true, .press_time = 0, .debounce_flag = false, .long_press_handled = false},
|
||||||
|
{.physical_key = true, .press_time = 0, .debounce_flag = false, .long_press_handled = false},
|
||||||
|
{.physical_key = true, .press_time = 0, .debounce_flag = false, .long_press_handled = false},
|
||||||
|
{.physical_key = true, .press_time = 0, .debounce_flag = false, .long_press_handled = false}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
timer_handle_t g_key_debounce_timer[SWITCH_COUNT] = {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_key_scan_task_handle = NULL;
|
||||||
osal_task *g_config_task_handle = NULL;
|
osal_task *g_config_task_handle = NULL;
|
||||||
|
osal_task *g_save_task_handle = NULL; // 异步保存任务句柄
|
||||||
|
osal_task *g_report_task_handle = NULL; // 异步上报任务句柄
|
||||||
|
|
||||||
static bool g_initialized = false;
|
static bool g_initialized = false;
|
||||||
static uint32_t g_config_start_time = 0;
|
static uint32_t g_config_start_time = 0;
|
||||||
static bool g_config_led_state = false;
|
static bool g_config_led_state = false;
|
||||||
|
|
||||||
|
//====================== 异步保存系统 ======================
|
||||||
|
#include "osal_mutex.h"
|
||||||
|
#include "osal_semaphore.h"
|
||||||
|
|
||||||
|
static osal_mutex g_save_mutex; // 保护持久化状态的互斥锁
|
||||||
|
static osal_semaphore g_save_semaphore; // 触发保存的信号量
|
||||||
|
static bool g_save_system_running = false; // 异步保存系统是否运行中
|
||||||
|
static bool g_save_mutex_initialized = false; // 互斥锁是否已初始化
|
||||||
|
static bool g_save_sem_initialized = false; // 信号量是否已初始化
|
||||||
|
|
||||||
|
//====================== 异步上报系统实现 ======================
|
||||||
|
#include "osal_semaphore.h"
|
||||||
|
#include "osal_mutex.h"
|
||||||
|
|
||||||
|
static osal_semaphore g_report_semaphore; // 触发上报的信号量
|
||||||
|
static osal_mutex g_report_mutex; // 保护上报掩码的互斥锁
|
||||||
|
static volatile uint8_t g_report_mask = 0; // 待上报的服务ID位掩码
|
||||||
|
static bool g_report_system_running = false; // 异步上报系统是否运行中
|
||||||
|
static bool g_report_sem_initialized = false; // 信号量是否已初始化
|
||||||
|
static bool g_report_mutex_initialized = false; // 互斥锁是否已初始化
|
||||||
|
|
||||||
|
// 异步上报任务
|
||||||
|
int async_report_task(void *arg) {
|
||||||
|
(void)arg;
|
||||||
|
|
||||||
|
e_printf("异步上报任务启动\r\n");
|
||||||
|
|
||||||
|
// 引用外部的fast_report函数
|
||||||
|
extern int fast_report(const char* svc_id);
|
||||||
|
|
||||||
|
while (g_report_system_running && !osal_kthread_should_stop()) {
|
||||||
|
// 等待上报信号量
|
||||||
|
if (osal_sem_down(&g_report_semaphore) == OSAL_SUCCESS) {
|
||||||
|
if (!g_report_system_running) {
|
||||||
|
break; // 系统关闭
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取当前的上报掩码(使用互斥锁保护)
|
||||||
|
uint8_t current_mask = 0;
|
||||||
|
if (g_report_mutex_initialized && osal_mutex_lock(&g_report_mutex) == OSAL_SUCCESS) {
|
||||||
|
current_mask = g_report_mask;
|
||||||
|
g_report_mask = 0; // 清零掩码
|
||||||
|
osal_mutex_unlock(&g_report_mutex);
|
||||||
|
} else {
|
||||||
|
current_mask = g_report_mask;
|
||||||
|
g_report_mask = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_mask == 0) {
|
||||||
|
continue; // 无上报任务
|
||||||
|
}
|
||||||
|
|
||||||
|
e_printf("开始异步上报,掩码: 0x%02X\r\n", current_mask);
|
||||||
|
|
||||||
|
// 上报总开关
|
||||||
|
if (current_mask & REPORT_SWITCH_MASK) {
|
||||||
|
fast_report("switch");
|
||||||
|
e_printf("上报总开关状态\r\n");
|
||||||
|
osal_msleep(50); // 防止上报过快
|
||||||
|
}
|
||||||
|
|
||||||
|
// 上报各个子开关
|
||||||
|
for (int i = 0; i < SWITCH_COUNT; i++) {
|
||||||
|
uint8_t switch_mask = (REPORT_SWITCH1_MASK << i);
|
||||||
|
if (current_mask & switch_mask) {
|
||||||
|
char svc_id[16] = {0};
|
||||||
|
snprintf(svc_id, sizeof(svc_id), "switch%d", i + 1);
|
||||||
|
fast_report(svc_id);
|
||||||
|
e_printf("上报开关%d状态\r\n", i + 1);
|
||||||
|
osal_msleep(50); // 防止上报过快
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
e_printf("异步上报完成\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
e_printf("异步上报任务退出\r\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化异步上报系统
|
||||||
|
int report_system_init(void) {
|
||||||
|
// 初始化互斥锁
|
||||||
|
if (osal_mutex_init(&g_report_mutex) != OSAL_SUCCESS) {
|
||||||
|
e_printf("初始化上报互斥锁失败\r\n");
|
||||||
|
return HF_FAIL;
|
||||||
|
}
|
||||||
|
g_report_mutex_initialized = true;
|
||||||
|
|
||||||
|
// 初始化信号量(初始值为0)
|
||||||
|
if (osal_sem_init(&g_report_semaphore, 0) != OSAL_SUCCESS) {
|
||||||
|
e_printf("初始化上报信号量失败\r\n");
|
||||||
|
osal_mutex_destroy(&g_report_mutex);
|
||||||
|
g_report_mutex_initialized = false;
|
||||||
|
return HF_FAIL;
|
||||||
|
}
|
||||||
|
g_report_sem_initialized = true;
|
||||||
|
|
||||||
|
// 启动异步上报任务
|
||||||
|
g_report_system_running = true;
|
||||||
|
g_report_task_handle = osal_kthread_create((osal_kthread_handler)async_report_task,
|
||||||
|
NULL,
|
||||||
|
"report_task",
|
||||||
|
TASK_STACK_SIZE);
|
||||||
|
if (g_report_task_handle == NULL) {
|
||||||
|
e_printf("创建异步上报任务失败\r\n");
|
||||||
|
g_report_system_running = false;
|
||||||
|
if (g_report_sem_initialized) {
|
||||||
|
osal_sem_destroy(&g_report_semaphore);
|
||||||
|
g_report_sem_initialized = false;
|
||||||
|
}
|
||||||
|
if (g_report_mutex_initialized) {
|
||||||
|
osal_mutex_destroy(&g_report_mutex);
|
||||||
|
g_report_mutex_initialized = false;
|
||||||
|
}
|
||||||
|
return HF_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置任务优先级为低优先级,避免影响实时性
|
||||||
|
osal_kthread_set_priority(g_report_task_handle, TASK_PRIORITY_LOW);
|
||||||
|
|
||||||
|
e_printf("异步上报系统初始化成功\r\n");
|
||||||
|
return HF_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清理异步上报系统
|
||||||
|
void report_system_deinit(void) {
|
||||||
|
e_printf("清理异步上报系统\r\n");
|
||||||
|
|
||||||
|
// 停止上报系统
|
||||||
|
g_report_system_running = false;
|
||||||
|
|
||||||
|
// 唤醒上报任务使其退出
|
||||||
|
if (g_report_sem_initialized) {
|
||||||
|
osal_sem_up(&g_report_semaphore);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 等待任务退出
|
||||||
|
if (g_report_task_handle) {
|
||||||
|
osal_kthread_destroy(g_report_task_handle, 1);
|
||||||
|
g_report_task_handle = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清理同步原语
|
||||||
|
if (g_report_sem_initialized) {
|
||||||
|
osal_sem_destroy(&g_report_semaphore);
|
||||||
|
g_report_sem_initialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_report_mutex_initialized) {
|
||||||
|
osal_mutex_destroy(&g_report_mutex);
|
||||||
|
g_report_mutex_initialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清零上报掩码
|
||||||
|
g_report_mask = 0;
|
||||||
|
|
||||||
|
e_printf("异步上报系统清理完成\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 触发异步上报
|
||||||
|
void trigger_async_report(uint8_t report_mask) {
|
||||||
|
if (!g_report_system_running || !g_report_sem_initialized) {
|
||||||
|
e_printf("异步上报系统未初始化,使用同步上报\r\n");
|
||||||
|
// 如果异步系统未初始化,回退到同步上报
|
||||||
|
extern int fast_report(const char* svc_id);
|
||||||
|
if (report_mask & REPORT_SWITCH_MASK) {
|
||||||
|
fast_report("switch");
|
||||||
|
}
|
||||||
|
for (int i = 0; i < SWITCH_COUNT; i++) {
|
||||||
|
if (report_mask & (REPORT_SWITCH1_MASK << i)) {
|
||||||
|
char svc_id[16] = {0};
|
||||||
|
snprintf(svc_id, sizeof(svc_id), "switch%d", i + 1);
|
||||||
|
fast_report(svc_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用互斥锁保护更新上报掩码
|
||||||
|
bool should_signal = false;
|
||||||
|
if (g_report_mutex_initialized && osal_mutex_lock(&g_report_mutex) == OSAL_SUCCESS) {
|
||||||
|
uint8_t old_mask = g_report_mask;
|
||||||
|
g_report_mask |= report_mask;
|
||||||
|
should_signal = (old_mask == 0);
|
||||||
|
osal_mutex_unlock(&g_report_mutex);
|
||||||
|
} else {
|
||||||
|
uint8_t old_mask = g_report_mask;
|
||||||
|
g_report_mask |= report_mask;
|
||||||
|
should_signal = (old_mask == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果是新的上报请求,唤醒上报任务
|
||||||
|
if (should_signal) {
|
||||||
|
osal_sem_up(&g_report_semaphore);
|
||||||
|
e_printf("已触发异步上报,掩码: 0x%02X\r\n", report_mask);
|
||||||
|
} else {
|
||||||
|
e_printf("合并上报请求,掩码: 0x%02X\r\n", g_report_mask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 异步上报单个开关
|
||||||
|
void fast_report_switch_async(int switch_id) {
|
||||||
|
if (switch_id < 0 || switch_id >= SWITCH_COUNT) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t switch_mask = (REPORT_SWITCH1_MASK << switch_id);
|
||||||
|
trigger_async_report(switch_mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 异步上报总开关
|
||||||
|
void fast_report_master_switch_async(void) {
|
||||||
|
trigger_async_report(REPORT_SWITCH_MASK);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 异步上报所有开关
|
||||||
|
void fast_report_all_switches_async(void) {
|
||||||
|
trigger_async_report(REPORT_ALL_MASK);
|
||||||
|
}
|
||||||
|
|
||||||
//====================== 存储管理函数 ======================
|
//====================== 存储管理函数 ======================
|
||||||
|
|
||||||
// 计算数据校验码
|
// 计算数据校验码
|
||||||
@ -48,8 +289,9 @@ static uint8_t calculate_checksum(const uint8_t* data, int len)
|
|||||||
static bool read_device_data_from_addr(uint32_t addr, uint8_t* data, uint32_t len)
|
static bool read_device_data_from_addr(uint32_t addr, uint8_t* data, uint32_t len)
|
||||||
{
|
{
|
||||||
int total_size = sizeof(device_data_t) + len;
|
int total_size = sizeof(device_data_t) + len;
|
||||||
uint8_t checksum = 0;
|
|
||||||
device_data_t *data_all = malloc(total_size);
|
device_data_t *data_all = malloc(total_size);
|
||||||
|
uint8_t checksum;
|
||||||
|
|
||||||
if (data_all == NULL) {
|
if (data_all == NULL) {
|
||||||
e_printf("内存分配失败\r\n");
|
e_printf("内存分配失败\r\n");
|
||||||
return false;
|
return false;
|
||||||
@ -88,7 +330,7 @@ lab_err:
|
|||||||
// 写入数据到指定地址
|
// 写入数据到指定地址
|
||||||
static bool write_device_data_to_addr(uint32_t addr, uint8_t* data, uint32_t len)
|
static bool write_device_data_to_addr(uint32_t addr, uint8_t* data, uint32_t len)
|
||||||
{
|
{
|
||||||
int ret = hfuflash_erase_page(addr, 1);
|
uint32_t ret = hfuflash_erase_page(addr, 1);
|
||||||
if (ret != HF_SUCCESS) {
|
if (ret != HF_SUCCESS) {
|
||||||
e_printf("擦除地址0x%x的Flash页失败,错误码:%d\r\n", addr, ret);
|
e_printf("擦除地址0x%x的Flash页失败,错误码:%d\r\n", addr, ret);
|
||||||
return false;
|
return false;
|
||||||
@ -99,7 +341,8 @@ static bool write_device_data_to_addr(uint32_t addr, uint8_t* data, uint32_t len
|
|||||||
e_printf("内存分配失败\r\n");
|
e_printf("内存分配失败\r\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
memset(data_all, 0, total_size);
|
memset_s(data_all, total_size, 0, total_size);
|
||||||
|
data_all->data_len = len;
|
||||||
memcpy_s(data_all->data, len, data, len);
|
memcpy_s(data_all->data, len, data, len);
|
||||||
data_all->checksum = calculate_checksum(data_all->data, data_all->data_len);
|
data_all->checksum = calculate_checksum(data_all->data, data_all->data_len);
|
||||||
data_all->magic = DEVICE_DATA_MAGIC;
|
data_all->magic = DEVICE_DATA_MAGIC;
|
||||||
@ -115,10 +358,10 @@ static bool write_device_data_to_addr(uint32_t addr, uint8_t* data, uint32_t len
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 从 Flash 加载设备状态
|
// 从 Flash 加载持久化状态
|
||||||
int load_device_state(void) {
|
int load_persistent_state(void) {
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
device_state_t state;
|
device_persistent_state_t state;
|
||||||
bool valid = false;
|
bool valid = false;
|
||||||
|
|
||||||
// 尝试读取主数据区
|
// 尝试读取主数据区
|
||||||
@ -131,96 +374,252 @@ int load_device_state(void) {
|
|||||||
|
|
||||||
// 两个存储区都失败,使用默认状态
|
// 两个存储区都失败,使用默认状态
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
e_printf("[STORAGE] 存储区数据损坏,使用默认状态\r\n");
|
e_printf("存储区数据损坏,使用默认状态\r\n");
|
||||||
reset_device_state();
|
reset_persistent_state();
|
||||||
save_device_state();
|
save_persistent_state();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// 更新设备控制状态
|
|
||||||
e_printf("设备状态恢复:\r\n");
|
// 更新持久化状态
|
||||||
e_printf("首次启动: %d => %d\r\n", g_device_state.is_first_boot, state.is_first_boot);
|
e_printf("持久化状态恢复:\r\n");
|
||||||
e_printf("配网状态: %d => %d\r\n", g_device_state.is_bound, state.is_bound);
|
e_printf("首次启动: %d => %d\r\n", g_persistent_state.is_first_boot, state.is_first_boot);
|
||||||
e_printf("总开关: %d => %d\r\n", g_device_state.master_switch, state.master_switch);
|
e_printf("配网状态: %d => %d\r\n", g_persistent_state.is_bound, state.is_bound);
|
||||||
e_printf("面板背光: %d => %d\r\n", g_device_state.panel_led, state.panel_led);
|
e_printf("总开关: %d => %d\r\n", g_persistent_state.master_switch, state.master_switch);
|
||||||
e_printf("工作模式: %d => %d\r\n", g_device_state.mode, state.mode);
|
e_printf("面板背光: %d => %d\r\n", g_persistent_state.panel_led, state.panel_led);
|
||||||
|
|
||||||
for (int i = 0; i < SWITCH_COUNT; i++) {
|
for (int i = 0; i < SWITCH_COUNT; i++) {
|
||||||
e_printf("开关%d: %d => %d, LED%d: %d => %d, 物理按键%d: %d => %d\r\n",
|
e_printf("开关%d(%s): %d => %d, LED%d: %d => %d\r\n",
|
||||||
i + 1, g_device_state.switches[i].switch_on, state.switches[i].switch_on,
|
i + 1, state.switches[i].name,
|
||||||
i + 1, g_device_state.switches[i].led_state, state.switches[i].led_state,
|
g_persistent_state.switches[i].switch_on, state.switches[i].switch_on,
|
||||||
i + 1, g_device_state.switches[i].physical_key, state.switches[i].physical_key);
|
i + 1, g_persistent_state.switches[i].led_state, state.switches[i].led_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(&g_device_state, &state, sizeof(device_state_t));
|
memcpy(&g_persistent_state, &state, sizeof(device_persistent_state_t));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存设备状态到 Flash
|
//====================== 异步保存系统实现 ======================
|
||||||
int save_device_state(void) {
|
|
||||||
int ret = 0;
|
// 异步保存任务
|
||||||
static device_state_t state = {};
|
static int save_data_task(void *arg) {
|
||||||
bool valid = false;
|
(void)arg;
|
||||||
if (state.is_first_boot == g_device_state.is_first_boot &&
|
|
||||||
state.is_bound == g_device_state.is_bound &&
|
e_printf("异步保存任务启动\r\n");
|
||||||
state.master_switch == g_device_state.master_switch &&
|
|
||||||
state.panel_led == g_device_state.panel_led &&
|
while (g_save_system_running && !osal_kthread_should_stop()) {
|
||||||
state.mode == g_device_state.mode)
|
// 等待保存信号量
|
||||||
{
|
if (osal_sem_down(&g_save_semaphore) == OSAL_SUCCESS) {
|
||||||
for (int i = 0; i < SWITCH_COUNT; i++) {
|
if (!g_save_system_running) {
|
||||||
if (state.switches[i].switch_on != g_device_state.switches[i].switch_on
|
break; // 系统关闭
|
||||||
|| state.switches[i].led_state != g_device_state.switches[i].led_state
|
}
|
||||||
|| state.switches[i].physical_key != g_device_state.switches[i].physical_key) {
|
|
||||||
valid = true;
|
// 执行实际的同步保存操作
|
||||||
break;
|
int ret = save_persistent_state_sync();
|
||||||
|
if (ret != HF_SUCCESS) {
|
||||||
|
e_printf("异步保存失败: %d\r\n", ret);
|
||||||
|
} else {
|
||||||
|
e_printf("异步保存成功\r\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!valid) {
|
|
||||||
e_printf("[STORAGE] 设备状态未变化,跳过保存\r\n");
|
|
||||||
return HF_SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 准备数据
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存到备份区
|
e_printf("异步保存任务退出\r\n");
|
||||||
ret = write_device_data_to_addr(DEVICE_DATA_BACKUP_ADDR, (uint8_t*)&state, sizeof(state));
|
return 0;
|
||||||
if (ret != HF_SUCCESS) {
|
}
|
||||||
e_printf("[STORAGE] 写入备份区失败: %d\r\n", ret);
|
|
||||||
|
// 初始化异步保存系统
|
||||||
|
int save_system_init(void) {
|
||||||
|
int ret = HF_SUCCESS;
|
||||||
|
|
||||||
|
// 初始化互斥锁
|
||||||
|
if (osal_mutex_init(&g_save_mutex) != OSAL_SUCCESS) {
|
||||||
|
e_printf("初始化保存互斥锁失败\r\n");
|
||||||
|
return HF_FAIL;
|
||||||
}
|
}
|
||||||
e_printf("[STORAGE] 设备状态保存完成\r\n");
|
g_save_mutex_initialized = true;
|
||||||
|
|
||||||
|
// 初始化信号量(初始值为0)
|
||||||
|
if (osal_sem_init(&g_save_semaphore, 0) != OSAL_SUCCESS) {
|
||||||
|
e_printf("初始化保存信号量失败\r\n");
|
||||||
|
osal_mutex_destroy(&g_save_mutex);
|
||||||
|
g_save_mutex_initialized = false;
|
||||||
|
return HF_FAIL;
|
||||||
|
}
|
||||||
|
g_save_sem_initialized = true;
|
||||||
|
|
||||||
|
// 启动异步保存任务
|
||||||
|
g_save_system_running = true;
|
||||||
|
g_save_task_handle = osal_kthread_create((osal_kthread_handler)save_data_task,
|
||||||
|
NULL,
|
||||||
|
"save_data_task",
|
||||||
|
TASK_STACK_SIZE);
|
||||||
|
if (g_save_task_handle == NULL) {
|
||||||
|
e_printf("创建异步保存任务失败\r\n");
|
||||||
|
g_save_system_running = false;
|
||||||
|
if (g_save_sem_initialized) {
|
||||||
|
osal_sem_destroy(&g_save_semaphore);
|
||||||
|
g_save_sem_initialized = false;
|
||||||
|
}
|
||||||
|
if (g_save_mutex_initialized) {
|
||||||
|
osal_mutex_destroy(&g_save_mutex);
|
||||||
|
g_save_mutex_initialized = false;
|
||||||
|
}
|
||||||
|
return HF_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置任务优先级为低优先级,避免影响实时性
|
||||||
|
osal_kthread_set_priority(g_save_task_handle, TASK_PRIORITY_LOW);
|
||||||
|
|
||||||
|
e_printf("异步保存系统初始化成功\r\n");
|
||||||
return HF_SUCCESS;
|
return HF_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 重置设备状态为默认值
|
// 清理异步保存系统
|
||||||
void reset_device_state(void) {
|
void save_system_deinit(void) {
|
||||||
// memset(&g_device_state, 0, sizeof(device_data_t));
|
e_printf("清理异步保存系统\r\n");
|
||||||
|
|
||||||
// 设置默认状态
|
// 停止保存系统
|
||||||
g_device_state.master_switch = false; // 总开关关闭
|
g_save_system_running = false;
|
||||||
g_device_state.panel_led = true; // 面板背光开启
|
|
||||||
g_device_state.is_bound = false; // 设备未绑定
|
|
||||||
g_device_state.is_first_boot = false; // 标记为非首次启动
|
|
||||||
g_device_state.mode = MODE_NORMAL; // 正常模式
|
|
||||||
|
|
||||||
// 所有开关默认关闭,所有LED默认黄灯
|
// 唤醒保存任务使其退出
|
||||||
for (int i = 0; i < SWITCH_COUNT; i++) {
|
if (g_save_sem_initialized) {
|
||||||
g_device_state.switches[i].switch_on = false; // 开关关闭
|
osal_sem_up(&g_save_semaphore);
|
||||||
g_device_state.switches[i].led_state = false; // LED黄灯
|
|
||||||
g_device_state.switches[i].physical_key = true; // 按键松开
|
|
||||||
}
|
}
|
||||||
|
|
||||||
e_printf("[STATE] 设备状态已重置为默认值\r\n");
|
// 等待任务退出
|
||||||
|
if (g_save_task_handle) {
|
||||||
|
osal_kthread_destroy(g_save_task_handle, 1);
|
||||||
|
g_save_task_handle = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清理同步原语
|
||||||
|
if (g_save_sem_initialized) {
|
||||||
|
osal_sem_destroy(&g_save_semaphore);
|
||||||
|
g_save_sem_initialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_save_mutex_initialized) {
|
||||||
|
osal_mutex_destroy(&g_save_mutex);
|
||||||
|
g_save_mutex_initialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
e_printf("异步保存系统清理完成\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 异步保存持久化状态(触发保存任务)
|
||||||
|
int save_persistent_state(void) {
|
||||||
|
if (!g_save_system_running || !g_save_sem_initialized) {
|
||||||
|
e_printf("异步保存系统未初始化,使用同步保存\r\n");
|
||||||
|
return save_persistent_state_sync();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送保存信号
|
||||||
|
osal_sem_up(&g_save_semaphore);
|
||||||
|
|
||||||
|
e_printf("已触发异步保存\r\n");
|
||||||
|
return HF_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 同步保存持久化状态到 Flash(实际的Flash写入操作)
|
||||||
|
int save_persistent_state_sync(void) {
|
||||||
|
int ret = 0;
|
||||||
|
static device_persistent_state_t state = {};
|
||||||
|
bool need_save = false;
|
||||||
|
|
||||||
|
// 使用互斥锁保护状态访问
|
||||||
|
if (g_save_mutex_initialized && osal_mutex_lock(&g_save_mutex) != OSAL_SUCCESS) {
|
||||||
|
e_printf("获取保存互斥锁失败\r\n");
|
||||||
|
return HF_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否有变化,避免不必要的Flash写入
|
||||||
|
if (memcmp(&state, &g_persistent_state, sizeof(device_persistent_state_t)) != 0) {
|
||||||
|
need_save = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!need_save) {
|
||||||
|
if (g_save_mutex_initialized) {
|
||||||
|
osal_mutex_unlock(&g_save_mutex);
|
||||||
|
}
|
||||||
|
e_printf("持久化状态未变化,跳过保存\r\n");
|
||||||
|
return HF_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 准备数据
|
||||||
|
memcpy(&state, &g_persistent_state, sizeof(device_persistent_state_t));
|
||||||
|
|
||||||
|
// 释放互斥锁,避免在Flash写入过程中长时间锁定
|
||||||
|
if (g_save_mutex_initialized) {
|
||||||
|
osal_mutex_unlock(&g_save_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存到主存储区
|
||||||
|
bool ret_main = write_device_data_to_addr(DEVICE_DATA_FLASH_ADDR, (uint8_t*)&state, sizeof(state));
|
||||||
|
if (!ret_main) {
|
||||||
|
e_printf("写入主存储区失败\r\n");
|
||||||
|
return HF_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存到备份区
|
||||||
|
bool ret_backup = write_device_data_to_addr(DEVICE_DATA_BACKUP_ADDR, (uint8_t*)&state, sizeof(state));
|
||||||
|
if (!ret_backup) {
|
||||||
|
e_printf("写入备份区失败\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
g_runtime_state.last_save_time = hfsys_get_time();
|
||||||
|
e_printf("持久化状态保存完成\r\n");
|
||||||
|
return HF_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重置持久化状态为默认值
|
||||||
|
void reset_persistent_state(void) {
|
||||||
|
// 设置默认状态
|
||||||
|
g_persistent_state.master_switch = false; // 总开关关闭
|
||||||
|
g_persistent_state.panel_led = true; // 面板背光开启
|
||||||
|
g_persistent_state.is_bound = false; // 设备未绑定
|
||||||
|
g_persistent_state.is_first_boot = true; // 标记为首次启动
|
||||||
|
|
||||||
|
// 所有开关默认关闭,所有LED默认黄灯,初始化默认名字
|
||||||
|
for (int i = 0; i < SWITCH_COUNT; i++) {
|
||||||
|
g_persistent_state.switches[i].switch_on = false; // 开关关闭
|
||||||
|
g_persistent_state.switches[i].led_state = false; // LED黄灯
|
||||||
|
snprintf(g_persistent_state.switches[i].name, SWITCH_NAME_MAX_LEN, "开关%d", i + 1); // 默认名字
|
||||||
|
}
|
||||||
|
|
||||||
|
g_persistent_state.magic = DEVICE_DATA_MAGIC;
|
||||||
|
g_persistent_state.version = DEVICE_DATA_VERSION;
|
||||||
|
|
||||||
|
e_printf("[STATE] 持久化状态已重置为默认值\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化运行时状态
|
||||||
|
void init_runtime_state(void) {
|
||||||
|
g_runtime_state.mode = MODE_NORMAL;
|
||||||
|
g_runtime_state.ble_mode_enabled = false;
|
||||||
|
g_runtime_state.config_start_time = 0;
|
||||||
|
g_runtime_state.config_key_id = -1;
|
||||||
|
g_runtime_state.config_led_blink_state = false;
|
||||||
|
g_runtime_state.factory_test_running = false;
|
||||||
|
g_runtime_state.last_save_time = 0;
|
||||||
|
|
||||||
|
// 初始化所有开关的运行时状态
|
||||||
|
for (int i = 0; i < SWITCH_COUNT; i++) {
|
||||||
|
g_runtime_state.switches[i].physical_key = true; // 按键松开
|
||||||
|
g_runtime_state.switches[i].press_time = 0;
|
||||||
|
g_runtime_state.switches[i].debounce_flag = false;
|
||||||
|
g_runtime_state.switches[i].long_press_handled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
e_printf("[STATE] 运行时状态已初始化\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
//====================== GPIO配置数据结构 ======================
|
//====================== GPIO配置数据结构 ======================
|
||||||
typedef struct {
|
typedef struct {
|
||||||
pin_t pin;
|
pin_t pin;
|
||||||
|
pin_mode_t mode;
|
||||||
|
pin_pull_t pull;
|
||||||
|
pin_drive_strength_t ds;
|
||||||
gpio_direction_t direction;
|
gpio_direction_t direction;
|
||||||
const char* name;
|
const char* name;
|
||||||
} gpio_config_t;
|
} gpio_config_t;
|
||||||
@ -228,25 +627,25 @@ typedef struct {
|
|||||||
// GPIO初始化配置表
|
// GPIO初始化配置表
|
||||||
static const gpio_config_t gpio_configs[] = {
|
static const gpio_config_t gpio_configs[] = {
|
||||||
// 开关控制 - 输出
|
// 开关控制 - 输出
|
||||||
{SWITCH1_GPIO, GPIO_DIRECTION_OUTPUT, "SWITCH1"},
|
{SWITCH1_GPIO, PIN_MODE_1, PIN_PULL_TYPE_DOWN, PIN_DS_4, GPIO_DIRECTION_OUTPUT, "SWITCH1"},
|
||||||
{SWITCH2_GPIO, GPIO_DIRECTION_OUTPUT, "SWITCH2"},
|
{SWITCH2_GPIO, PIN_MODE_1, PIN_PULL_TYPE_DOWN, PIN_DS_4, GPIO_DIRECTION_OUTPUT, "SWITCH2"},
|
||||||
{SWITCH3_GPIO, GPIO_DIRECTION_OUTPUT, "SWITCH3"},
|
{SWITCH3_GPIO, PIN_MODE_1, PIN_PULL_TYPE_DOWN, PIN_DS_4, GPIO_DIRECTION_OUTPUT, "SWITCH3"},
|
||||||
{SWITCH4_GPIO, GPIO_DIRECTION_OUTPUT, "SWITCH4"},
|
{SWITCH4_GPIO, PIN_MODE_1, PIN_PULL_TYPE_DOWN, PIN_DS_4, GPIO_DIRECTION_OUTPUT, "SWITCH4"},
|
||||||
|
|
||||||
// 物理按键 - 输入
|
// 物理按键 - 输入
|
||||||
{KEY1_GPIO, GPIO_DIRECTION_INPUT, "KEY1"},
|
{KEY1_GPIO, PIN_MODE_0, PIN_PULL_TYPE_STRONG_UP, PIN_DS_3, GPIO_DIRECTION_INPUT, "KEY1"},
|
||||||
{KEY2_GPIO, GPIO_DIRECTION_INPUT, "KEY2"},
|
{KEY2_GPIO, PIN_MODE_0, PIN_PULL_TYPE_STRONG_UP, PIN_DS_3, GPIO_DIRECTION_INPUT, "KEY2"},
|
||||||
{KEY3_GPIO, GPIO_DIRECTION_INPUT, "KEY3"},
|
{KEY3_GPIO, PIN_MODE_0, PIN_PULL_TYPE_STRONG_UP, PIN_DS_3, GPIO_DIRECTION_INPUT, "KEY3"},
|
||||||
{KEY4_GPIO, GPIO_DIRECTION_INPUT, "KEY4"},
|
{KEY4_GPIO, PIN_MODE_0, PIN_PULL_TYPE_STRONG_UP, PIN_DS_3, GPIO_DIRECTION_INPUT, "KEY4"},
|
||||||
|
|
||||||
// 面板背光 - 输出
|
// 面板背光 - 输出
|
||||||
{PANEL_LED_GPIO, GPIO_DIRECTION_OUTPUT, "PANEL_LED"},
|
{PANEL_LED_GPIO, PIN_MODE_1, PIN_PULL_TYPE_DISABLE, PIN_DS_7, GPIO_DIRECTION_OUTPUT, "PANEL_LED"},
|
||||||
|
|
||||||
// LED指示灯 - 输出
|
// LED指示灯 - 输出
|
||||||
{LED1_GPIO, GPIO_DIRECTION_OUTPUT, "LED1"},
|
{LED1_GPIO, PIN_MODE_1, PIN_PULL_TYPE_DISABLE, PIN_DS_7, GPIO_DIRECTION_OUTPUT, "LED1"},
|
||||||
{LED2_GPIO, GPIO_DIRECTION_OUTPUT, "LED2"},
|
{LED2_GPIO, PIN_MODE_1, PIN_PULL_TYPE_DISABLE, PIN_DS_7, GPIO_DIRECTION_OUTPUT, "LED2"},
|
||||||
{LED3_GPIO, GPIO_DIRECTION_OUTPUT, "LED3"},
|
{LED3_GPIO, PIN_MODE_1, PIN_PULL_TYPE_DISABLE, PIN_DS_7, GPIO_DIRECTION_OUTPUT, "LED3"},
|
||||||
// {LED4_GPIO, GPIO_DIRECTION_OUTPUT, "LED4"},
|
{LED4_GPIO, PIN_MODE_1, PIN_PULL_TYPE_DISABLE, PIN_DS_7, GPIO_DIRECTION_OUTPUT, "LED4"},
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -260,24 +659,34 @@ int switch_panel_gpio_init(void) {
|
|||||||
|
|
||||||
// 初始化pinctrl和GPIO
|
// 初始化pinctrl和GPIO
|
||||||
uapi_pin_init();
|
uapi_pin_init();
|
||||||
// uapi_gpio_init();
|
uapi_gpio_init();
|
||||||
|
|
||||||
// 使用循环配置所有GPIO
|
// 使用循环配置所有GPIO
|
||||||
for (uint32_t i = 0; i < GPIO_CONFIG_COUNT; i++) {
|
for (uint32_t i = 0; i < GPIO_CONFIG_COUNT; i++) {
|
||||||
const gpio_config_t* config = &gpio_configs[i];
|
const gpio_config_t* config = &gpio_configs[i];
|
||||||
|
|
||||||
// 设置为GPIO模式
|
// 设置为GPIO模式
|
||||||
ret = uapi_pin_set_mode(config->pin, PIN_MODE_0);
|
ret = uapi_pin_set_mode(config->pin, config->mode);
|
||||||
if (ret != HF_SUCCESS) {
|
if (ret != 0) {
|
||||||
e_printf("[GPIO] %s pinctrl初始化失败: %d\r\n", config->name, ret);
|
e_printf("[GPIO] %s pinctrl初始化失败: %d\r\n", config->name, ret);
|
||||||
return ret;
|
return HF_FAIL;
|
||||||
|
}
|
||||||
|
ret = uapi_pin_set_pull(config->pin, config->pull);
|
||||||
|
if (ret != 0) {
|
||||||
|
e_printf("[GPIO] %s pinctrl初始化失败: %d\r\n", config->name, ret);
|
||||||
|
return HF_FAIL;
|
||||||
|
}
|
||||||
|
ret = uapi_pin_set_ds(config->pin, config->ds);
|
||||||
|
if (ret != 0) {
|
||||||
|
e_printf("[GPIO] %s pinctrl初始化失败: %d\r\n", config->name, ret);
|
||||||
|
return HF_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置GPIO方向
|
// 设置GPIO方向
|
||||||
ret = uapi_gpio_set_dir(config->pin, config->direction);
|
ret = uapi_gpio_set_dir(config->pin, config->direction);
|
||||||
if (ret != HF_SUCCESS) {
|
if (ret != 0) {
|
||||||
e_printf("[GPIO] %s 设置方向失败: %d\r\n", config->name, ret);
|
e_printf("[GPIO] %s 设置方向失败: %d\r\n", config->name, ret);
|
||||||
return ret;
|
return HF_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
e_printf("[GPIO] %s 初始化完成 (方向: %s)\r\n",
|
e_printf("[GPIO] %s 初始化完成 (方向: %s)\r\n",
|
||||||
@ -361,16 +770,16 @@ bool get_key_input(int key_id) {
|
|||||||
|
|
||||||
//====================== 设备状态同步函数 ======================
|
//====================== 设备状态同步函数 ======================
|
||||||
|
|
||||||
// 同步硬件状态与软件状态
|
// 同步硬件状态与持久化状态
|
||||||
void sync_hardware_state(void) {
|
void sync_hardware_state(void) {
|
||||||
// 同步所有开关状态
|
// 同步所有开关状态
|
||||||
for (int i = 0; i < SWITCH_COUNT; i++) {
|
for (int i = 0; i < SWITCH_COUNT; i++) {
|
||||||
set_switch_output(i, g_device_state.switches[i].switch_on);
|
set_switch_output(i, g_persistent_state.switches[i].switch_on);
|
||||||
set_led_output(i, g_device_state.switches[i].led_state ? LED_WHITE : LED_YELLOW);
|
set_led_output(i, g_persistent_state.switches[i].led_state ? LED_WHITE : LED_YELLOW);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 同步面板背光状态
|
// 同步面板背光状态
|
||||||
set_panel_led(g_device_state.panel_led ? PANEL_LED_ON : PANEL_LED_OFF);
|
set_panel_led(g_persistent_state.panel_led ? PANEL_LED_ON : PANEL_LED_OFF);
|
||||||
|
|
||||||
e_printf("[STATE] 硬件状态已同步\r\n");
|
e_printf("[STATE] 硬件状态已同步\r\n");
|
||||||
}
|
}
|
||||||
@ -381,32 +790,50 @@ int switch_panel_main(void) {
|
|||||||
int ret = HF_SUCCESS;
|
int ret = HF_SUCCESS;
|
||||||
|
|
||||||
if (g_initialized) {
|
if (g_initialized) {
|
||||||
e_printf("[MAIN] 开关面板已初始化\r\n");
|
e_printf("开关面板已初始化\r\n");
|
||||||
return HF_SUCCESS;
|
return HF_SUCCESS;
|
||||||
}
|
}
|
||||||
g_initialized = true;
|
g_initialized = true;
|
||||||
e_printf("[MAIN] 开始初始化SORONTEK智能面板...\r\n");
|
e_printf("开始初始化SORONTEK智能面板...\r\n");
|
||||||
|
|
||||||
// 加载设备状态
|
// 初始化运行时状态
|
||||||
ret = load_device_state();
|
init_runtime_state();
|
||||||
|
|
||||||
|
// 初始化异步保存系统
|
||||||
|
ret = save_system_init();
|
||||||
if (ret != HF_SUCCESS) {
|
if (ret != HF_SUCCESS) {
|
||||||
e_printf("[MAIN] 加载设备状态失败: %d\r\n", ret);
|
e_printf("异步保存系统初始化失败: %d\r\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
// 检查是否首次启动,如果是则标记为非首次
|
|
||||||
bool first_boot = g_device_state.is_first_boot;
|
// 初始化异步上报系统
|
||||||
if (g_device_state.is_first_boot) {
|
ret = report_system_init();
|
||||||
g_device_state.is_first_boot = false; // 标记为非首次启动
|
if (ret != HF_SUCCESS) {
|
||||||
e_printf("[MAIN] 检测到首次启动\r\n");
|
e_printf("异步上报系统初始化失败: %d\r\n", ret);
|
||||||
|
// 上报系统失败不影响主流程,继续运行
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 加载持久化状态
|
||||||
|
ret = load_persistent_state();
|
||||||
|
if (ret != HF_SUCCESS) {
|
||||||
|
e_printf("加载持久化状态失败: %d\r\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否首次启动
|
||||||
|
bool first_boot = g_persistent_state.is_first_boot;
|
||||||
|
|
||||||
|
e_printf("设备状态 - 首次启动: %s, 绑定状态: %s\r\n",
|
||||||
|
first_boot ? "是" : "否",
|
||||||
|
g_persistent_state.is_bound ? "已绑定" : "未绑定");
|
||||||
// 初始化GPIO
|
// 初始化GPIO
|
||||||
ret = switch_panel_gpio_init();
|
ret = switch_panel_gpio_init();
|
||||||
if (ret != HF_SUCCESS) {
|
if (ret != HF_SUCCESS) {
|
||||||
e_printf("[MAIN] GPIO初始化失败: %d\r\n", ret);
|
e_printf("GPIO初始化失败: %d\r\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
if(key_system_init() != HF_SUCCESS) {
|
if(key_system_init() != HF_SUCCESS) {
|
||||||
e_printf("[MAIN] 按键系统初始化失败: %d\r\n", ret);
|
e_printf("按键系统初始化失败: %d\r\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -414,24 +841,27 @@ int switch_panel_main(void) {
|
|||||||
sync_hardware_state();
|
sync_hardware_state();
|
||||||
|
|
||||||
// 保存状态更新
|
// 保存状态更新
|
||||||
save_device_state();
|
save_persistent_state();
|
||||||
|
|
||||||
// 配网逻辑:
|
// 配网逻辑:
|
||||||
// 1. 如果设备未绑定 且 是第一次启动 -> 直接进入配网
|
// 1. 如果设备未绑定 且 是第一次启动 -> 直接进入配网
|
||||||
// 2. 如果设备未绑定 且 不是第一次启动 -> 等待按键触发配网
|
// 2. 如果设备未绑定 且 不是第一次启动 -> 等待按键触发配网
|
||||||
if (!g_device_state.is_bound) {
|
if (!g_persistent_state.is_bound) {
|
||||||
if (first_boot) {
|
if (first_boot) {
|
||||||
e_printf("[MAIN] 首次启动且未绑定,直接进入配网模式\r\n");
|
e_printf("首次启动且未绑定,直接进入配网模式\r\n");
|
||||||
enter_config_mode();
|
enter_config_mode();
|
||||||
} else {
|
} else {
|
||||||
e_printf("[MAIN] 设备未绑定,等待按键触发配网\r\n");
|
e_printf("设备未绑定,等待按键触发配网\r\n");
|
||||||
// 配网逻辑将在按键处理函数中实现
|
// 配网逻辑将在按键处理函数中实现
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
e_printf("[MAIN] 设备已绑定,正常运行\r\n");
|
e_printf("设备已绑定,正常运行\r\n");
|
||||||
|
// 设备已绑定时禁用蓝牙模式,使用云端控制
|
||||||
|
extern void switch_panel_ble_disable(void);
|
||||||
|
switch_panel_ble_disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
e_printf("[MAIN] SORONTEK智能面板初始化完成\r\n");
|
e_printf("SORONTEK智能面板初始化完成\r\n");
|
||||||
print_device_state();
|
print_device_state();
|
||||||
|
|
||||||
return HF_SUCCESS;
|
return HF_SUCCESS;
|
||||||
@ -441,17 +871,18 @@ int switch_panel_main(void) {
|
|||||||
|
|
||||||
void print_device_state(void) {
|
void print_device_state(void) {
|
||||||
e_printf("\r\n===== 设备状态信息 =====\r\n");
|
e_printf("\r\n===== 设备状态信息 =====\r\n");
|
||||||
e_printf("总开关: %s\r\n", g_device_state.master_switch ? "开" : "关");
|
e_printf("总开关: %s\r\n", g_persistent_state.master_switch ? "开" : "关");
|
||||||
e_printf("面板背光: %s\r\n", g_device_state.panel_led ? "开" : "关");
|
e_printf("面板背光: %s\r\n", g_persistent_state.panel_led ? "开" : "关");
|
||||||
e_printf("绑定状态: %s\r\n", g_device_state.is_bound ? "已绑定" : "未绑定");
|
e_printf("绑定状态: %s\r\n", g_persistent_state.is_bound ? "已绑定" : "未绑定");
|
||||||
e_printf("首次启动: %s\r\n", g_device_state.is_first_boot ? "是" : "否");
|
e_printf("首次启动: %s\r\n", g_persistent_state.is_first_boot ? "是" : "否");
|
||||||
e_printf("工作模式: %s\r\n", get_mode_string(g_device_state.mode));
|
e_printf("工作模式: %s\r\n", get_mode_string(g_runtime_state.mode));
|
||||||
|
|
||||||
for (int i = 0; i < SWITCH_COUNT; i++) {
|
for (int i = 0; i < SWITCH_COUNT; i++) {
|
||||||
e_printf("开关%d: %s, LED: %s\r\n",
|
e_printf("开关%d(%s): %s, LED: %s\r\n",
|
||||||
i + 1,
|
i + 1,
|
||||||
g_device_state.switches[i].switch_on ? "开" : "关",
|
g_persistent_state.switches[i].name,
|
||||||
g_device_state.switches[i].led_state ? "白灯" : "黄灯");
|
g_persistent_state.switches[i].switch_on ? "开" : "关",
|
||||||
|
g_persistent_state.switches[i].led_state ? "白灯" : "黄灯");
|
||||||
}
|
}
|
||||||
e_printf("=======================\r\n\r\n");
|
e_printf("=======================\r\n\r\n");
|
||||||
}
|
}
|
||||||
@ -465,3 +896,114 @@ const char* get_mode_string(system_mode_t mode) {
|
|||||||
default: return "未知模式";
|
default: return "未知模式";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//====================== 开关名字操作函数 ======================
|
||||||
|
|
||||||
|
// 获取开关名字
|
||||||
|
const char* get_switch_name(int switch_id) {
|
||||||
|
if (switch_id < 0 || switch_id >= SWITCH_COUNT) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return g_persistent_state.switches[switch_id].name;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置开关名字
|
||||||
|
int set_switch_name(int switch_id, const char* name) {
|
||||||
|
if (switch_id < 0 || switch_id >= SWITCH_COUNT || !name) {
|
||||||
|
e_printf("无效的开关ID或名字参数: switch_id=%d\r\n", switch_id);
|
||||||
|
return HF_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用互斥锁保护状态访问
|
||||||
|
if (g_save_mutex_initialized && osal_mutex_lock(&g_save_mutex) != OSAL_SUCCESS) {
|
||||||
|
e_printf("获取互斥锁失败\r\n");
|
||||||
|
return HF_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查名字是否相同,相同则跳过保存
|
||||||
|
if (strcmp(g_persistent_state.switches[switch_id].name, name) == 0) {
|
||||||
|
if (g_save_mutex_initialized) {
|
||||||
|
osal_mutex_unlock(&g_save_mutex);
|
||||||
|
}
|
||||||
|
e_printf("开关%d名字未变化,跳过保存: %s\r\n", switch_id + 1, name);
|
||||||
|
return HF_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 复制名字,确保不会溢出
|
||||||
|
int ret = strncpy_s(g_persistent_state.switches[switch_id].name,
|
||||||
|
SWITCH_NAME_MAX_LEN,
|
||||||
|
name,
|
||||||
|
SWITCH_NAME_MAX_LEN - 1);
|
||||||
|
|
||||||
|
if (ret != 0) {
|
||||||
|
e_printf("开关%d名字复制失败: %d\r\n", switch_id + 1, ret);
|
||||||
|
if (g_save_mutex_initialized) {
|
||||||
|
osal_mutex_unlock(&g_save_mutex);
|
||||||
|
}
|
||||||
|
return HF_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保字符串以NULL结尾
|
||||||
|
g_persistent_state.switches[switch_id].name[SWITCH_NAME_MAX_LEN - 1] = '\0';
|
||||||
|
|
||||||
|
if (g_save_mutex_initialized) {
|
||||||
|
osal_mutex_unlock(&g_save_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
e_printf("开关%d名字已更新为: %s\r\n",
|
||||||
|
switch_id + 1, g_persistent_state.switches[switch_id].name);
|
||||||
|
|
||||||
|
// 异步保存状态
|
||||||
|
save_persistent_state();
|
||||||
|
|
||||||
|
return HF_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化默认开关名字
|
||||||
|
void init_default_switch_names(void) {
|
||||||
|
for (int i = 0; i < SWITCH_COUNT; i++) {
|
||||||
|
snprintf(g_persistent_state.switches[i].name, SWITCH_NAME_MAX_LEN, "开关%d", i + 1);
|
||||||
|
}
|
||||||
|
e_printf("默认开关名字已初始化\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
//====================== 状态访问便利函数 ======================
|
||||||
|
|
||||||
|
// 获取开关状态
|
||||||
|
bool get_switch_state(int switch_id) {
|
||||||
|
if (switch_id < 0 || switch_id >= SWITCH_COUNT) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return g_persistent_state.switches[switch_id].switch_on;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取总开关状态
|
||||||
|
bool get_master_switch_state(void) {
|
||||||
|
return g_persistent_state.master_switch;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取设备绑定状态
|
||||||
|
bool is_device_bound(void) {
|
||||||
|
return g_persistent_state.is_bound;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取是否首次启动
|
||||||
|
bool is_first_boot(void) {
|
||||||
|
return g_persistent_state.is_first_boot;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取当前工作模式
|
||||||
|
system_mode_t get_device_mode(void) {
|
||||||
|
return g_runtime_state.mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置设备工作模式
|
||||||
|
void set_device_mode(system_mode_t mode) {
|
||||||
|
if (g_runtime_state.mode != mode) {
|
||||||
|
system_mode_t old_mode = g_runtime_state.mode;
|
||||||
|
g_runtime_state.mode = mode;
|
||||||
|
|
||||||
|
e_printf("[MODE] 设备模式切换: %s -> %s\r\n",
|
||||||
|
get_mode_string(old_mode), get_mode_string(mode));
|
||||||
|
}
|
||||||
|
}
|
@ -287,7 +287,7 @@ target = {
|
|||||||
},
|
},
|
||||||
'ws63-liteos-app-iot': {
|
'ws63-liteos-app-iot': {
|
||||||
'base_target_name': 'target_ws63_app_rom_template',
|
'base_target_name': 'target_ws63_app_rom_template',
|
||||||
# 'liteos_kconfig': 'ws63_iot',
|
'liteos_kconfig': 'ws63_iot', # EKKO add for remove indie upgrade
|
||||||
'os': 'liteos',
|
'os': 'liteos',
|
||||||
'defines': [
|
'defines': [
|
||||||
"USE_CMSIS_OS",
|
"USE_CMSIS_OS",
|
||||||
@ -330,7 +330,7 @@ target = {
|
|||||||
"SUPPORT_SOFTAP_NETCFG", # softAP配网
|
"SUPPORT_SOFTAP_NETCFG", # softAP配网
|
||||||
"SUPPORT_BLE_ANCILLAY_NETCFG", # ble辅助配网
|
"SUPPORT_BLE_ANCILLAY_NETCFG", # ble辅助配网
|
||||||
# "SUPPORT_QUICK_NETCFG", # 快速配网
|
# "SUPPORT_QUICK_NETCFG", # 快速配网
|
||||||
"CONFIG_SUPPORT_HILINK_INDIE_UPGRADE",
|
# "CONFIG_SUPPORT_HILINK_INDIE_UPGRADE", # EKKO remove indie upgrade
|
||||||
"CONFIG_DHCPS_GW",
|
"CONFIG_DHCPS_GW",
|
||||||
"_HSF_",
|
"_HSF_",
|
||||||
# "ENABLE_BLE_SCAN" #open ble scan
|
# "ENABLE_BLE_SCAN" #open ble scan
|
||||||
@ -375,10 +375,10 @@ target = {
|
|||||||
'cjson',
|
'cjson',
|
||||||
'xo_trim_port',
|
'xo_trim_port',
|
||||||
'hilink',
|
'hilink',
|
||||||
'app_addr_map',
|
# 'app_addr_map', # ekko remove for remove indie upgrade
|
||||||
# 'hilinkdevicesdk',
|
'hilinkdevicesdk', # ekko add for remove indie upgrade
|
||||||
# 'hilinkota',
|
'hilinkota', # ekko add for remove indie upgrade
|
||||||
# 'hilinkbtsdk',
|
'hilinkbtsdk', # ekko add for remove indie upgrade
|
||||||
'huks_sdk',
|
'huks_sdk',
|
||||||
'deviceauth',
|
'deviceauth',
|
||||||
'little_fs', 'littlefs_adapt_ws63',
|
'little_fs', 'littlefs_adapt_ws63',
|
||||||
|
@ -125,6 +125,10 @@ def all_build():
|
|||||||
|
|
||||||
build_update_package(os.path.join(info.upg_output, "update.fwpkg"), temp_dir, info.upg_output)
|
build_update_package(os.path.join(info.upg_output, "update.fwpkg"), temp_dir, info.upg_output)
|
||||||
|
|
||||||
|
print("gen package.zip")
|
||||||
|
file_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
os.system("cd " + file_dir + " && python3 package.py")
|
||||||
|
|
||||||
fwpkg_src_file = os.path.join(info.output, "fwpkg", "ws63-liteos-app-iot", "ws63-liteos-app-iot_all.fwpkg")
|
fwpkg_src_file = os.path.join(info.output, "fwpkg", "ws63-liteos-app-iot", "ws63-liteos-app-iot_all.fwpkg")
|
||||||
copy_files = {
|
copy_files = {
|
||||||
info.hilink_bin: temp_dir,
|
info.hilink_bin: temp_dir,
|
||||||
|
172
readme.md
172
readme.md
@ -34,6 +34,7 @@ application/samples/wifi/ohos_connect/hilink_adapt/product/
|
|||||||
1. 其物理模型2Q4G.json,但是里面的netInfo timer update这几个是hilink内部已经实现无需我们关心,我们只需要关心switch3、switch2、switch1、switch4 switch这几个物理模型。
|
1. 其物理模型2Q4G.json,但是里面的netInfo timer update这几个是hilink内部已经实现无需我们关心,我们只需要关心switch3、switch2、switch1、switch4 switch这几个物理模型。
|
||||||
1. switch 是整个面板的总开关,其是属于一个软件上的控制,只有当其属于打开状态时其他的开关才允许控制
|
1. switch 是整个面板的总开关,其是属于一个软件上的控制,只有当其属于打开状态时其他的开关才允许控制
|
||||||
2. switch1->switch4 是对应四个物理开关,每个switch可以控制对应的一个开关。
|
2. switch1->switch4 是对应四个物理开关,每个switch可以控制对应的一个开关。
|
||||||
|
3. 设备的状态是开是数值1,关闭是数值0.
|
||||||
|
|
||||||
## 物理连接相关定义及其中一些信息进行补充:
|
## 物理连接相关定义及其中一些信息进行补充:
|
||||||
GPOP00 <--> LED1
|
GPOP00 <--> LED1
|
||||||
@ -56,46 +57,62 @@ LED 是整个控制面板的背光灯,高电平亮灯(黄色),低电平灭
|
|||||||
|
|
||||||
|
|
||||||
## 需求分析
|
## 需求分析
|
||||||
### 设备的一些信息需要存储在flash中
|
### 基本功能需求:
|
||||||
|
1. 设备的一些信息需要存储在flash中
|
||||||
1. 设备的每个按键的开关状态
|
1. 设备的每个按键的开关状态
|
||||||
2. 设备的背光灯状态
|
2. 设备的背光灯状态
|
||||||
3. 设备的总开关状态
|
3. 设备的总开关状态
|
||||||
4. 设备的配网状态
|
4. 设备的配网状态
|
||||||
|
|
||||||
### 物理按键和APP按键控制要统一
|
2. 物理按键和APP按键控制要统一
|
||||||
设备可以通过APP进行控制,也可以通过物理按键进行控制,通过物理按键进行控制时也需要存储按键的开关状态APP控制时也需要存储按键的开关状态。这样二者的信息能够统一同步
|
1. 设备可以通过APP进行控制,也可以通过物理按键进行控制,通过物理按键进行控制时也需要存储按键的开关状态APP控制时也需要存储按键的开关状态。这样二者的信息能够统一同步
|
||||||
|
|
||||||
### 每个按键的的指示灯和开关状态需要同步,当按键按下时,指示灯亮,当按键松开时,指示灯需要保持长亮。
|
3. 每个按键的的指示灯和开关状态需要同步,当按键按下时,指示灯亮,当按键松开时,指示灯需要保持长亮。
|
||||||
### 你需要在HILINK_NotifyDevStatus对应的 HILINK_M2M_CLOUD_ONLINE 和 HILINK_M2M_CLOUD_OFFLINE 中添加对应的逻辑,当设备上线时,需要将按键的开关状态和指示灯状态进行同步,当设备下线时,需要将按键的开关状态和指示灯状态进行同步。
|
4. 你需要在HILINK_NotifyDevStatus对应的 HILINK_M2M_CLOUD_ONLINE 和 HILINK_M2M_CLOUD_OFFLINE 中添加对应的逻辑,当设备上线时,需要将按键的开关状态和指示灯状态进行同步,当设备下线时,需要将按键的开关状态和指示灯状态进行同步。
|
||||||
|
|
||||||
### 你需要在 HILINK_DEVICE_UNREGISTER 中添加对应的逻辑,当设备被删除时,需要将按键的开关状态和指示灯状态进行同步。
|
5. 你需要在 HILINK_DEVICE_UNREGISTER 中添加对应的逻辑,当设备被删除时,需要将按键的开关状态和指示灯状态进行同步。
|
||||||
### 设备的按键状态的修改请立即进行保存,避免突然断电导致状态丢失。
|
6. 设备的按键状态的修改请立即进行保存,避免突然断电导致状态丢失。
|
||||||
### 设备上线后才能立即进行同步所有物模型信息,避免APP界面异常
|
7. 设备上线后才能立即进行同步所有物模型信息,避免同步失败导致APP界面异常
|
||||||
|
8. 需要支持离线后的本地蓝牙控制。
|
||||||
|
|
||||||
|
### 产测需求:
|
||||||
|
1. 只有处于出厂状态,从未被绑定才会触发产测
|
||||||
|
2. 主动扫描识别固定的热点名 ShuorongSelfTest 作为进入产测的信号,5秒未搜索扫指定名字退出产测
|
||||||
|
=> 搜索识别指定wifi热点名称是后台的行为,其他诸如配网逻辑保持不变。所以这里建议单开一个线程实现
|
||||||
|
产测获取wifi信息相关代码可以参考 /home/ekko.bao/work/hilink-hf_lpt26x/SR_Light_Hilink_14.2.1.312_20250704/application/ws63/user_main/spotlight/factory_test.c wifi_scan_and_check函数的实现。
|
||||||
|
3. 测试流程:开1-开2-开3-开4-全关-全开-全关,每1.5秒执行一个动作
|
||||||
|
4. 需要校验WIFI 信号强度 -70
|
||||||
|
|
||||||
|
|
||||||
|
### SORONTEK智能面板配网:
|
||||||
|
配网有两种触发条件:
|
||||||
|
1. **自动配网**: 设备处于出厂状态(`is_first_boot = true`)时,上电自动进入配网
|
||||||
|
2. **手动配网**: 设备处于未绑定状态时,长按左上角第一个按键10秒进入配网
|
||||||
|
3. 配网过程中,面板背光灯快闪1秒,表示开关已进入配网状态
|
||||||
|
4. 配网中途只有被按下的按键的指示灯进行闪烁,固定1HZ闪烁,其他按键指示灯保持长亮
|
||||||
|
5. 配网超时10分钟,超时未配网按键指示灯恢复长亮
|
||||||
|
=》前三分钟指示灯保持闪烁,后七分钟指示灯保持长亮。
|
||||||
|
|
||||||
## 软件编写规范
|
## 软件编写规范
|
||||||
1. 实现需求需要在application/ws63/user_main另外新建文件夹(命名你根据产品需求定义)实现相关逻辑
|
1. 实现需求需要在application/ws63/user_main另外新建文件夹(命名你根据产品需求定义)实现相关逻辑
|
||||||
2. flush操作的api可见 application/ws63/hsf/hfflash.h 里面定义的 HSF_API 修饰的api
|
2. hf的接口提供了多套api架构,
|
||||||
3. gpio其相关api可见 include/driver/pinctrl.h 和 include/driver/gpio.h。
|
1. include/driver 里面存放的是更底层的api 是hf开头的api。
|
||||||
其中 PIN_MODE_0 为输入模式,PIN_MODE_1输出模式
|
2. application/ws63/hsf 里面存放的高一层级的api。是uapi开头的api
|
||||||
GPIO口枚举可见drivers/chips/ws63/include/platform_core_rom.h
|
二者均可提供服务但是请优先使用 application/ws63/hsf 里面的接口
|
||||||
5. 延时使用msleep
|
如:
|
||||||
6. 定时器使用 uapi_timer_xx 头文件定义在-> include/driver/timer.h
|
1. flush操作的api可见 application/ws63/hsf/hfflash.h 里面定义的 HSF_API 修饰的api
|
||||||
7. 线程相关使用 osal_kthread_xx 头文件定义在-> kernel/osal/include/schedule/osal_task.h
|
但是有一些例外:
|
||||||
|
1. 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
|
||||||
|
2. 定时器使用 uapi_timer_xx 头文件定义在-> include/driver/timer.h
|
||||||
|
3. 离线本地蓝牙上报和接收接口可见:
|
||||||
|
1. 处理接受的数据 application/samples/wifi/ohos_connect/hilink_adapt/entry/hilink_ble_main.c => BleHandleCustomData
|
||||||
|
2. 上报数据 application/samples/wifi/ohos_connect/hilink_adapt/include/ble_cfg_net_api.h => BLE_SendCustomData
|
||||||
|
使用示例可见application/samples/wifi/ohos_connect/hilink_adapt/entry/hilink_ble_main.c => ReporSwitchStatus
|
||||||
|
实现考虑和云端的合二为一,复用上报的代码:在 fast_report 函数里面根据当前处于的模式(离线蓝牙控制模式还是云端网络控制)选择走本地上报还是云端上报。
|
||||||
|
|
||||||
### SORONTEK智能面板产测:
|
|
||||||
1. 由信标发送产测信号
|
|
||||||
=》识别固定的热点名 ShuorongSelfTest 作为进入产测的信号
|
|
||||||
2. 开关循环:开1-开2-开3-开4-全关-全开-全关
|
|
||||||
3. 每1.5秒执行一个动作
|
|
||||||
4. 需要校验WIFI 信号强度 -70
|
|
||||||
|
|
||||||
### SORONTEK智能面板配网:
|
|
||||||
1. 只有设备处于未绑定状态才能进行配网(出厂或者被APP删除)
|
|
||||||
=》 设备处于出厂状态需要立刻进入配网。
|
|
||||||
2. 长按开关左上角第一个按键10秒, 进入配网,面板背光灯快闪1秒,表示开关已进入配网状态
|
|
||||||
3. 配网中途只有被按下的按键的指示灯进行闪烁,固定1HZ闪烁,其他按键指示灯保持长亮
|
|
||||||
4. 配网超时10分钟,超时未配网按键指示灯恢复长亮
|
|
||||||
=》前三分钟指示灯保持闪烁,后七分钟指示灯保持长亮。
|
|
||||||
|
|
||||||
## 其他补充信息
|
## 其他补充信息
|
||||||
### 出厂/复位 SORONTEK智能面板默认状态:
|
### 出厂/复位 SORONTEK智能面板默认状态:
|
||||||
@ -108,5 +125,104 @@ LED 是整个控制面板的背光灯,高电平亮灯(黄色),低电平灭
|
|||||||
上报使用 fast_report函数,传入对应的svc_id子串即可
|
上报使用 fast_report函数,传入对应的svc_id子串即可
|
||||||
|
|
||||||
|
|
||||||
|
## 编译和打包命令
|
||||||
|
|
||||||
|
### 基本编译命令
|
||||||
|
```bash
|
||||||
|
# 清除构建并编译主程序
|
||||||
|
python3 build.py -c ws63-liteos-hilink
|
||||||
|
|
||||||
|
# 并行编译(推荐)
|
||||||
|
python3 build.py -j8 ws63-liteos-hilink
|
||||||
|
|
||||||
|
# 独立升级编译(包含两个目标)
|
||||||
|
python3 indie_build.py sdk # 仅编译SDK
|
||||||
|
python3 indie_build.py all # 编译所有组件
|
||||||
|
|
||||||
|
# 生成升级包
|
||||||
|
python3 package.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### 编译输出目录
|
||||||
|
- `output/LPT262_hilink.fwpkg` - 主固件包
|
||||||
|
- `output/LPT262_hilink_UPGRADE.bin` - 升级固件
|
||||||
|
- `output/package.zip` - OTA升级包
|
||||||
|
|
||||||
|
### 调试编译选项
|
||||||
|
```bash
|
||||||
|
# 添加编译宏
|
||||||
|
python3 build.py -def=DEBUG_SWITCH_PANEL,LOG_LEVEL=3 ws63-liteos-hilink
|
||||||
|
|
||||||
|
# 仅编译指定组件
|
||||||
|
python3 build.py -component=user_main ws63-liteos-hilink
|
||||||
|
|
||||||
|
# 使用ninja生成器(更快)
|
||||||
|
python3 build.py -ninja ws63-liteos-hilink
|
||||||
|
```
|
||||||
|
|
||||||
|
## 关键API参考
|
||||||
|
|
||||||
|
### GPIO控制
|
||||||
|
```c
|
||||||
|
// 引用头文件
|
||||||
|
#include "driver/gpio.h"
|
||||||
|
#include "driver/pinctrl.h"
|
||||||
|
|
||||||
|
// GPIO初始化
|
||||||
|
uapi_pin_set_mode(GPIO_00, PIN_MODE_1); // 输出模式
|
||||||
|
uapi_gpio_set_dir(GPIO_00, GPIO_DIRECTION_OUTPUT);
|
||||||
|
|
||||||
|
// GPIO操作
|
||||||
|
uapi_gpio_set_val(GPIO_00, GPIO_LEVEL_HIGH);
|
||||||
|
uapi_gpio_get_val(GPIO_00, &level);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Flash存储
|
||||||
|
```c
|
||||||
|
// 引用头文件
|
||||||
|
#include "application/ws63/hsf/hfflash.h"
|
||||||
|
|
||||||
|
// Flash操作
|
||||||
|
HSF_WriteFlash(offset, data, len);
|
||||||
|
HSF_ReadFlash(offset, data, len);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 定时器
|
||||||
|
```c
|
||||||
|
// 引用头文件
|
||||||
|
#include "driver/timer.h"
|
||||||
|
|
||||||
|
// 定时器操作
|
||||||
|
uapi_timer_create(&timer_id);
|
||||||
|
uapi_timer_start(timer_id, timeout, callback);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 延时操作
|
||||||
|
```c
|
||||||
|
msleep(1000); // 延时1秒
|
||||||
|
```
|
||||||
|
|
||||||
|
## 设备状态管理要点
|
||||||
|
|
||||||
|
### 设备绑定状态管理
|
||||||
|
- **`is_first_boot` 标志**: 表示设备从未被绑定的状态(可理解为 `not_first_bind`)
|
||||||
|
- 出厂状态:`is_first_boot = true` (从未被绑定)
|
||||||
|
- 首次绑定后:`is_first_boot = false` (永久设置,不可逆)
|
||||||
|
- 设备删除后:`is_first_boot` 保持 `false` (不影响该标志)
|
||||||
|
- **未绑定状态**: 设备当前没有绑定到任何用户账户(包括出厂状态和被删除后的状态)
|
||||||
|
- **产测触发条件**: 只有 `is_first_boot = true` 时才会触发产测流程
|
||||||
|
- **配网触发条件**:
|
||||||
|
- 出厂状态(`is_first_boot = true`):上电自动进入配网
|
||||||
|
- 未绑定状态:长按左上角第一个按键10秒可进入配网
|
||||||
|
|
||||||
|
### 设备状态同步要点
|
||||||
|
1. **云端上报入口**: `fast_report(svc_id)` - 自动处理蓝牙/云端模式
|
||||||
|
2. **云端控制入口**: `application/samples/wifi/ohos_connect/hilink_adapt/product/hilink_device.c` 中的 `handle_put_xxx` 函数
|
||||||
|
3. **状态存储**: 所有设备状态变化必须立即调用Flash写入操作
|
||||||
|
4. **设备事件处理**: 在 `HILINK_NotifyDevStatus` 中处理设备上线/下线/删除事件
|
||||||
|
- `HILINK_M2M_CLOUD_ONLINE`: 设备上线时同步所有状态
|
||||||
|
- `HILINK_M2M_CLOUD_OFFLINE`: 设备下线时保持本地状态
|
||||||
|
- `HILINK_DEVICE_UNREGISTER`: 设备删除时不影响 `is_first_boot` 标志
|
||||||
|
|
||||||
现在需要请你帮我实现一个四开关面板程序功能
|
现在需要请你帮我实现一个四开关面板程序功能
|
||||||
请先分析需求,拆解步骤,然后逐步进行编码。
|
请先分析需求,拆解步骤,然后逐步进行编码。
|
Reference in New Issue
Block a user