# Page 1

语⾔版本函数调⽤指南
C
版本V1.0
1. 概述
本指南旨在为 CH32 单⽚机其他业务代码提供调⽤“图像预处理模块”和“TCP 打包与发送模块”的 C 语⾔ API 说明。这两个模块被封装为独⽴的底层库函数，
负责将原始采集数据处理并推送⾄上位机，同时接收上位机配置。
开发者⽆需关⼼内部的滑窗算⼒优化或是 TCP 连接维持、分⽚等细节，只需按照约定的结构体提供⼊参并调⽤相关 API 即可。
2. 核⼼数据结构
2.1 原始图像数据结构 ( RawImageBuffer_t )
该结构由采集模块（⿊盒）在采集完成后构建并传⼊处理库。注意：本库所有内部计算和过滤针对的均是 16位整数矩阵 (精确到 0.1℃的定点数)。
typedef struct {
uint16_t* pData; // 指向二维 16位 整数矩阵的起始指针(如 275 代表 27.5℃)
uint16_t Width; // 原始图像宽度
uint16_t Height; // 原始图像高度
uint32_t FrameNumber; // 当前帧号（或时间戳），用于溯源
} RawImageBuffer_t;
2.2 预处理结果结构 ( PreprocessResult_t )
预处理模块运算完毕后产出的有效数据载荷结构。
typedef struct {
uint8_t* pValidData; // 必须是 uint8_t 类型的外部缓冲区指针，规避结构体强转导致的内存对齐陷阱
uint32_t DataLength; // 有效数据的字节长度 (宽度 * 高度 * sizeof(元素))
uint16_t ValidWidth; // 产出图像宽度 (对于一维，可表示点数)
uint16_t ValidHeight; // 产出图像高度
int16_t MinTemp; // 有效区域内的最低温度
int16_t MaxTemp; // 有效区域内的最高温度
int16_t AvgTemp; // 有效区域内的平均温度
int16_t RoiTemp; // 触发点温度
uint8_t Status; // 处理状态 (0: OK, 1: 异常)
uint32_t FrameNumber; // 继承自原始图像的帧号
} PreprocessResult_t;
2.3 ⽹络封装缓冲结构 ( TcpTxBuffer_t )
专为 TCP 零拷⻉封包设计的外部分配缓冲区。应⽤层（或专⻔的内存池）提供⾜够⼤的连续内存空间。
typedef struct {
uint8_t* pBuffer; // 指向由应用层分配的具体内存区 (包含物理组装全空间)
uint32_t TotalCapacity; // 该 Buffer 总容量
uint32_t HeadOffset; // 【核心】预留给封包用的首部偏移量。载荷将从 pBuffer + HeadOffset 开始写入
uint32_t ValidPayloadLen; // 在调用封装函数后，由网络库回填的最终报文总长度
} TcpTxBuffer_t;

# Page 2

