RTU/mimo/工程/DCU_HOST/04-参数定值与文件服务.md

7.3 KiB

04 - 参数定值与文件服务回调详解

源码: DCU_HOST/applications/data/iec_itfc/GbParamItfs.c (882行)


1. 回调注册

// 定值区管理
CS10x_S_ParamAreaHandler(pstCs10x, GbParamGetParamArea, GbParamSetParamArea);
// 参数读写
CS10x_S_IECParamHandler(pstCs10x, GbParamAddElement, GbParamRunRding, GbParamRunWting);
// 参数信息查询
CS10x_S_GetParamInfoHandler(pstCs10x, GbParamGetTotalNum, GbParamGetIecParam);

2. 定值区管理

2.1 GbParamGetParamArea — 获取当前定值区号

u16 GbParamGetParamArea(void *pParam) {
    return g_stParamMappingTable.stComCommunitParam.pucCurRunParamArea;
    // 返回当前运行区号 (0-255)
}

2.2 GbParamSetParamArea — 切换定值区

s32 GbParamSetParamArea(u16 usAreaNum, void *pParam) {
    g_stParamMappingTable.stComCommunitParam.pucCurRunParamArea = (u8)usAreaNum;
    // 执行定值区切换逻辑...
    return 1;  // 成功
}

定值区概念:

  • 电力装置通常有多个定值区 (0-3 或更多)
  • 0 区通常是当前运行区
  • 主站通过 C_SR_NA (TypeID=200) 切换定值区
  • 通过 C_RR_NA (TypeID=201) 读取当前区号

3. 参数读写 (核心)

3.1 GbParamAddElement — 添加参数项到规约参数表

s32 GbParamAddElement(IECPARAM_T *pstIecParam, void *pParam) {
    // 1. 从参数映射表中查找对应参数
    u16 usIdx = GbParamSearchIndex(pstIecParam->uiInfoAddr);

    // 2. 填充 IECPARAM_T 的类型和长度
    pstIecParam->ucType = g_stParamMap[usIdx].ucTagType;   // TAG_TPYE_FLOAT 等
    pstIecParam->ucLen  = g_stParamMap[usIdx].ucDataLen;   // 数据长度

    // 3. 根据类型填充值
    switch(pstIecParam->ucType) {
        case TAG_TPYE_FLOAT:
            pstIecParam->unVal.fVal = GetParamFloatValue(usIdx);
            break;
        case TAG_TPYE_INT:
            pstIecParam->unVal.lVal = GetParamIntValue(usIdx);
            break;
        // ...
    }
    return 1;
}

IECPARAM_T 结构体:

typedef struct {
    unsigned char  ucType;       // 类型 (TAG_TPYE_FLOAT/INT/STR...)
    unsigned char  ucLen;        // 数据长度
    union {
        unsigned char  ucVal;
        char           cVal;
        unsigned short usVal;
        short          sVal;
        unsigned int   ulVal;
        int            lVal;
        float          fVal;
        unsigned long long ullVal;
        long long      llVal;
        double         dVal;
        char           caBuf[64];  // 字符串
    } unVal;
    unsigned int   uiInfoAddr;   // 信息体地址
} IECPARAM_T;

3.2 GbParamRunRding — 执行参数读取

s32 GbParamRunRding(u16 usReqAddr, u16 usNum, void *pParam, u8 ucArea) {
    // 主站请求读取 usReqAddr 开始的 usNum 个参数

    for(u16 i = 0; i < usNum; i++) {
        u16 usIdx = GbParamSearchIndex(usReqAddr + i);
        if(usIdx == 0xFFFF) continue;  // 未找到

        IECPARAM_T stParam;
        stParam.uiInfoAddr = usReqAddr + i;
        GbParamFillValue(&stParam, usIdx, ucArea);  // 从指定定值区填充值
        GbParamAddToResponse(&stParam);             // 加入响应缓存
    }
    return usNum;
}

3.3 GbParamRunWting — 执行参数写入

参数写入有预置 → 固化两步流程 (南网规约) 或直接写入 (标准规约):

s32 GbParamRunWting(IECPARAM_T *pstParam, u8 ucType, void *pParam) {
    // ucType: WRITE_PARAM_YZ (预置) / WRITE_PARAM_GH (固化)

    u16 usIdx = GbParamSearchIndex(pstParam->uiInfoAddr);

    if(ucType == WRITE_PARAM_YZ) {
        // 预置: 暂存到编辑区,不立即生效
        GbParamPresetValue(usIdx, &pstParam->unVal);
        return 1;
    } else if(ucType == WRITE_PARAM_GH) {
        // 固化: 将编辑区值写入运行区
        GbParamSolidifyValue(usIdx);
        // ★ 触发参数生效逻辑 (如重启保护等)
        return 1;
    }
    return -1;
}

