# DCU_HOST 项目 lib60870 CBB 库调用参考 > **用途**: RTU 项目开发 IEC 101/104 时的参考工程 > **源项目**: [DCU_HOST](../../../../DCU_HOST/) (科大智能 DCU 通信板) > **原理由**: DCU_HOST 已成熟使用 lib60870 CBB 库实现 101/104 从站,调用模式可直接参考 --- ## 1. DCU_HOST 项目背景 DCU_HOST 是基于 **RT-Thread** 实时操作系统的嵌入式通信板项目,运行在 STM32H743 平台。其 `applications/iec_prtcl/` 模块是对 lib60870 CBB 规约库的完整封装。 ### 1.1 模块文件结构 ``` DCU_HOST/applications/ ├── iec_prtcl/ # ★ IEC 规约应用层 │ ├── Iec_Use.h # CS10x 实体封装 + 外部接口声明 │ ├── Iec_Use.c # ★ 主循环驱动 (IecEntry) + 收/发/调度 │ ├── Protocol_Config.h # 参数配置接口声明 │ └── Protocol_Config.c # ★ 参数配置 + 回调注册 (SetProtocolItfc) ├── data/iec_itfc/ # ★ 数据回调层 (规约 ↔ 业务数据) │ ├── YcItfc.c/h # 遥测回调 (GetYcCountByGroup / GetYcValueByGroup) │ ├── YxItfc.c/h # 遥信回调 + SOE 回调 │ ├── YkItfc.c/h # 遥控回调 (SetYkInfor / YkResultNofify) │ ├── GbParamItfs.c/h # ★ 参数/定值读写回调 (882行) │ ├── DdItfc.c/h # 电度回调 │ ├── FaultItfc.c/h # 故障事件回调 │ └── FileParamItfs.c/h # 文件服务回调 └── cbblibs/lib60870/ # lib60870 CBB 库 (git submodule) ``` ### 1.2 lib60870 CBB 库版本 与 RTU 项目使用**同一套** CBB 库(同为科大智能 IECVer2.01.059_260202),API 完全一致。 --- ## 2. 核心架构:实体池 + 线程驱动 ### 2.1 实体封装 `stLIB60870ENTITY` DCU_HOST 将 `CS10x` 封装了一层: ```c #define MAX_CS10X_NUM 2 // 最大支持 2 个 CS10x 实例 (如一路104 + 一路101) typedef struct { u8 ucBusy; // 是否使用中 u8 ucType; // PRTCL_104_S / PRTCL_101_S u32 uiItfs; // 绑定的通信接口编号 (如 ETH0=0x0A000001) u32 uiTime; // 链路空闲超时累计 (ms) stLIB60870BUFF stBuf; // 内部收发缓冲区 CS10x stCs10x; // ★ CBB 库的 CS10x 结构体 (值语义) } stLIB60870ENTITY; // 全局实体池 stLIB60870ENTITY g_astLib60870Entity[MAX_CS10X_NUM]; ``` ### 2.2 线程入口 `IecEntry()` ```c void IecEntry(void *pvArg) { // 1. 创建 10ms 周期定时器 rt_timer_create("IEC_tm1", TmExpire, ..., 10, RT_TIMER_FLAG_PERIODIC); // 2. 初始化环形缓冲区 (用于跨线程数据传递) IecRingblkInit(); // 3. 主循环 while(1) { rt_event_recv(..., &uiEvent); // 等待事件 if(uiEvent & EV_TIMER1_IEC) { Schedule60870(10); // ★ 10ms 驱动一次 } if(uiEvent & EV_PARA_UPDATE) { UpdateParamLib60870(...); // 参数热更新 } rb_channel_process(&g_stIecChannel); // 处理收到的数据 } } ``` ### 2.3 数据接收链路 ``` 串口/网口收数据 → CommChannel_SendData / 加密解密 → IecRingblkInput(pucData, usLen, uiItfs) // 写入环形缓冲 → rb_channel_process() // 主循环中消费 → RecvDateProtocolItfs() → DataProc60870() ├── GetEntity60870(ucType, uiItfs) // 获取/创建实体 │ ├── pstEntity->ucBusy = 1 │ ├── memset(&stCs10x, 0, sizeof(CS10x)) │ ├── 绑定缓冲区指针 │ ├── ProtocolEntityConfig() → CS10x_104Init / CS10x_101Init │ └── Cs10xConfig() → 参数配置 + 回调注册 └── CS10x_DoRecv(&pstEntity->stCs10x, pucData, usLen) // ★ 喂给规约栈 ``` ### 2.4 发送回调 ```c s32 DataSend60870(u8 *pucBuf, u16 usLen, void* pvArg) { u32 uiItfs = *(u32*)pvArg; // pvArg = &pstEntity->uiItfs return CommChannel_SendData(pucBuf, usLen, uiItfs); } ``` --- ## 3. 初始化流程 ### 3.1 104 从站初始化 ```c // 1. 选择协议类型 enType = CS104_TYPE_S; // 或 CS101_TYPE_S // 2. 初始化规约栈 CS10x_104Init(pCs10x, DataSend60870, &pstEntity->uiItfs, enType); // 3. 配置参数 (通过参数映射表) Cs10xConfig(pstEntity, &g_stParamMappingTable); // → SetProtocol104Param() // ├── CS10x_SetAppParameters(&stAppParam) // ├── CS10x_SetAPCIParameters(&stApciParam) // ├── CS10x_SetYcType(浮点/整形) // ├── CS10x_SetYxType(单点/双点) // ├── CS10x_SetDdType / CS10x_FrameGap / CS10x_SetMultFrameEn // ├── CS10x_FaultEventEn / CS10x_SetSendSoe / CS10x_SetSendCos // ├── CS10x_SetYKEendFrame / CS10x_SetReadFileVSQ // └── CS10x_SetPresetContType // → SetProtocolItfc() ← ★ 所有回调在此注册 ``` ### 3.2 101 从站初始化 (差异项) 101 额外配置: - `CS10x_SetAppParameters`: 需要 `iSzOfLinkAddr` + `iLinkAddr` - `CS10x_ResendGap` / `CS10x_ResendCnt`: 重发参数 - `CS10x_SetHeartTimeGap`: 心跳间隔 - `CS10x_SetFileAckType`: 文件确认 - `CS10x_SetInitType`: 简单初始化 --- ## 4. 回调注册全景 (SetProtocolItfc) ```c void SetProtocolItfc(stLIB60870ENTITY *pstEntity, u8 ucType) { CS10x *pstCs10x = &pstEntity->stCs10x; // ── 对所有类型 (主站/从站) ── CS10x_TimeRWHandler(pstCs10x, GetTimeItfs, SetTimeItfs); CS10x_WR_ResetHandler(pstCs10x, Cs10xReadFileResetCOI, Cs10xWriteFileResetCOI); CS10x_SetYkInforHandler(pstCs10x, SetYkInfor); // ── 仅从站 ── if (PRTCL_104_S == ucType || PRTCL_101_S == ucType) { // 遥测 CS10x_S_GetYcByGroupHandler(pstCs10x, GetYcCountByGroup, GetYcValueByGroup); // 扰动遥测 CS10x_S_DiturbYcHandler(pstCs10x, GetDiturbYc, GetDiturbYcSendNum, UpdateDiturbYcPtrOut); // 遥信 CS10x_S_GetYxByGroupHandler(pstCs10x, GetYxCountByGroup, GetYxStatusByGroup); // SOE CS10x_S_SOEHandler(pstCs10x, GetSOE, GetSOESendNum, UpdateSoePtrOut); // 电度 CS10x_S_GetDdByGroupHandler(pstCs10x, GetDdCountByGroup, GetDdValueByGroup); // 时标电度 CS10x_S_DiturbDduHandler(pstCs10x, GetTimeDdu, GetTimeDduSendNum, UpdateTimeDduPtrOut); // 故障事件 CS10x_S_FaultEventHandler(pstCs10x, GetEventSendNum, GetFaultEvent, UpdateFaultEventPtrOut); // 遥控校验 CS10x_S_YkVerifyHandler(pstCs10x, Cs10xYkVerifyItfs); // 定值区 CS10x_S_ParamAreaHandler(pstCs10x, GbParamGetParamArea, GbParamSetParamArea); // 参数读写 CS10x_S_IECParamHandler(pstCs10x, GbParamAddElement, GbParamRunRding, GbParamRunWting); // 参数信息 CS10x_S_GetParamInfoHandler(pstCs10x, GbParamGetTotalNum, GbParamGetIecParam); // 文件服务 CS10x_S_FileReadOprtHandler(pstCs10x, Fm_GetDirFile, Fm_SearchDirFileNum, Fm_ReadFile, ...); CS10x_S_FileWriteOprtHandler(pstCs10x, Cs10xWriteItfs, Cs10xWriteFileCheckItfs, Cs10xWriteFinishItfs, ...); // 升级 CS10x_S_UpdateProcHandler(pstCs10x, NULL); } } ``` --- ## 5. 子文档索引 | 子文档 | 内容 | 对应回调 | |--------|------|----------| | [01-总召与遥测遥信](01-总召与遥测遥信.md) | GetYcCountByGroup / GetYcValueByGroup / GetYxCountByGroup / GetYxStatusByGroup 详细实现 | `CS10x_S_GetYcByGroupHandler` / `CS10x_S_GetYxByGroupHandler` | | [02-SOE与扰动数据](02-SOE与扰动数据.md) | GetSOE / GetSOESendNum / UpdateSoePtrOut + 扰动遥测回调 | `CS10x_S_SOEHandler` / `CS10x_S_DiturbYcHandler` | | [03-遥控与对时](03-遥控与对时.md) | SetYkInfor / YkResultNofify / Cs10xYkVerifyItfs / GetTimeItfs / SetTimeItfs | `CS10x_S_YkVerifyHandler` / `CS10x_TimeRWHandler` | | [04-参数定值与文件服务](04-参数定值与文件服务.md) | GbParamGetParamArea / GbParamAddElement / 文件读写 | `CS10x_S_ParamAreaHandler` / `CS10x_S_IECParamHandler` / 文件回调 | | [05-故障事件与电度](05-故障事件与电度.md) | GetFaultEvent / GetDdValueByGroup | `CS10x_S_FaultEventHandler` / `CS10x_S_GetDdByGroupHandler` |