2.4 系统运⾏状态与配置 ( ConfigCommon_t , Config2D_t , Config1D_t )
系统参数配置不再使⽤单⼀的句柄封装，⽽是由通信协议中定义的三个独⽴结构体分别管理： ConfigCommon_t （通⽤参数）、 Config2D_t （⼆维专有参数）
与
Config1D_t
（⼀维专有参数）。TCP 模块会通过回调动态更新这三个结构体，应⽤层需要保存最新配置以供预处理等模块使⽤（详⻅通信协议规范 2.0）。
3. 预处理模块 API
3.1 Preprocess_Init
功能：初始化预处理模块，分配静态计算所需的⼯作内存（如列累加数组）。
原型：
int8_t Preprocess_Init(uint16_t maxWidth, uint16_t maxHeight);
⼊参：
maxWidth / maxHeight : 系统允许的最⼤处理分辨率，⽤于预分配内存池。
返回值： 0 成功， <0 失败。
3.2 Preprocess_Execute
功能：对单帧⼆维矩阵进⾏裁剪并导出。系统会基于温度过滤启动滑动窗⼝去寻找热源，锁定⽬标区域（ROI）后，会将这段区域内未被修改过的真实
原始像素原样导出，写⼊外部提供的 Buffer 中。
原型： int8_t Preprocess_Execute(const RawImageBuffer_t* input, TcpTxBuffer_t* out_buffer, PreprocessResult_t* output_meta);
⼊参：
input : 采集模块提供的原始数据句柄。
out_buffer : 应⽤层预先分配好的待发送缓冲区。库将直接通过 out_buffer->pBuffer + out_buffer->HeadOffset 零拷⻉写⼊原始图像测温字节。
出参：
output_meta : 运算完成的规范化统计结果（⻓宽、最⼤、最⼩温度、平均温度等信息，统计依据同样为未失真的原始像素）。
返回值：
0
表⽰处理成功并锁定 ROI，
<0
表⽰内存越界或其他致命错误。
3.3 Preprocess_CheckInternalTrigger2D
功能：根据上位机设定的“触发 ROI 区域”、“温度触发阈值”及“判定条件(最⾼温/平均温)”，对传⼊的单帧原始图像进⾏内部热源触发判定。
原型：
int8_t Preprocess_CheckInternalTrigger2D(const RawImageBuffer_t* input);
⼊参：
input : 当前需要评判的原始图像。
返回值： 1 表⽰触发条件满⾜（画⾯中设定的 ROI 区域发现了⾜够⾼温的⽬标）， 0 表⽰未触发， <0 参数错误。
使⽤场景：在内部触发机制（ TriggerMode = 0 ）下，结合相机的连续 DMA 或轮询输出使⽤。
3.4 Preprocess_Settings_Change
功能：安全地将通过 TCP 接收到的最新业务⼯作参数更新⾄预处理库内部。⽀持影⼦机制加锁更新策略，确保不会破坏正在进⾏处理的流⽔线帧。
原型： int8_t Preprocess_Settings_Change(const Config2D_t* newConfig2D, const Config1D_t* newConfig1D, const ConfigCommon_t* newCommon);
⼊参：
newConfig2D / newConfig1D : 从上位机新下发的专⽤参数结构体（如 TargetWidth , TriggerTemperatureThreshold ）。
newCommon : 从上位机新下发的通⽤配置结构体。
返回值： 0 成功， <0 失败。
4. TCP 打包与发送模块 API
4.1 TcpLogic_Init
功能：初始化整个应⽤层 TCP 管理任务，包括底层 Socket 绑定、接收任务建⽴以及缓冲池初始化。
原型： int8_t TcpLogic_Init(const uint8_t* deviceUUID, const uint8_t* authToken);
⼊参：
deviceUUID : 16 字节的设备物理识别码（如 MAC 或 UID）。
authToken : ⾝份验证令牌。
返回值：
0
成功，
<0
失败。

# Page 3

