10
This commit is contained in:
parent
fbe2e121db
commit
c1121aecd6
300
doc/TCPClient测试指南.md
Normal file
300
doc/TCPClient测试指南.md
Normal file
@ -0,0 +1,300 @@
|
|||||||
|
# TCPClient FreeRTOS 集成测试指南
|
||||||
|
|
||||||
|
## 1. 测试环境准备
|
||||||
|
|
||||||
|
### 1.1 硬件
|
||||||
|
|
||||||
|
| 项目 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| MCU 开发板 | CH32V307WCU6(需支持 FLASH/SRAM 分配配置) |
|
||||||
|
| 红外传感器 | 256×192 DVP 接口热成像模组 |
|
||||||
|
| 网络 | RJ45 网线,连接到与上位机同一局域网的交换机/路由器 |
|
||||||
|
| NG 输出 | PA8 引脚可接 LED 或示波器观察脉冲 |
|
||||||
|
| 串口 | USART1 (115200 baud),连接 USB-TTL 调试串口 |
|
||||||
|
|
||||||
|
### 1.2 网络参数(代码默认值)
|
||||||
|
|
||||||
|
| 参数 | 值 | 对应文件 |
|
||||||
|
|------|-----|----------|
|
||||||
|
| MCU IP | `192.168.1.10` | `main.c` → `IPAddr` |
|
||||||
|
| 网关 | `192.168.1.1` | `main.c` → `GWIPAddr` |
|
||||||
|
| 子网掩码 | `255.255.255.0` | `main.c` → `IPMask` |
|
||||||
|
| 上位机 IP | `192.168.1.50` | `main.c` → `DESIP`,`qdx_tcp_logic.c` → `SERVER_IP` |
|
||||||
|
| 控制流端口 | `5511` | `qdx_tcp_logic.c` → `CONTROL_PORT` |
|
||||||
|
| 数据流端口 | `5512` | `qdx_tcp_logic.c` → `DATA_PORT` |
|
||||||
|
|
||||||
|
> **注意**:如果需要修改上位机 IP,需同时修改 `main.c` 中的 `DESIP` 和 `qdx_tcp_logic.c` 中的 `SERVER_IP`,保持一致。
|
||||||
|
|
||||||
|
### 1.3 上位机软件
|
||||||
|
|
||||||
|
将上位机 IP 设为 `192.168.1.50`,确保防火墙放行端口 5511 和 5512。
|
||||||
|
|
||||||
|
**方式 A — PC Demo 程序**(推荐先用此方式验证基本通信):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd pc/
|
||||||
|
build.bat # 需要 MinGW GCC (C:\MinGW\bin\gcc.exe)
|
||||||
|
api_demo.exe # 运行后作为 TCP 服务端监听 5511/5512
|
||||||
|
```
|
||||||
|
|
||||||
|
**方式 B — 网络调试工具**(如 NetAssist / Packet Sender / Wireshark):
|
||||||
|
- 创建 2 个 TCP Server,分别监听 5511 和 5512
|
||||||
|
- 用于观察裸数据收发
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 编译与烧录
|
||||||
|
|
||||||
|
### 2.1 编译
|
||||||
|
|
||||||
|
1. 打开 MounRiver Studio (MRS)
|
||||||
|
2. 导入工程:`prj/TCPClient/TCPClient.wvproj`
|
||||||
|
3. 点击 **Build** (锤子图标) 或 `Ctrl+B`
|
||||||
|
4. 确认编译成功,**无 RAM overflow 错误**
|
||||||
|
|
||||||
|
### 2.2 烧录
|
||||||
|
|
||||||
|
1. WCH-Link 连接开发板 SWD 接口
|
||||||
|
2. MRS 菜单 → **Flash → Download**
|
||||||
|
3. 烧录完成后芯片自动复位
|
||||||
|
|
||||||
|
> 首次烧录后,如果 Option Bytes 的 FLASH/SRAM 分配不是 128K/192K 模式,
|
||||||
|
> 代码会自动写入 Option Bytes 并触发复位。串口可看到:
|
||||||
|
> `Flash/SRAM config changed to 3, resetting...`
|
||||||
|
> 第二次复位后进入正常运行。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 分阶段测试
|
||||||
|
|
||||||
|
### 阶段一:基础启动与 FreeRTOS 调度器
|
||||||
|
|
||||||
|
**目的**:确认 MCU 正常启动、FreeRTOS 调度器运行、心跳任务工作。
|
||||||
|
|
||||||
|
**操作**:
|
||||||
|
1. 连接串口终端(115200, 8N1)
|
||||||
|
2. 上电或复位
|
||||||
|
|
||||||
|
**预期串口输出**:
|
||||||
|
```
|
||||||
|
TCPClient Test
|
||||||
|
SystemClk:144000000
|
||||||
|
UserByte: c7
|
||||||
|
net version:...
|
||||||
|
mac addr:XX XX XX XX XX XX
|
||||||
|
WCHNET_LibInit Success
|
||||||
|
[HB] 0 tick=xxx
|
||||||
|
[HB] 1 tick=xxx
|
||||||
|
[HB] 2 tick=xxx
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
**检查项**:
|
||||||
|
|
||||||
|
| # | 检查点 | 通过条件 |
|
||||||
|
|---|--------|----------|
|
||||||
|
| 1 | 系统时钟 | 显示 `SystemClk:144000000` |
|
||||||
|
| 2 | Option Bytes | UserByte 的高 3 位为 `110`(即 `0xC?`) |
|
||||||
|
| 3 | WCHNET 初始化 | 显示 `WCHNET_LibInit Success` |
|
||||||
|
| 4 | 心跳打印 | `[HB]` 每 2 秒递增一次 |
|
||||||
|
| 5 | 无 assert/HardFault | 不出现 `err at line` 或 `mcause` 等错误 |
|
||||||
|
|
||||||
|
**故障排查**:
|
||||||
|
|
||||||
|
| 现象 | 可能原因 | 解决方案 |
|
||||||
|
|------|----------|----------|
|
||||||
|
| 无任何输出 | 串口未连接/波特率错误 | 检查 USART1 TX 引脚连线,确认 115200 |
|
||||||
|
| 反复重启打印 `Flash/SRAM config changed` | Option Bytes 写入但未生效 | 先用 WCH-ISP 工具手动设置 Option Bytes |
|
||||||
|
| `err at line XXX of file "../FreeRTOS/tasks.c"` | Heap 不足 | 检查 `configTOTAL_HEAP_SIZE`(当前 12KB) |
|
||||||
|
| 卡死无心跳 | HardFault / startup 配置错 | 检查 mstatus=0x7800、CSR 0x804=0x1f |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 阶段二:以太网物理链路
|
||||||
|
|
||||||
|
**目的**:确认 PHY 芯片链路正常。
|
||||||
|
|
||||||
|
**操作**:
|
||||||
|
1. 插入网线
|
||||||
|
2. 观察串口
|
||||||
|
|
||||||
|
**预期输出**:
|
||||||
|
```
|
||||||
|
PHY Link Success
|
||||||
|
```
|
||||||
|
|
||||||
|
**检查项**:
|
||||||
|
|
||||||
|
| # | 检查点 | 通过条件 |
|
||||||
|
|---|--------|----------|
|
||||||
|
| 1 | PHY 链路 | 插入网线后出现 `PHY Link Success` |
|
||||||
|
| 2 | 上位机 ping | 上位机执行 `ping 192.168.1.10` 能通 |
|
||||||
|
|
||||||
|
**故障排查**:
|
||||||
|
|
||||||
|
| 现象 | 可能原因 | 解决方案 |
|
||||||
|
|------|----------|----------|
|
||||||
|
| 无 PHY Link Success | 网线/PHY 硬件问题 | 检查 RJ45 座子焊接、网线 |
|
||||||
|
| ping 不通 | IP 冲突或子网不同 | 确认上位机 IP 在 192.168.1.x 段 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 阶段三:TCP 双通道连接
|
||||||
|
|
||||||
|
**目的**:验证 Control(5511)和 Data(5512)两条 TCP 连接成功建立。
|
||||||
|
|
||||||
|
**操作**:
|
||||||
|
1. 上位机启动 TCP 服务端监听 5511 和 5512(PC Demo 或网络工具)
|
||||||
|
2. MCU 上电(或已在阶段一上电,此时它会自动重连)
|
||||||
|
|
||||||
|
**预期串口输出**:
|
||||||
|
```
|
||||||
|
TCP Connected, socket 0
|
||||||
|
TCP Connected, socket 1
|
||||||
|
```
|
||||||
|
|
||||||
|
> `TcpLogic_Start()` 内部会创建管理线程,自动以 3 秒间隔尝试连接。
|
||||||
|
> 如果上位机未就绪,串口可能显示 `qdx_port: connect timeout`,属正常行为。
|
||||||
|
|
||||||
|
**检查项**:
|
||||||
|
|
||||||
|
| # | 检查点 | 通过条件 |
|
||||||
|
|---|--------|----------|
|
||||||
|
| 1 | Socket 0 连接 | 串口显示 `TCP Connected, socket 0` |
|
||||||
|
| 2 | Socket 1 连接 | 串口显示 `TCP Connected, socket 1` |
|
||||||
|
| 3 | 上位机收到握手包 | PC Demo 显示收到 Handshake |
|
||||||
|
|
||||||
|
**故障排查**:
|
||||||
|
|
||||||
|
| 现象 | 可能原因 | 解决方案 |
|
||||||
|
|------|----------|----------|
|
||||||
|
| `connect timeout` 循环出现 | 上位机未监听/防火墙 | 确认上位机 TCP Server 已启动、端口未被占用 |
|
||||||
|
| `SocketCreat fail XX` | WCHNET socket 数不够 | 检查 `WCHNET_NUM_TCP >= 2` |
|
||||||
|
| `no free SocketCtx` | 连接泄漏 | 排查上次断开是否正确释放了 context |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 阶段四:心跳与协议通信
|
||||||
|
|
||||||
|
**目的**:验证 QDX 协议心跳包在 TCP 通道上正常收发。
|
||||||
|
|
||||||
|
**操作**:
|
||||||
|
1. 保持双通道连接
|
||||||
|
2. Wireshark 抓包或 PC Demo 观察
|
||||||
|
|
||||||
|
**预期行为**:
|
||||||
|
- MCU 每 2 秒发送心跳包到 Control 通道
|
||||||
|
- 若 6 秒无响应,MCU 主动断开并重连
|
||||||
|
|
||||||
|
**检查项**:
|
||||||
|
|
||||||
|
| # | 检查点 | 通过条件 |
|
||||||
|
|---|--------|----------|
|
||||||
|
| 1 | 心跳发送 | Wireshark 可见每 ~2s 一个小包到端口 5511 |
|
||||||
|
| 2 | 超时断开 | 强制关闭上位机后,串口显示 `TCP Timeout` / `TCP Disconnected` |
|
||||||
|
| 3 | 自动重连 | 重新启动上位机后,MCU 自动重连成功 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 阶段五:配置下发
|
||||||
|
|
||||||
|
**目的**:验证上位机通过 Control 通道下发配置,MCU 正确接收并回调。
|
||||||
|
|
||||||
|
**操作**(使用 PC Demo):
|
||||||
|
1. 连接成功后,PC Demo 控制台输入操作选项
|
||||||
|
2. 选择下发配置(2D 模式参数)
|
||||||
|
|
||||||
|
**预期行为**:
|
||||||
|
- MCU 串口输出配置回调信息(如有添加 printf)
|
||||||
|
- `OnConfigUpdate()` 被调用,参数传入 `Preprocess_Settings_Change()`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 阶段六:图像采集与发送
|
||||||
|
|
||||||
|
**目的**:验证 DVP 图像采集 → 预处理 → TCP 数据发送完整流程。
|
||||||
|
|
||||||
|
**前提**:红外传感器模组已连接并正常输出。
|
||||||
|
|
||||||
|
**操作**:
|
||||||
|
1. 保持 TCP 双通道连接
|
||||||
|
2. 传感器开始输出图像
|
||||||
|
|
||||||
|
**预期行为**:
|
||||||
|
1. `DVP_Task()` 检测到 `Frame_Ready_Flag`
|
||||||
|
2. `Preprocess_CheckInternalTrigger2D()` 判断触发条件
|
||||||
|
3. `Preprocess_Execute()` 执行预处理
|
||||||
|
4. `TcpLogic_BuildAndSendTemperatureFrame()` 将数据通过 Data 通道发送
|
||||||
|
5. 上位机在 5512 端口收到温度帧数据
|
||||||
|
|
||||||
|
**检查项**:
|
||||||
|
|
||||||
|
| # | 检查点 | 通过条件 |
|
||||||
|
|---|--------|----------|
|
||||||
|
| 1 | DVP 中断 | 确认 DMA 完成中断正常置位 `Frame_Ready_Flag` |
|
||||||
|
| 2 | 数据发送 | Wireshark 抓到到 5512 端口的大数据包 |
|
||||||
|
| 3 | 帧率 | 发送频率与传感器帧率大致匹配 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 阶段七:NG 输出脉冲
|
||||||
|
|
||||||
|
**目的**:验证上位机下发检测结果为 NG 时,PA8 输出 200ms 高电平脉冲。
|
||||||
|
|
||||||
|
**操作**:
|
||||||
|
1. 上位机通过 Control 通道下发检测结果(resultStatus = 0 → NG)
|
||||||
|
2. 示波器/逻辑分析仪接 PA8,或接 LED 观察
|
||||||
|
|
||||||
|
**预期行为**:
|
||||||
|
- PA8 拉高 → 持续 200ms → 自动拉低
|
||||||
|
- 串口无额外打印(NG 逻辑在 `task_business_entry` 中轮询 `sys_tick_ms`)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 压力测试
|
||||||
|
|
||||||
|
| 测试场景 | 操作 | 观察 |
|
||||||
|
|----------|------|------|
|
||||||
|
| 长时间运行 | 持续运行 24 小时 | 心跳持续、无 assert、无内存泄漏 |
|
||||||
|
| 反复断线重连 | 每 30 秒拔插网线 | 每次重连后双通道恢复 |
|
||||||
|
| 高频图像发送 | 传感器满帧率连续采集 | 无丢帧、无栈溢出 |
|
||||||
|
| 上位机先断后连 | MCU 先开机,30s 后再启动上位机 | MCU 自动重连成功 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 关键配置速查
|
||||||
|
|
||||||
|
| 参数 | 当前值 | 文件 |
|
||||||
|
|------|--------|------|
|
||||||
|
| `configTOTAL_HEAP_SIZE` | 12 KB | `FreeRTOSConfig.h` |
|
||||||
|
| `configTICK_RATE_HZ` | 500 | `FreeRTOSConfig.h` |
|
||||||
|
| `configMINIMAL_STACK_SIZE` | 256 words | `FreeRTOSConfig.h` |
|
||||||
|
| task_wchnet 栈 | 512 words (2 KB) | `main.c` |
|
||||||
|
| task_business 栈 | 512 words (2 KB) | `main.c` |
|
||||||
|
| task_heartbeat 栈 | 256 words (1 KB) | `main.c` |
|
||||||
|
| FLASH / SRAM | 128 KB / 192 KB | `Link.ld` + `Config_Flash_SRAM()` |
|
||||||
|
| `WCHNET_NUM_TCP` | 2 | `net_config.h` |
|
||||||
|
| `RECE_BUF_LEN` | 2920 (MSS×2) | `net_config.h` |
|
||||||
|
| `RX_RING_SIZE` | 2920 | `qdx_port.c` |
|
||||||
|
| DVP 分辨率 | 256×192 | `dvp.h` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. 常见问题 FAQ
|
||||||
|
|
||||||
|
**Q: 心跳正常但 TCP 连不上?**
|
||||||
|
> 检查:① 上位机 IP 是否为 `192.168.1.50`;② 防火墙是否放行 5511/5512;③ `qdx_tcp_logic.c` 中 `SERVER_IP` 是否与 `main.c` 中 `DESIP` 一致。
|
||||||
|
|
||||||
|
**Q: 编译报 RAM overflow?**
|
||||||
|
> 检查 `.bss` 总量。FrameBuffer (96KB) + ETH buffers (~32KB) + ucHeap (12KB) + 应用缓冲区 (~47KB) ≈ 187KB。如果增大了某个缓冲区导致超 192KB,需要相应缩减其他部分。
|
||||||
|
|
||||||
|
**Q: 运行时 assert (`err at line XXX`)?**
|
||||||
|
> 通常是 Heap 不足导致 `pvPortMalloc` 失败。确认 `configTOTAL_HEAP_SIZE` 为 12KB,任务栈未超预算。
|
||||||
|
|
||||||
|
**Q: 如何启用栈溢出检测进行调试?**
|
||||||
|
> 在 `FreeRTOSConfig.h` 中设置 `configCHECK_FOR_STACK_OVERFLOW` 为 `2`,并实现 `vApplicationStackOverflowHook()` 函数打印任务名。**仅用于调试,发布时关闭**。
|
||||||
|
|
||||||
|
**Q: 如何调整上位机 IP?**
|
||||||
|
> 同时修改两处(保持一致):
|
||||||
|
> 1. `main.c` 第 107 行:`DESIP[4] = {x, x, x, x};`
|
||||||
|
> 2. `qdx_tcp_logic.c` 第 58 行:`SERVER_IP = "x.x.x.x";`
|
||||||
@ -167,13 +167,17 @@ void qdx_port_sock_recv_notify(uint8_t sockid)
|
|||||||
/* Read data from WCHNET into ring buffer */
|
/* Read data from WCHNET into ring buffer */
|
||||||
uint8_t tmp[512];
|
uint8_t tmp[512];
|
||||||
uint32_t len;
|
uint32_t len;
|
||||||
|
uint32_t total = 0;
|
||||||
while (1) {
|
while (1) {
|
||||||
len = sizeof(tmp);
|
len = sizeof(tmp);
|
||||||
uint8_t err = WCHNET_SocketRecv(sockid, tmp, &len);
|
uint8_t err = WCHNET_SocketRecv(sockid, tmp, &len);
|
||||||
if (len == 0) break;
|
if (len == 0) break;
|
||||||
ring_write(&ctx->rx_ring, tmp, (uint16_t)len);
|
ring_write(&ctx->rx_ring, tmp, (uint16_t)len);
|
||||||
|
total += len;
|
||||||
if (err != WCHNET_ERR_SUCCESS) break;
|
if (err != WCHNET_ERR_SUCCESS) break;
|
||||||
}
|
}
|
||||||
|
DBG_PORT("recv_notify sock%d: %lu bytes, ring=%d\r\n",
|
||||||
|
sockid, total, ring_available(&ctx->rx_ring));
|
||||||
/* Wake blocking recv thread */
|
/* Wake blocking recv thread */
|
||||||
xSemaphoreGive(ctx->rx_sem);
|
xSemaphoreGive(ctx->rx_sem);
|
||||||
}
|
}
|
||||||
@ -183,6 +187,7 @@ void qdx_port_sock_connect_notify(uint8_t sockid)
|
|||||||
SocketCtx_t *ctx = find_ctx_by_wchnet_id(sockid);
|
SocketCtx_t *ctx = find_ctx_by_wchnet_id(sockid);
|
||||||
if (!ctx) return;
|
if (!ctx) return;
|
||||||
ctx->connected = 1;
|
ctx->connected = 1;
|
||||||
|
DBG_PORT("connect_notify sock%d\r\n", sockid);
|
||||||
xSemaphoreGive(ctx->connect_sem);
|
xSemaphoreGive(ctx->connect_sem);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,6 +196,7 @@ void qdx_port_sock_disconnect_notify(uint8_t sockid)
|
|||||||
SocketCtx_t *ctx = find_ctx_by_wchnet_id(sockid);
|
SocketCtx_t *ctx = find_ctx_by_wchnet_id(sockid);
|
||||||
if (!ctx) return;
|
if (!ctx) return;
|
||||||
ctx->connected = 0;
|
ctx->connected = 0;
|
||||||
|
DBG_PORT("disconnect_notify sock%d\r\n", sockid);
|
||||||
/* Wake recv thread so it can detect disconnect */
|
/* Wake recv thread so it can detect disconnect */
|
||||||
xSemaphoreGive(ctx->rx_sem);
|
xSemaphoreGive(ctx->rx_sem);
|
||||||
}
|
}
|
||||||
@ -203,6 +209,7 @@ void qdx_port_init(void)
|
|||||||
{
|
{
|
||||||
memset(g_sock_ctx, 0, sizeof(g_sock_ctx));
|
memset(g_sock_ctx, 0, sizeof(g_sock_ctx));
|
||||||
g_wchnet_mutex = xSemaphoreCreateMutex();
|
g_wchnet_mutex = xSemaphoreCreateMutex();
|
||||||
|
DBG_PORT("init done, mutex=%p\r\n", g_wchnet_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
@ -261,6 +268,8 @@ int8_t qdx_port_thread_create(const char *name, qdx_thread_entry_t entry,
|
|||||||
BaseType_t ret = xTaskCreate((TaskFunction_t)entry, name,
|
BaseType_t ret = xTaskCreate((TaskFunction_t)entry, name,
|
||||||
(uint16_t)stack_words, arg,
|
(uint16_t)stack_words, arg,
|
||||||
(UBaseType_t)priority, NULL);
|
(UBaseType_t)priority, NULL);
|
||||||
|
DBG_PORT("thread_create \"%s\" stack=%lu pri=%d -> %s\r\n",
|
||||||
|
name, stack_words, priority, (ret == pdPASS) ? "OK" : "FAIL");
|
||||||
return (ret == pdPASS) ? 0 : -1;
|
return (ret == pdPASS) ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -272,13 +281,15 @@ qdx_socket_t qdx_port_tcp_connect(const char *ip, uint16_t port)
|
|||||||
{
|
{
|
||||||
uint8_t dest_ip[4];
|
uint8_t dest_ip[4];
|
||||||
if (parse_ip(ip, dest_ip) != 0) {
|
if (parse_ip(ip, dest_ip) != 0) {
|
||||||
printf("qdx_port: bad IP \"%s\"\r\n", ip);
|
DBG_PORT("bad IP \"%s\"\r\n", ip);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DBG_PORT("connecting to %s:%d\r\n", ip, port);
|
||||||
|
|
||||||
SocketCtx_t *ctx = alloc_sock_ctx();
|
SocketCtx_t *ctx = alloc_sock_ctx();
|
||||||
if (!ctx) {
|
if (!ctx) {
|
||||||
printf("qdx_port: no free SocketCtx\r\n");
|
DBG_PORT("no free SocketCtx\r\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -289,6 +300,12 @@ qdx_socket_t qdx_port_tcp_connect(const char *ip, uint16_t port)
|
|||||||
sock_inf.DesPort = port;
|
sock_inf.DesPort = port;
|
||||||
memcpy(sock_inf.IPAddr, dest_ip, 4);
|
memcpy(sock_inf.IPAddr, dest_ip, 4);
|
||||||
|
|
||||||
|
DBG_PORT("SOCK_INF: proto=%d dst=%d.%d.%d.%d:%d\r\n",
|
||||||
|
sock_inf.ProtoType,
|
||||||
|
sock_inf.IPAddr[0], sock_inf.IPAddr[1],
|
||||||
|
sock_inf.IPAddr[2], sock_inf.IPAddr[3],
|
||||||
|
sock_inf.DesPort);
|
||||||
|
|
||||||
uint8_t wchnet_id = 0;
|
uint8_t wchnet_id = 0;
|
||||||
|
|
||||||
xSemaphoreTake(g_wchnet_mutex, portMAX_DELAY);
|
xSemaphoreTake(g_wchnet_mutex, portMAX_DELAY);
|
||||||
@ -296,10 +313,11 @@ qdx_socket_t qdx_port_tcp_connect(const char *ip, uint16_t port)
|
|||||||
xSemaphoreGive(g_wchnet_mutex);
|
xSemaphoreGive(g_wchnet_mutex);
|
||||||
|
|
||||||
if (err != WCHNET_ERR_SUCCESS) {
|
if (err != WCHNET_ERR_SUCCESS) {
|
||||||
printf("qdx_port: SocketCreat fail %02X\r\n", err);
|
DBG_PORT("SocketCreat fail %02X\r\n", err);
|
||||||
free_sock_ctx(ctx);
|
free_sock_ctx(ctx);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
DBG_PORT("SocketCreat OK, wchnet_id=%d\r\n", wchnet_id);
|
||||||
|
|
||||||
ctx->wchnet_sock_id = wchnet_id;
|
ctx->wchnet_sock_id = wchnet_id;
|
||||||
|
|
||||||
@ -312,19 +330,27 @@ qdx_socket_t qdx_port_tcp_connect(const char *ip, uint16_t port)
|
|||||||
xSemaphoreGive(g_wchnet_mutex);
|
xSemaphoreGive(g_wchnet_mutex);
|
||||||
|
|
||||||
if (err != WCHNET_ERR_SUCCESS) {
|
if (err != WCHNET_ERR_SUCCESS) {
|
||||||
printf("qdx_port: SocketConnect fail %02X\r\n", err);
|
DBG_PORT("SocketConnect fail %02X\r\n", err);
|
||||||
WCHNET_SocketClose(wchnet_id, 0);
|
WCHNET_SocketClose(wchnet_id, 0);
|
||||||
free_sock_ctx(ctx);
|
free_sock_ctx(ctx);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
DBG_PORT("SocketConnect OK (err=0x%02X), waiting connect_sem (5s)...\r\n", err);
|
||||||
|
|
||||||
/* Block until SINT_STAT_CONNECT or 5s timeout */
|
/* Block until SINT_STAT_CONNECT or 5s timeout */
|
||||||
if (xSemaphoreTake(ctx->connect_sem, pdMS_TO_TICKS(5000)) != pdTRUE) {
|
uint32_t t0 = xTaskGetTickCount();
|
||||||
printf("qdx_port: connect timeout\r\n");
|
BaseType_t sem_ret = xSemaphoreTake(ctx->connect_sem, pdMS_TO_TICKS(5000));
|
||||||
|
uint32_t elapsed = (xTaskGetTickCount() - t0) * portTICK_PERIOD_MS;
|
||||||
|
|
||||||
|
if (sem_ret != pdTRUE) {
|
||||||
|
DBG_PORT("connect_sem TIMEOUT after %lu ms -> %d.%d.%d.%d:%d\r\n",
|
||||||
|
elapsed, dest_ip[0], dest_ip[1], dest_ip[2], dest_ip[3], port);
|
||||||
|
DBG_PORT(" ctx->connected=%d wchnet_id=%d\r\n", ctx->connected, wchnet_id);
|
||||||
WCHNET_SocketClose(wchnet_id, 0);
|
WCHNET_SocketClose(wchnet_id, 0);
|
||||||
free_sock_ctx(ctx);
|
free_sock_ctx(ctx);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
DBG_PORT("connect_sem got after %lu ms, connected=%d\r\n", elapsed, ctx->connected);
|
||||||
|
|
||||||
if (!ctx->connected) {
|
if (!ctx->connected) {
|
||||||
WCHNET_SocketClose(wchnet_id, 0);
|
WCHNET_SocketClose(wchnet_id, 0);
|
||||||
@ -336,7 +362,7 @@ qdx_socket_t qdx_port_tcp_connect(const char *ip, uint16_t port)
|
|||||||
WCHNET_SocketSetKeepLive(wchnet_id, ENABLE);
|
WCHNET_SocketSetKeepLive(wchnet_id, ENABLE);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
printf("qdx_port: connected sock %d -> %d.%d.%d.%d:%d\r\n",
|
DBG_PORT("connected sock %d -> %d.%d.%d.%d:%d\r\n",
|
||||||
wchnet_id, dest_ip[0], dest_ip[1], dest_ip[2], dest_ip[3], port);
|
wchnet_id, dest_ip[0], dest_ip[1], dest_ip[2], dest_ip[3], port);
|
||||||
return (qdx_socket_t)ctx;
|
return (qdx_socket_t)ctx;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,11 +11,37 @@
|
|||||||
#define QDX_PORT_H
|
#define QDX_PORT_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* ============================================================
|
||||||
|
* Debug Print Macros (set to 0 to disable, 1 to enable)
|
||||||
|
* ============================================================ */
|
||||||
|
#define QDX_DEBUG_PORT 1 /* qdx_port.c: socket/mutex/thread ops */
|
||||||
|
#define QDX_DEBUG_LOGIC 1 /* qdx_tcp_logic.c: protocol/TLV parsing */
|
||||||
|
#define QDX_DEBUG_APP 1 /* main.c: application-level events */
|
||||||
|
|
||||||
|
#if QDX_DEBUG_PORT
|
||||||
|
#define DBG_PORT(fmt, ...) printf("[PORT] " fmt, ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define DBG_PORT(fmt, ...) ((void)0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if QDX_DEBUG_LOGIC
|
||||||
|
#define DBG_LOGIC(fmt, ...) printf("[LOGIC] " fmt, ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define DBG_LOGIC(fmt, ...) ((void)0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if QDX_DEBUG_APP
|
||||||
|
#define DBG_APP(fmt, ...) printf("[APP] " fmt, ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define DBG_APP(fmt, ...) ((void)0)
|
||||||
|
#endif
|
||||||
|
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
* Time & Delay
|
* Time & Delay
|
||||||
* ============================================================ */
|
* ============================================================ */
|
||||||
|
|||||||
@ -55,7 +55,7 @@ static struct {
|
|||||||
|
|
||||||
/* Server endpoint prototype - user would configure these, but we map to demo
|
/* Server endpoint prototype - user would configure these, but we map to demo
|
||||||
* defaults */
|
* defaults */
|
||||||
static const char *SERVER_IP = "127.0.0.1";
|
static const char *SERVER_IP = "192.168.7.50";
|
||||||
static const uint16_t CONTROL_PORT = 5511;
|
static const uint16_t CONTROL_PORT = 5511;
|
||||||
static const uint16_t DATA_PORT = 5512;
|
static const uint16_t DATA_PORT = 5512;
|
||||||
|
|
||||||
@ -69,6 +69,7 @@ static void tcp_stream_init(TcpStreamCtx_t *ctx, const char *label) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void tcp_stream_disconnect(TcpStreamCtx_t *ctx) {
|
static void tcp_stream_disconnect(TcpStreamCtx_t *ctx) {
|
||||||
|
DBG_LOGIC("[%s] disconnecting\r\n", ctx->label);
|
||||||
ctx->is_connected = 0;
|
ctx->is_connected = 0;
|
||||||
if (ctx->sock) {
|
if (ctx->sock) {
|
||||||
qdx_port_tcp_close(ctx->sock);
|
qdx_port_tcp_close(ctx->sock);
|
||||||
@ -78,14 +79,18 @@ static void tcp_stream_disconnect(TcpStreamCtx_t *ctx) {
|
|||||||
|
|
||||||
static int8_t tcp_stream_connect(TcpStreamCtx_t *ctx, const char *ip,
|
static int8_t tcp_stream_connect(TcpStreamCtx_t *ctx, const char *ip,
|
||||||
uint16_t port) {
|
uint16_t port) {
|
||||||
|
DBG_LOGIC("[%s] connecting %s:%d...\r\n", ctx->label, ip, port);
|
||||||
ctx->sock = qdx_port_tcp_connect(ip, port);
|
ctx->sock = qdx_port_tcp_connect(ip, port);
|
||||||
if (ctx->sock == NULL)
|
if (ctx->sock == NULL) {
|
||||||
|
DBG_LOGIC("[%s] connect FAILED\r\n", ctx->label);
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
ctx->is_connected = 1;
|
ctx->is_connected = 1;
|
||||||
ctx->last_activity_ms = qdx_port_get_tick_ms();
|
ctx->last_activity_ms = qdx_port_get_tick_ms();
|
||||||
ctx->last_heartbeat_ms = ctx->last_activity_ms;
|
ctx->last_heartbeat_ms = ctx->last_activity_ms;
|
||||||
ctx->recv_len = 0;
|
ctx->recv_len = 0;
|
||||||
|
DBG_LOGIC("[%s] connected OK\r\n", ctx->label);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,6 +121,7 @@ static int32_t tcp_send_frame(TcpStreamCtx_t *ctx, uint8_t msg_class,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void tcp_send_handshake(TcpStreamCtx_t *ctx) {
|
static void tcp_send_handshake(TcpStreamCtx_t *ctx) {
|
||||||
|
DBG_LOGIC("[%s] sending handshake\r\n", ctx->label);
|
||||||
uint8_t payload[54];
|
uint8_t payload[54];
|
||||||
memset(payload, 0, sizeof(payload));
|
memset(payload, 0, sizeof(payload));
|
||||||
qdx_write_u16_le(payload + 0, 0x0200);
|
qdx_write_u16_le(payload + 0, 0x0200);
|
||||||
@ -135,6 +141,7 @@ static void tcp_send_handshake(TcpStreamCtx_t *ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void tcp_send_heartbeat(TcpStreamCtx_t *ctx) {
|
static void tcp_send_heartbeat(TcpStreamCtx_t *ctx) {
|
||||||
|
DBG_LOGIC("[%s] heartbeat\r\n", ctx->label);
|
||||||
uint8_t payload[6];
|
uint8_t payload[6];
|
||||||
qdx_write_u32_le(payload + 0, qdx_port_get_tick_ms());
|
qdx_write_u32_le(payload + 0, qdx_port_get_tick_ms());
|
||||||
payload[4] = 10; /* Placeholder CpuLoad */
|
payload[4] = 10; /* Placeholder CpuLoad */
|
||||||
@ -244,19 +251,18 @@ static void parse_and_dispatch_tlv(TcpStreamCtx_t *ctx, const uint8_t *packet,
|
|||||||
|
|
||||||
uint8_t cfg_updated = 0;
|
uint8_t cfg_updated = 0;
|
||||||
|
|
||||||
//printf("\n[DEBUG][%s] 收到 TLV 包: Seq=%d, PayloadLen=%d\n", ctx->label,
|
DBG_LOGIC("[%s] TLV pkt: Seq=%d, PayloadLen=%d\r\n", ctx->label,
|
||||||
// hdr_seq, payload_len);
|
hdr_seq, payload_len);
|
||||||
|
|
||||||
while (parsed_len <= payload_len - 3) {
|
while (parsed_len <= payload_len - 3) {
|
||||||
uint8_t type = packet[offset];
|
uint8_t type = packet[offset];
|
||||||
uint16_t len = qdx_read_u16_le(packet + offset + 1);
|
uint16_t len = qdx_read_u16_le(packet + offset + 1);
|
||||||
|
|
||||||
//printf("[DEBUG][%s] -> 解析 TLV: Type=0x%02X, Len=%d\n", ctx->label, type,
|
DBG_LOGIC("[%s] TLV: Type=0x%02X, Len=%d\r\n", ctx->label, type, len);
|
||||||
//len);
|
|
||||||
|
|
||||||
if (parsed_len + 3 + len > payload_len) {
|
if (parsed_len + 3 + len > payload_len) {
|
||||||
//printf("[DEBUG][%s] ! 结构错误: 剩余长度不足 (需 %d, 剩 %d)\n",
|
DBG_LOGIC("[%s] ! TLV truncated (need %d, have %d)\r\n",
|
||||||
//ctx->label, len, payload_len - parsed_len - 3);
|
ctx->label, len, payload_len - parsed_len - 3);
|
||||||
break; /* Malformed */
|
break; /* Malformed */
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,15 +289,15 @@ static void parse_and_dispatch_tlv(TcpStreamCtx_t *ctx, const uint8_t *packet,
|
|||||||
}
|
}
|
||||||
case TYPE_CONFIG_2D: {
|
case TYPE_CONFIG_2D: {
|
||||||
if (len >= sizeof(Config2D_t)) {
|
if (len >= sizeof(Config2D_t)) {
|
||||||
//printf("[DEBUG][%s] * 解析 Config2D 成功\n", ctx->label);
|
DBG_LOGIC("[%s] Config2D parsed OK\r\n", ctx->label);
|
||||||
qdx_port_mutex_lock(g_TcpLogic.config_mutex);
|
qdx_port_mutex_lock(g_TcpLogic.config_mutex);
|
||||||
qdx_deserialize_config2d(&g_TcpLogic.cached_cfg2d, value);
|
qdx_deserialize_config2d(&g_TcpLogic.cached_cfg2d, value);
|
||||||
g_TcpLogic.has_valid_config = 1; /* 任意配置到达即标记有效 */
|
g_TcpLogic.has_valid_config = 1; /* 任意配置到达即标记有效 */
|
||||||
cfg_updated = 1;
|
cfg_updated = 1;
|
||||||
qdx_port_mutex_unlock(g_TcpLogic.config_mutex);
|
qdx_port_mutex_unlock(g_TcpLogic.config_mutex);
|
||||||
} else {
|
} else {
|
||||||
//printf("[DEBUG][%s] ! Config2D 长度不对: len=%d, sizeof=%d\n",
|
DBG_LOGIC("[%s] ! Config2D bad len=%d (need %d)\r\n",
|
||||||
//ctx->label, len, (int)sizeof(Config2D_t));
|
ctx->label, len, (int)sizeof(Config2D_t));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -379,19 +385,16 @@ static void tcp_process_rx_buffer(TcpStreamCtx_t *ctx) {
|
|||||||
uint16_t length = qdx_read_u16_le(ctx->recv_buffer + 3);
|
uint16_t length = qdx_read_u16_le(ctx->recv_buffer + 3);
|
||||||
|
|
||||||
if (version != PROTO_VERSION || length < HEADER_SIZE + CRC_SIZE) {
|
if (version != PROTO_VERSION || length < HEADER_SIZE + CRC_SIZE) {
|
||||||
/* 丢弃 Magic 标记,缓冲区内部左移 2 字节 */
|
DBG_LOGIC("[%s] bad header: ver=0x%02X(exp 0x%02X) len=%d\r\n",
|
||||||
//printf("\n[DEBUG][%s] 错误: Header 验证失败! Version=0x%02X "
|
ctx->label, version, PROTO_VERSION, length);
|
||||||
//"(Expected=0x%02X), Length=%d\n",
|
|
||||||
//ctx->label, version, PROTO_VERSION, length);
|
|
||||||
memmove(ctx->recv_buffer, ctx->recv_buffer + 2, ctx->recv_len - 2);
|
memmove(ctx->recv_buffer, ctx->recv_buffer + 2, ctx->recv_len - 2);
|
||||||
ctx->recv_len -= 2;
|
ctx->recv_len -= 2;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (length > sizeof(ctx->recv_buffer)) {
|
if (length > sizeof(ctx->recv_buffer)) {
|
||||||
/* Frame too large, drop entirely */
|
DBG_LOGIC("[%s] frame too large: %d > %d\r\n", ctx->label,
|
||||||
//printf("\n[DEBUG][%s] 错误: 帧长度超限 (length=%d, max=%d)\n", ctx->label,
|
length, (int)sizeof(ctx->recv_buffer));
|
||||||
//length, (int)sizeof(ctx->recv_buffer));
|
|
||||||
ctx->recv_len = 0;
|
ctx->recv_len = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -408,9 +411,8 @@ static void tcp_process_rx_buffer(TcpStreamCtx_t *ctx) {
|
|||||||
/* 3. Dispatch */
|
/* 3. Dispatch */
|
||||||
parse_and_dispatch_tlv(ctx, ctx->recv_buffer, length);
|
parse_and_dispatch_tlv(ctx, ctx->recv_buffer, length);
|
||||||
} else {
|
} else {
|
||||||
//printf("\n[DEBUG][%s] 错误: CRC 校验失败! Calc=0x%04X, Recv=0x%04X "
|
DBG_LOGIC("[%s] CRC fail: calc=0x%04X recv=0x%04X len=%d\r\n",
|
||||||
//"(Len=%d)\n",
|
ctx->label, calculated_crc, received_crc, length);
|
||||||
//ctx->label, calculated_crc, received_crc, length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 4. 移除已处理帧(缓冲区内部左移,必须 memmove) */
|
/* 4. 移除已处理帧(缓冲区内部左移,必须 memmove) */
|
||||||
|
|||||||
@ -101,10 +101,10 @@ static void Config_Flash_SRAM(FLASH_SRAM_DEFIN mode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
u8 MACAddr[6];
|
u8 MACAddr[6];
|
||||||
u8 IPAddr[4] = {192, 168, 1, 10};
|
u8 IPAddr[4] = {192, 168, 7, 10};
|
||||||
u8 GWIPAddr[4] = {192, 168, 1, 1};
|
u8 GWIPAddr[4] = {192, 168, 7, 1};
|
||||||
u8 IPMask[4] = {255, 255, 255, 0};
|
u8 IPMask[4] = {255, 255, 255, 0};
|
||||||
u8 DESIP[4] = {192, 168, 1, 50};
|
u8 DESIP[4] = {192, 168, 7, 50};
|
||||||
u16 desport = 5512;
|
u16 desport = 5512;
|
||||||
u16 srcport = 5511;
|
u16 srcport = 5511;
|
||||||
|
|
||||||
@ -145,6 +145,7 @@ extern void qdx_port_init(void);
|
|||||||
|
|
||||||
void WCHNET_HandleSockInt(u8 socketid, u8 intstat)
|
void WCHNET_HandleSockInt(u8 socketid, u8 intstat)
|
||||||
{
|
{
|
||||||
|
DBG_APP("SockInt: id=%d stat=0x%02X\r\n", socketid, intstat);
|
||||||
if (intstat & SINT_STAT_RECV)
|
if (intstat & SINT_STAT_RECV)
|
||||||
{
|
{
|
||||||
qdx_port_sock_recv_notify(socketid);
|
qdx_port_sock_recv_notify(socketid);
|
||||||
@ -153,17 +154,17 @@ void WCHNET_HandleSockInt(u8 socketid, u8 intstat)
|
|||||||
{
|
{
|
||||||
WCHNET_ModifyRecvBuf(socketid, (u32)SocketRecvBuf[socketid], RECE_BUF_LEN);
|
WCHNET_ModifyRecvBuf(socketid, (u32)SocketRecvBuf[socketid], RECE_BUF_LEN);
|
||||||
qdx_port_sock_connect_notify(socketid);
|
qdx_port_sock_connect_notify(socketid);
|
||||||
printf("TCP Connected, socket %d\r\n", socketid);
|
DBG_APP("TCP Connected, socket %d\r\n", socketid);
|
||||||
}
|
}
|
||||||
if (intstat & SINT_STAT_DISCONNECT)
|
if (intstat & SINT_STAT_DISCONNECT)
|
||||||
{
|
{
|
||||||
qdx_port_sock_disconnect_notify(socketid);
|
qdx_port_sock_disconnect_notify(socketid);
|
||||||
printf("TCP Disconnected, socket %d\r\n", socketid);
|
DBG_APP("TCP Disconnected, socket %d\r\n", socketid);
|
||||||
}
|
}
|
||||||
if (intstat & SINT_STAT_TIM_OUT)
|
if (intstat & SINT_STAT_TIM_OUT)
|
||||||
{
|
{
|
||||||
qdx_port_sock_disconnect_notify(socketid);
|
qdx_port_sock_disconnect_notify(socketid);
|
||||||
printf("TCP Timeout, socket %d\r\n", socketid);
|
DBG_APP("TCP Timeout, socket %d\r\n", socketid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,11 +174,13 @@ void WCHNET_HandleGlobalInt(void)
|
|||||||
u16 i;
|
u16 i;
|
||||||
u8 socketint;
|
u8 socketint;
|
||||||
intstat = WCHNET_GetGlobalInt();
|
intstat = WCHNET_GetGlobalInt();
|
||||||
if (intstat & GINT_STAT_UNREACH) printf("GINT_STAT_UNREACH\r\n");
|
DBG_APP("GlobalInt: 0x%02X\r\n", intstat);
|
||||||
if (intstat & GINT_STAT_IP_CONFLI) printf("GINT_STAT_IP_CONFLI\r\n");
|
if (intstat & GINT_STAT_UNREACH) DBG_APP("GINT_STAT_UNREACH\r\n");
|
||||||
|
if (intstat & GINT_STAT_IP_CONFLI) DBG_APP("GINT_STAT_IP_CONFLI\r\n");
|
||||||
if (intstat & GINT_STAT_PHY_CHANGE) {
|
if (intstat & GINT_STAT_PHY_CHANGE) {
|
||||||
if (WCHNET_GetPHYStatus() & PHY_Linked_Status)
|
i = WCHNET_GetPHYStatus();
|
||||||
printf("PHY Link Success\r\n");
|
DBG_APP("PHY_CHANGE: status=0x%04X %s\r\n", i,
|
||||||
|
(i & PHY_Linked_Status) ? "LINK_UP" : "LINK_DOWN");
|
||||||
}
|
}
|
||||||
if (intstat & GINT_STAT_SOCKET) {
|
if (intstat & GINT_STAT_SOCKET) {
|
||||||
for (i = 0; i < WCHNET_MAX_SOCKET_NUM; i++) {
|
for (i = 0; i < WCHNET_MAX_SOCKET_NUM; i++) {
|
||||||
@ -301,11 +304,14 @@ int main(void)
|
|||||||
TcpLogic_Init(MACAddr, NULL);
|
TcpLogic_Init(MACAddr, NULL);
|
||||||
TcpLogic_RegisterConfigCallback(OnConfigUpdate);
|
TcpLogic_RegisterConfigCallback(OnConfigUpdate);
|
||||||
TcpLogic_RegisterDetectionCallback(OnDetectionResult);
|
TcpLogic_RegisterDetectionCallback(OnDetectionResult);
|
||||||
|
DBG_APP("TcpLogic_Start...\r\n");
|
||||||
TcpLogic_Start();
|
TcpLogic_Start();
|
||||||
|
|
||||||
|
DBG_APP("Creating RTOS tasks...\r\n");
|
||||||
xTaskCreate(task_wchnet_entry, "wchnet", 512, NULL, 6, NULL);
|
xTaskCreate(task_wchnet_entry, "wchnet", 512, NULL, 6, NULL);
|
||||||
xTaskCreate(task_business_entry, "business", 512, NULL, 5, NULL);
|
xTaskCreate(task_business_entry, "business", 512, NULL, 5, NULL);
|
||||||
xTaskCreate(task_heartbeat_entry, "hb", 256, NULL, 3, NULL);
|
xTaskCreate(task_heartbeat_entry, "hb", 256, NULL, 3, NULL);
|
||||||
|
DBG_APP("Starting scheduler\r\n");
|
||||||
vTaskStartScheduler();
|
vTaskStartScheduler();
|
||||||
|
|
||||||
/* Should never reach here */
|
/* Should never reach here */
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user