RTU/mimo/工程/lib60870_CBB库解析.md

27 KiB
Raw Permalink Blame History

lib60870 CBB 库详细解析

库版本: IECVer2.01.059_260202 (2026-02-02) 厂家: 科大智能电气有限公司 (2013-2026) 用途: IEC 60870-5-101 / 60870-5-104 / 60870-5-103 电力远动规约协议栈 源码路径: src/protocol/lib60870/ 编译兼容头: cbb_compat.h (通过 gcc -include 注入,不修改库文件)


1. 模块总览

1.1 文件清单

src/protocol/lib60870/
├── ChangeList.md              # 版本变更记录 (V2.01.035 → V2.01.059)
├── 规约参数说明.md             # 参数配置字典 (必读)
├── 规约库默认参数.md           # 初始化的默认值
├── inc/                       # 头文件目录
│   ├── lib60870_inc.h         # 基础包含 (stdint/stdio) + 字节序宏
│   ├── lib60870_common.h      # ★ 核心头文件: CS10x 结构体 + 全部 API 声明 + 常量
│   ├── lib60870_public.h      # 公共工具: TaskFlag/checksum/CP56Time 编解码
│   ├── lib60870_process.h     # 公共流程: SOE/故障/扰动检查与调度
│   ├── Asdu.h                 # ASDU 数据域解析: 品质描述词 + 发送/解码函数
│   ├── gb101.h                # ★ IEC 101 链路层: 帧编解码/重发/链路状态
│   ├── gb104.h                # ★ IEC 104 APCI 层: I/S/U帧/计时器
│   ├── gb103.h                # IEC 103 规约: 保护通信/通用分类服务
│   └── md5.h                  # MD5 校验
└── src/                       # 源文件目录
    ├── lib60870_common.c       # CS10x 公共接口实现 + 回调注册
    ├── lib60870_public.c       # 工具函数实现
    ├── lib60870_process.c      # 公共流程实现
    ├── Asdu.c                  # ASDU 编解码 + 业务数据发送
    ├── gb101.c                 # 101 链路层实现
    ├── gb104.c                 # 104 APCI 层实现
    ├── gb103.c                 # 103 规约实现
    └── md5.c                  # MD5 实现

1.2 头文件依赖关系

graph TD
    A[lib60870_inc.h] --> B[lib60870_common.h]
    B --> C[lib60870_public.h]
    B --> D[lib60870_process.h]
    B --> E[Asdu.h]
    B --> F[gb101.h]
    B --> G[gb104.h]
    B --> H[gb103.h]
    C --> E
    D --> E
    E --> F
    E --> G

lib60870_common.h 是所有模块的单一依赖入口。外部只需 #include "lib60870_common.h" 即可获得全部类型和 API。


2. 核心数据结构

2.1 协议类型枚举 CS10x_Type

typedef enum {
    CS101_TYPE_S = 0,   // CS101 从站 (被控站/终端)
    CS101_TYPE_M,       // CS101 主站
    CS104_TYPE_S,       // CS104 从站 (被控站/终端)
    CS104_TYPE_M,       // CS104 主站
} CS10x_Type;

理解要点

  • _S = slave/从站 = 终端侧 = 本项目 RTU 使用的模式
  • _M = master/主站 = 调度侧
  • 101 和 104 共用同一个 CS10x 结构体,通过类型枚举区分行为