4.2 TcpLogic_Start
功能：⾮阻塞启动 TCP 服务管理引擎。此后库将在后台⾃动进⾏ 5511 (控制流) 与 5512 (数据流) 的连接、握⼿(Handshake)、重连和⼼跳维持。
原型：
void TcpLogic_Start(void);
4.3 TcpLogic_BuildAndSendTemperatureFrame
功能：将之前由预处理写⼊ TcpTxBuffer_t 内的数据（连同 PreprocessResult_t 结构体中的统计数据）封装。函数不需要搬移⼤块矩阵数据，直接利
⽤移位操作和 HeadOffset 空间从前向后组装报⽂头（包含 TLV、Magic等），最后压⼊ 5512 发送缓冲。
原
型：
int8_t TcpLogic_BuildAndSendTemperatureFrame(TcpTxBuffer_t* io_buffer, const PreprocessResult_t* processMeta, uint8_t frameType, uint8_t is2D);
⼊参：
io_buffer : 包含已被预处理模块填充过载荷的 Buffer 包裹器。本函数执⾏完后，其中的 ValidPayloadLen 将被更新。
processMeta : 包含帧号与温区极值统计。
frameType : 帧类型 (0x00 LIVE, 0x01 TRIGGER, 0x02 MASKED)。
is2D : 1 为⼆维数组， 0 为⼀维。
返回值： 0 已组装完毕并压⼊队列， <0 失败。
4.4 TcpLogic_GetLatestConfig
功能：主动查询并返回 TCP 库缓存的、由上位机最近⼀次下发的完整配置参数结构体。适⽤于应⽤层需要在⾮回调上下⽂中（如初始化后⾸次同步或
故障恢复后重新拉取）获取当前⽣效配置的场景。
原型：
int8_t TcpLogic_GetLatestConfig(ConfigCommon_t* out_common, Config2D_t* out_cfg2d, Config1D_t* out_cfg1d);
出参：
out_common : 由调⽤者提供的通⽤配置结构体指针，库将最新缓存的通⽤配置拷⻉到此处。
out_cfg2d : 由调⽤者提供的⼆维专有配置结构体指针。
out_cfg1d : 由调⽤者提供的⼀维专有配置结构体指针。
返回值：
0
成功（配置有效），
-1
尚未从上位机收到过任何配置，
<0
其他错误。
4.5 接收与配置更新回调注册
TCP 库在后台线程处理收到的指令（如参数更改或控制信号）。主业务通过注册回调函数来处理这些上位机下发的事件，确保底层安全。
// 定义回调函数类型
typedef void (*ConfigUpdateCallback_t)(const ConfigCommon_t* common, const Config2D_t* cfg2d, const Config1D_t* cfg1d);
typedef void (*DetectionResultCallback_t)(uint32_t frameNumber, uint8_t resultStatus);
// 【注意】：此回调专门用于测试上位机主动请求帧。实际业务由硬件触发或DMA循环完成，业务代码不应依赖或实现此回调。
typedef void (*TempFrameRequestCallback_t)(uint8_t is2dRequest);
// 注册回调 API
void TcpLogic_RegisterConfigCallback(ConfigUpdateCallback_t cb);
void TcpLogic_RegisterDetectionCallback(DetectionResultCallback_t cb);
void TcpLogic_RegisterTempFrameRequestCallback(TempFrameRequestCallback_t cb);
应⽤⽰例：参数热更新
当注册了 ConfigUpdateCallback_t ，TCP 发⽣控制流的参数接收时，后台库完成参数解析及 CRC 校验后，触发此回调。⽤⼾可在回调中利⽤软中断或影⼦
积存器机制将新参数赋予当前正在使⽤的
SystemConfig_t
。
5. 核⼼ API 设计准则与开发规范
为兼顾底层性能考量与可靠性⽹络封装，本库严格遵循以下原则：
1. “传⼊指针 + ⻓度” 与预留偏移封包 (Zero-Copy Offset) ⽅案
物理内存分配由应⽤层（依托其内存池机制）负责，传递给库的操作句柄为 out_buffer 。预处理在填充矩阵数据时，会越过 HeadOffset （这个偏移量
等于后续 TCP 组合包所需的 Header 及 TLV 指⽰器的⼤⼩）。后续 TCP ⽹络库封装时，仅需要往前填充封包信息，⽆需对上百 KB 的矩阵数据做任何
memcpy
内存搬移动作。

# Page 4

