1. 解决PWM 更新导致周期混乱继而亮度抖动的问题
2. 增加无论何种状态都能强制复位的机制 3. 添加设备注册检查机制,如果设备已经处于配网但是还是注册的状态,强制进行一次复位 4. 添加串口控制协议
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,3 +1,6 @@
|
||||
.cache/
|
||||
.spec-workflow/
|
||||
.vscode/
|
||||
*.a
|
||||
*.so
|
||||
*.bin
|
||||
|
||||
1056
LPT262_PWM_user_guide.md
Normal file
1056
LPT262_PWM_user_guide.md
Normal file
File diff suppressed because it is too large
Load Diff
320
PWM参数计算详解.md
Normal file
320
PWM参数计算详解.md
Normal file
@@ -0,0 +1,320 @@
|
||||
# PWM参数计算详解(通俗易懂版)
|
||||
|
||||
## 文档说明
|
||||
|
||||
本文档专门解释PWM的各个参数计算原理,用通俗的语言和图表帮助理解复杂的PWM概念。适合只熟悉0-255亮度控制的开发者快速理解PWM参数。
|
||||
|
||||
---
|
||||
|
||||
## 1. 什么是PWM?
|
||||
|
||||
PWM就像开关灯一样,快速地开关来控制亮度。想象你手里有个开关,如果一直开着,灯就是100%亮;如果一直关着,灯就是0%亮。但如果你快速地开开关关,开的时间长一点,灯就亮一点;关的时间长一点,灯就暗一点。
|
||||
|
||||
### PWM波形图解
|
||||
|
||||
```
|
||||
100%亮度 (一直开着):
|
||||
████████████████████████████████████████████████████
|
||||
|
||||
50%亮度 (一半时间开,一半时间关):
|
||||
████████ ████████ ████████ ████
|
||||
|
||||
25%亮度 (1/4时间开,3/4时间关):
|
||||
████ ████ ████ ████ ████ ████ ████
|
||||
|
||||
0%亮度 (一直关着):
|
||||
________________________________________________
|
||||
```
|
||||
|
||||
### 关键概念图解
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
A[频率<br/>每秒开关多少次] --> B[周期<br/>一次开关的总时间]
|
||||
B --> C[占空比<br/>开的时间占比例]
|
||||
C --> D[亮度效果<br/>人眼感知的亮度]
|
||||
|
||||
style A fill:#e3f2fd
|
||||
style B fill:#f1f8e9
|
||||
style C fill:#fff3e0
|
||||
style D fill:#fce4ec
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 从0-255到实际参数的转换
|
||||
|
||||
### 2.1 对应关系表
|
||||
|
||||
| 你熟悉的数值 | 百分比 | PWM术语 | 实际效果 |
|
||||
|-------------|--------|---------|----------|
|
||||
| 0 | 0% | 0%占空比 | 完全不亮 |
|
||||
| 64 | 25% | 25%占空比 | 1/4亮度 |
|
||||
| 128 | 50% | 50%占空比 | 一半亮度 |
|
||||
| 192 | 75% | 75%占空比 | 3/4亮度 |
|
||||
| 255 | 100% | 100%占空比 | 最亮 |
|
||||
|
||||
### 2.2 转换公式
|
||||
|
||||
```c
|
||||
// 从你熟悉的0-255转换到百分比
|
||||
uint8_t brightness = 128; // 你设置的亮度值
|
||||
float duty_percent = (brightness / 255.0f) * 100.0f; // 转换成百分比
|
||||
|
||||
// 例子:
|
||||
// brightness = 0 → duty_percent = 0% (完全不亮)
|
||||
// brightness = 64 → duty_percent = 25% (1/4亮度)
|
||||
// brightness = 128 → duty_percent = 50% (一半亮度)
|
||||
// brightness = 192 → duty_percent = 75% (3/4亮度)
|
||||
// brightness = 255 → duty_percent = 100% (最亮)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. PWM参数计算原理
|
||||
|
||||
### 3.1 基础概念图解
|
||||
|
||||
```
|
||||
系统就像一个超快的时钟(80MHZ),每秒"滴答(cycle)"8000万次,每个滴答节奏所对应的时间是固定的。
|
||||
也就是这个PWM的最高精度就是(1/80*1000*1000)s =
|
||||
|
||||
如果我们要让PWM 1000HZ,也就是每秒开关1000次:
|
||||
那么每次开关需要:80M ÷ 1000 = 80000 cycle所对应的时间
|
||||
所以我们控制PWM本质上是控制这个PWM,一个周期的cycle总个数以及比例分配。
|
||||
|
||||
比如我要 PWM 是1KHZ
|
||||
首先计算,1KHZ 一个PWM周期就是1/1000s 也就是1ms
|
||||
然后计算1ms 对应多少个cycle: 0.001 / (1/80*1000*1000) = 80,000
|
||||
然后再根据占空比去分配这 80,000 个数字就行了
|
||||
只要确保high_time low_time加起来是8000就行
|
||||
|
||||
```
|
||||
|
||||
### 3.2 时间轴图解
|
||||
|
||||
```
|
||||
一个PWM周期 (1000Hz = 1ms):
|
||||
|
||||
0 20000 40000 60000 80000
|
||||
|---------|---------|---------|---------|
|
||||
25% 50% 75% 100%
|
||||
|
||||
如果要50%亮度:
|
||||
████████████████████████████████████████
|
||||
|←----- 开40000-----→|←---- 关40000 ----|
|
||||
|
||||
如果要75%亮度:
|
||||
████████████████████████████████████████████████████████
|
||||
|←-------- 开 (60000滴答) ---------→|←- 关 (20000滴答) -|
|
||||
```
|
||||
|
||||
### 3.3 计算步骤详解
|
||||
|
||||
```c
|
||||
// 第1步:确定系统时钟(这是硬件固定的,不用改)
|
||||
uint32_t system_clock = 80000000; // 80MHz = 每秒8000万次计数
|
||||
|
||||
// 第2步:设定PWM频率(就是每秒开关多少次)
|
||||
uint32_t pwm_frequency = 1000; // 1000Hz = 每秒开关1000次
|
||||
|
||||
// 第3步:计算一个开关周期需要多少个时钟计数
|
||||
// 打个比方:如果系统每秒有8000万下,你要让它每秒开关1000次
|
||||
// 那么每次开关就需要:8000万 ÷ 1000 = 80000个计数
|
||||
uint32_t period_count = system_clock / pwm_frequency;
|
||||
|
||||
// 第4步:根据亮度(占空比)计算开和关的时间
|
||||
// 如果要60%亮度,那么80000个计数中,48000个用来"开",32000个用来"关"
|
||||
float brightness_percent = 60.0; // 60%亮度
|
||||
uint32_t on_time = (uint32_t)(period_count * brightness_percent / 100.0);
|
||||
uint32_t off_time = period_count - on_time;
|
||||
|
||||
// 结果:
|
||||
// on_time = 48000 (开的时间)
|
||||
// off_time = 32000 (关的时间)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. PWM参数详解图表
|
||||
|
||||
### 4.1 pwm_config_t结构体参数图解
|
||||
|
||||
```c
|
||||
typedef struct pwm_config {
|
||||
uint32_t high_time; // 高电平时间("开"的时间,用计数表示)
|
||||
uint32_t low_time; // 低电平时间("关"的时间,用计数表示)
|
||||
uint32_t offset_time; // 相位偏移时间(延迟启动时间)
|
||||
uint16_t cycles; // 重复次数(0=无限重复)
|
||||
bool repeat; // 连续输出标志(true=一直输出)
|
||||
} pwm_config_t;
|
||||
```
|
||||
|
||||
### 4.2 参数关系图
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
A[一个PWM周期] --> B[high_time<br/>开的时间]
|
||||
A --> C[low_time<br/>关的时间]
|
||||
|
||||
B --> D[占空比 = high_time / (high_time + low_time)]
|
||||
C --> D
|
||||
|
||||
D --> E[最终亮度效果]
|
||||
|
||||
F[offset_time<br/>延迟启动] --> G[多通道同步控制]
|
||||
H[cycles<br/>重复次数] --> I[输出控制]
|
||||
J[repeat<br/>连续标志] --> I
|
||||
|
||||
style A fill:#e3f2fd
|
||||
style D fill:#f1f8e9
|
||||
style E fill:#fff3e0
|
||||
```
|
||||
|
||||
### 4.3 各参数的通俗解释
|
||||
|
||||
#### **high_time(高电平时间)**
|
||||
- **通俗理解**:就是"开关"中"开"的时间,用时钟计数表示
|
||||
- **计算方法**:`high_time = 周期计数 × 亮度百分比`
|
||||
- **例子**:如果high_time = 40000,系统时钟80MHz,那么"开"的时间 = 40000 ÷ 80000000 = 0.5ms
|
||||
|
||||
#### **low_time(低电平时间)**
|
||||
- **通俗理解**:就是"开关"中"关"的时间,用时钟计数表示
|
||||
- **计算方法**:`low_time = 周期计数 - high_time`
|
||||
- **例子**:如果low_time = 40000,那么"关"的时间也是0.5ms
|
||||
|
||||
#### **offset_time(相位偏移)**
|
||||
- **通俗理解**:延迟多长时间再开始PWM输出
|
||||
- **使用场景**:多个LED需要错开时间启动,避免同时启动造成电流冲击
|
||||
- **大多数情况**:设为0即可
|
||||
|
||||
#### **cycles(重复次数)**
|
||||
- **通俗理解**:PWM波形重复多少次后停止
|
||||
- **常用设置**:
|
||||
- `0`:无限重复(最常用)
|
||||
- `具体数字`:输出指定次数后停止
|
||||
|
||||
#### **repeat(连续输出标志)**
|
||||
- **通俗理解**:是否持续输出PWM波形
|
||||
- **常用设置**:
|
||||
- `true`:持续输出(最常用)
|
||||
- `false`:只输出指定次数后停止
|
||||
|
||||
---
|
||||
|
||||
## 5. 实际计算示例
|
||||
|
||||
### 5.1 示例1:设置50%亮度
|
||||
|
||||
```c
|
||||
// 目标:PWM频率1000Hz,50%亮度
|
||||
|
||||
// 第1步:计算周期计数
|
||||
uint32_t period_cnt = 80000000 / 1000; // = 80000
|
||||
|
||||
// 第2步:计算高低电平时间
|
||||
uint32_t high_time = 80000 * 50 / 100; // = 40000
|
||||
uint32_t low_time = 80000 - 40000; // = 40000
|
||||
|
||||
// 第3步:配置PWM
|
||||
pwm_config_t cfg = {
|
||||
.high_time = 40000, // "开" 0.5ms
|
||||
.low_time = 40000, // "关" 0.5ms
|
||||
.offset_time = 0, // 不延迟
|
||||
.repeat = true, // 持续输出
|
||||
.cycles = 0 // 无限重复
|
||||
};
|
||||
```
|
||||
|
||||
### 5.2 示例2:设置75%亮度
|
||||
|
||||
```c
|
||||
// 目标:PWM频率1000Hz,75%亮度
|
||||
|
||||
uint32_t period_cnt = 80000;
|
||||
uint32_t high_time = 80000 * 75 / 100; // = 60000
|
||||
uint32_t low_time = 80000 - 60000; // = 20000
|
||||
|
||||
pwm_config_t cfg = {
|
||||
.high_time = 60000, // "开" 0.75ms (更长)
|
||||
.low_time = 20000, // "关" 0.25ms (更短)
|
||||
.offset_time = 0,
|
||||
.repeat = true,
|
||||
.cycles = 0
|
||||
};
|
||||
```
|
||||
|
||||
### 5.3 波形对比图
|
||||
|
||||
```
|
||||
50%占空比 (high_time=40000, low_time=40000):
|
||||
████████████████████████████████████████ ████████████████████████████████████████
|
||||
|←-------- 0.5ms ------→|←-- 0.5ms --→| |←-------- 0.5ms ------→|←-- 0.5ms --→|
|
||||
|
||||
75%占空比 (high_time=60000, low_time=20000):
|
||||
████████████████████████████████████████████████████████ ████████████████████████████████████████████████████████
|
||||
|←-------------- 0.75ms ------------→|0.25ms| |←-------------- 0.75ms ------------→|0.25ms|
|
||||
|
||||
25%占空比 (high_time=20000, low_time=60000):
|
||||
████████████████████ ████████████████████
|
||||
|←-- 0.25ms --→|←---- 0.75ms ----→| |←-- 0.25ms --→|←---- 0.75ms ----→|
|
||||
```
|
||||
---
|
||||
|
||||
## 7. 简化使用函数
|
||||
|
||||
### 7.1 推荐的简化函数
|
||||
|
||||
```c
|
||||
// 这个函数让PWM像以前一样简单
|
||||
errcode_t set_pwm_brightness_simple(uint8_t channel, uint8_t brightness_0_255)
|
||||
{
|
||||
// 固定使用1000Hz频率,适合LED调光
|
||||
uint32_t frequency = 1000;
|
||||
|
||||
// 将0-255转换为百分比
|
||||
float duty_percent = (brightness_0_255 / 255.0f) * 100.0f;
|
||||
|
||||
// 计算周期计数(80MHz ÷ 1000Hz = 80000)
|
||||
uint32_t period_cnt = 80000000 / frequency;
|
||||
|
||||
// 计算高低电平时间
|
||||
uint32_t high_time = (uint32_t)(period_cnt * duty_percent / 100.0f);
|
||||
uint32_t low_time = period_cnt - high_time;
|
||||
|
||||
// 配置PWM
|
||||
pwm_config_t cfg = {
|
||||
.high_time = high_time, // "开"的时间(计数值)
|
||||
.low_time = low_time, // "关"的时间(计数值)
|
||||
.offset_time = 0, // 不需要相位偏移
|
||||
.repeat = true, // 持续输出
|
||||
.cycles = 0 // 无限循环
|
||||
};
|
||||
|
||||
return uapi_pwm_open(channel, &cfg);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 常见问题解答
|
||||
|
||||
### Q1: 为什么不能直接用0-255,要用这些复杂参数?
|
||||
**A**: PWM硬件需要知道具体的时钟计数,不是百分比。就像你告诉司机"开快点",司机需要知道具体开多少码一样。
|
||||
|
||||
### Q2: high_time和low_time的单位是什么?
|
||||
**A**: 单位是时钟计数次数,不是时间。1个计数 = 1/80000000秒 = 12.5纳秒。
|
||||
|
||||
### Q3: 为什么推荐1000Hz频率?
|
||||
**A**:
|
||||
- 高于100Hz:人眼看不到闪烁
|
||||
- 低于20kHz:不会产生高频噪音
|
||||
- 1000Hz刚好在这个范围内,且计算简单
|
||||
|
||||
### Q4: offset_time什么时候用?
|
||||
**A**: 主要用于多通道同步,比如RGB灯的三个颜色错开启动,避免电流冲击。
|
||||
|
||||
### Q5: 如何实现渐变效果?
|
||||
**A**: 在循环中逐步改变brightness_0_255的值,每次改变后调用set_pwm_brightness_simple()。
|
||||
|
||||
---
|
||||
@@ -54,11 +54,15 @@ errcode_t SsapsAddDescriptorSync(uint8_t serverId, uint16_t serviceHandle, uint1
|
||||
return ssaps_add_descriptor_sync(serverId, serviceHandle, propertyHandle, (ssaps_desc_info_t *)descriptor);
|
||||
}
|
||||
|
||||
#define DEFAULT_SLE_SPEED_MTU_SIZE 1500
|
||||
errcode_t SsapsStartService(uint8_t serverId, uint16_t serviceHandle)
|
||||
{
|
||||
SsapcExchangeInfo info = {0};
|
||||
info.mtuSize = DEFAULT_SLE_SPEED_MTU_SIZE;
|
||||
info.version = 1;
|
||||
SsapsSetInfo(serverId, &info);
|
||||
return ssaps_start_service(serverId, serviceHandle);
|
||||
}
|
||||
|
||||
errcode_t SsapsDeleteAllServices(uint8_t serverId)
|
||||
{
|
||||
return ssaps_delete_all_services(serverId);
|
||||
|
||||
@@ -294,7 +294,7 @@ static void HILINK_BT_StateChangeHandler(HILINK_BT_SdkStatus event, const void *
|
||||
HILINK_SAL_ERROR("set addr err\n");
|
||||
}
|
||||
/* 设置蓝牙广播格式,包括靠近发现、碰一碰等,下一次发送广播生效 */
|
||||
BLE_SetAdvType(BLE_ADV_NEARBY_V0);
|
||||
BLE_SetAdvType(BLE_ADV_LOCAL_NAME);
|
||||
|
||||
/* BLE配网广播控制:参数代表广播时间,0:停止;0xFFFFFFFF:一直广播,其他:广播指定时间后停止,单位秒 */
|
||||
if(ble_adv_time) {
|
||||
@@ -617,7 +617,7 @@ int hilink_ble_main(void)
|
||||
}
|
||||
|
||||
/* 设置广播方式为靠近发现 */
|
||||
BLE_SetAdvType(BLE_ADV_NEARBY_V0);
|
||||
BLE_SetAdvType(BLE_ADV_LOCAL_NAME);
|
||||
|
||||
/* 初始化ble sdk */
|
||||
ret = BLE_CfgNetInit(&g_bleInitParam, &g_bleCfgNetCb);
|
||||
|
||||
@@ -30,7 +30,7 @@ extern "C" {
|
||||
|
||||
#define DEVICE_HIVERSION "1.0.0"
|
||||
/* 设备固件版本号 */
|
||||
#define FIRMWARE_VER "1.0.13"
|
||||
#define FIRMWARE_VER "1.0.6"
|
||||
/* 设备硬件版本号 */
|
||||
#define HARDWARE_VER "1.0.0"
|
||||
/* 设备软件版本号 */
|
||||
|
||||
@@ -112,7 +112,7 @@ int HILINK_GetDevInfo(HILINK_DevInfo *devinfo)
|
||||
return -1;
|
||||
}
|
||||
HILINK_SAL_DEBUG("HILINK_GetDevInfo manuName: [%s]\r\n", devinfo->manuName);
|
||||
#ifdef CONFIG_SUPPORT_HILINK_INDIE_UPGRADE
|
||||
#if 0 //def CONFIG_SUPPORT_HILINK_INDIE_UPGRADE
|
||||
err = sprintf_s(devinfo->fwv, sizeof(devinfo->fwv), "%s_%s_%s", "103","1.312", FIRMWARE_VER);
|
||||
if (err <= 0) {
|
||||
HILINK_SAL_ERROR("sprintf_s err:%d\r\n", err);
|
||||
@@ -632,6 +632,7 @@ void HILINK_NotifyDevStatus(int status)
|
||||
case HILINK_LINK_CONNECTED_WIFI:
|
||||
/* 设备已经连上路由器,请在此处添加实现 */
|
||||
hf_set_wifi_state(1);
|
||||
handle_device_online();
|
||||
break;
|
||||
case HILINK_M2M_CONNECTTING_CLOUD:
|
||||
/* 设备正在连接云端,请在此处添加实现 */
|
||||
|
||||
@@ -57,6 +57,10 @@ int myhandle_put_brightness(const char* svc_id, const char* payload, unsigned in
|
||||
// 处理色温控制
|
||||
int myhandle_put_cct(const char* svc_id, const char* payload, unsigned int len)
|
||||
{
|
||||
// 🔧 添加调试信息:显示调用前的状态
|
||||
e_printf("[put_cct] 调用开始: g_device_control.cct_local=%d, duty_cw=%d, duty_ww=%d\n",
|
||||
g_device_control.cct_local, g_device_control.duty_cw, g_device_control.duty_ww);
|
||||
|
||||
int ret = -1;
|
||||
cJSON *json = cJSON_Parse(payload);
|
||||
if (json == NULL) {
|
||||
|
||||
@@ -100,8 +100,14 @@ typedef struct __attribute__((packed, aligned(1))) {
|
||||
#define BRIGHTNESS_MAX 100 // 最大亮度
|
||||
#define BRIGHTNESS_LOCAL_MIN 0 // 最小亮度
|
||||
#define BRIGHTNESS_LOCAL_MAX 10000 // 最大亮度
|
||||
#define BRIGHTNESS_REMOTE2LOCAL(x) (x * 100) //变化范围0 -10000
|
||||
#define BRIGHTNESS_LOCAL2REMOTE(x) (x / 100)
|
||||
|
||||
// 亮度映射函数:仅对1-10%范围进行映射到2-10%,11-100%保持不变
|
||||
// 映射公式:
|
||||
// - 1-10%: 实际亮度 = 2 + (APP亮度 - 1) * 8 / 9
|
||||
// - 11-100%: 实际亮度 = APP亮度
|
||||
// 当APP亮度为1%时,实际亮度为2%;当APP亮度为10%时,实际亮度为10%;11%及以上保持不变
|
||||
#define BRIGHTNESS_REMOTE2LOCAL(x) (((x) <= 0) ? 0 : ((x) <= 10 ? (200 + (((x) - 1) * 800) / 9) : ((x) * 100)))
|
||||
#define BRIGHTNESS_LOCAL2REMOTE(x) (((x) <= 0) ? 0 : ((x) <= 1000 ? (1 + (((x) - 200) * 9) / 800) : ((x) / 100)))
|
||||
|
||||
#define BRIGHTNESS_LITME_RANGE(x) do { \
|
||||
if (x > BRIGHTNESS_LOCAL_MAX) x = BRIGHTNESS_LOCAL_MAX; \
|
||||
@@ -113,9 +119,9 @@ typedef struct __attribute__((packed, aligned(1))) {
|
||||
#define INIT_STA__BRIGHTNESS 50
|
||||
#define INIT_STA__CCT 4000
|
||||
|
||||
#define INIT_NET_CFG_PWOER_ON_KEEP_TIME (5 * 1000) // 统计进入配网每次打开状态的保持时间
|
||||
#define INIT_NET_CFG_PWOER_ON_KEEP_TIME (5 * 1000) // 上电保持超过该时间则清零计数(防误触)
|
||||
|
||||
#define NET_CFG_ENTRY_CNT 8 // 配网进入的上电次数
|
||||
#define NET_CFG_ENTRY_CNT 8 // 快速上电计数阈值:达到即强制解绑并恢复出厂
|
||||
#define NET_CFG_BREATH_DURATION 1*60*1000 // 配网呼吸灯持续时间(ms)
|
||||
#define NET_CFG_TOTAL_TIMEOUT 10*60*1000 // 配网总超时时间(ms)
|
||||
|
||||
@@ -195,6 +201,10 @@ typedef enum {
|
||||
#define CCT_PIN GPIO_00 // 暖白LED (WW)
|
||||
#define SWITCH_PIN GPIO_13
|
||||
|
||||
// PWM 更新标志输出引脚(用于逻辑分析仪观察控制时序)
|
||||
// 选取 GPIO10:每次调用 update_pwm_output() 时翻转一次电平
|
||||
#define PWM_UPDATE_FLAG_PIN GPIO_10
|
||||
|
||||
#define CONFIG_PWM_GROUP_ID 2
|
||||
|
||||
#define OPEN_LIGHT GPIO_LEVEL_HIGH
|
||||
@@ -213,6 +223,7 @@ typedef enum {
|
||||
.is_net_configured = false, \
|
||||
.duty_cw = 0, \
|
||||
.duty_ww = 0, \
|
||||
.power_on_cnt = 0, \
|
||||
};
|
||||
|
||||
int spotlight_main(void);
|
||||
@@ -228,4 +239,3 @@ void stop_net_config(void);
|
||||
extern int fast_report(const char* svc_id);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -64,6 +64,8 @@ bool g_reset_factory_flag = false;
|
||||
static uint32_t pwm_period_cnt = 0; // PWM周期 40us
|
||||
static uint8_t channel_id_cw = 0; // 冷白LED通道ID
|
||||
static uint8_t channel_id_ww = 0; // 暖白LED通道ID
|
||||
// PWM参数更新调试标志引脚是否已初始化
|
||||
static bool g_pwm_update_flag_inited = false;
|
||||
|
||||
void save_device_data(void);
|
||||
void read_device_data(void);
|
||||
@@ -112,6 +114,7 @@ static struct fade_ctx_t {
|
||||
uint16_t fade_time; //s
|
||||
uint32_t smooth_time_us; // 渐变总时长(us)
|
||||
uint32_t update_interval; // 更新间隔(us)
|
||||
volatile bool timer_active; // 渐变定时器是否允许自重启(竞态保护)
|
||||
// 打印限制器
|
||||
print_limiter_t print_limiter;
|
||||
};
|
||||
@@ -208,7 +211,7 @@ static void *fade_task(const char *arg)
|
||||
fade_ctx.current_cct, fade_ctx.target_cct, fade_ctx.step_cct, fade_ctx.is_closing_fade);
|
||||
}
|
||||
|
||||
// 检查是否达到目标值(恢复原始逻辑)
|
||||
// 检查是否达到目标值
|
||||
bool brightness_reached = (fade_ctx.step_brightness > 0) ?
|
||||
(fade_ctx.current_brightness >= fade_ctx.target_brightness) :
|
||||
(fade_ctx.current_brightness <= fade_ctx.target_brightness);
|
||||
@@ -216,14 +219,14 @@ static void *fade_task(const char *arg)
|
||||
bool cct_reached = (fade_ctx.step_cct > 0) ?
|
||||
(fade_ctx.current_cct >= fade_ctx.target_cct) :
|
||||
(fade_ctx.current_cct <= fade_ctx.target_cct);
|
||||
// 更新当前值(恢复原始逻辑)
|
||||
// 更新当前值
|
||||
if (!brightness_reached) {
|
||||
fade_ctx.current_brightness += fade_ctx.step_brightness;
|
||||
}
|
||||
if (!cct_reached) {
|
||||
fade_ctx.current_cct += fade_ctx.step_cct;
|
||||
}
|
||||
// 如果达到目标值,停止渐变(恢复原始逻辑)
|
||||
// 达到目标,停止渐变
|
||||
if (brightness_reached && cct_reached) {
|
||||
e_printf("[fade_task] Fade completed, Final brightness: %d, CCT: %d, closing_fade: %d\r\n",
|
||||
fade_ctx.target_brightness, fade_ctx.target_cct, fade_ctx.is_closing_fade);
|
||||
@@ -231,6 +234,7 @@ static void *fade_task(const char *arg)
|
||||
fade_ctx.fade_completed = true;
|
||||
fade_ctx.current_brightness = fade_ctx.target_brightness;
|
||||
fade_ctx.current_cct = fade_ctx.target_cct;
|
||||
fade_ctx.timer_active = false; // 防止回调自重启
|
||||
uapi_timer_stop(fade_ctx.timer_handle);
|
||||
}
|
||||
|
||||
@@ -335,6 +339,10 @@ static void *breath_task(const char *arg)
|
||||
// 渐变定时器回调函数
|
||||
static void fade_timer_callback(uintptr_t data)
|
||||
{
|
||||
// 若已被取消或未处于渐变态,禁止回调重入自重启,避免双定时器抖动
|
||||
if (!fade_ctx.timer_active || !fade_ctx.is_fading) {
|
||||
return;
|
||||
}
|
||||
osal_sem_up(&fade_ctx.sem); // 唤醒渐变任务 fade_task
|
||||
uapi_timer_start(fade_ctx.timer_handle, fade_ctx.update_interval, fade_timer_callback, 0);
|
||||
}
|
||||
@@ -364,6 +372,27 @@ static void init_fade_ctx(void)
|
||||
// 初始化打印限制器
|
||||
init_print_limiter(&fade_ctx.print_limiter, "[fade_task]");
|
||||
|
||||
// 🔧 智能初始化:根据设备状态决定初始值
|
||||
if (g_device_control.read_done) {
|
||||
// 数据已读取完成(正常启动)
|
||||
if (g_device_control.on) {
|
||||
// 开机渐变:从0开始渐变到目标亮度
|
||||
fade_ctx.current_brightness = 0;
|
||||
fade_ctx.current_cct = g_device_control.cct_local; // 色温保持目标值
|
||||
e_printf("[init_fade_ctx] 开机渐变模式: brightness=0->%d, cct=%d\n",
|
||||
g_device_control.brightness_local, fade_ctx.current_cct);
|
||||
} else {
|
||||
// 设备关闭状态
|
||||
fade_ctx.current_brightness = 0;
|
||||
fade_ctx.current_cct = g_device_control.cct_local;
|
||||
}
|
||||
} else {
|
||||
// 数据尚未读取(初始化阶段)- 保持原有逻辑
|
||||
fade_ctx.current_brightness = 0;
|
||||
fade_ctx.current_cct = 0;
|
||||
e_printf("[init_fade_ctx] 初始化阶段: brightness=0, cct=0\n");
|
||||
}
|
||||
|
||||
// 创建渐变任务
|
||||
osal_kthread_lock();
|
||||
fade_ctx.task_handle = osal_kthread_create((osal_kthread_handler)fade_task, NULL, "FadeTask",
|
||||
@@ -380,8 +409,7 @@ static void init_fade_ctx(void)
|
||||
|
||||
// 设置默认更新间隔
|
||||
fade_ctx.update_interval = FADE_INTERVAL_MIN;
|
||||
// fade_ctx.current_brightness = g_device_control.brightness_local;
|
||||
// fade_ctx.current_cct = g_device_control.cct_local;
|
||||
fade_ctx.timer_active = false; // 默认禁用,只有开始渐变时启用
|
||||
}
|
||||
|
||||
// 初始化呼吸灯控制
|
||||
@@ -491,8 +519,12 @@ void calculate_pwm_duty(device_control_t* pdevice_control)
|
||||
// 更新PWM输出
|
||||
void update_pwm_output(bool on_state, uint16_t duty_cw_val, uint16_t duty_ww_val)
|
||||
{
|
||||
pwm_config_t cfg_repeat = {0};
|
||||
cfg_repeat.repeat = true;
|
||||
// 说明:为了避免每步“重相位 + 动态拼接”导致的低亮抖动,
|
||||
// 这里改为固定相位(offset_time=0),并避免每次重复start_group。
|
||||
// 若平台支持 uapi_pwm_update_duty_ratio,可切换为更新接口;否则退回 open 配置。
|
||||
|
||||
pwm_config_t cfg = {0};
|
||||
cfg.repeat = true;
|
||||
|
||||
uint16_t current_duty_cw = duty_cw_val;
|
||||
uint16_t current_duty_ww = duty_ww_val;
|
||||
@@ -512,29 +544,53 @@ void update_pwm_output(bool on_state, uint16_t duty_cw_val, uint16_t duty_ww_val
|
||||
|
||||
if (!on_state) {
|
||||
high_cnt_cw = 0;
|
||||
low_cnt_cw = pwm_period_cnt; // Ensure low_cnt is full period if off
|
||||
low_cnt_cw = pwm_period_cnt; // 关灯时保持低电平整周期
|
||||
high_cnt_ww = 0;
|
||||
low_cnt_ww = pwm_period_cnt; // Ensure low_cnt is full period if off
|
||||
low_cnt_ww = pwm_period_cnt;
|
||||
}
|
||||
|
||||
// uapi_pwm_stop_group(CONFIG_PWM_GROUP_ID);
|
||||
cfg_repeat.high_time = high_cnt_cw;
|
||||
cfg_repeat.low_time = low_cnt_cw;
|
||||
uapi_pwm_open(channel_id_cw, &cfg_repeat);
|
||||
// uapi_pwm_update_duty_ratio(channel_id_cw, cfg_repeat.low_time, cfg_repeat.high_time);
|
||||
#if defined(CONFIG_PWM_USING_V150)
|
||||
// V150: 先更新占空,再通过 start_group 触发加载
|
||||
(void)uapi_pwm_update_duty_ratio(channel_id_cw, low_cnt_cw, high_cnt_cw);
|
||||
(void)uapi_pwm_update_duty_ratio(channel_id_ww, low_cnt_ww, high_cnt_ww);
|
||||
// 需要显式触发加载
|
||||
(void)uapi_pwm_start_group(CONFIG_PWM_GROUP_ID);
|
||||
#else
|
||||
// V151 场景
|
||||
cfg.offset_time = 0; // 固定相位,避免相位不断重置造成抖动
|
||||
#if defined(CONFIG_PWM_PRELOAD)
|
||||
// 使用预加载:配置写入影子寄存器,等当前周期结束后自动无缝切换。
|
||||
cfg.high_time = high_cnt_cw;
|
||||
cfg.low_time = low_cnt_cw;
|
||||
(void)uapi_pwm_config_preload(CONFIG_PWM_GROUP_ID, channel_id_cw, &cfg);
|
||||
|
||||
cfg_repeat.high_time = high_cnt_ww;
|
||||
cfg_repeat.low_time = low_cnt_ww;
|
||||
cfg_repeat.offset_time = high_cnt_cw; // WW PWM starts after CW PWM high time
|
||||
cfg.high_time = high_cnt_ww;
|
||||
cfg.low_time = low_cnt_ww;
|
||||
(void)uapi_pwm_config_preload(CONFIG_PWM_GROUP_ID, channel_id_ww, &cfg);
|
||||
// 预加载模式下不重复调用 start_group,避免打乱当前计数器与周期
|
||||
#else
|
||||
// 无预加载能力时的回退:直接 open + start_group(可能导致轻微周期扰动)
|
||||
cfg.high_time = high_cnt_cw;
|
||||
cfg.low_time = low_cnt_cw;
|
||||
(void)uapi_pwm_open(channel_id_cw, &cfg);
|
||||
|
||||
uapi_pwm_open(channel_id_ww, &cfg_repeat);
|
||||
// uapi_pwm_update_duty_ratio(channel_id_ww, cfg_repeat.low_time, cfg_repeat.high_time);
|
||||
|
||||
uapi_pwm_start_group(CONFIG_PWM_GROUP_ID);
|
||||
cfg.high_time = high_cnt_ww;
|
||||
cfg.low_time = low_cnt_ww;
|
||||
(void)uapi_pwm_open(channel_id_ww, &cfg);
|
||||
(void)uapi_pwm_start_group(CONFIG_PWM_GROUP_ID);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (should_print(&pwm_limiter)) {
|
||||
e_printf("on:%d, cw:high:%u, low:%u, duty:%u/%u, ww:high:%u, low:%u, duty:%u/%u, offset_time:%u\r\n",
|
||||
on_state, high_cnt_cw, low_cnt_cw, current_duty_cw, PWM_DUTY_RATIO_MAX, high_cnt_ww, low_cnt_ww, current_duty_ww, PWM_DUTY_RATIO_MAX, cfg_repeat.offset_time);
|
||||
e_printf("on:%d, cw(H/L):%u/%u, duty:%u, ww(H/L):%u/%u, duty:%u\r\n",
|
||||
on_state, high_cnt_cw, low_cnt_cw, current_duty_cw,
|
||||
high_cnt_ww, low_cnt_ww, current_duty_ww);
|
||||
}
|
||||
|
||||
// 调试:每次更新PWM参数后,翻转一次 GPIO10(PWM_UPDATE_FLAG_PIN)
|
||||
// 便于使用逻辑分析仪观察控制发生的时间点
|
||||
if (g_pwm_update_flag_inited) {
|
||||
(void)uapi_gpio_toggle(PWM_UPDATE_FLAG_PIN);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -608,6 +664,8 @@ lab_exit:
|
||||
|
||||
static void cancel_current_light_fade(void)
|
||||
{
|
||||
// 竞态保护:先拉低标志再停计时器,避免回调自重启
|
||||
fade_ctx.timer_active = false;
|
||||
uapi_timer_stop(fade_ctx.timer_handle);
|
||||
// 如果我打断了渐变,则将当前值更新到目标值不然下次计算会异常
|
||||
// g_device_control.cct_local = fade_ctx.current_cct;
|
||||
@@ -887,10 +945,17 @@ int set_light(light_ctrl_source_e source,
|
||||
// 如果打开灯,则需要手动将前置状态设置为关闭的样子,这样子后面计算渐变才能正常计算
|
||||
if (APP_OPEN_LIGHT == source || DEV_POWER_ON == source) {
|
||||
g_device_control.on = true;
|
||||
// fade_ctx.current_brightness = 0;
|
||||
|
||||
if (DEV_POWER_ON == source) {
|
||||
// 🔧 开机渐变:明确设置从0开始
|
||||
fade_ctx.current_brightness = 0; // 从0开始渐变
|
||||
fade_ctx.current_cct = g_device_control.cct_local; // 色温保持目标值
|
||||
e_printf("[set_light] 开机渐变设置: brightness=0->%d, cct=%d\n",
|
||||
g_device_control.brightness_local, fade_ctx.current_cct);
|
||||
}
|
||||
|
||||
brightness_local_target = g_device_control.brightness_local;
|
||||
// 色温不进行变化,只改变亮度
|
||||
fade_ctx.current_cct = g_device_control.cct_local;
|
||||
cct_local_target = g_device_control.cct_local;
|
||||
|
||||
if (g_device_control.colourMode != COLOUR_MODE_DUAL) {
|
||||
@@ -930,6 +995,7 @@ int set_light(light_ctrl_source_e source,
|
||||
calculate_fade_steps(&tmp_fade_ctx); // 复用原有计算流程
|
||||
memcpy(&fade_ctx, &tmp_fade_ctx, FADE_CTRL_DATA_SIZE(tmp_fade_ctx));
|
||||
e_printf("start close light fade\r\n");
|
||||
fade_ctx.timer_active = true;
|
||||
uapi_timer_start(fade_ctx.timer_handle, fade_ctx.update_interval, fade_timer_callback, 0);
|
||||
start_report_task(REPORT_SWITCH | REPORT_LIGHT_MODE);
|
||||
req_save_device_data();
|
||||
@@ -953,6 +1019,7 @@ int set_light(light_ctrl_source_e source,
|
||||
calculate_fade_steps(&tmp_fade_ctx);
|
||||
memcpy(&fade_ctx, &tmp_fade_ctx, FADE_CTRL_DATA_SIZE(tmp_fade_ctx));
|
||||
e_printf("start fade\r\n");
|
||||
fade_ctx.timer_active = true;
|
||||
uapi_timer_start(fade_ctx.timer_handle, fade_ctx.update_interval, fade_timer_callback, 0);
|
||||
start_report_task(REPORT_SWITCH | REPORT_BRIGHTNESS | REPORT_CCT | REPORT_LIGHT_MODE | REPORT_COLOUR_MODE);
|
||||
req_save_device_data();
|
||||
@@ -972,6 +1039,7 @@ int set_light(light_ctrl_source_e source,
|
||||
calculate_fade_steps(&tmp_fade_ctx);
|
||||
memcpy(&fade_ctx, &tmp_fade_ctx, FADE_CTRL_DATA_SIZE(tmp_fade_ctx));
|
||||
e_printf("start fade\r\n");
|
||||
fade_ctx.timer_active = true;
|
||||
uapi_timer_start(fade_ctx.timer_handle, fade_ctx.update_interval, fade_timer_callback, 0);
|
||||
start_report_task(REPORT_BRIGHTNESS | REPORT_CCT | REPORT_LIGHT_MODE | REPORT_COLOUR_MODE);
|
||||
req_save_device_data();
|
||||
@@ -1025,27 +1093,34 @@ static void pwm_init(pin_t pin, pin_t pin1)
|
||||
uapi_pin_set_mode(pin, PIN_MODE_1);
|
||||
uapi_pin_set_mode(pin1, PIN_MODE_1);
|
||||
uapi_pwm_init();
|
||||
uint32_t frequency = uapi_pwm_get_frequency(pin%8);
|
||||
// uint32_t pwm_base_period_ns = 1000 * 1000 * 1000 / frequency;
|
||||
// uint32_t pwm_base_period_ns = 1000 * 1000 * 1000 / (80 * 1000 * 1000);// 80MHZ
|
||||
// uint32_t pwm_target_period_ns = 1000 * 1000 * 1000 / PWM_FREQUENCY;
|
||||
pwm_period_cnt = ((80 * 1000 * 1000) / PWM_FREQUENCY);
|
||||
// 基准时钟固定 80MHz(客户指定)。不要使用 uapi_pwm_get_frequency 返回值。
|
||||
channel_id_cw = pin % 8;
|
||||
channel_id_ww = pin1 % 8;
|
||||
const uint32_t base_clk = 80 * 1000 * 1000; // 80MHz 固定
|
||||
pwm_period_cnt = (base_clk / PWM_FREQUENCY);
|
||||
|
||||
// 初始为关灯:高电平0,低电平整周期;固定相位
|
||||
cfg_repeat.high_time = 0;
|
||||
cfg_repeat.low_time = pwm_period_cnt;
|
||||
// 设置PWM组
|
||||
channel_id_cw = pin%8;
|
||||
channel_id_ww = pin1%8;
|
||||
cfg_repeat.offset_time = 0;
|
||||
|
||||
// 先打开两个通道
|
||||
(void)uapi_pwm_open(channel_id_cw, &cfg_repeat);
|
||||
(void)uapi_pwm_open(channel_id_ww, &cfg_repeat);
|
||||
|
||||
// 设置分组并启动(分组只需启动一次)
|
||||
uint8_t channel_ids[2] = {channel_id_cw, channel_id_ww};
|
||||
// uapi_pwm_open(channel_id_cw, &cfg_repeat);
|
||||
// uapi_pwm_open(channel_id_ww, &cfg_repeat);
|
||||
uapi_pwm_set_group(CONFIG_PWM_GROUP_ID, channel_ids, sizeof(channel_ids));
|
||||
// uapi_pwm_start_group(CONFIG_PWM_GROUP_ID);
|
||||
e_printf("PWM基础时钟频率: %dHz, 目标时钟频率: %dHz, 周期计数: %d\r\n", frequency, PWM_FREQUENCY, pwm_period_cnt);
|
||||
(void)uapi_pwm_set_group(CONFIG_PWM_GROUP_ID, channel_ids, sizeof(channel_ids));
|
||||
(void)uapi_pwm_start_group(CONFIG_PWM_GROUP_ID);
|
||||
|
||||
e_printf("PWM基础时钟频率(固定): %uHz, 目标时钟频率: %dHz, 周期计数: %u\r\n", base_clk, PWM_FREQUENCY, pwm_period_cnt);
|
||||
}
|
||||
|
||||
extern int start_hilink_ble_net_config(int32_t net_cfg_time_s);
|
||||
void start_net_config(void) {
|
||||
e_printf("进入配网状态,上电次数:%d, is_new_device:%d\r\n", g_device_control.power_on_cnt, !g_device_control.is_net_configured);
|
||||
g_device_control.power_on_cnt = 0;//
|
||||
e_printf("进入配网状态,上电次数:%d, is_new设备:%d\r\n", g_device_control.power_on_cnt, !g_device_control.is_net_configured);
|
||||
// 按新规则:上电计数仅能在上电超过5秒后自然清零,
|
||||
// 配网流程不再主动清除 power_on_cnt。
|
||||
int ret = start_hilink_ble_net_config(NET_CFG_TOTAL_TIMEOUT/1000);
|
||||
if (ret) {
|
||||
// FIXME: 这里简单恢复之前等待配网的灯效即可
|
||||
@@ -1075,23 +1150,16 @@ static int handle_network_status(void)
|
||||
|
||||
// 检查是否需要进入配网状态或恢复出厂设置
|
||||
if (g_device_control.power_on_cnt >= NET_CFG_ENTRY_CNT) {
|
||||
// 任何状态下达到阈值都强制解绑并恢复出厂设置
|
||||
e_printf("快速上电达到 %d 次,强制恢复出厂设置(解绑)\r\n", NET_CFG_ENTRY_CNT);
|
||||
g_reset_factory_flag = true;
|
||||
g_device_control.power_on_cnt = 0;
|
||||
if (g_device_control.is_net_configured) {
|
||||
// 已出厂设备:上下电6次后恢复出厂设置并重启
|
||||
e_printf("已到达出厂设备上电次,执行恢复出厂设置\r\n");
|
||||
g_reset_factory_flag = true;
|
||||
extern int HILINK_RestoreFactorySettings(void);
|
||||
while (!hf_hilink_main_is_runing()) {
|
||||
msleep(10);
|
||||
}
|
||||
HILINK_RestoreFactorySettings();
|
||||
return start_net_cfg;
|
||||
} else {
|
||||
// 未出厂设备:进入配网模式
|
||||
e_printf("未出厂设备上电6次,进入配网模式\r\n");
|
||||
start_net_config();
|
||||
start_net_cfg = 1;
|
||||
extern int HILINK_RestoreFactorySettings(void);
|
||||
while (!hf_hilink_main_is_runing()) {
|
||||
msleep(10);
|
||||
}
|
||||
HILINK_RestoreFactorySettings();
|
||||
return start_net_cfg;
|
||||
} else if (!g_device_control.is_net_configured) {
|
||||
// 未出厂设备直接进入配网
|
||||
start_net_config();
|
||||
@@ -1274,18 +1342,17 @@ void handle_device_offline(void)
|
||||
// 处理设备解绑
|
||||
void handle_device_unbind(void)
|
||||
{
|
||||
e_printf("设备被解绑,重置配网状态\r\n");
|
||||
e_printf("设备被解绑,重置配网状态:%d\r\n", g_device_control.is_bound);
|
||||
if (g_device_control.is_bound) {
|
||||
g_device_control.is_bound = false;
|
||||
g_device_control.power_on_cnt = 0; // 重置上电计数
|
||||
// stop_spotlight_main_task();
|
||||
device_control_t tmp = DEFAULT_DEVICE_DATA;//恢复默认
|
||||
// if (!g_reset_factory_flag) {
|
||||
// tmp.is_net_configured = g_device_control.is_net_configured;
|
||||
// }
|
||||
g_device_control = tmp;
|
||||
save_device_data();
|
||||
}
|
||||
save_device_data();
|
||||
}
|
||||
|
||||
uint64_t startup_time = 0;
|
||||
@@ -1312,10 +1379,27 @@ static void *spotlight_main_task(const char *arg)
|
||||
unused(arg);
|
||||
e_printf("[spotlight_main_task] Task started\r\n");
|
||||
uint32_t current_time = 0; //uapi_systick_get_ms();
|
||||
// 自愈:在HiLink Main运行后做一次绑定状态一致性检查
|
||||
static bool s_bind_consistency_checked = false;
|
||||
while (spotlight_main_task_running) {
|
||||
// 检查配网超时
|
||||
check_net_cfg_timeout();
|
||||
check_net_cfg_power_on_keep_time();
|
||||
|
||||
if (!s_bind_consistency_checked && hf_hilink_main_is_runing()) {
|
||||
// 仅执行一次:检查应用层与HiLink SDK的绑定状态是否一致
|
||||
extern int HILINK_IsRegister(void);
|
||||
extern int HILINK_RestoreFactorySettings(void);
|
||||
int reg = HILINK_IsRegister();
|
||||
bool sdk_bound = (reg != 0);
|
||||
bool app_bound = g_device_control.is_bound;
|
||||
if (sdk_bound != app_bound) {
|
||||
e_printf("[consistency] app_bound=%d, sdk_bound=%d, do factory reset\r\n", app_bound, sdk_bound);
|
||||
// 触发完整流程:由HiLink框架内部清理持久化并按注册的重启回调执行
|
||||
HILINK_RestoreFactorySettings();
|
||||
}
|
||||
s_bind_consistency_checked = true;
|
||||
}
|
||||
osal_msleep(20);
|
||||
}
|
||||
|
||||
@@ -1402,6 +1486,10 @@ int spotlight_main(void) {
|
||||
read_device_data();
|
||||
// 初始化GPIO并将灯关闭
|
||||
gpio_init(SWITCH_PIN);
|
||||
|
||||
// 初始化 PWM 更新标志引脚(GPIO10)为普通GPIO输出,默认拉低
|
||||
gpio_init(PWM_UPDATE_FLAG_PIN);
|
||||
g_pwm_update_flag_inited = true;
|
||||
// 初始化PWM系统
|
||||
pwm_sys_init();
|
||||
pwm_init(BRIGHTNESS_PIN, CCT_PIN);
|
||||
@@ -1476,12 +1564,23 @@ static void set_light2net_cfg_done(void)
|
||||
g_device_control.brightness_local = BRIGHTNESS_REMOTE2LOCAL(NET_CFG_DEFAULT_BRIGHTNESS);
|
||||
g_device_control.cct_local = CCT_REMOTE2LOCAL(NET_CFG_DEFAULT_CCT);
|
||||
g_device_control.fade_time = NET_CFG_DEFAULT_FADE_TIME;
|
||||
|
||||
// 🔧 关键修复:配网完成后直接使用目标色温,不从PWM反推
|
||||
// PWM反推逻辑是错误的,因为呼吸灯PWM状态不代表用户期望的色温
|
||||
fade_ctx.current_brightness = g_device_control.brightness_local;
|
||||
fade_ctx.current_cct = g_device_control.cct_local;
|
||||
fade_ctx.current_cct = g_device_control.cct_local; // 直接使用目标色温
|
||||
e_printf("[set_light2net_cfg_done] 配网完成,同步色温: brightness=%d, cct=%d\n",
|
||||
fade_ctx.current_brightness, fade_ctx.current_cct);
|
||||
|
||||
// 设置目标值(与当前值一致,避免不必要的渐变)
|
||||
fade_ctx.target_brightness = g_device_control.brightness_local;
|
||||
fade_ctx.target_cct = g_device_control.cct_local;
|
||||
|
||||
calculate_pwm_duty(&g_device_control);
|
||||
update_pwm_output(g_device_control.on, g_device_control.duty_cw, g_device_control.duty_ww);
|
||||
|
||||
e_printf("[set_light2net_cfg_done] 配网完成状态同步: current_cct=%d, target_cct=%d\n",
|
||||
fade_ctx.current_cct, fade_ctx.target_cct);
|
||||
}
|
||||
|
||||
// 启动呼吸灯
|
||||
@@ -1502,4 +1601,3 @@ lightMode_e convert_mode_for_report(lightMode_e current_mode)
|
||||
// 否则上报基础模式
|
||||
return LIGHT_MODE_GET_BASE(current_mode);
|
||||
}
|
||||
|
||||
|
||||
@@ -130,7 +130,7 @@ target = {
|
||||
'-:hal_systick', 'partition', 'partition_ws63','pmp_cfg_ws63', 'nonos_malloc', 'nonos_malloc_port',
|
||||
'update_common', 'update_local', 'update_local_ws63', 'lzma_22.00', 'update_storage', 'update_common_ws63', 'update_ab_ws63', 'factory_ws63',
|
||||
'efuse', 'hal_efuse_v151', 'efuse_port', 'soc_port',
|
||||
'pwm', 'hal_pwm', 'pwm_port', # ADD
|
||||
# 'pwm', 'hal_pwm', 'pwm_port', # ADD
|
||||
],
|
||||
'ram_component_set': ['uart', "time_set", "cpu", "pinctrl", "watchdog", "security_unified",'pmp_set'],
|
||||
'os': 'non-os',
|
||||
@@ -288,7 +288,7 @@ target = {
|
||||
},
|
||||
'ws63-liteos-app-iot': {
|
||||
'base_target_name': 'target_ws63_app_rom_template',
|
||||
'liteos_kconfig': 'ws63_iot', #ekko add for remove indie upgrade
|
||||
'liteos_kconfig': 'ws63_iot', # EKKO add for remove indie upgrade
|
||||
'os': 'liteos',
|
||||
'defines': [
|
||||
"USE_CMSIS_OS",
|
||||
@@ -336,7 +336,7 @@ target = {
|
||||
"CONFIG_USE_CUSTOMER_SVC_INFO", #EKKO ADD
|
||||
"CONFIG_DHCPS_GW",
|
||||
"_HSF_",
|
||||
"CONFIG_PWM_USING_V150", #EKKO ADD
|
||||
"CONFIG_PWM_PRELOAD", # Enable PWM preload (period-boundary update)
|
||||
# "ENABLE_BLE_SCAN" #open ble scan
|
||||
],
|
||||
'ram_component': [
|
||||
@@ -379,11 +379,10 @@ target = {
|
||||
'cjson',
|
||||
'xo_trim_port',
|
||||
'hilink',
|
||||
#'app_addr_map', #ekko remove for indie upgrade
|
||||
'hilinkdevicesdk', #ekko add for remove indie upgrade
|
||||
'hilinkota', #ekko add for remove indie upgrade
|
||||
'hilinkbtsdk', #ekko add for remove indie upgrade
|
||||
#'hilinkquickcfg', #ekko add for remove indie upgrade
|
||||
# 'app_addr_map', # ekko remove for remove indie upgrade
|
||||
'hilinkdevicesdk', # ekko add for remove indie upgrade
|
||||
'hilinkota', # ekko add for remove indie upgrade
|
||||
'hilinkbtsdk', # ekko add for remove indie upgrade
|
||||
'huks_sdk',
|
||||
'deviceauth',
|
||||
'little_fs', 'littlefs_adapt_ws63',
|
||||
|
||||
361
docs/serial_control_protocol.md
Normal file
361
docs/serial_control_protocol.md
Normal file
@@ -0,0 +1,361 @@
|
||||
# 串口控制协议
|
||||
|
||||
## 目录
|
||||
|
||||
- [1. 指令格式](#1-指令格式)
|
||||
- [1.1 串口参数](#11-串口参数)
|
||||
- [2. JSON 结构](#2-json-结构)
|
||||
- [2.1 字段说明](#21-字段说明)
|
||||
- [2.2 发送提示](#22-发送提示)
|
||||
- [2.3 查询命令(AT+QUERY)](#23-查询命令atquery)
|
||||
- [3. 支持服务与字段(详解)](#3-支持服务与字段详解)
|
||||
- [3.1 switch(开关)](#31-switch开关)
|
||||
- [3.2 brightness(亮度)](#32-brightness亮度)
|
||||
- [3.3 cct(色温)](#33-cct色温)
|
||||
- [3.4 lightMode(场景模式)](#34-lightmode场景模式)
|
||||
- [3.5 progressSwitch(渐变时长)](#35-progressswitch渐变时长)
|
||||
- [3.6 colourMode(色温模式)](#36-colourmode色温模式)
|
||||
- [4. 约束](#4-约束)
|
||||
- [5. 错误码](#5-错误码)
|
||||
- [5.1 NotControllable(112)用法建议](#51-notcontrollable112用法建议)
|
||||
- [6. 时序图示(Mermaid)](#6-时序图示mermaid)
|
||||
- [7. 示例](#7-示例)
|
||||
|
||||
## 1. 指令格式
|
||||
|
||||
- 下发:`AT+CTRL={JSON}\r\n`
|
||||
- 查询:`AT+QUERY={JSON}\r\n`
|
||||
- 回执:`OK,<id>\r\n` 或 `ERROR,<code>[,<message>]\r\n`
|
||||
- 异步结果:`AT+RESP={JSON}\r\n`
|
||||
- 规则:
|
||||
- 单行 JSON(内部换行请写成 `\n`)
|
||||
- 行结束统一为 CRLF `\r\n`(Windows 兼容)
|
||||
- 接收端应兼容仅 LF `\n`
|
||||
|
||||
### 1.1 串口参数
|
||||
- 波特率:`9600`
|
||||
- 数据位:`8`
|
||||
- 校验位:`None`
|
||||
- 停止位:`1`
|
||||
- 流控:`None`
|
||||
- 编码:`UTF-8`(无 BOM)
|
||||
- 建议:行缓冲读取,按 CRLF `\r\n` 作为帧结束。
|
||||
|
||||
## 2. JSON 结构
|
||||
|
||||
- 单服务控制(必须携带 id):
|
||||
- 下发:`{"id": <u32>, "sid":"<serviceId>", "data": {<fields>}}`
|
||||
- 返回:`{"id": <u32>, "sid":"<serviceId>", "data": {<fields>}, "error": <u32>, "message": "<可选>"}`(`error=0` 表示成功)
|
||||
|
||||
### 2.1 字段说明
|
||||
- `id`(number, u32>0,必填)
|
||||
- 会话标识,用于将异步结果与请求一一对应、便于定位问题。
|
||||
- 由发起方分配与维护,建议使用一个全局自增计数(溢出后回绕到 1)。
|
||||
- 受控方不做去重与顺序检查,仅在 RESP 中原样回显。
|
||||
- `sid`(string,必填)
|
||||
- 服务功能 ID。合法值:`switch`、`brightness`、`cct`、`lightMode`、`progressSwitch`、`colourMode`。
|
||||
- 区分大小写;不在集合内的值视为不支持服务。
|
||||
- `data`(object,必填)
|
||||
- 具体服务的数据负载。各服务的字段与范围见“支持服务与字段(详解)”。
|
||||
- 缺字段或类型不符为业务错误,RESP `error=105`(`message` 可携带原因)。
|
||||
- `error`(number, u32,RESP 必带)
|
||||
- 业务执行结果码:`0` 成功;非 0 失败。常见值见“错误码”。
|
||||
- `message`(string,可选,RESP 可带)
|
||||
- 人类可读的错误或提示信息,用于调试。
|
||||
|
||||
### 2.2 发送提示
|
||||
- 多次控制:请按需多次发送 `AT+CTRL=...`,每次使用不同的 `id`。
|
||||
- ACK 超时与重发建议:
|
||||
- 发送后等待 `OK,<id>`,超时建议 `200–500 ms`。
|
||||
- 未收到 ACK 则按原 `id` 与完全相同的 JSON 重发,重发 `2–3 次`,间隔 `200–300 ms`。
|
||||
- 注意:设备不做去重,重复下发可能重复执行;建议尽量使用幂等设置(如重复设置相同亮度)。
|
||||
- 结果等待与超时:
|
||||
- 收到 `OK,<id>` 后等待 `AT+RESP`,建议超时阈值 `1–2 s`(视业务而定)。
|
||||
- 超时未收到可按失败处理并在上层重试(使用新的 `id`)。
|
||||
- 换行约定:所有发送与回执均以 CRLF `\r\n` 结束;示例为单行展示,实际发送需包含 CRLF。
|
||||
|
||||
### 2.3 查询命令(AT+QUERY)
|
||||
- 作用:查询指定 `sid` 的当前状态(只读,不改变设备状态)。
|
||||
- 下发:`AT+QUERY={"id": <u32>, "sid":"<serviceId>"}`\r\n
|
||||
- 回执:`OK,<id>`\r\n
|
||||
- 异步结果:`AT+RESP={"id": <u32>, "sid":"<serviceId>", "data": {<current-fields>}, "error": <u32>, "message": "<可选>"}`\r\n
|
||||
- 说明:
|
||||
- `data` 与“支持服务与字段(详解)”中各 `sid` 的状态格式一致(等同于 Get 接口的输出)。
|
||||
- 若 `sid` 不支持,返回 `ERROR,104,UnsupportedSid`(协议级错误)。
|
||||
|
||||
## 3. 支持服务与字段(详解)
|
||||
|
||||
### 3.1 switch(开关)
|
||||
- 功能:控制灯具开/关。
|
||||
- 下发:`{"id":<u32>,"sid":"switch","data":{"on":0|1}}`
|
||||
- 返回:`{"id":<u32>,"sid":"switch","data":{"on":0|1},"error":<u32>,"message":"<可选>"}`
|
||||
- 参数:`on` 为 int,取值 `0` 关、`1` 开。
|
||||
- 行为:当处于“离家模式”(mode=7)时,收到 `on=1` 会先退出离家模式再开灯。
|
||||
- 示例:
|
||||
- 开灯
|
||||
- 【发起方发送】`AT+CTRL={"id":101,"sid":"switch","data":{"on":1}}`
|
||||
- 【受控方返回】`OK,101` 与 `AT+RESP={"id":101,"sid":"switch","data":{"on":1},"error":0}`
|
||||
- 关灯
|
||||
- 【发起方发送】`AT+CTRL={"id":102,"sid":"switch","data":{"on":0}}`
|
||||
- 【受控方返回】`OK,102` 与 `AT+RESP={"id":102,"sid":"switch","data":{"on":0},"error":0}`
|
||||
|
||||
### 3.2 brightness(亮度)
|
||||
- 功能:设置亮度百分比。
|
||||
- 下发:`{"id":<u32>,"sid":"brightness","data":{"brightness":0..100}}`
|
||||
- 返回:`{"id":<u32>,"sid":"brightness","data":{"brightness":<0..100>},"error":<u32>,"message":"<可选>"}`
|
||||
- 参数:`brightness` 为 int,范围 `0..100`;超出范围按边界钳制。
|
||||
- 示例:
|
||||
- 设为 60%:`AT+CTRL={"id":201,"sid":"brightness","data":{"brightness":60}}`
|
||||
- 最小值:`AT+CTRL={"id":202,"sid":"brightness","data":{"brightness":0}}`
|
||||
- 最大值:`AT+CTRL={"id":203,"sid":"brightness","data":{"brightness":100}}`
|
||||
|
||||
### 3.3 cct(色温)
|
||||
- 功能:设置色温(单位 K)。
|
||||
- 下发:`{"id":<u32>,"sid":"cct","data":{"colorTemperature":2700..6000}}`
|
||||
- 返回:`{"id":<u32>,"sid":"cct","data":{"colorTemperature":<2700..6000>},"error":<u32>,"message":"<可选>"}`
|
||||
- 参数:`colorTemperature` 为 int,范围 `2700..6000`;超出范围按边界钳制。
|
||||
- 示例:
|
||||
- 暖色 3000K:`AT+CTRL={"id":301,"sid":"cct","data":{"colorTemperature":3000}}`
|
||||
- 中性 4000K:`AT+CTRL={"id":302,"sid":"cct","data":{"colorTemperature":4000}}`
|
||||
- 冷色 6000K:`AT+CTRL={"id":303,"sid":"cct","data":{"colorTemperature":6000}}`
|
||||
|
||||
### 3.4 lightMode(场景模式)
|
||||
- 功能:按预设场景设置亮度与色温,或进入离家模式。
|
||||
- 下发:`{"id":<u32>,"sid":"lightMode","data":{"mode":0..7}}`
|
||||
- 返回:`{"id":<u32>,"sid":"lightMode","data":{"mode":<0..7>},"error":<u32>,"message":"<可选>"}`
|
||||
- 参数:`mode` 为 int:
|
||||
- 0 customer(自定义模式)
|
||||
- 1 relax (休闲模式)(约 50%,4000K)
|
||||
- 2 movie(观影模式)(约 10%,3000K)
|
||||
- 3 dining(用餐模式)(约 100%,4000K)
|
||||
- 4 home(回家模式)(约 80%,3500K)
|
||||
- 5 winter(冬天模式)(约 100%,2700K)
|
||||
- 6 summer(夏天模式)(约 100%,6000K)
|
||||
- 7 leave(离家模式)(直接关灯)
|
||||
- 示例:
|
||||
- 观影模式:`AT+CTRL={"id":401,"sid":"lightMode","data":{"mode":2}}`
|
||||
- 离家模式:`AT+CTRL={"id":402,"sid":"lightMode","data":{"mode":7}}`
|
||||
- 回家模式:`AT+CTRL={"id":403,"sid":"lightMode","data":{"mode":4}}`
|
||||
|
||||
### 3.5 progressSwitch(渐变时长)
|
||||
- 功能:设置亮度/色温变化的平滑过渡时间(秒)。
|
||||
- 下发:`{"id":<u32>,"sid":"progressSwitch","data":{"fadeTime":0..30}}`
|
||||
- 返回:`{"id":<u32>,"sid":"progressSwitch","data":{"fadeTime":<0..30>},"error":<u32>,"message":"<可选>"}`
|
||||
- 参数:`fadeTime` 为 int,范围 `0..30` 秒;`0` 表示尽快变化。
|
||||
- 示例:
|
||||
- 设为 5 秒:`AT+CTRL={"id":501,"sid":"progressSwitch","data":{"fadeTime":5}}`
|
||||
- 立即变化:`AT+CTRL={"id":502,"sid":"progressSwitch","data":{"fadeTime":0}}`
|
||||
|
||||
### 3.6 colourMode(色温模式)
|
||||
- 功能:设置色温工作模式。
|
||||
- 下发:`{"id":<u32>,"sid":"colourMode","data":{"mode":0|1}}`
|
||||
- 返回:`{"id":<u32>,"sid":"colourMode","data":{"mode":0|1},"error":<u32>,"message":"<可选>"}`
|
||||
- 参数:`mode` 为 int:`0` 单色温、`1` 双色温。
|
||||
- 行为:单色温(0)下,设备固定到预设色温(6000K);双色温(1)下,使用/保持当前色温。
|
||||
- 示例:
|
||||
- 单色温:`AT+CTRL={"id":601,"sid":"colourMode","data":{"mode":0}}`
|
||||
- 双色温:`AT+CTRL={"id":602,"sid":"colourMode","data":{"mode":1}}`
|
||||
|
||||
## 4. 约束
|
||||
- `{JSON}` 最大长度:≤ 1024 字节(不含前缀与行尾)。
|
||||
- 单行承载,不允许真实换行;内部换行使用 `\n` 字符串。
|
||||
- 行结束采用 CRLF `\r\n`;接收端应兼容仅 LF `\n`。
|
||||
- `id` 必须存在且为 u32>0;缺失/类型不符即返回 `ERROR,105,TypeError`。
|
||||
|
||||
## 5. 错误码
|
||||
- `100` BadPrefix(未以 `AT+CTRL=` 开头)
|
||||
- `101` MalformedJSON(JSON 语法错误)
|
||||
- `102` EmptyJSON(空 JSON)
|
||||
- `103` PayloadTooLong(负载超长)
|
||||
- `104` UnsupportedSid(不支持的 `sid`)
|
||||
- `105` TypeError(字段缺失或类型不符)
|
||||
- `106` Busy(设备忙)
|
||||
- `107` ApplyTimeout(内部执行超时)
|
||||
- `112` NotControllable(非受控状态:设备处于不可被控制的模式,例如升级/维护/工厂测试/安全锁定等)
|
||||
- `111` RateLimited(限频)
|
||||
|
||||
### 5.1 NotControllable(112)用法建议
|
||||
- 触发场景(示例):
|
||||
- 升级进行中(OTA/独立升级/固件校验)
|
||||
- 维护/自检/烧录/工厂测试模式
|
||||
- 安全锁定/童锁/设备被上级网关临时锁定
|
||||
- 热保护/过温降额/低电量保护等安全策略生效
|
||||
- 正在配网/关键迁移流程,不允许外部控制
|
||||
- 返回规范:
|
||||
- 收到控制后先回 ACK:`OK,<id>`
|
||||
- 业务结束后返回:`AT+RESP={"id":<id>,"sid":"<sid>","data":{...},"error":112,"message":"<原因>"}`
|
||||
- `message` 建议取值(便于前端统一展示与日志聚合):
|
||||
- `upgrading`(升级中)
|
||||
- `maintenance`(维护/自检)
|
||||
- `factory_test`(工厂测试)
|
||||
- `locked`(安全/家长锁定)
|
||||
- `thermal_protect`(热保护)
|
||||
- `low_power`(低电量保护)
|
||||
- `net_config`(正在配网)
|
||||
- 查询建议:
|
||||
- `AT+QUERY` 通常仍应返回当前状态并 `error=0`;若状态不可读,再返回 `error=112` 与合适的 `message`。
|
||||
|
||||
## 6. 时序图示(Mermaid)
|
||||
|
||||
1) 多次控制(均成功,异步返回 `error=0`)
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant 发起方
|
||||
participant 受控方
|
||||
|
||||
发起方->>受控方: AT+CTRL={"id":7001,"sid":"switch","data":{"on":1}}\r\n
|
||||
受控方-->>发起方: OK,7001\r\n
|
||||
note over 受控方: 执行开关控制
|
||||
受控方-->>发起方: AT+RESP={"id":7001,"sid":"switch","data":{"on":1},"error":0}\r\n
|
||||
|
||||
发起方->>受控方: AT+CTRL={"id":7201,"sid":"lightMode","data":{"mode":2}}\r\n
|
||||
受控方-->>发起方: OK,7201\r\n
|
||||
note over 受控方: 执行场景模式切换
|
||||
受控方-->>发起方: AT+RESP={"id":7201,"sid":"lightMode","data":{"mode":2},"error":0}\r\n
|
||||
|
||||
发起方->>受控方: AT+CTRL={"id":7301,"sid":"progressSwitch","data":{"fadeTime":5}}\r\n
|
||||
受控方-->>发起方: OK,7301\r\n
|
||||
note over 受控方: 设置渐变时长
|
||||
受控方-->>发起方: AT+RESP={"id":7301,"sid":"progressSwitch","data":{"fadeTime":5},"error":0}\r\n
|
||||
```
|
||||
|
||||
2) 协议级错误(JSON 语法错误,直接 `ERROR`,不产生 RESP)
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant 发起方
|
||||
participant 受控方
|
||||
|
||||
发起方->>受控方: AT+CTRL={"sid":"switch","data":{"on":1}
|
||||
受控方-->>发起方: ERROR,101,MalformedJSON
|
||||
note over 受控方: 帧被丢弃,无 AT+RESP
|
||||
```
|
||||
|
||||
3) 业务错误(收到并受理,但参数类型错误)
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant 发起方
|
||||
participant 受控方
|
||||
|
||||
发起方->>受控方: AT+CTRL={"id":7501,"sid":"brightness","data":{"brightness":"sixty"}}\r\n
|
||||
受控方-->>发起方: OK,7501\r\n
|
||||
note over 受控方: 参数校验失败(类型错误)
|
||||
受控方-->>发起方: AT+RESP={"id":7501,"sid":"brightness","data":{"brightness":50},"error":105,"message":"TypeError"}\r\n
|
||||
```
|
||||
|
||||
4) 查询状态(OK + RESP)
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant 发起方
|
||||
participant 受控方
|
||||
|
||||
发起方->>受控方: AT+QUERY={"id":7101,"sid":"brightness"}\r\n
|
||||
受控方-->>发起方: OK,7101\r\n
|
||||
note over 受控方: 读取并打包当前亮度状态
|
||||
受控方-->>发起方: AT+RESP={"id":7101,"sid":"brightness","data":{"brightness":60},"error":0}\r\n
|
||||
```
|
||||
|
||||
## 7. 示例
|
||||
|
||||
1) 开关:打开
|
||||
【发起方发送】
|
||||
```
|
||||
AT+CTRL={"id":7001,"sid":"switch","data":{"on":1}}
|
||||
```
|
||||
【受控方返回】
|
||||
```
|
||||
OK,7001
|
||||
```
|
||||
【受控方返回】
|
||||
```
|
||||
AT+RESP={"id":7001,"sid":"switch","data":{"on":1},"error":0}
|
||||
```
|
||||
|
||||
2) 查询当前亮度
|
||||
【发起方发送】
|
||||
```
|
||||
AT+QUERY={"id":7101,"sid":"brightness"}
|
||||
```
|
||||
【受控方返回】
|
||||
```
|
||||
OK,7101
|
||||
```
|
||||
【受控方返回】
|
||||
```
|
||||
AT+RESP={"id":7101,"sid":"brightness","data":{"brightness":60},"error":0}
|
||||
```
|
||||
|
||||
3) 场景模式:movie
|
||||
【发起方发送】
|
||||
```
|
||||
AT+CTRL={"id":7201,"sid":"lightMode","data":{"mode":2}}
|
||||
```
|
||||
【受控方返回】
|
||||
```
|
||||
OK,7201
|
||||
```
|
||||
【受控方返回】
|
||||
```
|
||||
AT+RESP={"id":7201,"sid":"lightMode","data":{"mode":2},"error":0}
|
||||
```
|
||||
|
||||
4) 渐变时长:5 秒
|
||||
【发起方发送】
|
||||
```
|
||||
AT+CTRL={"id":7301,"sid":"progressSwitch","data":{"fadeTime":5}}
|
||||
```
|
||||
【受控方返回】
|
||||
```
|
||||
OK,7301
|
||||
```
|
||||
【受控方返回】
|
||||
```
|
||||
AT+RESP={"id":7301,"sid":"progressSwitch","data":{"fadeTime":5},"error":0}
|
||||
```
|
||||
|
||||
5) 色温模式:单色温
|
||||
【发起方发送】
|
||||
```
|
||||
AT+CTRL={"id":7401,"sid":"colourMode","data":{"mode":0}}
|
||||
```
|
||||
【受控方返回】
|
||||
```
|
||||
OK,7401
|
||||
```
|
||||
【受控方返回】
|
||||
```
|
||||
AT+RESP={"id":7401,"sid":"colourMode","data":{"mode":0},"error":0}
|
||||
```
|
||||
|
||||
6) 业务失败(类型错误)
|
||||
【发起方发送】
|
||||
```
|
||||
AT+CTRL={"id":7501,"sid":"brightness","data":{"brightness":"sixty"}}
|
||||
```
|
||||
【受控方返回】
|
||||
```
|
||||
OK,7501
|
||||
```
|
||||
【受控方返回】
|
||||
```
|
||||
AT+RESP={"id":7501,"sid":"brightness","data":{"brightness":50},"error":105,"message":"TypeError"}
|
||||
```
|
||||
|
||||
7) 非法 JSON(协议级错误)
|
||||
【发起方发送】
|
||||
```
|
||||
AT+CTRL={"sid":"switch","data":{"on":1}
|
||||
```
|
||||
【受控方返回】
|
||||
```
|
||||
ERROR,101,MalformedJSON
|
||||
```
|
||||
|
||||
8) 不支持的服务(协议级错误)
|
||||
【发起方发送】
|
||||
```
|
||||
AT+CTRL={"id":7601,"sid":"foo","data":{"bar":1}}
|
||||
```
|
||||
【受控方返回】
|
||||
```
|
||||
ERROR,104,UnsupportedSid
|
||||
```
|
||||
BIN
docs/serial_control_protocol.pdf
Executable file
BIN
docs/serial_control_protocol.pdf
Executable file
Binary file not shown.
@@ -124,6 +124,7 @@ def all_build():
|
||||
os.makedirs(temp_dir)
|
||||
|
||||
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")
|
||||
|
||||
BIN
output/LPT262_hilink-SR_Switch-20251026-1.0.6.fwpkg
Normal file
BIN
output/LPT262_hilink-SR_Switch-20251026-1.0.6.fwpkg
Normal file
Binary file not shown.
BIN
output/package(SR_Switch-LPT262_hilink-20251026-1.0.6).zip
Normal file
BIN
output/package(SR_Switch-LPT262_hilink-20251026-1.0.6).zip
Normal file
Binary file not shown.
440
ws63_check_json_analysis.md
Normal file
440
ws63_check_json_analysis.md
Normal file
@@ -0,0 +1,440 @@
|
||||
# WS63 Check.json 文件分析完整文档
|
||||
|
||||
## 概述
|
||||
|
||||
本文档详细分析了 `ws63-liteos-hilink-check.json` 文件的生成机制、校验内容和对应关系。该文件是WS63项目独立升级功能的核心组件,用于验证HiLink固件与App-IoT固件之间的接口兼容性。
|
||||
|
||||
## 1. JSON文件基本信息
|
||||
|
||||
**文件路径**: `./output/ws63/acore/ws63-liteos-hilink/ws63-liteos-hilink-check.json`
|
||||
|
||||
**文件内容结构**:
|
||||
```json
|
||||
{
|
||||
"ver": 1,
|
||||
"app": "3A23309AAF0B692188B9C56755C084522354143382C5309A2D3258C3E6C834A500B53089C7A65C43392D51DFEF32BBC125B613C6B37656F59E142F0D713AD6115955749E72C53C3BA8CD96D2C69CB534231411DEAE5C4F1782DA2760BB04E0199813CAC4CBA339BEBF3D734FBF0955235DD160C0387CA4AD28BFC8766508F627D0B46BE48319EAC371921D27D806C9F3464BF4DFBAE09ADB95232386B021EEFBD3FAD2C6B405A1E9C13BB0420CAB5EF02D3D543090162EB8E51C2E1D10F3EE4EE5FE71A0BA8DF1E95E4A36694908DDB16E08F54B606E13CACB530F71320CC9DF6C3DCB70DC6E54BDA7B3C1720E7ECCB54E88950CFC3D4D700224AB40D9E568A89571387053E9BB3D77889DAA102DB1FC4CE38751F2E6A0BD27B0EC51B8EA015CE0E475ADF3E3CDB49580E84E228803A691F39D958D3F28B0E4D53C670A27B5AB436D11F83A8AAEB6538628D32F674C398B6CF1C295BAB9499E19EA993B11D07524E025EF6FF88F42331C3BE36689468DAF74C6B811187E2D7953251B9228B8A8C32422F97C0122332BB295C110F36291A845CD2FA2D6BC34E37B7CBE23083067AE8AF9346DEEEFCC168D2D4658A94AB5049858C11E8BE4672F492DE9B4046E4B0EEEA5E3D6FE8809743B2B6111718F2038742D7C48EE81BBD5D485373D34C70868622D3233179ADED3E8C5026A2217F6938E85AA7A6754CE869A8127656D364C00F05E95FE7738AD05E79CACA11368FAE6717C71C469FC934FF221953E9F7CA301D52266EA04E8184A6D5AF66621F90139D0642D0350FA3F28ED49CF23AC20D03710992FBE7E3DBCEBD737385AE906D8D885A6118F2416A45FFA93EC3483EDADE5864419C451689382274A6DEC6FD6734D3975199C9FFB561202FEAB34F195D595E791C43315669E430FB9E7288EF87BC4498A4DF1A93918FA7C7805F7131CCF092F762F28C0A502EC955661D19C624CD0B61E88F81F9D57108A971D268273CEABEE8013FF69661C1A29BBD995111C6A64314013FBA647F77B736AE8E330F3D7157E6C3774AFBCC38D643C7108363127CB03B902C6D32C202A73EE7099A65902A14959BA60D70D055A89A6C3E489489F355E418A02EF8A543D8DF826C59AD8FABD1564AF4FEE6224FCA67974F6F63E17D3036A50120E5449669A4D792E919F88C4BBEEC64E542216D35ED1DE5A21434FC521776D37F5C50257B639AA3F47D1CC1888A19961CD6F5D7C9BEF30D5EACE785DB24268E360581533F98458376DD1E770BF3612B6D1F9C62395F48BEDE23AE1514E24C79360CE44291140AFEC5576503E6EBBC1D453DC9ED772F6AA506112D26C5B806EC4E0EAEC6A98F6F1683AC86494FA565B7CE2A0540F45AC6A8A556CDEE96B315EF45ED456EF46F1E5C234ABF92B121CCE688D2163BDF57FB6098B4742FBC504AC5E03230ADF90428D53F024F9C20964CA8AEA8A9042D1CEF0A2BA9C88A011C1004A9B8F7F9EBEDA365056947E9426D868829904D70DA74B7276D93829D151333F3506E83032A8CF68630BD5D0A39237FDF0BADD131AB77B6092987F07139588081D140EB2A0CA25BF9267FBC809457528A7C5DFA1729552A8D76B3362B9915E84795CD770EB84A3AE73DE78F04D37E8FC2F53E2F72853D57F170FC2551F7CBBB9B63D119AC4775120418F3865792FEFAAFF69038BFD3AA3C2C476B26DFB2B48F3B3904203C394782FE1C40F718001C31504539827DDC80900966524DCE965006F86EBDA9C46226BC1DA2387E2AE9565DFEE621F0DA936298371D1AD83860B4E607BB473E4103ADF872D1A3CA9EB171CF73077B4AFC2D7FC3737FAE5337290D8116CE0826F347C621502BA313EEF20F1F67D00A7EB1BB555DE7B0FCDD05C747D7615136B35079DA4BF9A6EED5F0C5448B8364FB03476275BD823C8C7F3CBCC1D0BD41C5B49538D65C00C85F9C8D50201EDA6266D7A2A375141F7F5E69E1AD06932C3A6C044EAE908D43657EA22C5FA797FE8D04592541477B362753A05",
|
||||
"hilink": "BEC62B3A1B90717BABD8C9AD15D3BE1560977111A022C59CEF399A97E8B1D1D2D981EE972F4C881D0D3D30D8165FA46BEB1F07B4B8F1AECEA4335DFC7388E1234641EDD1AF31DFEDB616EBF0A9900778C03C4467D3CBCD6540F51D66CBE0FF998506BA06448D8BEB6CDA8E9E79BE4C8BF15449A4DEFEB22F342B09F03683E17D699DA475D08A2F079EDA59B99A96CD0E468B089224120EE96B86A8BB4B250B35E0E8B8A1E77FE8A13F50CF8B018FA5A91475DDA932141DAF1F5C4D9C5D7F8DC8E3CB582D0DB0EA8823396BF6BC0A30D68B968BEE77AB6014036385A68BB35701D274404A9BFA24348E7321F63FEA98B7"
|
||||
}
|
||||
```
|
||||
|
||||
## 2. 文件生成机制
|
||||
|
||||
### 2.1 生成触发条件
|
||||
|
||||
**触发时机**: 在构建过程的 `build_post` 阶段(构建完成后)
|
||||
|
||||
**配置条件**: 编译配置中必须包含 `CONFIG_SUPPORT_HILINK_INDIE_UPGRADE`
|
||||
- 当前项目状态:该配置**已被注释**(config.py:334行)
|
||||
- 因此只有HiLink固件生成了check.json,App-IoT固件未生成
|
||||
|
||||
### 2.2 生成调用链
|
||||
|
||||
```
|
||||
构建系统 (build.py)
|
||||
↓
|
||||
build_post 钩子
|
||||
↓
|
||||
entry.py:153 → dump_indie_upg_check_file()
|
||||
↓
|
||||
indie_upgrade_utils.py:324 → 生成JSON文件
|
||||
```
|
||||
|
||||
### 2.3 核心生成文件
|
||||
|
||||
**主要脚本文件**:
|
||||
- `build/config/target_config/ws63/script/entry.py:153` - 构建钩子调用点
|
||||
- `build/script/utils/indie_upgrade_utils.py:324` - JSON文件生成函数
|
||||
- `build/script/utils/indie_upgrade_utils.py:292-320` - 接口校验码生成核心逻辑
|
||||
|
||||
## 3. 校验内容详解
|
||||
|
||||
### 3.1 JSON字段含义
|
||||
|
||||
| 字段 | 含义 | 数据格式 |
|
||||
|------|------|----------|
|
||||
| `ver` | 校验文件版本号 | 整数,当前为1 |
|
||||
| `app` | App侧接口校验码串联 | CRC32十六进制字符串 |
|
||||
| `hilink` | HiLink侧接口校验码串联 | CRC32十六进制字符串 |
|
||||
|
||||
### 3.2 校验码生成原理
|
||||
|
||||
1. **接口函数扫描**: 通过正则表达式扫描源文件中的函数原型
|
||||
```python
|
||||
rgl = r"((?:const )?(?:unsigned )?(?:struct )?(?:enum )?\w+[ \*]*)" + \
|
||||
r"(\w+)[\s\n]*" + \
|
||||
r"(\()" + \
|
||||
r"([\s\*,\w\[\]]*?)" + \
|
||||
r"(\))" + \
|
||||
r"\s*\{"
|
||||
```
|
||||
|
||||
2. **原型标准化**: 去除参数名,保留参数类型,生成标准化函数原型字符串
|
||||
|
||||
3. **CRC32计算**: 对每个函数原型字符串计算CRC32校验码
|
||||
```python
|
||||
checksum = "{:08X}".format(zlib.crc32(prototype.encode("utf8")))
|
||||
```
|
||||
|
||||
4. **校验码串联**: 将所有接口的8位十六进制CRC32码按顺序串联
|
||||
|
||||
### 3.3 校验码对应的编译文件
|
||||
|
||||
| JSON字段 | 编译目标 | 二进制文件 | 签名文件 |
|
||||
|----------|----------|------------|----------|
|
||||
| `"app"` | `ws63-liteos-app-iot` | `output/ws63/acore/ws63-liteos-app-iot/ws63-liteos-app-iot.bin` | `ws63-liteos-app-iot-sign.bin` |
|
||||
| `"hilink"` | `ws63-liteos-hilink` | `output/ws63/acore/ws63-liteos-hilink/ws63-liteos-hilink.bin` | `ws63-liteos-hilink-sign.bin` |
|
||||
|
||||
## 4. 接口映射文件体系
|
||||
|
||||
### 4.1 App侧接口配置
|
||||
|
||||
**源文件路径**: `application/samples/wifi/hilink_indie_upgrade/address_mapping/hilinksdk/app_uapi/`
|
||||
|
||||
**主要接口文件**:
|
||||
- `uapi_hilink_kv_adapter.c` - KV存储适配器接口
|
||||
- `uapi_hilink_mem_adapter.c` - 内存管理适配器接口
|
||||
- `uapi_hilink_socket_adapter.c` - Socket网络适配器接口
|
||||
- `uapi_hilink_stdio_adapter.c` - 标准IO适配器接口
|
||||
- `uapi_hilink_thread_adapter.c` - 线程管理适配器接口
|
||||
- `uapi_hilink_time_adapter.c` - 时间管理适配器接口
|
||||
- `uapi_hilink_network_adapter.c` - 网络适配器接口
|
||||
- `uapi_hilink_device.c` - 设备管理接口
|
||||
- `uapi_hichain.c` - 设备认证接口
|
||||
- `uapi_hilink_ble_adapter.c` - BLE适配器接口
|
||||
- 等共52个接口适配文件
|
||||
|
||||
**生成的映射表**: `application/samples/wifi/hilink_indie_upgrade/address_mapping/application/app_function_mapping.c`
|
||||
|
||||
### 4.2 HiLink侧接口配置
|
||||
|
||||
**源文件路径**: `application/samples/wifi/hilink_indie_upgrade/address_mapping/application/hilink_uapi/`
|
||||
|
||||
**主要接口文件**:
|
||||
- `uapi_hilink.c` - HiLink核心接口
|
||||
- `uapi_hilink_log_manage.c` - 日志管理接口
|
||||
- `uapi_hilink_device_ext.c` - 设备扩展接口
|
||||
- `uapi_ble_cfg_net_api.c` - BLE配网接口
|
||||
- `uapi_hilink_bt_function.c` - 蓝牙功能接口
|
||||
- `uapi_hilink_network_adapter.c` - 网络适配器接口
|
||||
- `uapi_hilink_socket_adapter.c` - Socket适配器接口
|
||||
- `uapi_hilink_custom.c` - 自定义功能接口
|
||||
- `uapi_hilink_sle_api.c` - SLE接口
|
||||
- `uapi_hilink_quick_netcfg_api.c` - 快速配网接口
|
||||
|
||||
**生成的映射表**: `application/samples/wifi/hilink_indie_upgrade/address_mapping/hilinksdk/hilink_function_mapping.c`
|
||||
|
||||
### 4.3 接口头文件映射
|
||||
|
||||
**App侧头文件路径**:
|
||||
- `application/samples/wifi/ohos_connect/hilink_adapt/adapter/include/` - 适配器接口声明
|
||||
- `application/samples/wifi/ohos_connect/hilink_adapt/product/` - 产品相关接口
|
||||
- `application/samples/wifi/ohos_connect/hilink_adapt/include/` - 通用接口声明
|
||||
- `open_source/deviceauth/interfaces/innerkits/deviceauth_lite/` - 设备认证接口
|
||||
- `kernel/liteos/liteos_v208.5.0/Huawei_LiteOS/open_source/CMSIS/CMSIS/RTOS2/Include/` - RTOS接口
|
||||
- `open_source/cjson/cjson/` - JSON库接口
|
||||
- `open_source/mbedtls/mbedtls_v3.1.0/include/` - 加密库接口
|
||||
|
||||
**HiLink侧头文件路径**:
|
||||
- `application/samples/wifi/ohos_connect/hilink_adapt/include/` - HiLink核心接口声明
|
||||
- `application/samples/wifi/ohos_connect/hilink_adapt/product/` - 产品相关接口
|
||||
- `application/samples/wifi/ohos_connect/hilink_adapt/adapter/include/` - 适配器接口声明
|
||||
|
||||
## 5. 校验机制详解
|
||||
|
||||
### 5.1 接口兼容性检查函数
|
||||
|
||||
**函数位置**: `build/script/utils/indie_upgrade_utils.py:353-370`
|
||||
|
||||
**检查逻辑**:
|
||||
```python
|
||||
def check_indie_upg_match(hilink_check_file, app_check_file):
|
||||
# 读取两个check.json文件
|
||||
f = open(hilink_check_file, "r", encoding="utf-8")
|
||||
hilink_check = json.loads(f.read())
|
||||
f.close()
|
||||
f = open(app_check_file, "r", encoding="utf-8")
|
||||
app_check = json.loads(f.read())
|
||||
f.close()
|
||||
|
||||
# 版本号检查
|
||||
if hilink_check["ver"] != 1 or app_check["ver"] != 1:
|
||||
print("check file ver[h:%d,a:%d] not match" % (hilink_check["ver"], app_check["ver"]))
|
||||
return False
|
||||
|
||||
# HiLink侧接口向后兼容检查
|
||||
if not hilink_check["hilink"].startswith(app_check["hilink"]):
|
||||
prt_not_match_info("hilink", hilink_check["hilink"], app_check["hilink"], True)
|
||||
return False
|
||||
|
||||
# App侧接口向后兼容检查
|
||||
if not app_check["app"].startswith(hilink_check["app"]):
|
||||
prt_not_match_info("app", app_check["app"], hilink_check["app"], True)
|
||||
return False
|
||||
|
||||
return True
|
||||
```
|
||||
|
||||
### 5.2 校验失败信息输出
|
||||
|
||||
**函数位置**: `indie_upgrade_utils.py:330-350`
|
||||
|
||||
校验失败时会输出具体的不匹配接口信息:
|
||||
- 显示接口序号和对应的CRC32校验码
|
||||
- 帮助定位具体是哪个接口发生了变更
|
||||
- 每个CRC32码长度为8个十六进制字符
|
||||
|
||||
### 5.3 升级包构建时的校验
|
||||
|
||||
**调用位置**: `build/config/target_config/ws63/build_ws63_update.py:74`
|
||||
|
||||
```python
|
||||
if not check_indie_upg_match(info.hilink_check, info.app_iot_check):
|
||||
print("indie upg hilink and app not match")
|
||||
return False
|
||||
```
|
||||
|
||||
在生成升级包时会自动进行兼容性检查,如果接口不兼容,构建过程会失败。
|
||||
|
||||
## 6. 独立升级工作流程
|
||||
|
||||
### 6.1 独立升级概述
|
||||
|
||||
独立升级允许在不更新App-IoT固件的情况下,单独升级HiLink SDK固件。这种机制可以:
|
||||
- 快速修复HiLink SDK的bug
|
||||
- 更新云端协议和功能
|
||||
- 减少升级包大小和升级时间
|
||||
- 降低升级风险
|
||||
|
||||
### 6.2 配置开启流程
|
||||
|
||||
根据 `indie_upg.md` 文档,开启独立升级需要:
|
||||
|
||||
1. **修改配置** (`build/config/target_config/ws63/config.py`):
|
||||
- 删除 `'liteos_kconfig': 'ws63_iot'`
|
||||
- 在 `'defines'` 中增加 `CONFIG_SUPPORT_HILINK_INDIE_UPGRADE`
|
||||
- 在 `'ram_component'` 中增加 `'app_addr_map'`
|
||||
- 在 `'ram_component'` 中删除 `'hilinkdevicesdk'`、`'hilinkota'`、`'hilinkbtsdk'`、`'hilinkquickcfg'`
|
||||
|
||||
2. **分别编译两个固件**:
|
||||
```bash
|
||||
# 先编译HiLink固件
|
||||
python3 build.py -c ws63-liteos-hilink
|
||||
|
||||
# 再编译App-IoT固件
|
||||
python3 build.py -c ws63-liteos-app-iot
|
||||
|
||||
# 生成升级包
|
||||
python3 build/config/target_config/ws63/build_ws63_update.py --pkt=app_iot
|
||||
```
|
||||
|
||||
3. **使用简化编译工具**:
|
||||
```bash
|
||||
# 完整编译
|
||||
python3 indie_build.py all
|
||||
|
||||
# 仅编译SDK(用于独立升级)
|
||||
python3 indie_build.py sdk
|
||||
```
|
||||
|
||||
### 6.3 独立升级流程
|
||||
|
||||
1. **准备已认证的App-IoT固件**:
|
||||
- `ws63-liteos-app-iot-sign.bin`
|
||||
- `ws63-liteos-app-iot-check.json`
|
||||
|
||||
2. **更新HiLink SDK库文件**:
|
||||
- 替换 `application/samples/wifi/libhilink/` 中的库文件
|
||||
|
||||
3. **执行独立编译**:
|
||||
```bash
|
||||
python3 indie_build.py sdk
|
||||
```
|
||||
|
||||
4. **接口兼容性校验**:
|
||||
- 自动比较新HiLink固件与已认证App-IoT固件的接口
|
||||
- 如果接口不匹配,构建失败
|
||||
- 校验通过后生成完整升级包
|
||||
|
||||
### 6.4 约束条件
|
||||
|
||||
1. **分区兼容性**: 非独立升级版本与独立升级版本不可交叉升级
|
||||
2. **接口兼容性**: 模组App程序不变时,HiLink接口不能发生变更
|
||||
3. **版本号格式**:
|
||||
- 非独立升级:`1.0.0`
|
||||
- 独立升级:`1.0.0_14.2.0.304` (拼接SDK版本号)
|
||||
|
||||
## 7. 新增接口适配指南
|
||||
|
||||
### 7.1 接口调用机制
|
||||
|
||||
独立升级模式下,模组App和HiLink分别编译成两个固件:
|
||||
- 各自维护接口地址表
|
||||
- 通过查表机制获取对方接口函数指针
|
||||
- 实现跨固件的函数调用
|
||||
|
||||
### 7.2 新增HiLink接口步骤
|
||||
|
||||
**示例接口原型**:
|
||||
```c
|
||||
retType TestFuncName(type1 param1, type2 param2, type3 param3);
|
||||
```
|
||||
|
||||
1. **接口声明** (`application/samples/wifi/ohos_connect/hilink_adapt/include/hilink_test.h`):
|
||||
```c
|
||||
retType TestFuncName(type1 param1, type2 param2, type3 param3);
|
||||
```
|
||||
|
||||
2. **查表适配实现** (`application/samples/wifi/hilink_indie_upgrade/address_mapping/application/hilink_uapi/uapi_hilink_test.c`):
|
||||
```c
|
||||
retType TestFuncName(type1 param1, type2 param2, type3 param3)
|
||||
{
|
||||
hilink_call3(HILINK_CALL_TEST_FUNC_NAME, TestFuncName, retType, type1, param1, type2, param2, type3, param3);
|
||||
return (retType)0;
|
||||
}
|
||||
```
|
||||
|
||||
3. **添加到编译系统** (`application/samples/wifi/hilink_indie_upgrade/address_mapping/application/CMakeLists.txt`):
|
||||
```cmake
|
||||
uapi_hilink_test.c
|
||||
```
|
||||
|
||||
4. **配置脚本识别** (`build/script/utils/indie_upgrade_utils.py`):
|
||||
```python
|
||||
default_config["hilink"]["src_file"] += ("uapi_hilink_test.c",)
|
||||
default_config["hilink"]["mapping_header"]["application/samples/wifi/ohos_connect/hilink_adapt/include/"] += ("hilink_test.h",)
|
||||
```
|
||||
|
||||
5. **白名单配置**(可选):
|
||||
```python
|
||||
default_config["hilink"]["white_list"] += ("TestFuncName",)
|
||||
```
|
||||
|
||||
### 7.3 宏说明
|
||||
|
||||
**查表宏定义**:
|
||||
- `hilink_call0` / `hilink_call0_ret_void` - 无参数函数
|
||||
- `hilink_call1` / `hilink_call1_ret_void` - 1个参数函数
|
||||
- `hilink_call2` / `hilink_call2_ret_void` - 2个参数函数
|
||||
- `hilink_call3` / `hilink_call3_ret_void` - 3个参数函数
|
||||
- `hilink_callx` / `hilink_callx_ret_void` - x个参数函数
|
||||
|
||||
**参数说明**:
|
||||
1. 枚举值(如 `HILINK_CALL_TEST_FUNC_NAME`)
|
||||
2. 函数名
|
||||
3. 返回值类型
|
||||
4. 参数类型和参数名交替列出
|
||||
|
||||
## 8. 相关文件清单
|
||||
|
||||
### 8.1 核心脚本文件
|
||||
|
||||
| 文件路径 | 功能描述 |
|
||||
|----------|----------|
|
||||
| `build/script/utils/indie_upgrade_utils.py` | 独立升级工具核心逻辑 |
|
||||
| `build/config/target_config/ws63/script/entry.py` | 构建钩子入口 |
|
||||
| `build/config/target_config/ws63/build_ws63_update.py` | 升级包构建脚本 |
|
||||
| `build/config/target_config/ws63/config.py` | 编译配置文件 |
|
||||
| `indie_build.py` | 独立升级编译工具 |
|
||||
| `package.py` | 升级包生成工具 |
|
||||
|
||||
### 8.2 接口映射相关文件
|
||||
|
||||
| 目录/文件 | 描述 |
|
||||
|-----------|------|
|
||||
| `application/samples/wifi/hilink_indie_upgrade/address_mapping/` | 接口映射根目录 |
|
||||
| `application/samples/wifi/hilink_indie_upgrade/address_mapping/include/func_call_list.h` | 函数调用枚举定义(自动生成) |
|
||||
| `application/samples/wifi/hilink_indie_upgrade/address_mapping/application/` | App侧接口适配 |
|
||||
| `application/samples/wifi/hilink_indie_upgrade/address_mapping/hilinksdk/` | HiLink侧接口适配 |
|
||||
| `application/samples/wifi/ohos_connect/hilink_adapt/` | 接口声明头文件目录 |
|
||||
|
||||
### 8.3 输出文件
|
||||
|
||||
| 文件路径 | 描述 |
|
||||
|----------|------|
|
||||
| `output/ws63/acore/ws63-liteos-hilink/ws63-liteos-hilink-check.json` | HiLink固件接口校验文件 |
|
||||
| `output/ws63/acore/ws63-liteos-app-iot/ws63-liteos-app-iot-check.json` | App-IoT固件接口校验文件(需开启独立升级) |
|
||||
| `output/ws63/acore/ws63-liteos-hilink/ws63-liteos-hilink.bin` | HiLink固件二进制文件 |
|
||||
| `output/ws63/acore/ws63-liteos-hilink/ws63-liteos-hilink-sign.bin` | HiLink固件签名文件 |
|
||||
| `output/ws63/acore/ws63-liteos-app-iot/ws63-liteos-app-iot.bin` | App-IoT固件二进制文件 |
|
||||
| `output/ws63/acore/ws63-liteos-app-iot/ws63-liteos-app-iot-sign.bin` | App-IoT固件签名文件 |
|
||||
| `output/ws63/fwpkg/ws63-liteos-app-iot/ws63-liteos-app-iot_all.fwpkg` | 完整烧录包 |
|
||||
| `output/ws63/upgrade/update.fwpkg` | 升级包 |
|
||||
| `output/ws63/ws63-liteos_all.zip` | 完整产物压缩包 |
|
||||
|
||||
## 9. 当前项目状态
|
||||
|
||||
### 9.1 独立升级配置状态
|
||||
|
||||
**当前状态**: 独立升级功能**已关闭**
|
||||
|
||||
**证据**:
|
||||
- `config.py:334` 行:`"CONFIG_SUPPORT_HILINK_INDIE_UPGRADE"` 被注释
|
||||
- `config.py:291` 行:`'liteos_kconfig': 'ws63_iot'` 仍然存在
|
||||
- 只有HiLink固件生成了check.json文件
|
||||
- App-IoT固件目录下没有对应的check.json文件
|
||||
|
||||
### 9.2 编译产物状态
|
||||
|
||||
**已生成的文件**:
|
||||
- ✅ `ws63-liteos-hilink.bin` (278K)
|
||||
- ✅ `ws63-liteos-hilink-sign.bin` (279K)
|
||||
- ✅ `ws63-liteos-hilink-check.json` (3.4K)
|
||||
- ✅ `ws63-liteos-app-iot.bin` (1.7M)
|
||||
- ✅ `ws63-liteos-app-iot-sign.bin` (1.7M)
|
||||
- ❌ `ws63-liteos-app-iot-check.json` (未生成,因为独立升级未开启)
|
||||
|
||||
## 10. 故障排查指南
|
||||
|
||||
### 10.1 check.json文件未生成
|
||||
|
||||
**可能原因**:
|
||||
1. `CONFIG_SUPPORT_HILINK_INDIE_UPGRADE` 未在配置中启用
|
||||
2. 构建过程中 `build_post` 钩子未执行
|
||||
3. 接口映射文件生成失败
|
||||
|
||||
**排查步骤**:
|
||||
1. 检查 `config.py` 中的配置项
|
||||
2. 查看构建日志中是否有 "create indie upg mapping files succ" 消息
|
||||
3. 检查接口源文件和头文件是否存在语法错误
|
||||
|
||||
### 10.2 接口兼容性校验失败
|
||||
|
||||
**错误信息示例**:
|
||||
```
|
||||
indie upg hilink and app not match
|
||||
hilink checksum not match
|
||||
func 5 [A1B2C3D4:E5F6A7B8] not match
|
||||
```
|
||||
|
||||
**排查步骤**:
|
||||
1. 确定是哪个接口发生了变更(根据func序号)
|
||||
2. 检查接口原型是否发生改变
|
||||
3. 检查参数类型、顺序、返回值类型
|
||||
4. 如果是合理的接口升级,需要重新生成App-IoT的check.json
|
||||
|
||||
### 10.3 接口映射表生成失败
|
||||
|
||||
**可能原因**:
|
||||
1. 源文件中函数原型格式不规范
|
||||
2. 头文件中接口声明与源文件实现不匹配
|
||||
3. 正则表达式匹配失败
|
||||
|
||||
**排查步骤**:
|
||||
1. 检查函数原型是否符合标准C语法
|
||||
2. 确保头文件声明与源文件实现一致
|
||||
3. 查看构建日志中的正则匹配错误信息
|
||||
|
||||
## 11. 总结
|
||||
|
||||
`ws63-liteos-hilink-check.json` 文件是WS63项目独立升级功能的核心组件,通过CRC32校验码机制确保固件间接口兼容性。虽然当前项目未启用独立升级功能,但完整的技术框架已经就绪,可以通过简单的配置修改来启用该功能。
|
||||
|
||||
该机制的核心价值在于:
|
||||
- **风险控制**: 通过接口校验防止不兼容升级
|
||||
- **灵活部署**: 支持HiLink SDK的独立快速升级
|
||||
- **开发效率**: 减少完整固件的编译和测试周期
|
||||
- **维护便利**: 清晰的接口约定和自动化校验流程
|
||||
|
||||
---
|
||||
**文档创建时间**: 2025-09-10
|
||||
**项目版本**: SR_Light_Hilink_14.2.1.312_20250714
|
||||
**分析对象**: output/ws63/acore/ws63-liteos-hilink/ws63-liteos-hilink-check.json
|
||||
Reference in New Issue
Block a user