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

253 lines
7.3 KiB
Markdown

# 04 - 参数定值与文件服务回调详解
> 源码: [DCU_HOST/applications/data/iec_itfc/GbParamItfs.c](../../../../../../DCU_HOST/applications/data/iec_itfc/GbParamItfs.c) (882行)
---
## 1. 回调注册
```c
// 定值区管理
CS10x_S_ParamAreaHandler(pstCs10x, GbParamGetParamArea, GbParamSetParamArea);
// 参数读写
CS10x_S_IECParamHandler(pstCs10x, GbParamAddElement, GbParamRunRding, GbParamRunWting);
// 参数信息查询
CS10x_S_GetParamInfoHandler(pstCs10x, GbParamGetTotalNum, GbParamGetIecParam);
```
---
## 2. 定值区管理
### 2.1 GbParamGetParamArea — 获取当前定值区号
```c
u16 GbParamGetParamArea(void *pParam) {
return g_stParamMappingTable.stComCommunitParam.pucCurRunParamArea;
// 返回当前运行区号 (0-255)
}
```
### 2.2 GbParamSetParamArea — 切换定值区
```c
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 — 添加参数项到规约参数表
```c
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 结构体**:
```c
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 — 执行参数读取
```c
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 — 执行参数写入
参数写入有**预置 → 固化**两步流程 (南网规约) 或**直接写入** (标准规约):
```c
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 — 参数信息查询
```c
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. 参数读写时序 (南网规约)
```mermaid
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. 文件服务回调
```c
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`:
```c
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. 加密参数配置
```c
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 即可。