2. 防范访问陷阱 (Strict uint8_t Vectoring)
禁⽌将⽹⼝收发缓冲区中的指针强转为 uint32_t 或是具体通讯结构体使⽤。库内部所有的数据移动与地址递增处理严格使⽤ uint8_t * 处理⽹络数据
流，从根本上阻绝了因不同编译器或单⽚机对⻬法则不⼀导致的 HardFault 或越界访问。
3. 内置安全⼤⼩端转化 (Bitwise Disassembly/Assembly)
**这是针对 16位 整数矩阵数据的核⼼保障。**⽆论是将采集到的定点温度（ uint16_t / int16_t ）拆分成⽹络字节流（封包），还是从字节流解析成单⽚
机状态（解包），都彻底抛弃了直接强转或结构体对⻬强塞的⽅式。库内部严格规定使⽤单字节移位操作（如 val = (buf[0]) | (buf[1]<<8); ），完美
解决“⽹络端与主机⼩端”之间的安全切换，并在提取矩阵数据时保证 2-Byte Little-Endian 输出。
6. 底层数据收发机制与平台移植架构 (Port 层解耦)
（预处理及TCP封包逻辑）绝对不会直接操作硬件寄存器或特定的 Socket API。
取⽽代之的是⼀个位于 qdx_port.h 的硬件抽象层（HAL，Port层）。
1. 发送：硬件发送缓冲区写⼊地址 ( qdx_port_tcp_send )
当应⽤层调⽤类似 TcpLogic_BuildAndSendTemperatureFrame 时，传递的是在外部通过内存池预先分派好、并在前⾯加上了协议头的业务缓冲数组（即
io_buffer->pBuffer ）。⽹络库内部并不会“写⼊⽹卡相关的寄存器”，⽽是调⽤ qdx_port_tcp_send 。这保证了只需将封装好的完整、连续的 RAM 地址
指针和⻓度丢给驱动层。内部的 WCH NET 或 LwIP 会从给定的这个内存地址将其发往 DMA 或以太⽹ MAC。
2. 接收：硬件接收缓冲区 ( qdx_port_tcp_recv )
对应地，系统会启动后台线程监听 TCP 数据流。它每次都会从 qdx_port_tcp_recv 尝试获取数据，由底层协议栈驱动将接收到的真正⽹络⽐特流存⼊
库提供的接收缓冲中，随后库再去解析配置命令。
7. 常规调⽤流程图 (伪代码模式)
// 1. 初始化
Preprocess_Init(MAX_W, MAX_H);
TcpLogic_Init(MyUUID, MyToken);
TcpLogic_RegisterConfigCallback(OnConfigUpdated);
TcpLogic_RegisterDetectionCallback(OnHardwareReject);
// 2. 启动网络引擎线程 (RTOS环境下)
TcpLogic_Start();
// 3. 图像中断 / DMA 轮询回调
void OnCameraDataReady(uint16_t* matrix, uint16_t w, uint16_t h) {
RawImageBuffer_t rawBuff = {matrix, w, h, ++frameCnt};
// 【核心】判断这帧图像里是否有物体达到了设定的触发温度
if (Preprocess_CheckInternalTrigger2D(&rawBuff) == 1) {
// 发现高温目标！分配一块发送专用的零拷贝缓冲
TcpTxBuffer_t txBuff = MemoryPool_GetTxBuffer();
PreprocessResult_t resMeta = {0};
// 交由库执行滑动窗口剪裁，将最核心的高温区域内原始像素直接填入缓冲的预留偏移后
if (0 == Preprocess_Execute(&rawBuff, &txBuff, &resMeta)) {
// TCP封包：在头部预留好的 HeadOffset 内执行无损组包并发出
TcpLogic_BuildAndSendTemperatureFrame(&txBuff, &resMeta, 0x01, 1);
} else {
MemoryPool_FreeTxBuffer(&txBuff);
}
}
}
// 4. 当参数更新回调触发时
void OnConfigUpdated(const ConfigCommon_t* common, const Config2D_t* cfg2d, const Config1D_t* cfg1d) {
// 将获得配置输入给预处理模块，利用互斥锁安全地刷新工作参数（如 TriggerRoi）
Preprocess_Settings_Change(cfg2d, cfg1d, common);
}

## 4.6 TcpLogic_InjectTestConfig（测试模式配置注入）

功能：在不依赖服务器的情况下，直接向 TCP 逻辑模块注入配置参数。注入后走与服务器下发完全相同的缓存 + 回调路径。仅非 NULL 的参数会被更新。

原型：

```c
void TcpLogic_InjectTestConfig(const ConfigCommon_t *common, const Config2D_t *cfg2d, const Config1D_t *cfg1d);
```

入参：
- `common`：通用配置指针，NULL 表示不更新
- `cfg2d`：2D 配置指针，NULL 表示不更新
- `cfg1d`：1D 配置指针，NULL 表示不更新

内部行为：
1. 互斥锁保护下写入内部缓存
2. 设置 `has_valid_config = 1`
3. 触发已注册的 `ConfigUpdateCallback`

使用场景：
- 测试模式（`TEST_PATTERN_MODE=1`）启动时注入默认 2D 配置，使自主触发管线无需服务器即可工作
- 注入后若服务器连接并下发新配置，新配置会覆盖注入的默认值

