ch32v307_camera/doc/函数调用指南.md
2026-03-13 22:22:45 +08:00

238 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 空间从前向后组装报包含 TLVMagic等最后压 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 的硬件抽象层HALPort层)。
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);
}
# 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 (上位机)