Compare commits
5 Commits
6cd2908eaf
...
e6fc092d3a
| Author | SHA1 | Date | |
|---|---|---|---|
| e6fc092d3a | |||
| 0a4e83dad7 | |||
| 1a40c6f348 | |||
| e728a942a4 | |||
| 2a5be3af4b |
@@ -482,7 +482,7 @@ int hilink_ble_main(void)
|
||||
ret = HILINK_SetNetConfigMode(HILINK_NETCONFIG_OTHER);
|
||||
|
||||
/* 设备按需设置,例如接入蓝牙网关时,设置广播类型标志及心跳间隔 */
|
||||
unsigned char mpp[] = {0x02, 0x01, 0x01};
|
||||
unsigned char mpp[] = { 0x70, 0x30, 0x75};
|
||||
ret = BLE_SetAdvNameMpp(mpp, sizeof(mpp));
|
||||
if (ret != 0) {
|
||||
HILINK_SAL_NOTICE("set adv name mpp failed\r\n");
|
||||
|
||||
@@ -30,7 +30,7 @@ extern "C" {
|
||||
|
||||
#define DEVICE_HIVERSION "1.0.0"
|
||||
/* 设备固件版本号 */
|
||||
#define FIRMWARE_VER "1.0.0"
|
||||
#define FIRMWARE_VER "1.0.6"
|
||||
/* 设备硬件版本号 */
|
||||
#define HARDWARE_VER "1.0.0"
|
||||
/* 设备软件版本号 */
|
||||
|
||||
@@ -343,10 +343,6 @@ int handle_get_cmd(const char* svc_id, const char* in, unsigned int in_len, char
|
||||
// 支持蓝牙和云端双模式上报
|
||||
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()) {
|
||||
// 蓝牙模式下通过蓝牙上报
|
||||
|
||||
@@ -43,6 +43,9 @@
|
||||
#define CONFIG_BLINK_MS (3*60*1000) // 配网前3分钟闪烁时间
|
||||
#define PANEL_BLINK_MS 1000 // 面板背光快闪时间(1秒)
|
||||
#define LED_BLINK_FREQ_HZ 1 // 配网时LED闪烁频率(1Hz)
|
||||
#define CONSECUTIVE_PRESS_COUNT 4 // 强制解绑需要的连续按键次数
|
||||
#define CONSECUTIVE_PRESS_TIMEOUT_MS 2000 // 连续按键超时时间(2秒)
|
||||
#define FORCE_UNBIND_WAIT_TIMEOUT_MS 3000 // 等待长按超时时间(3秒)
|
||||
|
||||
//====================== 设备状态定义 ======================
|
||||
// 开关状态
|
||||
@@ -96,7 +99,7 @@ typedef struct {
|
||||
bool long_press_handled; // 长按处理标志
|
||||
} switch_runtime_info_t;
|
||||
|
||||
// 持久化设备状态(需要保存到Flash)
|
||||
// V1版本的持久化设备状态(老版本兼容)
|
||||
typedef struct {
|
||||
switch_persistent_info_t switches[SWITCH_COUNT]; // 4个开关的持久化状态
|
||||
bool master_switch; // 总开关状态 - 持久化
|
||||
@@ -106,7 +109,24 @@ typedef struct {
|
||||
uint32_t magic; // 魔数标识
|
||||
uint32_t version; // 版本号
|
||||
uint32_t reserved[8]; // 保留字段
|
||||
} device_persistent_state_t;
|
||||
} device_persistent_state_v1_t;
|
||||
|
||||
// V2版本的持久化设备状态(新版本,当前使用)
|
||||
typedef struct {
|
||||
switch_persistent_info_t switches[SWITCH_COUNT]; // 4个开关的持久化状态
|
||||
bool master_switch; // 总开关状态 - 持久化
|
||||
bool panel_led; // 面板背光状态 - 持久化
|
||||
bool is_bound; // 设备绑定状态 - 持久化
|
||||
bool is_first_boot; // 是否第一次上电 - 持久化
|
||||
bool memory_switches[SWITCH_COUNT]; // APP关闭总开关时记忆的子开关状态 - 持久化
|
||||
bool has_memory_state; // 是否有记忆状态 - 持久化
|
||||
uint32_t magic; // 魔数标识
|
||||
uint32_t version; // 版本号
|
||||
uint32_t reserved[6]; // 保留字段(减少2个给新字段使用)
|
||||
} device_persistent_state_v2_t;
|
||||
|
||||
// 当前使用的持久化状态结构(V2)
|
||||
typedef device_persistent_state_v2_t device_persistent_state_t;
|
||||
|
||||
// 运行时设备状态(不需要持久化,断电丢失)
|
||||
typedef struct {
|
||||
@@ -118,7 +138,14 @@ typedef struct {
|
||||
bool config_led_blink_state; // 配网LED闪烁状态
|
||||
bool factory_test_running; // 产测是否运行中
|
||||
uint32_t last_save_time; // 上次保存时间
|
||||
uint32_t reserved[16]; // 保留字段
|
||||
bool is_online;
|
||||
// 强制解绑连续按键检测状态
|
||||
uint32_t consecutive_press_count; // 连续按键计数
|
||||
uint32_t first_press_time; // 第一次按键时间
|
||||
uint32_t last_press_time; // 最后一次按键时间
|
||||
bool waiting_long_press; // 等待长按标志
|
||||
uint32_t wait_long_press_start_time; // 开始等待长按的时间
|
||||
uint32_t reserved[11]; // 保留字段(减少5个给新字段使用)
|
||||
} device_runtime_state_t;
|
||||
|
||||
|
||||
@@ -141,7 +168,9 @@ typedef struct {
|
||||
} device_data_t;
|
||||
|
||||
#define DEVICE_DATA_MAGIC 0x4C505426 // "LPT&"的ASCII码
|
||||
#define DEVICE_DATA_VERSION 1 // 数据版本号
|
||||
#define DEVICE_DATA_VERSION_V1 1 // 数据版本号V1(老版本,无记忆功能)
|
||||
#define DEVICE_DATA_VERSION_V2 2 // 数据版本号V2(新版本,支持记忆功能)
|
||||
#define DEVICE_DATA_VERSION DEVICE_DATA_VERSION_V2 // 当前版本
|
||||
|
||||
//====================== 配网相关定义 ======================
|
||||
#define FACTORY_TEST_SSID "ShuorongSelfTest" // 产测热点名称
|
||||
@@ -201,6 +230,18 @@ void fast_report_switch(int switch_id);
|
||||
void fast_report_master_switch(void);
|
||||
void set_device_mode(system_mode_t mode);
|
||||
|
||||
// 恢复出厂设置相关函数
|
||||
void perform_factory_reset_and_reboot(void);
|
||||
|
||||
// 记忆状态管理函数
|
||||
void save_memory_switches(void);
|
||||
void restore_memory_switches(void);
|
||||
void clear_memory_switches(void);
|
||||
|
||||
// 强制解绑检测函数
|
||||
bool check_consecutive_press(int key_id);
|
||||
void check_force_unbind_timeout(void);
|
||||
|
||||
// 状态访问便利函数
|
||||
bool get_switch_state(int switch_id);
|
||||
bool get_master_switch_state(void);
|
||||
@@ -243,6 +284,7 @@ void panel_led_blink(void);
|
||||
|
||||
// 产测相关函数
|
||||
void enter_factory_test_mode(void);
|
||||
void exit_factory_test_mode(void);
|
||||
void factory_test_sequence(void);
|
||||
bool check_factory_test_wifi(int32_t rssi_threshold);
|
||||
int factory_test_monitor_task(void *arg);
|
||||
@@ -288,4 +330,4 @@ bool switch_panel_ble_is_enabled(void);
|
||||
int switch_panel_ble_fast_report(const char *svc_id);
|
||||
|
||||
int start_hilink_ble_net_config(int32_t net_cfg_time_s);
|
||||
#endif // __SWITCH_PANEL_H__
|
||||
#endif // __SWITCH_PANEL_H__
|
||||
|
||||
@@ -39,15 +39,13 @@ static void ble_report_switch_state(int switch_id) {
|
||||
|
||||
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,
|
||||
g_persistent_state.switches[switch_id].name,
|
||||
svc_id);
|
||||
if (ret <= 0) {
|
||||
e_printf("[BLE] 开关%d状态格式化失败: %d\r\n", switch_id + 1, ret);
|
||||
@@ -86,9 +84,11 @@ static int ble_handle_master_switch(cJSON *dataItem) {
|
||||
}
|
||||
|
||||
bool new_state = (onItem->valueint != 0);
|
||||
bool old_state = g_persistent_state.master_switch;
|
||||
e_printf("[BLE] 接收到总开关控制指令: %s\r\n", new_state ? "开" : "关");
|
||||
|
||||
// 调用现有的总开关控制函数
|
||||
// 统一使用 update_master_switch 处理总开关逻辑
|
||||
// apply_master_switch_control 中已包含智能全开逻辑
|
||||
update_master_switch(new_state);
|
||||
|
||||
// 通过蓝牙上报状态确认
|
||||
@@ -113,18 +113,15 @@ static int ble_handle_switch_control(const char *svc_id, cJSON *dataItem) {
|
||||
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;
|
||||
|
||||
cJSON* on_item = cJSON_GetObjectItem(dataItem, "on");
|
||||
if (on_item) {
|
||||
update_switch_state(switch_id, cJSON_GetNumberValue(on_item));
|
||||
}
|
||||
cJSON* name_item = cJSON_GetObjectItem(dataItem, "name");
|
||||
if (name_item) {
|
||||
set_switch_name(switch_id, cJSON_GetStringValue(name_item));
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@@ -329,19 +329,25 @@ void enter_factory_test_mode(void) {
|
||||
g_factory_test_start_time = hfsys_get_time();
|
||||
}
|
||||
|
||||
// 产测序列
|
||||
void factory_test_sequence(void) {
|
||||
e_printf("开始产测序列\r\n");
|
||||
// 退出产测模式
|
||||
void exit_factory_test_mode(void) {
|
||||
e_printf("退出产测模式\r\n");
|
||||
|
||||
// 步骤1: 开始指示 - 交替闪烁白黄灯500ms
|
||||
for (int i = 0; i < 6; i++) {
|
||||
for (int j = 0; j < SWITCH_COUNT; j++) {
|
||||
set_led_output(j, (i % 2) ? LED_WHITE : LED_YELLOW);
|
||||
}
|
||||
osal_msleep(500);
|
||||
}
|
||||
// 停止产测循环
|
||||
g_factory_test_running = false;
|
||||
|
||||
// 步骤2-5: 单个开关测试 (开1->4, 每个1.5秒)
|
||||
// 更新设备模式
|
||||
set_device_mode(MODE_NORMAL);
|
||||
|
||||
// 恢复设备默认状态
|
||||
sync_hardware_state();
|
||||
|
||||
e_printf("已退出产测模式\r\n");
|
||||
}
|
||||
|
||||
// 单轮开关测试序列:开1->开2->开3->开4->全关->全开->全关
|
||||
static void switch_test_cycle(void) {
|
||||
// 步骤1-4: 单个开关测试 (开1->4, 每个1.5秒)
|
||||
for (int switch_id = 0; switch_id < SWITCH_COUNT; switch_id++) {
|
||||
e_printf("测试开关%d\r\n", switch_id + 1);
|
||||
|
||||
@@ -359,7 +365,7 @@ void factory_test_sequence(void) {
|
||||
osal_msleep(1500);
|
||||
}
|
||||
|
||||
// 步骤6: 全关 (1.5秒)
|
||||
// 步骤5: 全关 (1.5秒)
|
||||
e_printf("测试全关\r\n");
|
||||
for (int i = 0; i < SWITCH_COUNT; i++) {
|
||||
set_switch_output(i, false);
|
||||
@@ -367,7 +373,7 @@ void factory_test_sequence(void) {
|
||||
}
|
||||
osal_msleep(1500);
|
||||
|
||||
// 步骤7: 全开 (1.5秒)
|
||||
// 步骤6: 全开 (1.5秒)
|
||||
e_printf("测试全开\r\n");
|
||||
for (int i = 0; i < SWITCH_COUNT; i++) {
|
||||
set_switch_output(i, true);
|
||||
@@ -375,44 +381,79 @@ void factory_test_sequence(void) {
|
||||
}
|
||||
osal_msleep(1500);
|
||||
|
||||
// 步骤8: 再次全关
|
||||
e_printf("结束测试 - 全关\r\n");
|
||||
// 步骤7: 再次全关 (1.5秒)
|
||||
e_printf("结束本轮测试 - 全关\r\n");
|
||||
for (int i = 0; i < SWITCH_COUNT; i++) {
|
||||
set_switch_output(i, false);
|
||||
set_led_output(i, LED_YELLOW);
|
||||
}
|
||||
|
||||
osal_msleep(1500);
|
||||
// 步骤9: 检查WiFi信号强度
|
||||
for (int i = 0; i < SWITCH_COUNT; i++) {
|
||||
set_led_output(i, LED_WHITE);
|
||||
}
|
||||
bool wifi_test_pass = check_factory_test_wifi(FACTORY_TEST_RSSI_THRESHOLD);
|
||||
}
|
||||
|
||||
// 显示最终结果
|
||||
if (wifi_test_pass) {
|
||||
e_printf("产测全部通过\r\n");
|
||||
// 所有开关开启表示通过
|
||||
for (int i = 0; i < SWITCH_COUNT; i++) {
|
||||
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_led_output(i, LED_YELLOW);
|
||||
}
|
||||
// 产测序列
|
||||
void factory_test_sequence(void) {
|
||||
e_printf("开始产测序列\r\n");
|
||||
|
||||
// 步骤1: 进入产测后所有指示灯全亮(白灯)
|
||||
e_printf("步骤1: 进入产测模式,所有指示灯全亮\r\n");
|
||||
for (int i = 0; i < SWITCH_COUNT; i++) {
|
||||
set_led_output(i, LED_WHITE); // 所有灯白灯表示进入产测模式
|
||||
}
|
||||
|
||||
// 产测完成,返回正常模式
|
||||
g_factory_test_running = false;
|
||||
set_device_mode(MODE_NORMAL);
|
||||
// 步骤2: 校验WiFi信号强度
|
||||
e_printf("步骤2: 校验WiFi信号强度\r\n");
|
||||
bool wifi_test_pass = check_factory_test_wifi(FACTORY_TEST_RSSI_THRESHOLD);
|
||||
|
||||
// 恢复设备默认状态
|
||||
sync_hardware_state();
|
||||
if (!wifi_test_pass) {
|
||||
e_printf("WiFi信号强度测试失败,指示灯保持全亮,停留在产测模式\r\n");
|
||||
// WiFi测试失败,指示灯保持全亮(白灯),停留在产测模式方便测试人员观察
|
||||
wifi_unregister_event_cb(&wifi_event_cb);
|
||||
e_printf("产测序列完成(WiFi测试失败),停留在产测模式\r\n");
|
||||
|
||||
// 停留在产测模式,不退出,方便测试人员观察状态
|
||||
while (g_factory_test_running) {
|
||||
osal_msleep(1000); // 每秒检查一次
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
e_printf("WiFi信号强度测试通过,指示灯灭灯,开始开关老化测试\r\n");
|
||||
|
||||
// 步骤3: WiFi测试通过,所有指示灯灭灯(黄灯)
|
||||
for (int i = 0; i < SWITCH_COUNT; i++) {
|
||||
set_led_output(i, LED_YELLOW); // WiFi测试通过,指示灯灭灯(黄灯)
|
||||
}
|
||||
|
||||
// 步骤4: 直接开始循环进行开关测试,用于老化测试
|
||||
e_printf("开始循环开关老化测试...\r\n");
|
||||
uint32_t cycle_count = 0;
|
||||
|
||||
while (g_factory_test_running) {
|
||||
cycle_count++;
|
||||
e_printf("=== 开关测试循环 第%d轮 ===\r\n", cycle_count);
|
||||
|
||||
// 执行一轮开关测试
|
||||
switch_test_cycle();
|
||||
|
||||
// 每100轮输出一次统计信息
|
||||
if (cycle_count % 100 == 0) {
|
||||
e_printf("已完成%d轮开关老化测试\r\n", cycle_count);
|
||||
}
|
||||
|
||||
// 防止过度消耗CPU,可以在这里添加短暂延时
|
||||
// osal_msleep(10);
|
||||
}
|
||||
|
||||
e_printf("开关老化测试结束,共完成%d轮\r\n", cycle_count);
|
||||
|
||||
// 停留在产测模式,不退出,方便测试人员观察状态
|
||||
wifi_unregister_event_cb(&wifi_event_cb);
|
||||
e_printf("产测序列完成\r\n");
|
||||
e_printf("产测序列完成,停留在产测模式\r\n");
|
||||
|
||||
// 停留在产测模式,等待手动退出
|
||||
while (g_factory_test_running) {
|
||||
osal_msleep(1000); // 每秒检查一次
|
||||
}
|
||||
}
|
||||
|
||||
// 检查产测热点
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "securec.h"
|
||||
#include "cJSON.h"
|
||||
#include "switch_panel.h"
|
||||
#include "hfsys.h"
|
||||
|
||||
static int handle_get_switch_common(int switch_id, const char* svc_id,
|
||||
const char* in, unsigned int in_len,
|
||||
@@ -16,7 +17,7 @@ static int handle_put_switch_common(int switch_id, const char* svc_id,
|
||||
// 处理设备上线事件
|
||||
void handle_device_online(void) {
|
||||
e_printf("设备上线\r\n");
|
||||
|
||||
g_runtime_state.is_online = true;
|
||||
// 检查是否是新绑定的设备
|
||||
bool was_unbound = !g_persistent_state.is_bound;
|
||||
|
||||
@@ -51,7 +52,6 @@ void handle_device_online(void) {
|
||||
e_printf("已恢复默认状态:总开关关闭,所有子开关关闭,LED黄灯,面板背光开启\r\n");
|
||||
}
|
||||
// 设备上线时禁用蓝牙模式,启用云端模式
|
||||
extern void switch_panel_ble_disable(void);
|
||||
switch_panel_ble_disable();
|
||||
|
||||
// 同步所有状态到云端
|
||||
@@ -64,12 +64,9 @@ void handle_device_online(void) {
|
||||
// 处理设备下线事件
|
||||
void handle_device_offline(void) {
|
||||
e_printf("设备下线\r\n");
|
||||
|
||||
g_runtime_state.is_online = false;
|
||||
// 设备下线时启用蓝牙模式,支持本地控制
|
||||
extern void switch_panel_ble_enable(void);
|
||||
switch_panel_ble_enable();
|
||||
|
||||
// 设备下线时保持现有状态,不做特殊处理
|
||||
}
|
||||
|
||||
// 处理设备解绑事件
|
||||
@@ -83,16 +80,15 @@ void handle_device_unbind(void) {
|
||||
// 重置为出厂默认状态
|
||||
reset_persistent_state();
|
||||
g_persistent_state.is_bound = false; // 保持未绑定状态
|
||||
g_persistent_state.is_first_boot = false; // 标记为非出厂模式
|
||||
g_persistent_state.is_first_boot = true; // 标记为出厂模式,重启后自动配网
|
||||
|
||||
// 同步硬件状态
|
||||
sync_hardware_state();
|
||||
|
||||
// 保存状态
|
||||
save_persistent_state();
|
||||
// HILINK_RestoreFactorySettings();
|
||||
save_persistent_state_sync(); // 使用同步保存确保立即写入
|
||||
|
||||
e_printf("设备已重置为出厂默认状态\r\n");
|
||||
e_printf("设备已重置为出厂默认状态,重启后将自动进入配网模式\r\n");
|
||||
}
|
||||
|
||||
// 同步所有状态到云端
|
||||
@@ -123,7 +119,12 @@ int handle_put_switch(const char* svc_id, const char* payload, unsigned int len)
|
||||
}
|
||||
|
||||
cJSON* on_item = cJSON_GetObjectItem(json, "on");
|
||||
update_master_switch(cJSON_GetNumberValue(on_item));
|
||||
bool new_state = (bool)cJSON_GetNumberValue(on_item);
|
||||
bool old_state = g_persistent_state.master_switch;
|
||||
|
||||
// 统一使用 update_master_switch 处理总开关逻辑
|
||||
// apply_master_switch_control 中已包含智能全开逻辑
|
||||
update_master_switch(new_state);
|
||||
|
||||
cJSON_Delete(json);
|
||||
return 0;
|
||||
@@ -249,12 +250,103 @@ static int handle_get_switch_common(int switch_id, const char* svc_id,
|
||||
|
||||
//====================== HiLink 事件扩展函数 ======================
|
||||
|
||||
// 检查设备是否在线
|
||||
bool is_device_online(void) {
|
||||
return g_persistent_state.is_bound;
|
||||
}
|
||||
|
||||
// 获取设备当前模式
|
||||
system_mode_t get_current_mode(void) {
|
||||
return g_runtime_state.mode;
|
||||
}
|
||||
|
||||
//====================== 恢复出厂设置函数 ======================
|
||||
|
||||
// 执行恢复出厂设置并重启
|
||||
void perform_factory_reset_and_reboot(void) {
|
||||
e_printf("开始执行恢复出厂设置...\r\n");
|
||||
|
||||
// 调用HiLink恢复出厂设置API,该API内部会:
|
||||
// 1. 清除HiLink相关的所有绑定信息和云端数据
|
||||
// 2. 调用handle_device_unbind函数进行本地状态清除
|
||||
// 3. 自动重启设备
|
||||
int ret = HILINK_RestoreFactorySettings();
|
||||
if (ret != 0) {
|
||||
e_printf("HiLink恢复出厂设置失败,错误码: %d\r\n", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
e_printf("HiLink恢复出厂设置API调用成功,等待系统重启...\r\n");
|
||||
|
||||
// 注意:这里代码可能不会执行到很多,因为HILINK_RestoreFactorySettings会触发重启
|
||||
}
|
||||
|
||||
//====================== 记忆状态管理函数 ======================
|
||||
|
||||
// 保存当前子开关状态到记忆区
|
||||
void save_memory_switches(void) {
|
||||
e_printf("保存当前子开关状态到记忆区\r\n");
|
||||
|
||||
for (int i = 0; i < SWITCH_COUNT; i++) {
|
||||
g_persistent_state.memory_switches[i] = g_persistent_state.switches[i].switch_on;
|
||||
e_printf("记忆开关%d状态: %s\r\n", i + 1,
|
||||
g_persistent_state.memory_switches[i] ? "开" : "关");
|
||||
}
|
||||
|
||||
g_persistent_state.has_memory_state = true;
|
||||
|
||||
// 立即保存到Flash
|
||||
save_persistent_state();
|
||||
|
||||
e_printf("子开关状态记忆保存完成\r\n");
|
||||
}
|
||||
|
||||
// 从记忆区恢复子开关状态
|
||||
void restore_memory_switches(void) {
|
||||
if (!g_persistent_state.has_memory_state) {
|
||||
e_printf("没有记忆状态,无法恢复\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
e_printf("从记忆区恢复子开关状态\r\n");
|
||||
|
||||
bool any_switch_changed = false;
|
||||
for (int i = 0; i < SWITCH_COUNT; i++) {
|
||||
bool new_state = g_persistent_state.memory_switches[i];
|
||||
if (g_persistent_state.switches[i].switch_on != new_state) {
|
||||
g_persistent_state.switches[i].switch_on = new_state;
|
||||
g_persistent_state.switches[i].led_state = new_state;
|
||||
|
||||
// 同步硬件状态
|
||||
set_switch_output(i, new_state);
|
||||
set_led_output(i, new_state ? LED_WHITE : LED_YELLOW);
|
||||
|
||||
e_printf("恢复开关%d状态: %s\r\n", i + 1, new_state ? "开" : "关");
|
||||
any_switch_changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (any_switch_changed) {
|
||||
// 保存状态变化
|
||||
save_persistent_state();
|
||||
|
||||
// 同步到云端
|
||||
if (g_persistent_state.is_bound) {
|
||||
fast_report_all_switches_async();
|
||||
}
|
||||
}
|
||||
|
||||
e_printf("子开关状态恢复完成\r\n");
|
||||
}
|
||||
|
||||
// 清除记忆状态
|
||||
void clear_memory_switches(void) {
|
||||
if (!g_persistent_state.has_memory_state) {
|
||||
return;
|
||||
}
|
||||
|
||||
e_printf("清除记忆状态\r\n");
|
||||
|
||||
g_persistent_state.has_memory_state = false;
|
||||
memset(g_persistent_state.memory_switches, 0, sizeof(g_persistent_state.memory_switches));
|
||||
|
||||
// 立即保存到Flash
|
||||
save_persistent_state();
|
||||
|
||||
e_printf("记忆状态已清除\r\n");
|
||||
}
|
||||
@@ -13,16 +13,15 @@ void update_switch_state(int switch_id, bool state) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查总开关是否允许操作
|
||||
// 注意:如果设备未绑定,则不受总开关限制,可以自由控制
|
||||
if (g_persistent_state.is_bound && !g_persistent_state.master_switch && state) {
|
||||
e_printf("设备已绑定且总开关关闭,不允许开启开关%d\r\n", switch_id + 1);
|
||||
return;
|
||||
}
|
||||
// 新逻辑:移除总开关限制,允许本地按键自由控制子开关
|
||||
// 本地按键控制子开关时,如果要开启子开关且总开关关闭,则自动打开总开关并清除记忆状态
|
||||
bool need_auto_master_on = false;
|
||||
bool need_clear_memory = false;
|
||||
|
||||
// 如果设备未绑定,记录状态变化以便调试
|
||||
if (!g_persistent_state.is_bound) {
|
||||
e_printf("设备未绑定,允许自由控制开关%d\r\n", switch_id + 1);
|
||||
if (state && !g_persistent_state.master_switch) {
|
||||
need_auto_master_on = true;
|
||||
need_clear_memory = true; // 物理按键操作时清除记忆状态
|
||||
e_printf("子开关%d激活,将自动打开总开关并清除记忆状态\r\n", switch_id + 1);
|
||||
}
|
||||
|
||||
// 更新开关状态
|
||||
@@ -39,6 +38,20 @@ void update_switch_state(int switch_id, bool state) {
|
||||
e_printf("开关%d 状态更新: %s\r\n",
|
||||
switch_id + 1, state ? "开" : "关");
|
||||
|
||||
// 如果需要清除记忆状态
|
||||
if (need_clear_memory) {
|
||||
clear_memory_switches();
|
||||
}
|
||||
|
||||
// 如果需要自动打开总开关
|
||||
if (need_auto_master_on) {
|
||||
g_persistent_state.master_switch = true;
|
||||
e_printf("总开关已自动打开\r\n");
|
||||
|
||||
// 异步上报总开关状态变化
|
||||
fast_report_master_switch_async();
|
||||
}
|
||||
|
||||
// 立即保存状态
|
||||
save_persistent_state();
|
||||
|
||||
@@ -72,44 +85,42 @@ void update_master_switch(bool state) {
|
||||
// 应用总开关控制逻辑
|
||||
void apply_master_switch_control(void) {
|
||||
|
||||
// 如果设备未绑定,总开关不影响子开关控制
|
||||
if (!g_persistent_state.is_bound) {
|
||||
e_printf("设备未绑定,总开关不影响子开关控制\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!g_persistent_state.master_switch) {
|
||||
// 设备已绑定且总开关关闭时,强制关闭所有子开关
|
||||
e_printf("设备已绑定且总开关关闭,强制关闭所有子开关\r\n");
|
||||
// 总开关关闭时,先保存当前子开关状态到记忆区,再强制关闭所有子开关
|
||||
e_printf("总开关关闭,保存当前状态并强制关闭所有子开关\r\n");
|
||||
|
||||
// 保存当前子开关状态到记忆区
|
||||
save_memory_switches();
|
||||
|
||||
for (int i = 0; i < SWITCH_COUNT; i++) {
|
||||
// 如果子开关之前是开着的,需要同步状态
|
||||
if (g_persistent_state.switches[i].switch_on) {
|
||||
g_persistent_state.switches[i].switch_on = false;
|
||||
g_persistent_state.switches[i].led_state = false;
|
||||
e_printf("强制关闭子开关%d\r\n", i + 1);
|
||||
}
|
||||
// 强制关闭所有子开关
|
||||
g_persistent_state.switches[i].switch_on = false;
|
||||
g_persistent_state.switches[i].led_state = false;
|
||||
|
||||
// 更新硬件状态
|
||||
set_switch_output(i, false);
|
||||
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);
|
||||
// }
|
||||
}
|
||||
// 同步所有子开关状态到云端
|
||||
if (g_persistent_state.is_bound) {
|
||||
fast_report_all_switches_async();
|
||||
// 同步所有子开关状态到云端
|
||||
if (g_persistent_state.is_bound) {
|
||||
fast_report_all_switches_async();
|
||||
}
|
||||
} else {
|
||||
// 总开关开启时,尝试恢复记忆状态,如果没有记忆状态则不操控子开关
|
||||
e_printf("总开关开启\r\n");
|
||||
|
||||
if (g_persistent_state.has_memory_state) {
|
||||
// 恢复记忆的子开关状态
|
||||
e_printf("恢复记忆的子开关状态\r\n");
|
||||
restore_memory_switches();
|
||||
} else {
|
||||
// 没有记忆状态,不操控子开关(保持当前状态)
|
||||
e_printf("没有记忆状态,保持子开关当前状态不变\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
e_printf("所有子开关状态已同步\r\n");
|
||||
e_printf("总开关控制逻辑应用完成\r\n");
|
||||
}
|
||||
|
||||
//====================== 按键检测与处理 ======================
|
||||
@@ -138,6 +149,9 @@ int key_scan_task(void *arg) {
|
||||
while (1) {
|
||||
uint32_t current_time = hfsys_get_time();
|
||||
|
||||
// 检查强制解绑超时
|
||||
check_force_unbind_timeout();
|
||||
|
||||
// 扫描所有按键
|
||||
for (int i = 0; i < SWITCH_COUNT; i++) {
|
||||
bool new_raw_state = get_key_input(i);
|
||||
@@ -164,6 +178,21 @@ int key_scan_task(void *arg) {
|
||||
press_start_time[i] = current_time;
|
||||
is_long_press_handled[i] = false;
|
||||
e_printf("按键%d 按下\r\n", i + 1);
|
||||
|
||||
// 如果正在等待长按强制解绑
|
||||
if (g_runtime_state.waiting_long_press) {
|
||||
if (i == 0) {
|
||||
// 第一个按键:停止超时检测,等待长按处理
|
||||
e_printf("检测到第一个按键按下,停止强制解绑超时检测\r\n");
|
||||
g_runtime_state.wait_long_press_start_time = 0; // 停止超时检测
|
||||
} else {
|
||||
// 其他按键:取消等待状态
|
||||
e_printf("检测到其他按键按下,取消强制解绑等待\r\n");
|
||||
g_runtime_state.waiting_long_press = false;
|
||||
g_runtime_state.wait_long_press_start_time = 0;
|
||||
g_runtime_state.consecutive_press_count = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 按键松开
|
||||
uint32_t press_duration = current_time - press_start_time[i];
|
||||
@@ -224,6 +253,15 @@ void handle_key_press(int key_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果是第一个按键且设备已绑定,检测连续按键(用于强制解绑)
|
||||
if (key_id == 0 && g_persistent_state.is_bound) {
|
||||
if (check_consecutive_press(key_id)) {
|
||||
e_printf("检测到连续4次按键,等待长按10秒执行强制解绑\r\n");
|
||||
// 不执行正常的开关切换操作,等待长按
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 正常模式下切换开关状态
|
||||
bool current_state = g_persistent_state.switches[key_id].switch_on;
|
||||
update_switch_state(key_id, !current_state);
|
||||
@@ -237,21 +275,35 @@ void handle_key_long_press(int key_id) {
|
||||
|
||||
e_printf("处理按键%d 长按事件\r\n", key_id + 1);
|
||||
|
||||
// 只有第一个按键支持长按进入配网模式
|
||||
// 只有第一个按键支持长按进入配网模式或强制解绑
|
||||
if (key_id == 0) {
|
||||
e_printf("长按第一个按键,检查配网条件\r\n");
|
||||
e_printf("长按第一个按键,检查操作条件\r\n");
|
||||
|
||||
// 只有在正常模式下且设备未绑定时才能进入配网模式
|
||||
if (g_runtime_state.mode == MODE_NORMAL && !g_persistent_state.is_bound) {
|
||||
extern int g_config_key_id;
|
||||
g_config_key_id = key_id; // 设置触发配网的按键ID
|
||||
enter_config_mode();
|
||||
} else {
|
||||
if (g_persistent_state.is_bound) {
|
||||
e_printf("设备已绑定,不能进入配网模式\r\n");
|
||||
// 检查设备状态并执行相应操作
|
||||
if (g_runtime_state.mode == MODE_NORMAL) {
|
||||
if (!g_persistent_state.is_bound) {
|
||||
// 未绑定设备:直接进入配网模式
|
||||
e_printf("设备未绑定,进入配网模式\r\n");
|
||||
extern int g_config_key_id;
|
||||
g_config_key_id = key_id; // 设置触发配网的按键ID
|
||||
enter_config_mode();
|
||||
} else {
|
||||
e_printf("非正常模式,不能进入配网模式\r\n");
|
||||
// 已绑定设备:检查是否在等待长按状态(强制解绑)
|
||||
if (g_runtime_state.waiting_long_press) {
|
||||
// 执行强制解绑
|
||||
e_printf("检测到强制解绑条件:连续4次短按+长按10秒,执行强制解绑\r\n");
|
||||
// 清除等待状态
|
||||
g_runtime_state.waiting_long_press = false;
|
||||
g_runtime_state.wait_long_press_start_time = 0;
|
||||
g_runtime_state.consecutive_press_count = 0;
|
||||
perform_factory_reset_and_reboot();
|
||||
} else {
|
||||
// 普通长按:只有未绑定设备才能配网,已绑定设备需要连续4次短按后长按
|
||||
e_printf("设备已绑定,需要先连续按4次再长按10秒才能强制解绑\r\n");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
e_printf("非正常模式,不能进入配网模式或执行解绑\r\n");
|
||||
}
|
||||
} else {
|
||||
e_printf("非第一个按键的长按,忽略\r\n");
|
||||
@@ -297,4 +349,75 @@ void fast_report_switch(int switch_id) {
|
||||
// 快速上报总开关状态(兼容旧接口,内部使用异步上报)
|
||||
void fast_report_master_switch(void) {
|
||||
fast_report_master_switch_async();
|
||||
}
|
||||
|
||||
//====================== 强制解绑连续按键检测 ======================
|
||||
|
||||
// 检测连续按键(返回true表示达到连续按键条件,可以等待长按)
|
||||
bool check_consecutive_press(int key_id) {
|
||||
// 只有第一个按键支持强制解绑
|
||||
if (key_id != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t current_time = hfsys_get_time();
|
||||
|
||||
// 如果是首次按键或者超时,重置计数
|
||||
if (g_runtime_state.consecutive_press_count == 0 ||
|
||||
(current_time - g_runtime_state.last_press_time) > CONSECUTIVE_PRESS_TIMEOUT_MS) {
|
||||
|
||||
g_runtime_state.consecutive_press_count = 1;
|
||||
g_runtime_state.first_press_time = current_time;
|
||||
g_runtime_state.last_press_time = current_time;
|
||||
g_runtime_state.waiting_long_press = false;
|
||||
|
||||
e_printf("连续按键检测:第1次按键\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 增加按键计数
|
||||
g_runtime_state.consecutive_press_count++;
|
||||
g_runtime_state.last_press_time = current_time;
|
||||
|
||||
e_printf("连续按键检测:第%d次按键\r\n", g_runtime_state.consecutive_press_count);
|
||||
|
||||
// 检查是否达到连续按键次数
|
||||
if (g_runtime_state.consecutive_press_count >= CONSECUTIVE_PRESS_COUNT) {
|
||||
uint32_t total_time = current_time - g_runtime_state.first_press_time;
|
||||
e_printf("连续按键检测完成:%d次按键在%ums内完成\r\n",
|
||||
g_runtime_state.consecutive_press_count, total_time);
|
||||
|
||||
// 设置等待长按标志和开始时间
|
||||
g_runtime_state.waiting_long_press = true;
|
||||
g_runtime_state.wait_long_press_start_time = current_time;
|
||||
|
||||
// 重置连续按键计数,为下次检测做准备
|
||||
g_runtime_state.consecutive_press_count = 0;
|
||||
|
||||
e_printf("开始等待长按,3秒内必须开始长按否则超时\r\n");
|
||||
return true; // 可以等待长按了
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查强制解绑超时
|
||||
void check_force_unbind_timeout(void) {
|
||||
// 只有在等待长按状态下且设置了超时开始时间才检查超时
|
||||
if (!g_runtime_state.waiting_long_press || g_runtime_state.wait_long_press_start_time == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t current_time = hfsys_get_time();
|
||||
uint32_t wait_time = current_time - g_runtime_state.wait_long_press_start_time;
|
||||
|
||||
// 检查是否超时(3秒)
|
||||
if (wait_time >= FORCE_UNBIND_WAIT_TIMEOUT_MS) {
|
||||
e_printf("强制解绑超时:等待长按超过3秒,退出检测流程\r\n");
|
||||
|
||||
// 清除等待状态
|
||||
g_runtime_state.waiting_long_press = false;
|
||||
g_runtime_state.wait_long_press_start_time = 0;
|
||||
g_runtime_state.consecutive_press_count = 0; // 完全重置
|
||||
}
|
||||
}
|
||||
@@ -359,21 +359,76 @@ static bool write_device_data_to_addr(uint32_t addr, uint8_t* data, uint32_t len
|
||||
}
|
||||
|
||||
|
||||
// 从V1版本数据升级到V2版本
|
||||
static void upgrade_from_v1_to_v2(device_persistent_state_v1_t* v1_state, device_persistent_state_t* v2_state) {
|
||||
e_printf("检测到V1版本数据,升级到V2版本\r\n");
|
||||
|
||||
// 复制V1的所有字段到V2
|
||||
memcpy(v2_state->switches, v1_state->switches, sizeof(v1_state->switches));
|
||||
v2_state->master_switch = v1_state->master_switch;
|
||||
v2_state->panel_led = v1_state->panel_led;
|
||||
v2_state->is_bound = v1_state->is_bound;
|
||||
v2_state->is_first_boot = v1_state->is_first_boot;
|
||||
|
||||
// 初始化V2新增的记忆功能字段
|
||||
v2_state->has_memory_state = false;
|
||||
memset(v2_state->memory_switches, 0, sizeof(v2_state->memory_switches));
|
||||
|
||||
// 更新版本信息
|
||||
v2_state->magic = DEVICE_DATA_MAGIC;
|
||||
v2_state->version = DEVICE_DATA_VERSION_V2;
|
||||
memset(v2_state->reserved, 0, sizeof(v2_state->reserved));
|
||||
|
||||
e_printf("V1数据升级完成\r\n");
|
||||
}
|
||||
|
||||
// 从 Flash 加载持久化状态
|
||||
int load_persistent_state(void) {
|
||||
int ret = 0;
|
||||
device_persistent_state_t state;
|
||||
device_persistent_state_v1_t v1_state;
|
||||
bool valid = false;
|
||||
bool is_v1_data = false;
|
||||
|
||||
// 尝试读取主数据区
|
||||
// 先尝试读取V2版本数据
|
||||
valid = read_device_data_from_addr(DEVICE_DATA_FLASH_ADDR, (uint8_t*)&state, sizeof(state));
|
||||
|
||||
// 如果主数据区无效,尝试读取备份区
|
||||
if (!valid) {
|
||||
valid = read_device_data_from_addr(DEVICE_DATA_BACKUP_ADDR, (uint8_t*)&state, sizeof(state));
|
||||
}
|
||||
|
||||
// 两个存储区都失败,使用默认状态
|
||||
// 如果V2读取失败,尝试读取V1版本数据
|
||||
if (!valid) {
|
||||
e_printf("V2数据读取失败,尝试读取V1版本数据\r\n");
|
||||
valid = read_device_data_from_addr(DEVICE_DATA_FLASH_ADDR, (uint8_t*)&v1_state, sizeof(v1_state));
|
||||
if (!valid) {
|
||||
valid = read_device_data_from_addr(DEVICE_DATA_BACKUP_ADDR, (uint8_t*)&v1_state, sizeof(v1_state));
|
||||
}
|
||||
|
||||
if (valid) {
|
||||
// 检查是否确实是V1版本数据
|
||||
if (v1_state.magic == DEVICE_DATA_MAGIC && v1_state.version == DEVICE_DATA_VERSION_V1) {
|
||||
is_v1_data = true;
|
||||
e_printf("检测到V1版本数据\r\n");
|
||||
} else {
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 检查V2数据版本
|
||||
if (state.version != DEVICE_DATA_VERSION_V2) {
|
||||
if (state.version == DEVICE_DATA_VERSION_V1) {
|
||||
e_printf("读取到的数据是V1版本格式,需要升级\r\n");
|
||||
// 将读取的数据重新解释为V1格式
|
||||
memcpy(&v1_state, &state, sizeof(v1_state));
|
||||
is_v1_data = true;
|
||||
} else {
|
||||
e_printf("未知的数据版本: %d,使用默认状态\r\n", state.version);
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 所有存储区都失败,使用默认状态
|
||||
if (!valid) {
|
||||
e_printf("存储区数据损坏,使用默认状态\r\n");
|
||||
reset_persistent_state();
|
||||
@@ -381,21 +436,29 @@ int load_persistent_state(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 更新持久化状态
|
||||
e_printf("持久化状态恢复:\r\n");
|
||||
e_printf("首次启动: %d => %d\r\n", g_persistent_state.is_first_boot, state.is_first_boot);
|
||||
e_printf("配网状态: %d => %d\r\n", g_persistent_state.is_bound, state.is_bound);
|
||||
e_printf("总开关: %d => %d\r\n", g_persistent_state.master_switch, state.master_switch);
|
||||
e_printf("面板背光: %d => %d\r\n", g_persistent_state.panel_led, state.panel_led);
|
||||
|
||||
for (int i = 0; i < SWITCH_COUNT; i++) {
|
||||
e_printf("开关%d(%s): %d => %d, LED%d: %d => %d\r\n",
|
||||
i + 1, state.switches[i].name,
|
||||
g_persistent_state.switches[i].switch_on, state.switches[i].switch_on,
|
||||
i + 1, g_persistent_state.switches[i].led_state, state.switches[i].led_state);
|
||||
// 如果是V1数据,需要升级到V2
|
||||
if (is_v1_data) {
|
||||
upgrade_from_v1_to_v2(&v1_state, &state);
|
||||
// 升级后立即保存新版本数据
|
||||
memcpy(&g_persistent_state, &state, sizeof(device_persistent_state_t));
|
||||
save_persistent_state();
|
||||
} else {
|
||||
// 直接使用V2数据
|
||||
memcpy(&g_persistent_state, &state, sizeof(device_persistent_state_t));
|
||||
}
|
||||
|
||||
memcpy(&g_persistent_state, &state, sizeof(device_persistent_state_t));
|
||||
// 打印恢复的状态信息
|
||||
e_printf("持久化状态恢复 (版本%s):\r\n", is_v1_data ? "V1->V2" : "V2");
|
||||
e_printf("首次启动: %d, 配网状态: %d\r\n", g_persistent_state.is_first_boot, g_persistent_state.is_bound);
|
||||
e_printf("总开关: %d, 面板背光: %d\r\n", g_persistent_state.master_switch, g_persistent_state.panel_led);
|
||||
e_printf("记忆功能: %s\r\n", g_persistent_state.has_memory_state ? "有记忆" : "无记忆");
|
||||
|
||||
for (int i = 0; i < SWITCH_COUNT; i++) {
|
||||
e_printf("开关%d(%s): %s, LED: %s\r\n",
|
||||
i + 1, g_persistent_state.switches[i].name,
|
||||
g_persistent_state.switches[i].switch_on ? "开" : "关",
|
||||
g_persistent_state.switches[i].led_state ? "白灯" : "黄灯");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -581,6 +644,10 @@ void reset_persistent_state(void) {
|
||||
g_persistent_state.is_bound = false; // 设备未绑定
|
||||
g_persistent_state.is_first_boot = true; // 标记为首次启动
|
||||
|
||||
// 清除记忆状态
|
||||
g_persistent_state.has_memory_state = false;
|
||||
memset(g_persistent_state.memory_switches, 0, sizeof(g_persistent_state.memory_switches));
|
||||
|
||||
// 所有开关默认关闭,所有LED默认黄灯,初始化默认名字
|
||||
for (int i = 0; i < SWITCH_COUNT; i++) {
|
||||
g_persistent_state.switches[i].switch_on = false; // 开关关闭
|
||||
@@ -604,6 +671,13 @@ void init_runtime_state(void) {
|
||||
g_runtime_state.factory_test_running = false;
|
||||
g_runtime_state.last_save_time = 0;
|
||||
|
||||
// 初始化强制解绑连续按键检测状态
|
||||
g_runtime_state.consecutive_press_count = 0;
|
||||
g_runtime_state.first_press_time = 0;
|
||||
g_runtime_state.last_press_time = 0;
|
||||
g_runtime_state.waiting_long_press = false;
|
||||
g_runtime_state.wait_long_press_start_time = 0;
|
||||
|
||||
// 初始化所有开关的运行时状态
|
||||
for (int i = 0; i < SWITCH_COUNT; i++) {
|
||||
g_runtime_state.switches[i].physical_key = true; // 按键松开
|
||||
@@ -862,9 +936,11 @@ int switch_panel_main(void) {
|
||||
}
|
||||
} else {
|
||||
e_printf("设备已绑定,正常运行\r\n");
|
||||
// 设备已绑定时禁用蓝牙模式,使用云端控制
|
||||
extern void switch_panel_ble_disable(void);
|
||||
switch_panel_ble_disable();
|
||||
if (!g_runtime_state.is_online)
|
||||
{
|
||||
switch_panel_ble_enable();
|
||||
start_hilink_ble_net_config(0xFFFFFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
e_printf("SORONTEK智能面板初始化完成\r\n");
|
||||
|
||||
729
build/script/utils/mem_stats.py
Executable file
729
build/script/utils/mem_stats.py
Executable file
@@ -0,0 +1,729 @@
|
||||
#!/usr/bin/env python3
|
||||
# encoding=utf-8
|
||||
# ============================================================================
|
||||
# @brief Mem Script file
|
||||
# Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2022-2022. All rights reserved.
|
||||
# ============================================================================
|
||||
import os
|
||||
import sys
|
||||
import errno
|
||||
import re
|
||||
|
||||
# Security Core - Test Suite
|
||||
# --------------------------
|
||||
#
|
||||
# Section Start Addr Size Length
|
||||
# ------- ---------- ------ -------
|
||||
#
|
||||
# Flash 0x10000000 0x31f80 0x13360 = 78688
|
||||
# startup 0x10000000 0xa0
|
||||
# .flash_version 0x100000c0 0x28
|
||||
# .text 0x10000100 0x118b4
|
||||
# .ARM.exidx 0x100119b4 0xf08
|
||||
# .ARM.extab 0x100128bc 0x924
|
||||
# .ram_text 0x100131e0 0x88
|
||||
# .data 0x10013268 0xf8
|
||||
#
|
||||
# SRAM 0x38000000 0x2800 0x27A0 = 10144
|
||||
# .stacks 0x38000000 0x400
|
||||
# .ramtext 0x38000400 0x88 load address 0x100131e0
|
||||
# .data 0x38000488 0xf8 load address 0x10013268
|
||||
# .bss 0x38000580 0x1e34
|
||||
# .preserve 0x380023b4 0x9c
|
||||
# .heap 0x38002450 0x0
|
||||
# .ipc_mailbox 0x38002700 0xa0
|
||||
|
||||
flag_names = ["CONTENTS", "ALLOC", "LOAD", "READONLY", "CODE", "DATA", "DEBUGGING"]
|
||||
|
||||
|
||||
class Section:
|
||||
def __init__(self):
|
||||
self.name = ""
|
||||
self.size = 0
|
||||
self.vma = 0
|
||||
self.lma = 0
|
||||
self.flags = ""
|
||||
self.exclude = False
|
||||
|
||||
def get_name(self):
|
||||
return self.name
|
||||
|
||||
def get_size(self):
|
||||
return self.size
|
||||
|
||||
def is_loaded(self):
|
||||
if not self.exclude:
|
||||
if self.lma != self.vma:
|
||||
if "LOAD" in self.flags:
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_load_section(self):
|
||||
load_section = Section()
|
||||
load_section.name = self.name
|
||||
load_section.size = self.size
|
||||
load_section.vma = self.lma
|
||||
load_section.lma = self.lma
|
||||
load_section.flags = self.flags
|
||||
return load_section
|
||||
|
||||
def display(self):
|
||||
size_str = "%d" % self.size
|
||||
if self.vma == self.lma:
|
||||
print(
|
||||
" %-16s 0x%08X %10s %8s "
|
||||
% (self.name, self.vma, "", size_str)
|
||||
)
|
||||
else:
|
||||
print(
|
||||
" %-16s 0x%08X %10s %8s load address 0x%X"
|
||||
% (self.name, self.vma, "", size_str, self.lma)
|
||||
)
|
||||
|
||||
def display_raw(self):
|
||||
print(
|
||||
"<%-16s 0x%08X 0x%08X 0x%08X %s>"
|
||||
% (self.name, self.vma, self.lma, self.size, self.flags)
|
||||
)
|
||||
|
||||
def get_all_size(self, size_list):
|
||||
temp = "{0}:{1}:{2}".format(self.name, self.vma, self.size)
|
||||
size_list.append(temp)
|
||||
|
||||
|
||||
class Region:
|
||||
def __init__(self, name, origin, length):
|
||||
self.name = name
|
||||
self.origin = origin
|
||||
self.length = length
|
||||
self.sections = []
|
||||
|
||||
def get_name(self):
|
||||
return self.name
|
||||
|
||||
# Get used_size or region length, if it does not contain any sections
|
||||
def get_size(self):
|
||||
used_size = self.used_size()
|
||||
if used_size > 0:
|
||||
return used_size
|
||||
return self.length
|
||||
|
||||
def add_section(self, section):
|
||||
if not section.exclude:
|
||||
if (section.vma >= self.origin) and (
|
||||
section.vma < (self.origin + self.length)
|
||||
):
|
||||
self.sections.append(section)
|
||||
return True
|
||||
return False
|
||||
|
||||
def find_section(self, name):
|
||||
if name in self.name:
|
||||
return self
|
||||
|
||||
for section in self.sections:
|
||||
if name in section.name:
|
||||
return Region(section.name, section.vma, section.size)
|
||||
return None
|
||||
|
||||
# Calculate region size used based on contained sections
|
||||
def used_size(self):
|
||||
# Begin with start at end of memory region...
|
||||
start = self.origin + self.length
|
||||
end = self.origin # and end at beginning
|
||||
for section in self.sections:
|
||||
if section.vma < start:
|
||||
start = section.vma
|
||||
if (section.vma + section.size) > end:
|
||||
end = section.vma + section.size
|
||||
if start < end:
|
||||
return end - start # Beginning of first section to end of last
|
||||
else:
|
||||
return 0 # No sections cotained by this memory region
|
||||
|
||||
def display(self):
|
||||
used_size = self.used_size()
|
||||
if used_size > 0:
|
||||
used_size_str = "0x%X" % used_size
|
||||
length_str = "0x%X" % self.length
|
||||
print(" ")
|
||||
print(
|
||||
" %-18s 0x%08X %10s %8s = %d"
|
||||
% (self.name, self.origin, length_str, used_size_str, used_size)
|
||||
)
|
||||
for section in self.sections:
|
||||
section.display()
|
||||
|
||||
def get_section_size(self, section_name):
|
||||
size_list = []
|
||||
for section in self.sections:
|
||||
section.get_all_size(size_list)
|
||||
for val in size_list:
|
||||
if section_name in val:
|
||||
return int(val.split(":")[2])
|
||||
return 0
|
||||
|
||||
def get_section_used_size(self, section_name):
|
||||
size_list = []
|
||||
for section in self.sections:
|
||||
section.get_all_size(size_list)
|
||||
for i, x in enumerate(size_list):
|
||||
if section_name in x and i != (len(size_list) - 1):
|
||||
return x.split(":")[-1]
|
||||
return 0
|
||||
|
||||
|
||||
class Memory:
|
||||
def __init__(self):
|
||||
self.regions = []
|
||||
self.bth_list = [0] * 21
|
||||
self.btc_list = [0] * 21
|
||||
self.plt_list = [0] * 21
|
||||
self.all_size = 0
|
||||
self.filename = ""
|
||||
self.chipname = ""
|
||||
self.all_code_rodata_list = 0
|
||||
self.all_data_list = 0
|
||||
self.all_bss_list = 0
|
||||
self.all_memory_size = 985088
|
||||
|
||||
def add_region(self, region):
|
||||
self.regions.append(region)
|
||||
|
||||
def add_section(self, section):
|
||||
for region in self.regions:
|
||||
if region.add_section(section):
|
||||
return True
|
||||
return False
|
||||
|
||||
def find_section(self, name):
|
||||
for region in self.regions:
|
||||
section = region.find_section(name)
|
||||
if section is not None:
|
||||
return section
|
||||
return None
|
||||
|
||||
def display(self):
|
||||
print(" %-18s %10s %10s %8s" % ("Section", "Start Addr", "Size", "Used"))
|
||||
print(
|
||||
" %-18s %10s %10s %8s"
|
||||
% ("------------------", "----------", "----------", "--------")
|
||||
)
|
||||
for region in self.regions:
|
||||
region.display()
|
||||
|
||||
def summary_display(self, lst_file_name):
|
||||
print(" ")
|
||||
print(
|
||||
" %-18s %10s %10s %8s %8s" % ("Section", "Total", "BTH", "BTC", "PLT")
|
||||
)
|
||||
print(
|
||||
" %-18s %10s %10s %8s %8s"
|
||||
% ("------------------", "----------", "----------", "--------", "--------")
|
||||
)
|
||||
print(" ")
|
||||
self.memory_display(lst_file_name)
|
||||
print(" %-18s %10s %10s %8s" % ("Section", "Start Addr", "Size", "Used"))
|
||||
print(
|
||||
" %-18s %10s %10s %8s"
|
||||
% ("------------------", "----------", "----------", "--------")
|
||||
)
|
||||
for region in self.regions:
|
||||
region.display()
|
||||
|
||||
def get_region_section_size(self, region_name, section_name):
|
||||
for region in self.regions:
|
||||
if region_name in region.name:
|
||||
return region.get_section_size(section_name)
|
||||
return 0
|
||||
|
||||
def get_region_section_used_size(self, region_name, section_name):
|
||||
for region in self.regions:
|
||||
if region_name in region.name:
|
||||
return region.get_section_used_size(section_name)
|
||||
|
||||
def set_init_param(self, name, index, value):
|
||||
if name in "btc_list":
|
||||
self.btc_list[index] = value
|
||||
elif name in "plt_list":
|
||||
self.plt_list[index] = value
|
||||
elif name in "bth_list":
|
||||
self.bth_list[index] = value
|
||||
|
||||
|
||||
# Used to aid parsing lines of text from a Lst file
|
||||
class SectionLine:
|
||||
def __init__(self, line):
|
||||
self.line = line
|
||||
|
||||
def update(self, line):
|
||||
self.line = line
|
||||
|
||||
def append(self, line):
|
||||
self.line += line
|
||||
|
||||
def length(self):
|
||||
return len(self.line)
|
||||
|
||||
def find_space(self, pos):
|
||||
length = len(self.line)
|
||||
while (pos < length) and not self.line[pos].isspace():
|
||||
pos = pos + 1
|
||||
if pos < length:
|
||||
return pos
|
||||
return length
|
||||
|
||||
def find_nonspace(self, pos):
|
||||
length = len(self.line)
|
||||
while (pos < length) and self.line[pos].isspace():
|
||||
pos = pos + 1
|
||||
if pos < length:
|
||||
return pos
|
||||
return length
|
||||
|
||||
def get_word(self, index):
|
||||
start = self.find_nonspace(0)
|
||||
end = self.find_space(start)
|
||||
while index > 0:
|
||||
index = index - 1
|
||||
start = self.find_nonspace(end)
|
||||
end = self.find_space(start)
|
||||
return self.line[start:end]
|
||||
|
||||
def contains(self, line):
|
||||
if line in self.line:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class LstFile:
|
||||
def __init__(self, fp_filename, filename, lds_file, chip_name, chip_version):
|
||||
self.file = fp_filename
|
||||
self.line = SectionLine("")
|
||||
self.chip_name = chip_name
|
||||
self.memory = self.create_memory_map(lds_file)
|
||||
self.memory.chipname = chip_name
|
||||
self.filename = filename
|
||||
self.chip_version = chip_version
|
||||
|
||||
def __del__(self):
|
||||
self.file.close()
|
||||
|
||||
def valid_section_line(self):
|
||||
if self.line.length() > 0:
|
||||
if self.line.get_word(0).isdigit():
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_next_section(self):
|
||||
if self.read_section_line():
|
||||
if self.valid_section_line():
|
||||
section = self.parse_section_line()
|
||||
if section is not None:
|
||||
# Move this knowledge into Section?
|
||||
# Not a physical section
|
||||
if (
|
||||
("READONLY" in section.flags)
|
||||
and ("CODE" not in section.flags)
|
||||
and ("DATA" not in section.flags)
|
||||
):
|
||||
section.exclude = True
|
||||
# Debugging sections do not appear in binary
|
||||
if "DEBUGGING" in section.flags:
|
||||
section.exclude = True
|
||||
# Section might have a phantom load address
|
||||
if (section.lma != section.vma) and ("LOAD" not in section.flags):
|
||||
section.lma = section.vma
|
||||
return section
|
||||
return None
|
||||
|
||||
def get_first_section(self):
|
||||
self.file.seek(0)
|
||||
if self.find_file_sections():
|
||||
return self.get_next_section()
|
||||
return None
|
||||
|
||||
def find_file_sections(self):
|
||||
file_line = self.file.readline()
|
||||
while len(file_line) > 0:
|
||||
if file_line.find("Sections:") == 0:
|
||||
return True
|
||||
file_line = self.file.readline()
|
||||
return False
|
||||
|
||||
def read_section_line(self):
|
||||
file_line = SectionLine(self.file.readline())
|
||||
while file_line.length() > 0:
|
||||
if file_line.contains("SYMBOL TABLE:"):
|
||||
return False
|
||||
|
||||
# Use split instead? # Place in a function
|
||||
if file_line.get_word(0).isdigit():
|
||||
file_line.append(self.file.readline())
|
||||
self.line = file_line
|
||||
return True
|
||||
else:
|
||||
file_line.update(self.file.readline())
|
||||
return False
|
||||
|
||||
def parse_section_line(self):
|
||||
# Use split instead? # Place in a function
|
||||
if self.line.get_word(0).isdigit():
|
||||
section = Section()
|
||||
section.name = self.line.get_word(1)
|
||||
section.size = int(self.line.get_word(2), 16)
|
||||
section.vma = int(self.line.get_word(3), 16)
|
||||
section.lma = int(self.line.get_word(4), 16)
|
||||
section.flags = ""
|
||||
for flag_name in flag_names:
|
||||
if self.line.contains(flag_name):
|
||||
section.flags = "%s_%s_" % (section.flags, flag_name)
|
||||
return section
|
||||
return None
|
||||
|
||||
def create_memory_map(self, lds_file):
|
||||
memory = Memory()
|
||||
with open(lds_file, "r") as f:
|
||||
text = f.read()
|
||||
mem_map = re.findall(
|
||||
r"([A-Za-z0-9_]*?) *: *ORIGIN *= *([\(\)0-9A-Fa-f/\+\-x* ]*), *LENGTH *= *([\(\)0-9A-Fa-f/\+\-x* ]*)",
|
||||
text,
|
||||
)
|
||||
for item in mem_map:
|
||||
memory.add_region(
|
||||
Region(item[0], int(eval(item[1])), int(eval(item[2])))
|
||||
)
|
||||
|
||||
memory.add_region(Region("Unexpected", 0x00000000, 0xFFFFFFFF))
|
||||
|
||||
return memory
|
||||
|
||||
# Should this create and return a ProcessedLstFile, which contains the two
|
||||
# function below?
|
||||
def process(self):
|
||||
section = self.get_first_section()
|
||||
while section is not None:
|
||||
if self.memory.add_section(section):
|
||||
if section.is_loaded():
|
||||
load_section = section.get_load_section()
|
||||
self.memory.add_section(load_section)
|
||||
section = self.get_next_section()
|
||||
|
||||
def find_section(self, name):
|
||||
return self.memory.find_section(name)
|
||||
|
||||
def display(self):
|
||||
print("\n Memory Usage Summary...")
|
||||
self.memory.filename = self.filename
|
||||
self.memory.display()
|
||||
print("\n ====================================================\n")
|
||||
|
||||
|
||||
display_depth = {
|
||||
".": 99,
|
||||
"platform": 3,
|
||||
"drivers": 6,
|
||||
"hal": 6,
|
||||
}
|
||||
min_display_level = 1
|
||||
|
||||
|
||||
class SectionTree:
|
||||
last_display_level = 0
|
||||
last_section_size = 0
|
||||
|
||||
def __init__(self, name, level):
|
||||
self.root = name
|
||||
self.level = level
|
||||
self.size = 0
|
||||
self.children = []
|
||||
|
||||
def get_name(self):
|
||||
return self.root
|
||||
|
||||
def get_size(self):
|
||||
return self.size
|
||||
|
||||
def get_children(self):
|
||||
return self.children
|
||||
|
||||
def find(self, name):
|
||||
if self.root == name:
|
||||
return self
|
||||
for child in self.children:
|
||||
found_tree = child.find(name)
|
||||
if found_tree is not None:
|
||||
return found_tree
|
||||
return None
|
||||
|
||||
def add_content(self, size, content):
|
||||
assert len(content) > 0
|
||||
|
||||
if size > 0:
|
||||
self.size += size
|
||||
|
||||
if len(content) > 1:
|
||||
content_added = False
|
||||
for child in self.children:
|
||||
if child.root == content[0]:
|
||||
child.add_content(size, content[1:])
|
||||
content_added = True
|
||||
if not content_added:
|
||||
new_child = SectionTree(content[0], self.level + 1)
|
||||
self.children.append(new_child)
|
||||
new_child.add_content(size, content[1:])
|
||||
|
||||
def display(self, depth):
|
||||
if self.root in display_depth:
|
||||
depth = display_depth[self.root]
|
||||
if depth >= 0:
|
||||
if self.level < SectionTree.last_display_level:
|
||||
print()
|
||||
SectionTree.last_section_size = 0
|
||||
SectionTree.last_display_level = self.level
|
||||
|
||||
if self.level == min_display_level:
|
||||
print("\n Section Total Size")
|
||||
print("\n -------------------------------- -------- -----")
|
||||
print("\n")
|
||||
|
||||
if self.level >= min_display_level:
|
||||
if self.root.endswith(".c") or self.root.endswith(".s"):
|
||||
name = self.root[: len(self.root) - 2]
|
||||
else:
|
||||
name = self.root
|
||||
|
||||
# A top level section name
|
||||
if self.level == min_display_level:
|
||||
SectionTree.last_section_size = self.size
|
||||
print(
|
||||
" %-32s %8d"
|
||||
% (((self.level - min_display_level) * " ") + name, self.size)
|
||||
)
|
||||
print()
|
||||
# Last entry being dealt with so show its size
|
||||
elif (depth == 0) or (len(self.children) == 0):
|
||||
SectionTree.last_section_size = 0
|
||||
print(
|
||||
" %-42s %8d"
|
||||
% (((self.level - min_display_level) * " ") + name, self.size)
|
||||
)
|
||||
# Has children and size not the same as last size displayed
|
||||
elif len(self.children) > 0 and (
|
||||
SectionTree.last_section_size != self.size
|
||||
):
|
||||
SectionTree.last_section_size = self.size
|
||||
print(
|
||||
" %-32s %8d"
|
||||
% (((self.level - min_display_level) * " ") + name, self.size)
|
||||
)
|
||||
|
||||
else:
|
||||
print(
|
||||
" %-42s" % (((self.level - min_display_level) * " ") + name)
|
||||
)
|
||||
|
||||
if depth > 0:
|
||||
for child in self.children:
|
||||
child.display(depth - 1)
|
||||
|
||||
def get_section_child(
|
||||
self, depth, section_name, tree_data_list, start_flag, end_flag
|
||||
):
|
||||
if self.root in display_depth:
|
||||
depth = display_depth[self.root]
|
||||
if depth >= 0:
|
||||
if self.level < SectionTree.last_display_level:
|
||||
SectionTree.last_section_size = 0
|
||||
SectionTree.last_display_level = self.level
|
||||
|
||||
if self.level == min_display_level:
|
||||
if start_flag[-1] == 1:
|
||||
end_flag[-1] = 1
|
||||
|
||||
if start_flag[-1] and end_flag[-1]:
|
||||
return 1
|
||||
|
||||
if self.level >= min_display_level:
|
||||
if self.root.endswith(".c") or self.root.endswith(".s"):
|
||||
name = self.root[: len(self.root) - 2]
|
||||
else:
|
||||
name = self.root
|
||||
|
||||
if self.level == min_display_level:
|
||||
SectionTree.last_section_size = self.size
|
||||
|
||||
if name == section_name:
|
||||
tree_data_list.append(["{0}:{1}".format(name, self.size)])
|
||||
start_flag[-1] = 1
|
||||
|
||||
# Last entry being dealt with so show its size
|
||||
elif (depth == 0) or (len(self.children) == 0):
|
||||
SectionTree.last_section_size = 0
|
||||
|
||||
if start_flag[-1] == 1:
|
||||
tree_data_list[-1].append("{0}:{1}".format(name, self.size))
|
||||
# Has children and size not the same as last size displayed
|
||||
elif len(self.children) > 0 and (
|
||||
SectionTree.last_section_size != self.size
|
||||
):
|
||||
SectionTree.last_section_size = self.size
|
||||
|
||||
if start_flag[-1] == 1:
|
||||
tree_data_list[-1].append("{0}:{1}".format(name, self.size))
|
||||
|
||||
else:
|
||||
if start_flag[-1] == 1:
|
||||
tree_data_list[-1].append("{0}:{1}".format(name, ""))
|
||||
|
||||
if depth > 0:
|
||||
for child in self.children:
|
||||
if child.get_section_child(
|
||||
depth - 1, section_name, tree_data_list, start_flag, end_flag
|
||||
):
|
||||
return 1
|
||||
|
||||
|
||||
class DuFile:
|
||||
def __init__(self, fp_filename):
|
||||
self.file = fp_filename
|
||||
# Construct empty tree with '.' as root, since all pathnames in .du
|
||||
# file
|
||||
# begin in the same way
|
||||
self.section_tree = SectionTree(".", 0)
|
||||
|
||||
def __del__(self):
|
||||
self.file.close()
|
||||
|
||||
def get_next_section_content(self):
|
||||
# e.g. "216
|
||||
# ./.text/drivers/non-os/ipc/shared/ipc.c/ipc_send_message"
|
||||
file_line = SectionLine(self.file.readline())
|
||||
if file_line.length() > 0:
|
||||
# Obtains size e.g. "216"
|
||||
size = file_line.get_word(0)
|
||||
# Last line of .du file begins with non-numeric characters
|
||||
if size.isdigit():
|
||||
size = int(size)
|
||||
# Generates a list of words, separated by '/' e.g.
|
||||
# ".",".text","drivers","non-os","ipc" etc
|
||||
content = file_line.get_word(1).split(os.sep)
|
||||
return (size, content)
|
||||
return (0, None)
|
||||
|
||||
def get_first_section_content(self):
|
||||
# Point to beginning of file
|
||||
self.file.seek(0)
|
||||
return self.get_next_section_content()
|
||||
|
||||
# Should this create and return a ProcessedDuFile, which will contain the
|
||||
# two function below?
|
||||
def process(self):
|
||||
# Scan entire file contents
|
||||
(size, content) = self.get_first_section_content()
|
||||
while content is not None:
|
||||
self.section_tree.add_content(size, content[1:])
|
||||
(size, content) = self.get_next_section_content()
|
||||
|
||||
def find_section(self, name):
|
||||
return self.section_tree.find(name)
|
||||
|
||||
def display(self):
|
||||
print("\n Memory Usage Details...")
|
||||
# Use a 0 depth here as it will be overridden by entries in
|
||||
# display_depth
|
||||
self.section_tree.display(0)
|
||||
print("\n ====================================================\n")
|
||||
|
||||
def get_tree_size(self, section_name, path_name):
|
||||
tree_data_list = []
|
||||
flag_list = []
|
||||
start_flag = [0]
|
||||
end_flag = [0]
|
||||
self.section_tree.get_section_child(
|
||||
0, section_name, tree_data_list, start_flag, end_flag
|
||||
)
|
||||
|
||||
for i in range(len(tree_data_list[-1])):
|
||||
if path_name[0] == tree_data_list[-1][i].split(":")[0]:
|
||||
flag_list.append(1)
|
||||
for path_index in range(len(path_name[1:])):
|
||||
if (
|
||||
path_name[1:][path_index]
|
||||
== tree_data_list[-1][i + 1 + path_index].split(":")[0]
|
||||
):
|
||||
flag_list.append(1)
|
||||
else:
|
||||
flag_list.append(0)
|
||||
if len(flag_list) == sum(flag_list):
|
||||
size = tree_data_list[-1][i].split(":")[1]
|
||||
if size == "":
|
||||
size = 0
|
||||
return int(size)
|
||||
else:
|
||||
flag_list = []
|
||||
|
||||
|
||||
def display_mismatches(lst_file, du_file):
|
||||
section_names = [
|
||||
"startup",
|
||||
".flash_version",
|
||||
".text",
|
||||
".ramtext",
|
||||
".data",
|
||||
".bss",
|
||||
".preserve",
|
||||
".sys_status",
|
||||
".ipc_mailbox",
|
||||
"btc_ramtext",
|
||||
"bth_ramtext",
|
||||
"plt_ramtext",
|
||||
"bth_share_ramtext",
|
||||
"btc_data",
|
||||
"bth_data",
|
||||
"plt_data",
|
||||
"btc_bss",
|
||||
"bth_bss",
|
||||
"plt_bss",
|
||||
]
|
||||
|
||||
print(" Mismatched section sizes...\n")
|
||||
for section_name in section_names:
|
||||
lst_section = lst_file.find_section(section_name)
|
||||
du_section = du_file.find_section(section_name)
|
||||
if lst_section is not None and du_section is not None:
|
||||
lst_size = lst_section.get_size()
|
||||
du_size = du_section.get_size()
|
||||
if lst_size != du_size:
|
||||
print(
|
||||
" %12s .lst file = %d (0x%X)" % (section_name, lst_size, lst_size)
|
||||
)
|
||||
print(" %12s .du file = %d (0x%X)" % ("", du_size, du_size))
|
||||
print()
|
||||
print(" ====================================================\n")
|
||||
|
||||
|
||||
def main(lst_file_name, du_file_name, lds_file, chip_name, chip_version=None):
|
||||
with (
|
||||
open(lst_file_name, "r") as fp_lst_file_name,
|
||||
open(du_file_name, "r") as fp_du_file_name,
|
||||
):
|
||||
lst_file = LstFile(
|
||||
fp_lst_file_name, lst_file_name, lds_file, chip_name, chip_version
|
||||
)
|
||||
lst_file.process()
|
||||
du_file = DuFile(fp_du_file_name)
|
||||
du_file.process()
|
||||
|
||||
lst_file.display()
|
||||
|
||||
du_file.display()
|
||||
display_mismatches(lst_file, du_file)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) == 5:
|
||||
# main(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4])
|
||||
pass
|
||||
else:
|
||||
print("Usage: %s <lstfile> <dufile> <chip>" % os.path.basename(sys.argv[0]))
|
||||
@@ -0,0 +1,40 @@
|
||||
#include "stdio_impl.h"
|
||||
#include "pthread_impl.h"
|
||||
|
||||
#ifndef __LITEOS__
|
||||
#ifdef __GNUC__
|
||||
__attribute__((__noinline__))
|
||||
#endif
|
||||
static int locking_putc(int c, FILE *f)
|
||||
{
|
||||
if (a_cas(&f->lock, 0, MAYBE_WAITERS-1)) __lockfile(f);
|
||||
c = putc_unlocked(c, f);
|
||||
if (a_swap(&f->lock, 0) & MAYBE_WAITERS)
|
||||
__wake(&f->lock, 1, 1);
|
||||
return c;
|
||||
}
|
||||
#endif
|
||||
#ifndef _HSF_
|
||||
#define _HSF_
|
||||
#endif
|
||||
static inline int do_putc(int c, FILE *f)
|
||||
{
|
||||
#if defined(_HSF_) && !defined(_PRE_WLAN_FEATURE_MFG_TEST)
|
||||
extern int hf_off_factory_log(void);
|
||||
if(hf_off_factory_log())
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
#ifndef __LITEOS__
|
||||
int l = f->lock;
|
||||
if (l < 0 || l && (l & ~MAYBE_WAITERS) == __pthread_self()->tid)
|
||||
return putc_unlocked(c, f);
|
||||
return locking_putc(c, f);
|
||||
#else
|
||||
int ret;
|
||||
FLOCK(f);
|
||||
ret = putc_unlocked(c, f);
|
||||
FUNLOCK(f);
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
BIN
output/LPT262_hilink-20250724-1.0.3-SR_Switch.fwpkg
Normal file
BIN
output/LPT262_hilink-20250724-1.0.3-SR_Switch.fwpkg
Normal file
Binary file not shown.
BIN
output/LPT262_hilink-SR_Switch-20250722-1.0.1-初始版本.fwpkg
Normal file
BIN
output/LPT262_hilink-SR_Switch-20250722-1.0.1-初始版本.fwpkg
Normal file
Binary file not shown.
BIN
output/LPT262_hilink-SR_Switch-20250803-1.0.4.fwpkg
Executable file
BIN
output/LPT262_hilink-SR_Switch-20250803-1.0.4.fwpkg
Executable file
Binary file not shown.
BIN
output/LPT262_hilink-SR_Switch-20250807-1.0.5.fwpkg
Normal file
BIN
output/LPT262_hilink-SR_Switch-20250807-1.0.5.fwpkg
Normal file
Binary file not shown.
BIN
output/LPT262_hilink-SR_Switch-20250811-1.0.6.fwpkg
Normal file
BIN
output/LPT262_hilink-SR_Switch-20250811-1.0.6.fwpkg
Normal file
Binary file not shown.
BIN
output/package(SR_Switch-LPT262_hilink-20250722-1.0.1-初始版本).zip
Normal file
BIN
output/package(SR_Switch-LPT262_hilink-20250722-1.0.1-初始版本).zip
Normal file
Binary file not shown.
BIN
output/package(SR_Switch-LPT262_hilink-20250724-1.0.3).zip
Normal file
BIN
output/package(SR_Switch-LPT262_hilink-20250724-1.0.3).zip
Normal file
Binary file not shown.
BIN
output/package(SR_Switch-LPT262_hilink-20250803-1.0.4).zip
Executable file
BIN
output/package(SR_Switch-LPT262_hilink-20250803-1.0.4).zip
Executable file
Binary file not shown.
BIN
output/package(SR_Switch-LPT262_hilink-20250807-1.0.5).zip
Normal file
BIN
output/package(SR_Switch-LPT262_hilink-20250807-1.0.5).zip
Normal file
Binary file not shown.
BIN
output/package(SR_Switch-LPT262_hilink-20250811-1.0.6).zip
Normal file
BIN
output/package(SR_Switch-LPT262_hilink-20250811-1.0.6).zip
Normal file
Binary file not shown.
@@ -0,0 +1,92 @@
|
||||
#define LOSCFG_COMPILER_GNU_BINUTILS 1
|
||||
#define LOSCFG_COMPILER_GCC 1
|
||||
#define LOSCFG_COMPILER_TOOLCHAIN_MUSL 1
|
||||
#define LOSCFG_COMPILER_RISCV_GCC_MUSL 1
|
||||
#define LOSCFG_COMPILER_RISCV_UNKNOWN 1
|
||||
#define LOSCFG_RISCV_COMPILER_OPTIONS_USER_DEFINED ""
|
||||
#define LOSCFG_RISCV_COMPILER_OPTIONS_LDM_STM 1
|
||||
#define LOSCFG_RISCV_COMPILER_OPTIONS_EMIT_LLI 1
|
||||
#define LOSCFG_COMPILER_OPTIMIZE_SIZE 1
|
||||
#define LOSCFG_FAMILY_AIOT 1
|
||||
#define LOSCFG_FAMILY "aiot"
|
||||
#define LOSCFG_PLATFORM "ws63"
|
||||
#define LOSCFG_PLATFORM_WS63 1
|
||||
#define LOSCFG_USING_BOARD_LD 1
|
||||
#define LOSCFG_USING_BOARD_RESET_VECTOR 1
|
||||
#define LOSCFG_ARCH_FPU_ENABLE 1
|
||||
#define LOSCFG_APC_ENABLE 1
|
||||
#define LOSCFG_ARCH_PMU 1
|
||||
#define LOSCFG_ARCH_RISCV32 1
|
||||
#define LOSCFG_ARCH_RISCV_RV32IMC 1
|
||||
#define LOSCFG_ARCH_RISCV_RV32F 1
|
||||
#define LOSCFG_ARCH_LINXCORE_131 1
|
||||
#define LOSCFG_KERNEL_MIN 1
|
||||
#define LOSCFG_SCHED 1
|
||||
#define LOSCFG_SCHED_SQ 1
|
||||
#define LOSCFG_TASK_JOINABLE 1
|
||||
#define LOSCFG_BASE_CORE_TIMESLICE 1
|
||||
#define LOSCFG_BASE_CORE_TIMESLICE_TIMEOUT 2
|
||||
#define LOSCFG_BASE_CORE_TSK_MONITOR 1
|
||||
#define LOSCFG_TASK_STACK_DYNAMIC_ALLOCATION 1
|
||||
#define LOSCFG_BASE_CORE_TSK_LIMIT 32
|
||||
#define LOSCFG_BASE_CORE_TSK_MIN_STACK_SIZE 1024
|
||||
#define LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE 2048
|
||||
#define LOSCFG_BASE_CORE_TSK_SWTMR_STACK_SIZE 2048
|
||||
#define LOSCFG_BASE_CORE_TSK_IDLE_STACK_SIZE 1024
|
||||
#define LOSCFG_BASE_CORE_TSK_DEFAULT_PRIO 10
|
||||
#define LOSCFG_BASE_CORE_TICK_PER_SECOND 100
|
||||
#define LOSCFG_BASE_CORE_USE_SINGLE_LIST 1
|
||||
#define LOSCFG_STARTUP_STACK_SIZE 0x4000
|
||||
#define LOSCFG_KERNEL_MEM_ALLOC 1
|
||||
#define LOSCFG_KERNEL_MEM_BESTFIT 1
|
||||
#define LOSCFG_KERNEL_MEM_SLAB_EXTENTION 1
|
||||
#define LOSCFG_ARCH_INTERRUPT_TAKEOVER 1
|
||||
#define LOSCFG_ARCH_INTERRUPT_PREEMPTION 1
|
||||
#define LOSCFG_HWI_PRE_POST_PROCESS 1
|
||||
#define LOSCFG_HWI_WITH_ARG 1
|
||||
#define LOSCFG_IRQ_STACK_SIZE 0x2000
|
||||
#define LOSCFG_NMI_STACK_SIZE 0x800
|
||||
#define LOSCFG_PLATFORM_HWI_LIMIT 96
|
||||
#define LOSCFG_HWI_PRIO_LIMIT 7
|
||||
#define LOSCFG_EXC_STACK_SIZE 0x800
|
||||
#define LOSCFG_BASE_CORE_SWTMR 1
|
||||
#define LOSCFG_BASE_CORE_SWTMR_LIMIT 16
|
||||
#define LOSCFG_BASE_IPC_QUEUE 1
|
||||
#define LOSCFG_QUEUE_DYNAMIC_ALLOCATION 1
|
||||
#define LOSCFG_BASE_IPC_QUEUE_LIMIT 16
|
||||
#define LOSCFG_BASE_IPC_EVENT 1
|
||||
#define LOSCFG_BASE_IPC_MUX 1
|
||||
#define LOSCFG_MUTEX_WAITMODE_PRIO 1
|
||||
#define LOSCFG_BASE_IPC_MUX_LIMIT 66
|
||||
#define LOSCFG_BASE_IPC_SEM 1
|
||||
#define LOSCFG_BASE_IPC_SEM_LIMIT 32
|
||||
#define LOSCFG_KERNEL_PRINTF 1
|
||||
#define LOSCFG_KERNEL_PRINTF_SIZE_EXTEND 1
|
||||
#define LOSCFG_KERNEL_RINGBUF 1
|
||||
#define LOSCFG_BASE_CORE_SYS_RES_CHECK 1
|
||||
#define LOSCFG_LIB_LIBC 1
|
||||
#define LOSCFG_COMPAT_POSIX 1
|
||||
#define LOSCFG_LIB_VENDORNAME "vendor"
|
||||
#define LOSCFG_LIB_LIBM 1
|
||||
#define LOSCFG_LIB_FORMAT 1
|
||||
#define LOSCFG_LIB_STDIO 1
|
||||
#define LOSCFG_COMPAT_CMSIS 1
|
||||
#define LOSCFG_COMPAT_CMSIS_VER_2 1
|
||||
#define LOSCFG_COMPAT_LINUX 1
|
||||
#define LOSCFG_COMPAT_LINUX_PENDLIST 1
|
||||
#define LOSCFG_COMPAT_LINUX_TIMER 1
|
||||
#define LOSCFG_COMPAT_LINUX_COMPLETION 1
|
||||
#define LOSCFG_COMPAT_LINUX_WAITQUEUE 1
|
||||
#define LOSCFG_COMPAT_LINUX_DRIVER_BASE 1
|
||||
#define LOSCFG_FS_COMPAT_NUTTX 1
|
||||
#define LOSCFG_FS_VFS 1
|
||||
#define LOSCFG_NET_IPERF 1
|
||||
#define LOSCFG_BACKTRACE 1
|
||||
#define LOSCFG_SERIAL_OUTPUT_ENABLE 1
|
||||
#define LOSCFG_KERNEL_CPUP 1
|
||||
#define LOSCFG_DRIVERS_BASE 1
|
||||
#define LOSCFG_RISCV_HIMIDEERV200_PLIC 1
|
||||
#define LOSCFG_TIMER_VENDOR 1
|
||||
#define LOSCFG_DRIVERS_UART_VENDOR 1
|
||||
#define LOSCFG_DRIVERS_SIMPLE_UART 1
|
||||
#define LOSCFG_CC_NO_STACKPROTECTOR 1
|
||||
Reference in New Issue
Block a user