示例：
```c
Config2D_t test_cfg2d;
memset(&test_cfg2d, 0, sizeof(test_cfg2d));
test_cfg2d.Enabled = 1;
test_cfg2d.TriggerMode = 0;            // 内部触发 (0=内部, 1=外部)
test_cfg2d.TargetWidth = 64;
test_cfg2d.TargetHeight = 64;
test_cfg2d.TriggerTemperatureThreshold = 800;  // 80.0°C
test_cfg2d.TriggerBurstCount = 3;
TcpLogic_InjectTestConfig(NULL, &test_cfg2d, NULL);
```

## 8. MCU 实际业务调用流程（CH32V307 实现）

以下为 MCU 中 main.c 的实际初始化和业务循环流程，作为第 7 节伪代码的具体实现参考：

```c
// ===== 初始化阶段 (main 函数) =====

// 1. 硬件初始化
USART_Printf_Init(921600);
Config_Flash_SRAM(FLASH_128_SRAM_192);   // 128K Flash + 192K SRAM
#if !TEST_PATTERN_MODE
DVP_Init();                               // 正常模式初始化 DVP
#endif
TIM2_Init();                              // WCHNET 10ms 定时基准
ExtTrigger_GPIO_Init();                   // PA15/EXTI15 外部触发
NG_GPIO_Init();                           // PA8 NG 输出

// 2. 网络初始化
ETH_LibInit(IPAddr, GWIPAddr, IPMask, MACAddr);
qdx_port_init();

// 3. 库初始化 + 回调注册
Preprocess_Init(SENSOR_WIDTH, SENSOR_HEIGHT);
TcpLogic_Init(MACAddr, NULL);
TcpLogic_RegisterConfigCallback(OnConfigUpdate);
TcpLogic_RegisterDetectionCallback(OnDetectionResult);
TcpLogic_RegisterTempFrameRequestCallback(OnTempFrameRequest);

// 4. 测试模式注入默认配置
#if TEST_PATTERN_MODE
TcpLogic_InjectTestConfig(NULL, &test_cfg2d, NULL);
#endif

// 5. 启动 TCP 引擎 + RTOS 任务
TcpLogic_Start();
xTaskCreate(task_wchnet_entry,   "wchnet",   512, NULL, 6, NULL);
xTaskCreate(task_business_entry, "business", 512, NULL, 5, NULL);
xTaskCreate(task_heartbeat_entry,"hb",       256, NULL, 3, NULL);
#if TEST_PATTERN_MODE
xTaskCreate(task_test_pattern_entry, "testpat", 256, NULL, 4, NULL);
#endif
vTaskStartScheduler();

// ===== 业务循环 (task_business_entry) =====
// 全部行为由运行时 Config 驱动，无编译期功能开关

while (1) {
    // NG 脉冲超时检查
    if (g_ng_off_time && sys_tick_ms >= g_ng_off_time)
        GPIO_ResetBits(NG_GPIO_PORT, NG_GPIO_PIN);

    #if !TEST_PATTERN_MODE
    DVP_Task();  // 行 DMA 搬运
    #endif

    // 辅助通道：TEMP_REQ 服务器按需截图
    if (g_temp_req_pending) {
        // → 2D: Preprocess_Execute → TcpLogic_BuildAndSendTemperatureFrame
        // → 1D: send_1d_snapshot (30点空间采样)
    }

    // 主管线：自主触发
    if (Frame_Ready_Flag) {
        TcpLogic_GetLatestConfig(&tc, &t2, &t1);
        if (t2.Enabled)
            handle_2d_trigger(&raw, &t2, &use_buf);   // 2D 状态机
        else if (t1.Enabled)
            handle_1d_trigger(&raw, &t1, &use_buf);   // 1D 状态机
    }
}
```

# Page 5

6. 函数调⽤时序图 (Control Flow)
通过下⽅时序图，可清晰展⽰从设备启动，到外部通信介⼊，再到硬件持续触发采集的数据流动与函数调⽤顺序。

# Page 6