2.2 核心结构体 CS10x(约 300 行,源码

struct CS10x_t { ... } CS10x;          // 结构体定义 + typedef
typedef struct CS10x_t *CS10xHandle_t; // 句柄指针

关键成员分类

分类 成员 说明
协议标识 CS10x_Type eCS10x_Type 当前协议类型 (101/104 + 主/从)
101 链路 ucAddr, ucReSend_Num, usReSend_Gap 链路地址、重发次数、重发间隔
uc101InitFlag, uc101LinkState 101 链路初始化状态
CONTROL101 stControl101Up/Down 101 控制域位域
104 链路 usSendNum/usRecvNum, usAckSendNum/usAckRecvNum 104 发送/接收序号
VIec104Timer stM_vTimer[4] T0/T1/T2/T3 定时器
数据缓冲 VCommBuf stRecvBuf/SendBuf 接收/发送环形缓冲区
ASDU 参数 CS10x_AppLayerParameters stParam ASDU 字节长度配置
CS104_APCIParameters st104Param 104 K/W/T 参数
任务标志 VFLAGS stTaskFlags 128 位任务位图
回调函数 pfnSend, pfnGetTime, pfnSetTime ★ 核心回调接口(见 3.1
pfnGetYcCountByGroup / pfnGetYcValueByGroup 遥测回调
pfnGetYxCountByGroup / pfnGetYxStatusByGroup 遥信回调
pfnGetSOE / pfnUpdata_SOE_Pout / pfnGetSOE_SendNum SOE 回调
pfnGetFaultEvent / pfnUpdata_FaultEvent_Pout 故障事件回调
pfnFcYkVerify 遥控校验回调
pfnGetDdCountByGroup / pfnGetDdValueByGroup 电度回调
pfnGetDiturbYc / pfnGetTimeDdu 扰动遥测/电度时标回调
参数读写 pfnGetParamArea / pfnSetParamArea 定值区切换
pfnAddIECParam / pfnRunReadIECParam / pfnRunWriteIECParam 参数读写
pfnGetParamCount / pfnGetParamInfoByIndx 参数信息查询
文件传输 pfnGetProDirFile / pfnReadFile / pfnWrite 文件服务回调(已废弃旧接口,新接口为 CS10x_S_FileReadOprtHandler
软件升级 pfnOnlineProg / pfnUpdateOprt 在线升级回调
配置参数 usYcType(0/1/2) / usYxType(0/1) / usDdType(0/1) 数据类型选择
ucSOEEn, ucCOSEn, ucYkEndFrameEn SOE/COS/遥控结束帧使能
ucMutilFrameEn 104 多帧发送使能
ulSummon_Gap, ulHeart_Gap, ulSyn_Gap 定时器间隔(ms)
ucInitType, ucFileAckType 初始化类型/文件确认类型

2.3 ASDU 信息体数据结构

// 遥信—库发出给应用层填充数据
typedef struct {
    unsigned int   uiInfoAddr;   // 信息体地址 (点号)
    unsigned char  ucStatus;     // 状态 (0=分/1=合)
    unsigned char  ucStateType;  // 0=单点 / 1=双点
} Yx_Info;

// 遥测—库发出给应用层填充数据
typedef struct {
    unsigned int   uiInfoAddr;   // 信息体地址
    float          fVal;         // 遥测值 (浮点)
    unsigned char  ucQds;        // 品质描述词
} Yc_Info;

// SOE—事件顺序记录
typedef struct {
    unsigned int   uiInfoAddr;   // 信息体地址
    unsigned char  ucStatus;     // 状态
    unsigned char  ucStateType;  // 单点/双点
    __CP56Time2a   stCTime;      // 时标 (7字节 CP56 格式)
} SOE_Info;

// 遥控—库传递给应用层校验
typedef struct {
    unsigned int   uiInfoAddr;   // 信息体地址
    unsigned char  ucStatus;     // 命令值 (0=分/1=合)
    unsigned char  ucStateType;  // 单点遥控/双点遥控
    unsigned char  ucYkType;     // 选择/执行
} Yk_Info;

// 电度
typedef struct { unsigned int uiInfoAddr; float fVal; } Dd_Info;

// 带时标电度
typedef struct { unsigned int uiInfoAddr; float fVal; __CP56Time2a stCTime; } TimeDd_Info;

// 故障事件
typedef struct {
    unsigned short   usSoeNum;
    SOE_Info         staSoe[MAX_FAULT_EVENT_SOE_SIZE];
    unsigned short   usYcNum;
    Yc_Info          staYc[MAX_FAULT_EVENT_YC_SIZE];
} FAULT_EVENT_Info;

// 参数/定值
typedef struct {
    unsigned char  ucType;      // TAG_TYPE_xxx
    unsigned char  ucLen;       // 数据长度
    union { ... }  unVal;       // 值 (支持多种类型)
    unsigned int   uiInfoAddr;  // 信息体地址
} IECPARAM_T;

2.4 CP56Time2a 时间格式

typedef struct {
    unsigned char ucLMs;    // 毫秒低位
    unsigned char ucHMs;    // 毫秒高位 (含 IV 标志位)
    unsigned char ucMin;    // 分钟 (含 IV 标志)
    unsigned char ucHour;   // 小时 (含 SU 夏令时标志)
    unsigned char ucWeek;   // 星期 (0=未用)
    unsigned char ucMonth;  // 月
    unsigned char ucYear;   // 年 (0-99)
} __CP56Time2a;

// 编解码工具函数
unsigned char CP56Time2a_Pack2Buf(unsigned char *out, const __CP56Time2a *cp56);
unsigned char CP56Time2a_GetFromBuf(const unsigned char *in, __CP56Time2a *cp56);

2.5 帧格式定义

// 104 帧
typedef struct {
    unsigned char byStartCode;   // 0x68
    unsigned char byAPDULen;     // APDU 长度
    unsigned char byControl1..4; // 控制域 (4字节)
    unsigned char byASDU[249];   // ASDU 数据
} VIec104Frame;

// 101 帧—联合体:短帧(单字节地址/双字节地址) / 长帧
typedef union {
    VFrame10    stFrame10;       // 双字节地址短帧
    VFrame10_S  stFrame10_S;    // 单字节地址短帧
    VFrame68    stFrame68;       // 长帧
} VIec101Frame;

3. API 体系

3.1 生命周期 API必须调用

函数 说明
CS10x_101Init(pstSelf, cbSend, arg, CS101_TYPE_S/M) ★ 101 从站初始化
CS10x_104Init(pstSelf, cbSend, arg, CS104_TYPE_S/M) ★ 104 从站初始化
CS10x_DoRecv(pstSelf, pBuf, usLen) ★ 接收数据入口 (每收到一包调用一次)
CS10x_TimerHandle(pstSelf, usGap) ★ 定时器驱动入口 (每 usGap ms 调用一次)

cbSend 类型: int (*)(unsigned char *buf, unsigned short len, void *arg) 库通过此回调将编码好的报文交给应用层发送。

3.2 参数配置 API初始化后、运行前调用

// ★ 核心 ASDU 参数
void CS10x_SetAppParameters(CS10xHandle_t pstSelf, CS10x_AppLayerParameters *param);
// → 链路地址字节数(1-2)、传输原因字节数(1-2)、公共地址字节数(1-2)、
//   信息体地址字节数(2-3)、链路地址、公共地址

// ★ 104 APCI 参数
void CS10x_SetAPCIParameters(CS10xHandle_t pstSelf, CS104_APCIParameters *param);
// → K(0-600)、W(1-60)、T0/T1/T2/T3(2-120s)

// 数据类型
void CS10x_SetYcType(pstSelf, usType);  // 0=整形 1=标度化 2=浮点
void CS10x_SetYxType(pstSelf, usType);  // 0=单点 1=双点
void CS10x_SetDdType(pstSelf, usType);  // 0=不带时标 1=带时标

// 时间间隔 (ms)
void CS10x_SetSummonGap(pstSelf, uiGap);    // 总召间隔 (默认300s)
void CS10x_SetESummonGap(pstSelf, uiGap);   // 电度总召间隔 (默认60s)
void CS10x_SetHeartTimeGap(pstSelf, uiGap); // 心跳间隔 (默认90s)
void CS10x_FrameGap(pstSelf, uiGap);        // 发送帧间隔 (默认100ms)

// 101 特殊
void CS10x_ResendGap(pstSelf, uiGap);   // 重发超时 (默认5s)
void CS10x_ResendCnt(pstSelf, ucCnt);   // 重发次数 (默认5)
void CS10x_SetInitType(pstSelf, bType); // 简单初始化投退 (1=投入)
void CS10x_SetFileAckType(pstSelf, ucType); // 文件需确认帧 (0=需要, 1=不需要)

// 功能使能
void CS10x_SetMultFrameEn(pstSelf, ucEn);     // 104 多帧发送 (0=关闭 1=开启)
void CS10x_FaultEventEn(pstSelf, ucEn);        // 故障事件 (0=关, 1/2/3=开)
void CS10x_SetSendSoe(pstSelf, ucEn);          // SOE 发送 (0/1)
void CS10x_SetSendCos(pstSelf, ucEn);          // COS 发送 (0/1)
void CS10x_SetYKEendFrame(pstSelf, ucEn);      // 遥控结束帧 (0/1)
void CS10x_SetReadFileVSQ(pstSelf, ucEn);      // 文件传输VSQ状态值
void CS10x_SetPresetContType(pstSelf, ucEn);   // 参数预置忽略后续帧 (淮北主站=1)

3.3 回调注册 API按业务域分组

约定: 以 CS10x_S_ 为前缀的新接口是推荐使用的从站回调注册 API。旧的无前缀接口CS10x_GetYcValueByGroupHandler)已标记为"待删除"。

// ===== 遥测 (YC) =====
void CS10x_S_GetYcByGroupHandler(pstSelf,
    CS10x_GetYcCountByGroup    cbGetYcCount,   // → 返回该组遥测数量
    CS10x_GetYcValueByGroup    cbGetYcValue);  // → 填充特定遥测值 (Yc_Info*)

// ===== 遥信 (YX) =====
void CS10x_S_GetYxByGroupHandler(pstSelf,
    CS10x_GetYxCountByGroup    cbGetYxCount,   // → 返回该组遥信数量
    CS10x_GetYxStatusByGroup   cbGetYxStatus); // → 填充特定遥信状态 (Yx_Info*)

// ===== SOE (事件顺序记录) =====
void CS10x_S_SOEHandler(pstSelf,
    CS10x_GetSOE              cbGetSOE,         // → 获取SOE数据
    CS10x_GET_SOE_SendNum     cbSendNum,        // → 返回待发送SOE条数
    CS10x_Updata_SOE_Pout     cbUpdataSOEPout); // → 更新已发送指针

// ===== 遥控 (YK) =====
void CS10x_S_YkVerifyHandler(pstSelf,
    CS10x_YkVerify            cbYkVerify);      // → 校验遥控命令合法性

// ===== 电度 (DD) =====
void CS10x_S_GetDdByGroupHandler(pstSelf,
    CS10x_GetDdCountByGroup   cbGetDdCount,
    CS10x_GetDdValueByGroup   cbGetDdValue);

// ===== 扰动遥测 (Disturb YC) =====
void CS10x_S_DiturbYcHandler(pstSelf,
    CS10x_GetDiturbYc          cbGetDiturbYc,
    CS10x_GET_DiturbYc_SendNum cbSendNum,
    CS10x_Updata_DiturbYc_Pout cbUpdataPout);

// ===== 时标电度 =====
void CS10x_S_DiturbDduHandler(pstSelf,
    CS10x_GetTimeDdu           cbGetTimeDdu,
    CS10x_GetTimeDdu_SendNum   cbSendNum,
    CS10x_Updata_TimeDdu_Pout  cbUpdataPout);

// ===== 故障事件 =====
void CS10x_S_FaultEventHandler(pstSelf,
    CS10x_GET_Event_SendNum    cbSendNum,
    CS10x_GetFaultEvent        cbGetFaultEvent,
    CS10x_Updata_FaultEvent_Pout cbUpdataPout);

// ===== 参数/定值 =====
void CS10x_S_ParamAreaHandler(pstSelf,
    CS10x_GetParamArea         cbGetParamArea,   // 读取当前定值区号
    CS10x_SetParamArea         cbSetParamArea);  // 切换定值区

void CS10x_S_IECParamHandler(pstSelf,
    CS10x_AddIECParam          cbAddIECParam,    // 添加参数项
    CS10x_RunReadIECParam      cbReadIECParam,   // 读参数执行
    CS10x_RunWriteIECParam     cbWriteIECParam); // 写参数执行

void CS10x_S_GetParamInfoHandler(pstSelf,
    CS10x_GetParamCount        cbGetParamCount,    // 参数总数
    CS10x_GetParamInfoByIndx   cbGetParamInfo);    // 按索引获取参数信息

// ===== 时间 (对时) =====
void CS10x_TimeRWHandler(pstSelf,
    CS10x_GetTime              cbGetTime,       //  获取当前时间 (填充 __CP56Time2a)
    CS10x_SetTime              cbSetTime);      // → 设置时间 (解析 __CP56Time2a)

// ===== 文件服务 =====
void CS10x_S_FileReadOprtHandler(pstSelf, cbGetPro, cbGetNum, cbRead, pvParam);
void CS10x_S_FileWriteOprtHandler(pstSelf, cbWrite, cbCheck, cbFinish, pvParam);
void CS10x_S_UpdateProcHandler(pstSelf, cbUpdateProc);  // 软件升级

3.4 主动发送 API应用层调用库提供

// 任务类
unsigned char CS10x_SendTask(pstSelf);  // 调度所有待发送任务

// 遥控主动下发(主站模式使用)
void CS10x_SetYkTask(pstSelf, usInfoAddr, ucSE, ucCmd, ucDcs, ucQU, bEncrypt);

3.5 公共工具函数

// TaskFlag 操作
void SetTaskFlag(VFLAGS *flags, unsigned int flagNo);
unsigned int GetTaskFlag(VFLAGS *flags, unsigned int flagNo);
void ClearTaskFlag(VFLAGS *flags, unsigned int flagNo);

// 字节序编解码
unsigned char  IntBytes_Pack2Buf(unsigned char *out, unsigned int val, unsigned char size);
unsigned int   IntBytes_GetFromBuf(const unsigned char *in, unsigned char size);
unsigned char  Float_Pack2Buf(unsigned char *out, float val);
float          Float_GetFromBuf(const unsigned char *in);
unsigned char  U16_Pack2Buf(unsigned char *out, unsigned short val);
unsigned short U16_GetFromBuf(const unsigned char *in);

// 校验
unsigned char checksum_8(unsigned char *buf, unsigned char len);

4. 典型使用流程

4.1 IEC 104 从站完整流程

// ============ 步骤 1: 创建规约实例并初始化 ============
CS10x cs10x;
memset(&cs10x, 0, sizeof(CS10x));
CS10x_104Init(&cs10x, MySendCallback, myAppData, CS104_TYPE_S);

// ============ 步骤 2: 配置 ASDU 参数 ============
CS10x_AppLayerParameters appParam = {
    .iSzOfLinkAddr = 0,       // 104 无链路地址
    .iSzOfTypeId   = 1,
    .iSzOfVSQ      = 1,
    .iSzOfCOT      = 2,       // 传输原因 2 字节
    .iSzOfCA       = 2,       // 公共地址 2 字节
    .iSzOfIOA      = 3,       // 信息体地址 3 字节
    .iLinkAddr     = 0,
    .iPublicAddr   = 1,
    .iMaxSzOfAsduLen = 249
};
CS10x_SetAppParameters(&cs10x, &appParam);

// ============ 步骤 3: 配置 104 APCI 参数 ============
CS104_APCIParameters apciParam = {
    .iK  = 12,
    .iW  = 8,
    .iT0 = 10,   // 连接建立超时 10s
    .iT1 = 12,   // 发送超时 12s
    .iT2 = 8,    // 确认超时 8s
    .iT3 = 15    // 空闲测试超时 15s
};
CS10x_SetAPCIParameters(&cs10x, &apciParam);

// ============ 步骤 4: 配置数据类型 ============
CS10x_SetYcType(&cs10x, 2);    // 浮点遥测
CS10x_SetYxType(&cs10x, 0);    // 单点遥信
CS10x_SetDdType(&cs10x, 1);    // 带时标电度
CS10x_FrameGap(&cs10x, 10);    // 10ms 帧间隔
CS10x_SetSummonGap(&cs10x, 300000); // 300s 总召

// ============ 步骤 5: 注册回调 ============
CS10x_S_GetYcByGroupHandler(&cs10x, MyGetYcCount, MyGetYcValue);
CS10x_S_GetYxByGroupHandler(&cs10x, MyGetYxCount, MyGetYxStatus);
CS10x_S_SOEHandler(&cs10x, MyGetSOE, MySOESendNum, MyUpdateSOEPout);
CS10x_S_YkVerifyHandler(&cs10x, MyYkVerify);
CS10x_TimeRWHandler(&cs10x, MyGetTime, MySetTime);

// ============ 步骤 6: 主循环驱动 ============
while(running) {
    // 接收数据
    int len = recv(sock, buf, sizeof(buf), 0);
    if(len > 0) {
        CS10x_DoRecv(&cs10x, buf, len);  // ★ 喂给规约栈
    }

    // 定时器驱动 (每 10ms 调用一次)
    CS10x_TimerHandle(&cs10x, 10);       // ★ 驱动所有定时任务
}

4.2 回调函数签名参考

// 发送回调 → 库将编码好的帧传给此函数
int MySendCallback(unsigned char *buf, unsigned short len, void *arg) {
    return send(mySock, buf, len, 0);
}

// 获取遥测数量 (uiParam=组号)
int MyGetYcCount(void *param, unsigned int uiParam) {
    return (uiParam == 1) ? g_ycCount : 0;
}

// 获取特定遥测值 (usPos=组内偏移)
int MyGetYcValue(Yc_Info *info, void *param, unsigned int usPos) {
    info->uiInfoAddr = g_ycTable[usPos].addr;  // 信息体地址
    info->fVal       = g_ycTable[usPos].value; // 遥测值
    info->ucQds      = 0x00;                    // 品质: 有效
    return 0;
}

// 获取时间 (对时使用)
int MyGetTime(__CP56Time2a *pTime) {
    struct timespec ts;
    clock_gettime(CLOCK_REALTIME, &ts);
    struct tm *t = gmtime(&ts.tv_sec);
    pTime->ucYear  = t->tm_year - 100;
    pTime->ucMonth = t->tm_mon + 1;
    pTime->ucDay   = t->tm_mday;
    pTime->ucHour  = t->tm_hour;
    pTime->ucMin   = t->tm_min;
    int ms = ts.tv_nsec / 1000000 + t->tm_sec % 60 * 1000;
    pTime->ucLMs   = ms & 0xFF;
    pTime->ucHMs   = (ms >> 8) & 0xFF;
    return 0;
}

// 遥控校验
int MyYkVerify(Yk_Info *info, void *param) {
    // 校验成功后执行遥控,失败返回 -1
    return executeYk(info->uiInfoAddr, info->ucStatus, info->ucYkType) ? 0 : -1;
}

5. ASDU 类型标识码映射表

5.1 监视方向(终端 → 主站)

TypeID 说明 品质描述词
1 M_SP_NA 单点信息 SIQ
3 M_DP_NA 双点信息 DIQ
5 M_ST_NA 步位置信息 VTI
7 M_BO_NA 32位位串 QDS
9 M_ME_NA 测量值(归一化) QDS
11 M_ME_NB 测量值(标度化) QDS
13 M_ME_NC 测量值(短浮点) QDS
15 M_IT_NA 电能脉冲计数量 -
20 M_PS_NA 带状态变位检出的成组单点 SIQ
21 M_ME_ND 不带品质的测量值 -
30 M_SP_TB 带长时标单点 SIQ
31 M_DP_TB 带长时标双点 DIQ
34 M_ME_TD 带长时标测量值 QDS
42 M_FT_NA 故障事件 QDP
70 M_EI_NA 初始化结束 COI
206 M_IT_NB 不带时标累计量(浮点) -
207 M_IT_TC 带时标累计量(浮点) -

5.2 控制方向(主站 → 终端)

TypeID 说明
45 C_SC_NA 单点遥控命令
46 C_DC_NA 双点遥控命令
47 C_RC_NA 升降命令
48 C_SE_NA 设定命令
55 C_SP_NA 参数预置(南网)
100 C_IC_NA 总召唤命令
101 C_CI_NA 电度召唤命令
102 C_RD_NA 读数据命令
103 C_CS_NA 时钟同步命令
104 C_TS_NA 测试命令
105 C_RP_NA 复位进程命令
106 C_CD_NA 延时获得命令(南网)
107 C_TS_TA 带时标测试命令
108 C_RS_NA_NANWANG 读参数命令(南网)
112 P_ME_NC 参数预置
113 P_AC_NA 参数固化
200 C_SR_NA 切换定值区
201 C_RR_NA 读定值区号
202 C_RS_NA 读参数和定值
203 C_WS_NA 写参数和定值
210 F_FR_NA 文件升级
211 F_SR_NA 软件升级

6. 传送原因 (COT) 速查

COT 说明
1 COT_PERCYC 周期/循环
2 COT_BACK 背景扫描
3 COT_SPONT 突发(变位)
4 COT_INIT 初始化
5 COT_REQ 请求或被请求
6 COT_ACT 激活
7 COT_ACTCON 激活确认
8 COT_DEACT 停止激活
9 COT_DEACTCON 停止激活确认
10 COT_ACTTERM 激活结束
20 COT_INTROGEN 响应总召唤
37 COT_REQCOGCN 响应计数量总召唤
44 COT_E_TYPE 未知类型标识
45 COT_E_REASON 未知传送原因
46 COT_E_CADDR 未知公共地址
47 COT_E_IADDR 未知信息体地址

7. 定时器与任务调度

7.1 104 定时器

定时器 默认值 说明
T0 10s 连接建立超时—发送 STARTDT 后等待确认
T1 12s 发送 I 帧后等待确认超时
T2 8s 接收 I 帧后延迟确认 ACK
T3 15s 空闲测试超时—发送 TESTFR

定时器处理流程:

  1. CS10x_TimerHandle() 被调用 → 遍历 stM_vTimer[4]
  2. T0 超时 → 重试连接 / T1 超时 → 断开链路 / T3 超时 → 发送测试帧

7.2 任务标志系统

库内部使用 128 位位图 (VFLAGS) 管理所有待处理任务:

任务 ID 枚举值 说明
TSKID_SummonYx - 总招遥信响应
TSKID_SummonYc - 总招遥测响应
TSKID_SendCOS - 发送变位遥信
TSKID_SendSOE - 发送 SOE
TSKID_TimeSyn - 时钟同步
TSKID_HeartBeat - 心跳
TSKID_DdSummon - 总招电能量
TSKID_FaultSoe - 故障事件
TSKID_YcDisturb - 扰动数据
TSKID_ChgConst - 修改定值区
TSKID_ReadConst - 读取定值区

任务调度流程: CS10x_TimerHandle → 累计各定时计数 → 超时时 SetSendTask 置位 → CS10x_SendTask → 遍历任务标志 → 调用对应的 Do_* 函数。

8. 品质描述词 (Quality Descriptor)

库提供了 5 种品质描述词的位域定义,封装在 ASDU_CMD_T union 中:

类型 字段 说明
SIQ (单点) SPI 0 0=开, 1=合
BL 4 0=未锁定, 1=锁定
SB 5 0=未取代, 1=取代
NT 6 0=当前值, 1=非当前
IV 7 0=有效, 1=无效
DIQ (双点) DPI 0-1 0/3=不确定, 1=开, 2=合
QDS (测量值) OV 0 0=未溢出, 1=溢出
QDP (保护事件) EI 4 0=动作时间有效, 1=无效
SCO (单命令) SCS 0 0=开, 1=合
QU 1-5 0=无定义, 1=短脉冲, 2=长脉冲, 3=持续
SE 6 0=执行, 1=选择
DCO (双命令) DCS 0-1 1=开, 2=合
SE 6 0=执行, 1=选择
QOS (设定命令) QL 0-6 0=缺省
SE 6 0=执行, 1=选择
COI (初始化) UI7 0-6 0=电源合上, 1=手动复位, 2=远方复位

9. 101 与 104 的关键差异

特性 IEC 101 IEC 104
传输层 串口 (异步字节流) TCP/IP 网络
链路层帧 0x10 短帧 / 0x68 长帧 APCI 6字节头 (I/S/U帧)
地址 链路地址 (1-2 byte) 无链路地址
帧同步 起始+结束字符 (0x68/0x10+0x16) APDU 长度字段
重传机制 FCB/FCV + 超时重发 发送序号 + 接收序号 + T1 超时
链路管理 REQUEST_LINK / RESET_LINK 帧 STARTDT/STOPDT/TESTFR U帧
初始化 复位链路 → 简单/完整初始化 (可选) TCP 连接 → STARTDT 激活
初始化函数 CS10x_101Init(..., CS101_TYPE_S) CS10x_104Init(..., CS104_TYPE_S)
缓存 固定 255 字节帧 APCI 6 + ASDU max 249
多帧 101 连帧 (FCB 位机制) 104 I 帧序号连续发送

10. 文件服务与升级流程

库内建了基于 IEC 60870-5 文件传输服务的文件操作能力:

操作 TypeID / 说明
目录召唤 读目录 → 返回文件列表
读文件 激活 → 分段传输数据 → 传输确认
写文件 激活 → 分段写数据 → 写确认
软件升级 211 F_SR_NACS10x_S_UpdateProcHandler

注意: 旧文件服务接口 (CS10x_FileReadOprtHandler 不带 S_ 前缀) 在库中标记为"待删除",应使用 CS10x_S_FileReadOprtHandler / CS10x_S_FileWriteOprtHandler

11. 注意事项与踩坑指南

11.1 类型兼容

  • CBB 库使用 u8/u16/u32/s16/s32/f32/BOOL/TRUE/FALSE 自定义类型
  • 不能修改库文件 — 通过 release/inc/cbb_compat.h + gcc -include 注入解决
  • 本项目已在 makefile 中配置

11.2 回调约定

  • 所有回调返回 0 = 成功,非 0 = 失败
  • cbSend 回调中不要阻塞
  • 库内部是同步调用CS10x_DoRecv 内部会立即调用回调获取数据

11.3 线程安全

  • 库本身不是线程安全的,所有 API 调用建议在同一线程
  • 典型架构:通信线程收数据 → CS10x_DoRecv → 定时器线程驱动 CS10x_TimerHandle

11.4 多实例支持

  • 每个通信链路创建一个 CS10x 实例
  • 调用方通过 void *arg (初始化参数) 和 void *pParam (回调参数) 传递业务上下文

11.5 从站 vs 主站

  • 此项目 RTU 作为从站 (_S 类型) — 回调负责提供数据
  • 如果作为主站 (_M 类型) — 回调负责处理收到的数据

11.6 101 序列号与链路状态

  • FCB 位每发送一帧翻转
  • 重发帧 FCB 位不变
  • 链路重置时 FCB 复位

11.7 104 序号机制

  • 发送序号 usSendNum 与接收序号 usRecvNum 各自独立递增
  • usSendNum - usAckRecvNum >= K 时停止发送 (流量控制)
  • T1 超时断开链路,清初始化完成标识

12. 版本关键变更摘要

版本 日期 关键修改
V2.01.059 2026-02-02 增加 YC 上传品质描述词字段
V2.01.058 2026-01-31 增加确认帧通知回调接口(透传给下行设备)
V2.01.057 2025-12-25 T0-T3 最大范围 120→200
V2.01.056 2025-12-09 添加关闭链路接口
V2.01.055 2025-10-30 优化序号匹配,>=K 时继续闭锁
V2.01.054 2025-10-27 修复总召不上送、序号不匹配问题
V2.01.044 2025-09-03 参数预置忽略后续帧 + 修复 T1/T3 超时
V2.01.043 2025-08-11 添加普洱/贵州参数读写流程
V2.01.042 2025-07-17 南网规约参数读写和延时获得命令
V2.01.039 2025-04-21 101 错误帧继续解析后续报文
V2.01.038 2025-03-19 101 回复长帧 FCV 默认置 1