RTU/mimo/工程/DCU_HOST/01-总召与遥测遥信.md

8.2 KiB

01 - 总召与遥测遥信回调详解

源码: DCU_HOST/applications/data/iec_itfc/YcItfc.c DCU_HOST/applications/data/iec_itfc/YxItfc.c


1. 总召触发与延迟机制

DCU_HOST 有一个特殊设计:主站发起总召 → 终端需要先通过内部总线向采集板下发总召命令 → 等待采集板返回数据 → 再上报给主站

unsigned int GetSummonSlaveDelay(void *pParam) {
    const uint32_t uiDelayUpMs = 5000;  // 延迟 5 秒上传
    uint8_t cmd[2] = {1, 0};
    CPC_DataSend(NODE_BROADCAST, CPC_SUMMON_FRAME, cmd, 2); // 下发总招广播
    return uiDelayUpMs;
}

// 注册
CS10x_GetSummonSlaveDelayHandler(pstCs10x, GetSummonSlaveDelay);

关键理解: 此回调不是 CBB 库标准接口,是 DCU_HOST 扩展——主站召唤命令到达后,先广播给所有采集板,延迟 5s 后再开始组包上报。如果 RTU 的数据是直接可取的(如从 datacenter 读取),则不需要此延迟机制,直接返回 0 即可。


2. 遥测回调 CS10x_S_GetYcByGroupHandler

2.1 注册

CS10x_S_GetYcByGroupHandler(pstCs10x, GetYcCountByGroup, GetYcValueByGroup);

2.2 GetYcCountByGroup — 获取遥测数量

s32 GetYcCountByGroup(u16 usGroupID, void *pvParam, u32 *puiStartInf, u32 *puiEndInf) {
    stPOT_CONFIG_NUM stPotConfigNum;
    GetPotTableConfig(&stPotConfigNum);  // 从配置表获取遥测配置数量

    *puiStartInf = YC_START_PORT;              // 起始信息体地址 (如 0x4001)
    *puiEndInf = YC_START_PORT + stPotConfigNum.usYcConfigNum;  // 结束信息体地址
    return stPotConfigNum.usYcConfigNum;       // 返回配置的遥测总数
}

关键理解:

  • usGroupID 参数在此实现中未使用,所有遥测数据视为同一组返回
  • puiStartInf/puiEndInf 必须设置,规约库用它们来确定信息体地址范围
  • 返回 0 表示该组无数据

2.3 GetYcValueByGroup — 填充单条遥测值

s32 GetYcValueByGroup(u16 usGroupID, u16 usIdx, Yc_Info *pstInfo, void *pvParam) {
    u16 usInfoAddr = usIdx + YC_START_PORT;          // 信息体地址 = 偏移 + 起始地址

    u16 usTabIdx;
    GetPosYcTable(&usTabIdx, usInfoAddr);             // 通过信息体地址查找点表索引

    if(usTabIdx >= g_stYcMaxNum.usYcTotal) {
        pstInfo->fVal = 0;                            // 未配置 → 填0
    } else {
        UserGetYcValue(&pstInfo->fVal, usTabIdx, 1);  // 从数据池获取遥测原始值
        GetYcTableInform(&stYcTable, usTabIdx);       // 获取变比
        pstInfo->fVal = pstInfo->fVal * stYcTable.fScale; // ★ 乘以变比
    }

    pstInfo->uiInfoAddr = usInfoAddr;  // ★ 必须填信息体地址
    return 1;  // 成功
}

关键理解:

  • usIdx 从 0 开始递增,规约库会循环调用直到填满一帧 (48 个浮点遥测/帧)
  • uiInfoAddr 必须正确填写,与配置表中的点号对应
  • 品质描述词 ucQds 在此未显式设置(默认 0 = 有效),如需标记无效数据应设 IV
  • 变比乘法 fVal * fScale 是电力行业常见处理

2.4 RTU 适配要点

RTU 项目中,遥测数据应从 libdatacenter 获取:

// RTU 版 GetYcValueByGroup 参考实现
s32 GetYcValueByGroup(u16 usGroupID, u16 usIdx, Yc_Info *pstInfo, void *pvParam) {
    stru_iec_60870 *p_iec = iec60870_get_by_interface(*(uint32_t*)pvParam);
    if(!p_iec) return 0;

    // 从 datacenter 的 signal_out 表按索引获取信号
    dc_signal *sig = dc_get_signal_by_index(SIGNAL_OUT, usIdx);
    if(!sig) { pstInfo->fVal = 0; pstInfo->uiInfoAddr = usIdx + 0x4001; return 1; }

    pstInfo->fVal = dc_get_signal_float(sig);
    pstInfo->uiInfoAddr = sig->info_addr;
    pstInfo->ucQds = 0x00; // 有效
    return 1;
}

3. 遥信回调 CS10x_S_GetYxByGroupHandler

3.1 注册

CS10x_S_GetYxByGroupHandler(pstCs10x, GetYxCountByGroup, GetYxStatusByGroup);

3.2 GetYxCountByGroup — 获取遥信数量