3.4 GbParamGetTotalNum / GbParamGetIecParam — 参数信息查询

s32 GbParamGetTotalNum(void *pParam) {
    return g_stParamMapCount;  // 返回参数表总数
}

s32 GbParamGetIecParam(IECPARAM_T *pstParam, u16 usIdx, void *pParam) {
    pstParam->uiInfoAddr = g_stParamMap[usIdx].uiAddr;
    pstParam->ucType     = g_stParamMap[usIdx].ucTagType;
    pstParam->ucLen      = g_stParamMap[usIdx].ucDataLen;
    return 1;
}

4. 参数读写时序 (南网规约)

sequenceDiagram
    participant Master as 主站
    participant CBB as lib60870
    participant App as 应用层(GbParamItfs)

    Note over Master,CBB: === 读参数 ===
    Master->>CBB: C_RS_NA_NANWANG (TypeID=108, COT=5)
    CBB->>App: GbParamRunRding(起始地址, 数量)
    App-->>CBB: 返回参数值列表
    CBB->>Master: 参数数据帧

    Note over Master,CBB: === 写参数 (预置) ===
    Master->>CBB: C_SP_NA (TypeID=55, 预置, COT=6)
    CBB->>App: GbParamRunWting(param, WRITE_PARAM_YZ)
    App-->>CBB: 预置成功
    CBB->>Master: 预置确认 (COT=7)

    Note over Master,CBB: === 写参数 (固化) ===
    Master->>CBB: C_SP_NA (TypeID=55, 固化, COT=6)
    CBB->>App: GbParamRunWting(param, WRITE_PARAM_GH)
    App-->>CBB: 固化成功
    CBB->>Master: 固化确认 (COT=7)

标准规约 (TypeID=202/203) 流程类似,但无需预置/固化两步,直接读/写即可。


5. 文件服务回调

CS10x_S_FileReadOprtHandler(pstCs10x, Fm_GetDirFile, Fm_SearchDirFileNum, Fm_ReadFile, &pstEntity->stReadParam);
CS10x_S_FileWriteOprtHandler(pstCs10x, Cs10xWriteItfs, Cs10xWriteFileCheckItfs, Cs10xWriteFinishItfs, &pstEntity->stWriteParam);
CS10x_S_UpdateProcHandler(pstCs10x, NULL);  // 升级 (当前未实现)

文件服务使用 TypeID=210 (F_FR_NA),支持:

  • 目录召唤: 返回文件列表
  • 读文件: 分段传输
  • 写文件: 用于参数配置下发
  • 软件升级: TypeID=211 (F_SR_NA)

RTU 适配建议

文件服务在 RTU 场景中可能不需要 (通过 Web/WebSocket 管理配置更常见),可以暂时注册 NULL:

CS10x_S_FileReadOprtHandler(pstCs10x, NULL, NULL, NULL, NULL);
CS10x_S_FileWriteOprtHandler(pstCs10x, NULL, NULL, NULL, NULL);
CS10x_S_UpdateProcHandler(pstCs10x, NULL);

6. 参数类型映射表 (TAG_TYPE)

CBB 库内部使用的参数类型编码:

C 类型
TAG_TPYE_BOOL 1 bool
TAG_TPYE_INT 2 int
TAG_TPYE_STR 4 char[]
TAG_TPYE_UTINY 32 uint8_t
TAG_TPYE_SHORT 33 int16_t
TAG_TPYE_UINT 35 uint32_t
TAG_TPYE_LONG 36 int32_t
TAG_TPYE_ULONG 37 uint32_t
TAG_TPYE_FLOAT 38 float
TAG_TPYE_DOUBLE 39 double
TAG_TPYE_TINY 43 int8_t
TAG_TPYE_USHORT 45 uint16_t

7. 加密参数配置

void SetProtocolEncryParam(CS10x *pstCs10x, void *pvArg) {
    // 加密使能检查 (仅 4G 串口和维护口)
    if((isSlave) && (isEncryptInterface)) {
        CS10x_EncryptHandler(pstCs10x, Encryp_Encode);     // 加密回调
        CS10x_Md5ResultHandler(pstCs10x, Saft_Update_Md5); // MD5 校验
        Saft_Config_Param(1, ...);                          // 加密参数配置
    } else {
        CS10x_EncryptHandler(pstCs10x, NULL);
        CS10x_Md5ResultHandler(pstCs10x, NULL);
    }
}

RTU 注意: 如果不需要加密,注册 NULL 即可。