主机/中断(Main) TcpLogic (⽹络库) Preprocess (预处理库) ConfigServer (上位机)
1. Preprocess_Init(W, H)
2. TcpLogic_Init(UUID, Token)
3. TcpLogic_RegisterConfigCallback()
4. TcpLogic_Start()
5. ⾃动连接 5511 与 5512，完成握⼿
6. 下发⾸批动态配置指令 (Type 0x20/0x22)
7. 触发参数回调 OnConfigUpdated()
8. Preprocess_Settings_Change(cfg)
循环运转：依靠中断或任务调度持续⼯作
9. 分配待发内存 TcpTxBuffer_t(预留 Offset)
10. 等待相机 DMA 完成⼀帧或 IO 触发
11. Preprocess_Execute(&rawBuff, &txBuff)
在 Offset 位置后写⼊图⽚矩阵⻓串数据
返回处理 meta 信息及成功的 txBuff
12. TcpLogic_BuildAndSend(txBuff)
在头部 Offset 内利⽤移位封包 TLV/序列号
数据送⼊ TCP 流发送 (零拷⻉达成)
opt [获取到剔除响应]
TCP 数据流返回 Defect Result (NG)
触发 DetectionResultCallback
拉⾼ DO1 定时执⾏剔除动作
主机/中断(Main) TcpLogic (⽹络库) Preprocess (预处理库) ConfigServer (上位机)

# Page 7

## 7. 多级调试打印系统

### 7.1 概述

调试打印通过 `qdx_port.h` 中的宏体系实现，支持 **5 个级别** 和 **7 个分类**。仅需修改一个宏即可全局控制输出量：

```c
#define DBG_LEVEL  DBG_LEVEL_NORMAL   // 修改此值控制输出详细度
```

### 7.2 级别定义

| 值 | 宏名 | 说明 | 适用场景 |
|---|---|---|---|
| 0 | `DBG_LEVEL_NONE` | 完全关闭 | 量产固件 |
| 1 | `DBG_LEVEL_ERR` | 仅错误 | 最小输出排障 |
| 2 | `DBG_LEVEL_BRIEF` | + 服务器配置/网络事件 | **推荐日常使用** |
| 3 | `DBG_LEVEL_NORMAL` | + 触发/数据/初始化 | 开发调试（默认） |
| 4 | `DBG_LEVEL_VERBOSE` | + 心跳/TLV详情 | 深度调试 |

### 7.3 分类宏及打印级别

| 宏 | 级别阈值 | 前缀 | 用途 |
|---|---|---|---|
| `DBG_ERR` | ≥1 (ERR) | `[ERR]` | HardFault、CRC校验失败、连接失败、PP失败 |
| `DBG_CFG` | ≥2 (BRIEF) | `[CFG]` | **服务器下发的所有配置**（Config2D/1D/Common、DevID、ACK、DetResult、TempReq） |
| `DBG_NET` | ≥2 (BRIEF) | `[NET]` | TCP连接/断开、PHY状态、Socket事件 |
| `DBG_TRIG` | ≥3 (NORMAL) | `[TRIG]` | 外部/内部触发、防抖、Burst启停 |
| `DBG_DATA` | ≥3 (NORMAL) | `[DATA]` | 2D/1D帧发送结果、TEMP_REQ发送 |
| `DBG_INIT` | ≥3 (NORMAL) | `[INIT]` | 开机初始化（传感器、DVP、WCHNET、RTOS） |
| `DBG_HB` | ≥4 (VERBOSE) | `[HB]` | 心跳打印、TLV包头详情（高频） |

### 7.4 使用示例

```c
DBG_ERR("CRC fail: calc=0x%04X recv=0x%04X\r\n", calc, recv);
DBG_CFG("<< Config2D: En=%d %dx%d Trig=%d\r\n", en, w, h, trig);
DBG_NET("[Control] Connected to %s:%d\r\n", ip, port);
DBG_TRIG("2D ext trigger\r\n");
DBG_DATA("2D SEND frm=%d ret=%d\r\n", frm, ret);
DBG_INIT("Sensor: Y16 OK\r\n");
DBG_HB("%d tick=%d frm=%d\r\n", cnt, tick, frm);
```

### 7.5 各级别输出预期

- **NONE (0)**：静默，仅 HardFault 的 raw printf 输出
- **ERR (1)**：错误信息 — 约 13 条打印点
- **BRIEF (2)**：+ 服务器配置全量打印 + 网络事件 — 上位机交互一目了然
- **NORMAL (3)**：+ 触发事件、数据发送、初始化 — 标准开发模式
- **VERBOSE (4)**：+ 心跳（每2秒）、每个TLV包详情 — 仅深度调试使用