s32 GetYxCountByGroup(u16 usGroupID, void *pvParam, u32 *puiStartInf, u32 *puiEndInf) {
    stPOT_CONFIG_NUM stPotConfigNum;
    GetPotTableConfig(&stPotConfigNum);
    *puiStartInf = YX_START_PORT;
    *puiEndInf = *puiStartInf + stPotConfigNum.usYxConfigNum;
    return stPotConfigNum.usYxConfigNum;  // 最多 127 个单点遥信/帧
}

3.3 GetYxStatusByGroup — 填充单条遥信状态

s32 GetYxStatusByGroup(u16 usGroupID, u16 usIdx, Yx_Info *pstInfo, void *pvParam) {
    u16 usInfoAddr = usIdx + YX_START_PORT;
    u16 usTabIdx;
    GetPosYxTable(&usTabIdx, usInfoAddr);

    if(UserGetYxState(&pstInfo->ucStatus, usTabIdx, 1)) {
        pstInfo->uiInfoAddr = usInfoAddr;
        pstInfo->ucStateType = 0;  // 默认单点
    }

    stLIB60870ENTITY *pstEntity = GetEntityNum(*(u32*)pvParam);

    // ★ 关键:根据 CS10x.usYxType 决定单点/双点处理
    if(pstEntity->stCs10x.usYxType) {  // 双点遥信
        pstInfo->ucStateType = 1;       // 双点标记
        if(stYxTable.ucAttr) {          // 取反属性
            if(pstInfo->ucStatus == 2) pstInfo->ucStatus = 1;
            else if(pstInfo->ucStatus == 1) pstInfo->ucStatus = 2;
        }
    } else {  // 单点遥信
        pstInfo->ucStateType = 0;
        if(stYxTable.ucAttr) {          // 取反属性
            pstInfo->ucStatus = pstInfo->ucStatus ? 0 : 1;
        }
    }
    return 1;
}

双点遥信值含义:

ucStatus 含义
0 不确定/中间状态
1 确定状态:开 (OFF)
2 确定状态:合 (ON)
3 不确定

双点遥信时,单点状态需要 +1 转换 (0→1=开, 1→2=合)。

3.4 COS (变化遥信) 处理

COS 由库内部自动管理。当应用层通过 CS10x_AddCOS 或 SOE 队列产生变位后,库自动在定时调度中加上 TSKID_SendCOS 任务。


4. 扰动遥测回调

CS10x_S_DiturbYcHandler(pstCs10x, GetDiturbYc, GetDiturbYcSendNum, UpdateDiturbYcPtrOut);

扰动遥测用于故障录波期间上送连续遥测数据,与 SOE 类似使用队列 + 指针模式:

s32 GetDiturbYcSendNum(void *pvArg)    返回待发送扰动遥测条数
s32 GetDiturbYc(Yc_Info *pstInfo, void *pvParam, u32 uiPos)  填充单条扰动遥测
s32 UpdateDiturbYcPtrOut(void *pvParam, u32 uiPos)  主站确认后更新已发送指针

5. 数据类型配置速查

CS10x_SetYcType TypeID 帧内格式 说明
0 M_ME_NA (9) 归一化值 (int16) 整形遥测
1 M_ME_NB (11) 标度化值 (int16 + 标度) 标度化
2 M_ME_NC (13) 短浮点 (float32) 浮点遥测 — 99% 场合使用
CS10x_SetYxType TypeID 帧内格式 说明
0 M_SP_NA (1) 1 bit (SIQ) 单点遥信
1 M_DP_NA (3) 2 bit (DIQ) 双点遥信

6. 数据源适配对比

项目 数据获取方式 变比处理
DCU_HOST UserGetYcValue() → 内部数据池 回调中 fVal * fScale
RTU (建议) dc_get_signal_float() → datacenter 存信号时已乘好 / 或此处乘

7. 总召完整时序

sequenceDiagram
    participant Master as 主站
    participant CBB as lib60870 CBB库
    participant App as 应用层(iec_prtcl)
    participant Data as 数据层(YcItfc/YxItfc)

    Master->>CBB: C_IC_NA (总召激活, COT=6)
    CBB->>App: GetSummonSlaveDelay() → 5000ms
    Note over App: 向采集板下发总召广播 CPC_SUMMON_FRAME
    Note over App,Data: 等待 5s...

    loop 每帧最多48个遥测
        CBB->>App: GetYcCountByGroup() → 遥测总数
        CBB->>Data: GetYcValueByGroup(usIdx=0...N)
        Data-->>CBB: 返回 Yc_Info (fVal + uiInfoAddr)
        CBB->>Master: M_ME_NC 帧 (COT=20 响应总召)
    end

    loop 每帧最多127个遥信
        CBB->>App: GetYxCountByGroup() → 遥信总数
        CBB->>Data: GetYxStatusByGroup(usIdx=0...N)
        Data-->>CBB: 返回 Yx_Info (ucStatus + ucStateType)
        CBB->>Master: M_SP_NA 帧 (COT=20 响应总召)
    end

    CBB->>Master: C_IC_NA (总召结束, COT=10)