RTU/libiec61850/libiec61850手册/libiec61850_服务端开发手册.md

1497 lines
48 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# libiec61850 服务端开发手册
> 基于 libiec61850 v1.5.3 完整 API 参考。本文档旨在做到脱离代码即可完成服务端开发。
---
## 目录
1. [架构概述](#1-架构概述)
2. [数据模型](#2-数据模型)
3. [服务器生命周期](#3-服务器生命周期)
4. [IedServerConfig 配置详解](#4-iedserverconfig-配置详解)
5. [服务器创建与销毁](#5-服务器创建与销毁)
6. [数据模型锁定与更新](#6-数据模型锁定与更新)
7. [数据读取函数](#7-数据读取函数)
8. [连接管理与认证](#8-连接管理与认证)
9. [控制模型 (Control)](#9-控制模型-control)
10. [报告控制块 (RCB)](#10-报告控制块-rcb)
11. [GOOSE 发布](#11-goose-发布)
12. [GOOSE 控制块 (GoCB)](#12-goose-控制块-gocb)
13. [Sampled Values 控制块 (SVCB)](#13-sampled-values-控制块-svcb)
14. [数据访问控制 (Access Control)](#14-数据访问控制-access-control)
15. [设置组 (Setting Groups)](#15-设置组-setting-groups)
16. [文件服务](#16-文件服务)
17. [日志服务 (Log Service)](#17-日志服务-log-service)
18. [TLS 安全通信](#18-tls-安全通信)
19. [单线程模式 (Threadless)](#19-单线程模式-threadless)
20. [MmsServer 底层接口](#20-mmsserver-底层接口)
21. [完整示例](#21-完整示例)
---
## 1. 架构概述
服务端核心职责:
```
应用程序数据 --> [MmsValue] --> IedServer --> TCP/MMS --> 客户端
|
+--> GOOSE 发布 (L2 以太网)
+--> SV 发布 (L2 以太网)
```
**关键类型**:
- `IedServer` — 服务器实例句柄(不透明指针)
- `IedServerConfig` — 服务器配置对象
- `IedModel` — 数据模型根节点
- `LogicalDevice``LogicalNode``DataObject``DataAttribute` — 数据模型层级
---
## 2. 数据模型
### 2.1 模型节点类型枚举
```c
typedef enum {
LogicalDeviceModelType, // 逻辑设备
LogicalNodeModelType, // 逻辑节点
DataObjectModelType, // 数据对象
DataAttributeModelType // 数据属性
} ModelNodeType;
```
### 2.2 创建数据模型的三种方式
#### 方式一: 静态模型生成器(推荐)
使用 Java 工具 `genmodel.jar` 从 SCL/ICD 文件自动生成:
- 生成 `static_model.c``static_model.h`
- 所有节点作为全局变量,编译时确定,效率最高
- 生成宏定义方便访问,如 `IEDMODEL_Device1_LLN0_Mod_stVal`
```c
#include "static_model.h"
// 直接使用生成的全局模型
IedServer iedServer = IedServer_create(&iedModel);
```
#### 方式二: API 动态创建
通过 `iec61850_dynamic_model.h` API 在运行时构建模型:
```c
#include "iec61850_dynamic_model.h"
// 1. 创建根模型
IedModel* model = IedModel_create("myIED");
// 2. 创建逻辑设备
LogicalDevice* ld = LogicalDevice_create("SENSORS", model);
// 3. 创建逻辑节点
LogicalNode* lln0 = LogicalNode_create("LLN0", ld);
LogicalNode* ttmp1 = LogicalNode_create("TTMP1", ld);
// 4. 使用 CDC 快捷函数创建数据对象
DataObject* mod = CDC_ENS_create("Mod", (ModelNode*)lln0, 0);
DataObject* health = CDC_ENS_create("Health", (ModelNode*)lln0, 0);
DataObject* tmpSv = CDC_SAV_create("TmpSv", (ModelNode*)ttmp1, 0, false);
// 5. 手动创建数据属性
DataAttribute* da = DataAttribute_create("stVal", parent,
IEC61850_INT32, IEC61850_FC_ST,
TRG_OPT_DATA_CHANGED, 0, 0);
// 6. 创建数据集
DataSet* ds = DataSet_create("events", lln0);
DataSetEntry_create(ds, "TTMP1$MX$TmpSv$instMag$f", -1, NULL);
// 7. 创建报告控制块
ReportControlBlock_create("events01", lln0, "events01", false, NULL, 1,
TRG_OPT_DATA_CHANGED, RPT_OPT_SEQ_NUM | RPT_OPT_TIME_STAMP, 50, 0);
// 8. 创建 GOOSE 控制块
GSEControlBlock_create("gse01", lln0, "events01", "events", 1, false, 200, 3000);
// 9. 创建设置组控制块
SettingGroupControlBlock_create(lln0, 1, 1);
// --- 使用完毕后 ---
IedServer_destroy(iedServer);
IedModel_destroy(model); // 仅动态模型需要
```
#### 方式三: 配置文件解析
使用 `genconfig.jar` 工具从 SCL 生成 `model.cfg` 配置文件,然后运行时加载:
```c
#include "iec61850_config_file_parser.h"
IedModel* model = ConfigFileParser_createModelFromConfigFileEx("model.cfg");
// 通过对象引用路径查找
DataAttribute* attr = (DataAttribute*)
IedModel_getModelNodeByObjectReference(model, "simpleIOGenericIO/GGIO1.AnIn1.mag.f");
// 通过短地址查找
DataAttribute* attr2 = (DataAttribute*)
IedModel_getModelNodeByShortAddress(model, 101);
```
### 2.3 数据属性类型枚举 (DataAttributeType)
| 枚举值 | 含义 | 枚举值 | 含义 |
|--------|------|--------|------|
| `IEC61850_BOOLEAN` | 布尔 | `IEC61850_INT8` | 8位有符号整数 |
| `IEC61850_INT16` | 16位有符号 | `IEC61850_INT32` | 32位有符号 |
| `IEC61850_INT64` | 64位有符号 | `IEC61850_INT8U` | 8位无符号 |
| `IEC61850_INT16U` | 16位无符号 | `IEC61850_INT32U` | 32位无符号 |
| `IEC61850_FLOAT32` | 32位浮点 | `IEC61850_FLOAT64` | 64位浮点 |
| `IEC61850_ENUMERATED` | 枚举 | `IEC61850_TIMESTAMP` | 时间戳 |
| `IEC61850_QUALITY` | 品质 | `IEC61850_CONSTRUCTED` | 构造类型(子属性) |
| `IEC61850_VISIBLE_STRING_32` | 可见字符串(32) | `IEC61850_VISIBLE_STRING_64` | 可见字符串(64) |
| `IEC61850_VISIBLE_STRING_255` | 可见字符串(255) | `IEC61850_UNICODE_STRING_255` | Unicode字符串 |
| `IEC61850_CHECK` | 检查位 | `IEC61850_CODEDENUM` | 编码枚举 |
| `IEC61850_OCTET_STRING_64` | 字节串(64) | `IEC61850_GENERIC_BITSTRING` | 位串 |
### 2.4 功能约束枚举 (FunctionalConstraint)
```c
typedef enum eFunctionalConstraint {
IEC61850_FC_ST = 0, // 状态信息(Status)
IEC61850_FC_MX = 1, // 测量值(Measurands)
IEC61850_FC_SP = 2, // 设定值(Setpoint)
IEC61850_FC_SV = 3, // 替代(Substitution)
IEC61850_FC_CF = 4, // 配置(Configuration)
IEC61850_FC_DC = 5, // 描述(Description)
IEC61850_FC_SG = 6, // 设置组(Setting Group) - 活动值
IEC61850_FC_SE = 7, // 设置组可编辑(Setting Group Editable) - 编辑值
IEC61850_FC_SR = 8, // 服务追踪(Service Response)
IEC61850_FC_OR = 9, // 操作接收(Operate Received)
IEC61850_FC_BL = 10, // 闭锁(Blocking)
IEC61850_FC_EX = 11, // 扩展定义(Extended)
IEC61850_FC_CO = 12, // 控制(Control)
IEC61850_FC_US = 13, // 单播SV
IEC61850_FC_MS = 14, // 组播SV
IEC61850_FC_RP = 15, // 非缓冲报告
IEC61850_FC_BR = 16, // 缓冲报告
IEC61850_FC_LG = 17, // 日志控制块
IEC61850_FC_GO = 18, // GOOSE控制块
IEC61850_FC_ALL = 99, // 所有FC(通配符)
IEC61850_FC_NONE = -1 // 无FC
} FunctionalConstraint;
```
### 2.5 品质位定义 (Quality)
```c
typedef uint16_t Quality;
// 有效性
#define QUALITY_VALIDITY_GOOD 0 // 好
#define QUALITY_VALIDITY_INVALID 2 // 无效
#define QUALITY_VALIDITY_RESERVED 1 // 保留
#define QUALITY_VALIDITY_QUESTIONABLE 3 // 可疑
// 详细品质
#define QUALITY_DETAIL_OVERFLOW 4
#define QUALITY_DETAIL_OUT_OF_RANGE 8
#define QUALITY_DETAIL_BAD_REFERENCE 16
#define QUALITY_DETAIL_OSCILLATORY 32
#define QUALITY_DETAIL_FAILURE 64
#define QUALITY_DETAIL_OLD_DATA 128
#define QUALITY_DETAIL_INCONSISTENT 256
#define QUALITY_DETAIL_INACCURATE 512
// 来源
#define QUALITY_SOURCE_SUBSTITUTED 1024
```
### 2.6 触发器选项 (Trigger Options)
```c
#define TRG_OPT_DATA_CHANGED 1 // 数据变化(dchg)
#define TRG_OPT_QUALITY_CHANGED 2 // 品质变化(qchg)
#define TRG_OPT_DATA_UPDATE 4 // 数据更新(dupd)
#define TRG_OPT_INTEGRITY 8 // 完整性周期
#define TRG_OPT_GI 16 // 总召唤(General Interrogation)
#define TRG_OPT_TRANSIENT 128 // 瞬变
```
### 2.7 报告选项 (Report Options)
```c
#define RPT_OPT_SEQ_NUM 1 // 序列号
#define RPT_OPT_TIME_STAMP 2 // 报告时间戳
#define RPT_OPT_REASON_FOR_INCLUSION 4 // 包含原因
#define RPT_OPT_DATA_SET 8 // 数据集引用
#define RPT_OPT_DATA_REFERENCE 16 // 数据引用
#define RPT_OPT_BUFFER_OVERFLOW 32 // 缓冲区溢出
#define RPT_OPT_ENTRY_ID 64 // 条目ID
#define RPT_OPT_CONF_REV 128 // 配置版本
```
---
## 3. 服务器生命周期
```c
// 1. 创建配置
IedServerConfig config = IedServerConfig_create();
// ... 配置 config ...
// 2. 创建服务器
IedServer iedServer = IedServer_createWithConfig(&iedModel, tlsConfig, config);
IedServerConfig_destroy(config); // 配置对象不再需要
// 3. 设置各种处理器
IedServer_setControlHandler(...);
IedServer_setConnectionIndicationHandler(...);
// ...
// 4. 启动服务器
IedServer_start(iedServer, 102); // TCP端口102
// 5. 主循环 - 更新数据
while (running) {
IedServer_lockDataModel(iedServer);
IedServer_updateFloatAttributeValue(iedServer, attr, value);
IedServer_unlockDataModel(iedServer);
Thread_sleep(100);
}
// 6. 停止
IedServer_stop(iedServer);
// 7. 销毁
IedServer_destroy(iedServer);
// IedModel_destroy(model); // 仅动态模型
```
---
## 4. IedServerConfig 配置详解
```c
typedef struct sIedServerConfig {
int reportBufferSize; // 缓冲报告缓冲区大小(字节)
int reportBufferSizeURCBs; // 非缓冲报告缓冲区大小
char* fileServiceBasepath; // 文件服务根路径
bool enableFileService; // 启用文件服务(默认true)
bool enableDynamicDataSetService; // 启 用动态数据集服务(默认true)
int maxAssociationSpecificDataSets; // 每连接最多关联数据集
int maxDomainSpecificDataSets; // 最多域数据集
int maxDataSetEntries; // 动态数据集最大条目数
bool enableLogService; // 启用日志服务(默认true)
bool useIntegratedGoosePublisher; // 使用集成GOOSE发布者(默认true)
uint8_t edition; // IEC 61850版本(0=Ed1,1=Ed2,2=Ed2.1)
int maxMmsConnections; // 最大MMS连接数
bool enableEditSG; // 启用EditSG服务(默认true)
bool enableResvTmsForSGCB; // SGCB.ResvTms可见
bool enableResvTmsForBRCB; // BRCB.ResvTms可见
bool enableOwnerForRCB; // RCB.Owner可见
bool syncIntegrityReportTimes; // 同步完整性报告时间
uint8_t reportSettingsWritable; // 报告设置可写标志
} IedServerConfig;
```
### 4.1 配置函数清单
```c
// 创建与销毁
IedServerConfig IedServerConfig_create(void);
void IedServerConfig_destroy(IedServerConfig self);
// 版本设置
void IedServerConfig_setEdition(IedServerConfig self, uint8_t edition);
uint8_t IedServerConfig_getEdition(IedServerConfig self);
// edition 可选值: IEC_61850_EDITION_1 (0), IEC_61850_EDITION_2 (1), IEC_61850_EDITION_2_1 (2)
// 报告缓冲区
void IedServerConfig_setReportBufferSize(IedServerConfig self, int reportBufferSize);
int IedServerConfig_getReportBufferSize(IedServerConfig self);
void IedServerConfig_setReportBufferSizeForURCBs(IedServerConfig self, int reportBufferSize);
int IedServerConfig_getReportBufferSizeForURCBs(IedServerConfig self);
// 默认值: 65536 字节 (由 CONFIG_REPORTING_DEFAULT_REPORT_BUFFER_SIZE 控制)
// MMS连接数
void IedServerConfig_setMaxMmsConnections(IedServerConfig self, int maxConnections);
int IedServerConfig_getMaxMmsConnections(IedServerConfig self);
// 此值必须小于 CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS (若 != -1)
// 同步完整性报告时间
void IedServerConfig_setSyncIntegrityReportTimes(IedServerConfig self, bool enable);
bool IedServerConfig_getSyncIntegrityReportTimes(IedServerConfig self);
// 启用后完整性报告时间对齐UTC纪元
// 文件服务
void IedServerConfig_setFileServiceBasePath(IedServerConfig self, const char* basepath);
const char* IedServerConfig_getFileServiceBasePath(IedServerConfig self);
void IedServerConfig_enableFileService(IedServerConfig self, bool enable);
bool IedServerConfig_isFileServiceEnabled(IedServerConfig self);
// 动态数据集服务
void IedServerConfig_enableDynamicDataSetService(IedServerConfig self, bool enable);
bool IedServerConfig_isDynamicDataSetServiceEnabled(IedServerConfig self);
// 动态数据集限制
void IedServerConfig_setMaxAssociationSpecificDataSets(IedServerConfig self, int maxDataSets);
int IedServerConfig_getMaxAssociationSpecificDataSets(IedServerConfig self);
void IedServerConfig_setMaxDomainSpecificDataSets(IedServerConfig self, int maxDataSets);
int IedServerConfig_getMaxDomainSpecificDataSets(IedServerConfig self);
void IedServerConfig_setMaxDataSetEntries(IedServerConfig self, int maxDataSetEntries);
int IedServerConfig_getMaxDatasSetEntries(IedServerConfig self);
// 日志服务
void IedServerConfig_enableLogService(IedServerConfig self, bool enable);
bool IedServerConfig_isLogServiceEnabled(IedServerConfig self);
// EditSG 设置组编辑
void IedServerConfig_enableEditSG(IedServerConfig self, bool enable);
// 注意: 禁用后 SGCB.ResvTms 不可见
// ResvTms 可见性
void IedServerConfig_enableResvTmsForSGCB(IedServerConfig self, bool enable);
void IedServerConfig_enableResvTmsForBRCB(IedServerConfig self, bool enable);
bool IedServerConfig_isResvTmsForBRCBEnabled(IedServerConfig self);
// RCB Owner 属性
void IedServerConfig_enableOwnerForRCB(IedServerConfig self, bool enable);
bool IedServerConfig_isOwnerForRCBEnabled(IedServerConfig self);
// GOOSE 发布控制
void IedServerConfig_useIntegratedGoosePublisher(IedServerConfig self, bool enable);
// 默认启用; 如需使用独立的 GoosePublisher 可禁用
// 报告设置可写性
void IedServerConfig_setReportSetting(IedServerConfig self, uint8_t setting, bool isDyn);
bool IedServerConfig_getReportSetting(IedServerConfig self, uint8_t setting);
// setting 取值: IEC61850_REPORTSETTINGS_RPT_ID, _BUF_TIME, _DATSET, _TRG_OPS, _OPT_FIELDS, _INTG_PD
```
---
## 5. 服务器创建与销毁
```c
// 创建服务器实例
IedServer IedServer_create(IedModel* dataModel);
// 参数: dataModel - 指向 IedModel 数据结构的指针
// 返回: 新的 IedServer 实例
// 创建带 TLS 支持的服务器
IedServer IedServer_createWithTlsSupport(IedModel* dataModel, TLSConfiguration tlsConfiguration);
// 参数: tlsConfiguration - TLS 配置对象,或 NULL 表示不使用 TLS
// 创建带完整配置的服务器
IedServer IedServer_createWithConfig(IedModel* dataModel,
TLSConfiguration tlsConfiguration, IedServerConfig serverConfiguration);
// 参数: serverConfiguration - 高级配置对象
// 销毁服务器实例 (释放所有资源: 内存、TCP socket)
void IedServer_destroy(IedServer self);
// 添加额外的本地接入点 (多网卡监听)
bool IedServer_addAccessPoint(IedServer self,
const char* ipAddr, int tcpPort, TLSConfiguration tlsConfiguration);
// 返回: 成功 true失败 false
// 设置本地监听 IP 地址
void IedServer_setLocalIpAddress(IedServer self, const char* localIpAddress);
// 内部会创建 IP 字符串的副本
// 设置服务器身份 (MMS identify 服务)
void IedServer_setServerIdentity(IedServer self,
const char* vendor, const char* model, const char* revision);
// 条件编译: CONFIG_IEC61850_SUPPORT_SERVER_IDENTITY
// 获取底层 MmsServer 实例 (用于高级操作)
MmsServer IedServer_getMmsServer(IedServer self);
// 获取数据模型指针
IedModel* IedServer_getDataModel(IedServer self);
```
### 启动与停止
```c
// === 多线程模式 ===
// 启动服务器 (创建后台线程)
void IedServer_start(IedServer self, int tcpPort);
// tcpPort: TCP 端口号,-1 使用默认 (102 for MMS, 3872 for TLS)
// 检查服务器是否在运行
bool IedServer_isRunning(IedServer self);
// 获取当前连接数
int IedServer_getNumberOfOpenConnections(IedServer self);
// 停止服务器
void IedServer_stop(IedServer self);
// === 单线程模式 ===
// (详见第19节)
void IedServer_startThreadless(IedServer self, int tcpPort);
int IedServer_waitReady(IedServer self, unsigned int timeoutMs);
void IedServer_processIncomingData(IedServer self);
void IedServer_performPeriodicTasks(IedServer self);
void IedServer_stopThreadless(IedServer self);
```
### 时间品质设置
```c
void IedServer_setTimeQuality(IedServer self,
bool leapSecondKnown, // 闰秒已知
bool clockFailure, // 时钟故障
bool clockNotSynchronized, // 时钟未同步
int subsecondPrecision); // 亚秒精度 (fractionOfSecond 的有效位数)
```
---
## 6. 数据模型锁定与更新
### 6.1 线程安全
**重要规则**: 在回调函数内部ControlHandler、WriteAccessHandler 等),数据模型已经被锁住!不要在回调函数内部再调用 `lockDataModel`,否则会导致死锁。
```c
// 锁定数据模型 (暂停处理客户端请求)
void IedServer_lockDataModel(IedServer self);
// 解锁数据模型 (处理暂停的客户端请求)
void IedServer_unlockDataModel(IedServer self);
```
### 6.2 更新数据属性值
所有 `IedServer_update*` 函数都会自动:
- 检查触发条件是否满足 (dchg/qchg/dupd)
- 如果满足触发条件,通知相应的 RCB/GCB
- 自动更新内部缓存
```c
// === 通用更新函数 ===
void IedServer_updateAttributeValue(IedServer self,
DataAttribute* dataAttribute, MmsValue* value);
// 最通用的更新函数,接受 MmsValue 对象
// === 类型特定的便捷更新函数 ===
void IedServer_updateFloatAttributeValue(IedServer self,
DataAttribute* dataAttribute, float value);
void IedServer_updateInt32AttributeValue(IedServer self,
DataAttribute* dataAttribute, int32_t value);
void IedServer_updateInt64AttributeValue(IedServer self,
DataAttribute* dataAttribute, int64_t value);
void IedServer_updateUnsignedAttributeValue(IedServer self,
DataAttribute* dataAttribute, uint32_t value);
void IedServer_updateBooleanAttributeValue(IedServer self,
DataAttribute* dataAttribute, bool value);
void IedServer_updateBitStringAttributeValue(IedServer self,
DataAttribute* dataAttribute, uint32_t value);
void IedServer_updateVisibleStringAttributeValue(IedServer self,
DataAttribute* dataAttribute, char* value);
void IedServer_updateDbposValue(IedServer self,
DataAttribute* dataAttribute, Dbpos value);
// Dbpos 是双点位置 (Double Point Position)
// === 时间戳更新 ===
void IedServer_updateUTCTimeAttributeValue(IedServer self,
DataAttribute* dataAttribute, uint64_t value);
// value: 毫秒时间戳 (自Epoch以来的毫秒数, 如 Hal_getTimeInMs())
void IedServer_updateTimestampAttributeValue(IedServer self,
DataAttribute* dataAttribute, Timestamp* timestamp);
// timestamp: 完整 Timestamp 结构体 (含品质标志)
// === 品质更新 ===
void IedServer_updateQuality(IedServer self,
DataAttribute* dataAttribute, Quality quality);
```
---
## 7. 数据读取函数
```c
// 获取数据属性底层 MmsValue 对象 (谨慎使用, 直接修改不会触发报告)
MmsValue* IedServer_getAttributeValue(IedServer self,
DataAttribute* dataAttribute);
// 获取功能约束数据 (FCD) 的 MmsValue
MmsValue* IedServer_getFunctionalConstrainedData(IedServer self,
DataObject* dataObject, FunctionalConstraint fc);
// 直接获取 DataObject 指定 FC 下的全部 MmsValue
// 警告: 直接修改此值不会触发报告机制!
// === 类型特定读取函数 ===
bool IedServer_getBooleanAttributeValue(IedServer self,
const DataAttribute* dataAttribute);
int32_t IedServer_getInt32AttributeValue(IedServer self,
const DataAttribute* dataAttribute);
int64_t IedServer_getInt64AttributeValue(IedServer self,
const DataAttribute* dataAttribute);
uint32_t IedServer_getUInt32AttributeValue(IedServer self,
const DataAttribute* dataAttribute);
float IedServer_getFloatAttributeValue(IedServer self,
const DataAttribute* dataAttribute);
uint64_t IedServer_getUTCTimeAttributeValue(IedServer self,
const DataAttribute* dataAttribute);
uint32_t IedServer_getBitStringAttributeValue(IedServer self,
const DataAttribute* dataAttribute);
const char* IedServer_getStringAttributeValue(IedServer self,
const DataAttribute* dataAttribute);
```
### 7.1 数据更新典型模式
```c
while (running) {
uint64_t timestamp = Hal_getTimeInMs();
// 构建 IEC 61850 时间戳
Timestamp iecTimestamp;
Timestamp_clearFlags(&iecTimestamp);
Timestamp_setTimeInMilliseconds(&iecTimestamp, timestamp);
Timestamp_setLeapSecondKnown(&iecTimestamp, true);
IedServer_lockDataModel(iedServer);
// 更新测量值
IedServer_updateFloatAttributeValue(iedServer,
IEDMODEL_GenericIO_GGIO1_AnIn1_mag_f, sinf(t));
// 更新品质
IedServer_updateQuality(iedServer,
IEDMODEL_GenericIO_GGIO1_AnIn1_q, QUALITY_VALIDITY_GOOD);
// 更新时间戳
IedServer_updateTimestampAttributeValue(iedServer,
IEDMODEL_GenericIO_GGIO1_AnIn1_t, &iecTimestamp);
IedServer_unlockDataModel(iedServer);
Thread_sleep(100);
}
```
---
## 8. 连接管理与认证
### 8.1 连接指示处理器
```c
// 回调函数类型
typedef void (*IedConnectionIndicationHandler)(
IedServer self, // 服务器实例
ClientConnection connection, // 连接对象
bool connected, // true=新连接, false=连接关闭
void* parameter); // 用户参数
// 设置连接事件回调
void IedServer_setConnectionIndicationHandler(IedServer self,
IedConnectionIndicationHandler handler, void* parameter);
```
### 8.2 ClientConnection 操作
```c
// 获取客户端对端地址 (IP:Port)
const char* ClientConnection_getPeerAddress(ClientConnection self);
// 注意: 返回的字符串仅在连接存在期间有效
// 获取本地地址 (IP:Port)
const char* ClientConnection_getLocalAddress(ClientConnection self);
// 获取安全令牌 (认证阶段关联的)
void* ClientConnection_getSecurityToken(ClientConnection self);
// 如果没有认证器则返回 NULL
```
### 8.3 认证器 (Authenticator)
```c
// 设置认证回调
void IedServer_setAuthenticator(IedServer self,
AcseAuthenticator authenticator, void* authenticatorParameter);
// 每次客户端连接尝试时调用, 根据返回值决定接受或拒绝连接
// 如果不设置, 默认接受所有连接
// 认证机制枚举
typedef enum {
ACSE_AUTH_NONE = 0, // 无认证
ACSE_AUTH_PASSWORD = 1, // ACSE 密码
ACSE_AUTH_CERTIFICATE = 2, // ACSE 证书
ACSE_AUTH_TLS = 3 // TLS 证书
} AcseAuthenticationMechanism;
```
---
## 9. 控制模型 (Control)
### 9.1 控制模型枚举 (ControlModel)
```c
typedef enum {
CONTROL_MODEL_STATUS_ONLY = 0, // 仅状态 (不可控)
CONTROL_MODEL_DIRECT_NORMAL = 1, // 直接控制-普通安全
CONTROL_MODEL_SBO_NORMAL = 2, // 选择前操作-普通安全
CONTROL_MODEL_DIRECT_ENHANCED = 3, // 直接控制-增强安全 (含CommandTermination)
CONTROL_MODEL_SBO_ENHANCED = 4 // 选择前操作-增强安全
} ControlModel;
```
### 9.2 控制处理器回调类型
```c
// 1. 操作检查处理器 (PerformCheckHandler) - 静态测试 (可选)
typedef CheckHandlerResult (*ControlPerformCheckHandler)(
ControlAction action, // 控制动作上下文
void* parameter, // 用户参数
MmsValue* ctlVal, // 控制值
bool test, // 是否为测试命令
bool interlockCheck); // 是否请求联锁检查
// 返回值:
// CONTROL_ACCEPTED = -1 检查通过
// CONTROL_WAITING_FOR_SELECT = 0 等待选择
// CONTROL_HARDWARE_FAULT = 1 硬件故障
// CONTROL_TEMPORARILY_UNAVAILABLE = 2 暂时不可用(已被其他客户端控制)
// CONTROL_OBJECT_ACCESS_DENIED = 3 访问拒绝
// CONTROL_OBJECT_UNDEFINED = 4 对象未定义
// CONTROL_VALUE_INVALID = 11 值超出范围
// 2. 等待执行处理器 (WaitForExecutionHandler) - 动态测试 (可选)
typedef ControlHandlerResult (*ControlWaitForExecutionHandler)(
ControlAction action,
void* parameter,
MmsValue* ctlVal,
bool test,
bool synchroCheck); // 是否请求同步检查
// 返回值:
// CONTROL_RESULT_FAILED = 0 失败
// CONTROL_RESULT_OK = 1 成功
// CONTROL_RESULT_WAITING = 2 等待中 (稍后再次调用)
// 3. 控制执行处理器 (ControlHandler) - 实际执行 (必需)
typedef ControlHandlerResult (*ControlHandler)(
ControlAction action, // 控制动作上下文
void* parameter, // 用户参数 (通常是控制对象的 DataObject* 指针)
MmsValue* ctlVal, // 控制值
bool test); // 是否为测试命令
// 返回值: 同 WaitForExecutionHandler
// 4. 选择状态变化处理器 (v1.5 新增)
typedef void (*ControlSelectStateChangedHandler)(
ControlAction action,
void* parameter,
bool isSelected, // true=被选择, false=取消选择
SelectStateChangedReason reason); // 原因
typedef enum {
SELECT_STATE_REASON_SELECTED,
SELECT_STATE_REASON_CANCELED,
SELECT_STATE_REASON_TIMEOUT,
SELECT_STATE_REASON_OPERATED,
SELECT_STATE_REASON_OPERATE_FAILED,
SELECT_STATE_REASON_DISCONNECTED
} SelectStateChangedReason;
```
### 9.3 设置控制处理器
```c
// 设置控制处理器 (必需 - 在有控制模型中)
void IedServer_setControlHandler(IedServer self,
DataObject* node, // 可控数据对象
ControlHandler handler, // 控制回调函数
void* parameter); // 用户参数
// 设置操作检查处理器 (可选)
void IedServer_setPerformCheckHandler(IedServer self,
DataObject* node,
ControlPerformCheckHandler handler,
void* parameter);
// 设置等待执行处理器 (可选)
void IedServer_setWaitForExecutionHandler(IedServer self,
DataObject* node,
ControlWaitForExecutionHandler handler,
void* parameter);
// 设置选择状态变化处理器 (可选)
void IedServer_setSelectStateChangedHandler(IedServer self,
DataObject* node,
ControlSelectStateChangedHandler handler,
void* parameter);
```
### 9.4 ControlAction 上下文查询函数
在控制处理器内部,可以通过 ControlAction 获取更多上下文信息:
```c
// 获取客户端连接对象
ClientConnection ControlAction_getClientConnection(ControlAction self);
// 获取控制对象 (DataObject*)
DataObject* ControlAction_getControlObject(ControlAction self);
// 判断是否为 Select 命令 (vs Operate)
bool ControlAction_isSelect(ControlAction self);
// 获取控制序号
int ControlAction_getCtlNum(ControlAction self);
// 获取来源类别 (orCat)
int ControlAction_getOrCat(ControlAction self);
// 获取来源标识
uint8_t* ControlAction_getOrIdent(ControlAction self, int* orIdentSize);
// 获取同步检查位
bool ControlAction_getSynchroCheck(ControlAction self);
// 获取联锁检查位
bool ControlAction_getInterlockCheck(ControlAction self);
// 获取控制时间 (TimeActivatedControl), 非定时控制返回 0
uint64_t ControlAction_getControlTime(ControlAction self);
// 设置下一次 CommandTermination 的错误码
void ControlAction_setError(ControlAction self, ControlLastApplError error);
// 设置下一次 CommandTermination 的附加原因
void ControlAction_setAddCause(ControlAction self, ControlAddCause addCause);
```
### 9.5 更新控制模型
```c
void IedServer_updateCtlModel(IedServer self,
DataObject* ctlObject, ControlModel value);
// 同时更新 "ctlModel" 属性值和内部控制结构
// 注意: 对应的控制模型数据结构必须在数据模型中存在!
```
### 9.6 控制处理器典型实现
```c
static ControlHandlerResult
controlHandlerForBinaryOutput(ControlAction action, void* parameter,
MmsValue* value, bool test)
{
if (test)
return CONTROL_RESULT_FAILED; // 拒绝测试命令
if (MmsValue_getType(value) != MMS_BOOLEAN)
return CONTROL_RESULT_FAILED;
uint64_t timeStamp = Hal_getTimeInMs();
bool newState = MmsValue_getBoolean(value);
if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO1) {
// 执行实际 I/O 操作
setHardwareOutput(1, newState);
// 更新服务器状态
IedServer_updateUTCTimeAttributeValue(iedServer,
IEDMODEL_GenericIO_GGIO1_SPCSO1_t, timeStamp);
IedServer_updateAttributeValue(iedServer,
IEDMODEL_GenericIO_GGIO1_SPCSO1_stVal, value);
}
return CONTROL_RESULT_OK;
}
// 安装
IedServer_setControlHandler(iedServer,
IEDMODEL_GenericIO_GGIO1_SPCSO1,
(ControlHandler) controlHandlerForBinaryOutput,
IEDMODEL_GenericIO_GGIO1_SPCSO1);
```
---
## 10. 报告控制块 (RCB)
### 10.1 RCB 事件类型
```c
typedef enum {
RCB_EVENT_GET_PARAMETER, // 客户端读取参数
RCB_EVENT_SET_PARAMETER, // 客户端设置参数
RCB_EVENT_UNRESERVED, // RCB 取消预留
RCB_EVENT_RESERVED, // RCB 被预留
RCB_EVENT_ENABLE, // RCB 启用
RCB_EVENT_DISABLE, // RCB 禁用
RCB_EVENT_GI, // 总召唤触发
RCB_EVENT_PURGEBUF, // 清除缓冲区
RCB_EVENT_OVERFLOW, // 报告缓冲区溢出
RCB_EVENT_REPORT_CREATED // 新报告创建并写入缓冲区
} IedServer_RCBEventType;
```
### 10.2 RCB 事件处理器
```c
// 回调类型
typedef void (*IedServer_RCBEventHandler)(
void* parameter, // 用户参数
ReportControlBlock* rcb, // 受影响的 RCB
ClientConnection connection, // 相关客户端连接
IedServer_RCBEventType event, // 事件类型
const char* parameterName, // 参数名 (仅用于 SET_PARAMETER 事件)
MmsDataAccessError serviceError); // 服务错误 (仅用于 SET_PARAMETER 事件)
// 安装处理器
void IedServer_setRCBEventHandler(IedServer self,
IedServer_RCBEventHandler handler, void* parameter);
```
---
## 11. GOOSE 发布
### 11.1 GOOSE 发布控制
```c
// 启用所有 GOOSE 控制块 (设置 GoEna=true)
void IedServer_enableGoosePublishing(IedServer self);
// 在启动或重置时调用,否则 GCB 默认为非活跃
// 禁用所有 GOOSE 控制块 (设置 GoEna=false)
void IedServer_disableGoosePublishing(IedServer self);
// 设置 GOOSE 以太网接口
void IedServer_setGooseInterfaceId(IedServer self, const char* interfaceId);
// interfaceId: OS 相关, Linux 下如 "eth0"
// 如果未调用或 interfaceId=NULL使用 stack_config.h 中的默认值
// 为特定 GCB 设置接口
void IedServer_setGooseInterfaceIdEx(IedServer self,
LogicalNode* ln, // 包含 GCB 的逻辑节点, NULL 表示为所有 GCB
const char* gcbName, // GCB 名称 (非对象引用!)
const char* interfaceId);
// 控制 GOOSE VLAN 标签
void IedServer_useGooseVlanTag(IedServer self,
LogicalNode* ln, // NULL 表示所有 GCB
const char* gcbName,
bool useVlanTag);
```
### 11.2 独立 GOOSE 发布者 (不依赖服务器模型)
`useIntegratedGoosePublisher` 配置为 false或者需要独立控制时:
```c
#include "goose_publisher.h"
// 通信参数
typedef struct sCommParameters {
uint8_t vlanPriority;
uint16_t vlanId;
uint16_t appId;
uint8_t dstAddress[6]; // 目标 MAC 地址
} CommParameters;
// 创建发布者
GoosePublisher GoosePublisher_create(CommParameters* parameters,
const char* interfaceID);
// 扩展版: 可禁用 VLAN 标签
GoosePublisher GoosePublisher_createEx(CommParameters* parameters,
const char* interfaceID, bool useVlanTag);
// 销毁
void GoosePublisher_destroy(GoosePublisher self);
// 发布 GOOSE 消息
int GoosePublisher_publish(GoosePublisher self, LinkedList dataSet);
// dataSet: MmsValue* 链表
// 返回值: -1 表示发送错误
// 自动递增 sqNum
// 发布并保存到缓冲区 (调试用)
int GoosePublisher_publishAndDump(GoosePublisher self, LinkedList dataSet,
char* msgBuf, int32_t* msgLen, int32_t bufSize);
// 设置 GOOSE 消息字段
void GoosePublisher_setGoID(GoosePublisher self, char* goID);
void GoosePublisher_setGoCbRef(GoosePublisher self, char* goCbRef);
void GoosePublisher_setTimeAllowedToLive(GoosePublisher self, uint32_t timeAllowedToLive);
void GoosePublisher_setDataSetRef(GoosePublisher self, char* dataSetRef);
void GoosePublisher_setConfRev(GoosePublisher self, uint32_t confRev);
void GoosePublisher_setSimulation(GoosePublisher self, bool simulation);
void GoosePublisher_setNeedsCommission(GoosePublisher self, bool ndsCom);
// 状态管理
uint64_t GoosePublisher_increaseStNum(GoosePublisher self);
// 当数据集成员变化时调用, 重置 sqNum
void GoosePublisher_reset(GoosePublisher self);
// 重置 stNum=1, sqNum=0
// 仅用于测试
void GoosePublisher_setStNum(GoosePublisher self, uint32_t stNum);
void GoosePublisher_setSqNum(GoosePublisher self, uint32_t sqNum);
```
---
## 12. GOOSE 控制块 (GoCB)
```c
// GoCB 事件回调
typedef void (*GoCBEventHandler)(
MmsGooseControlBlock goCb, // GoCB 实例
int event, // IEC61850_GOCB_EVENT_ENABLE(1) 或 _DISABLE(0)
void* parameter);
// 设置 GoCB 事件处理器
void IedServer_setGoCBHandler(IedServer self,
GoCBEventHandler handler, void* parameter);
// GoCB 信息查询
char* MmsGooseControlBlock_getName(MmsGooseControlBlock self);
LogicalNode* MmsGooseControlBlock_getLogicalNode(MmsGooseControlBlock self);
DataSet* MmsGooseControlBlock_getDataSet(MmsGooseControlBlock self);
bool MmsGooseControlBlock_getGoEna(MmsGooseControlBlock self);
int MmsGooseControlBlock_getMinTime(MmsGooseControlBlock self);
int MmsGooseControlBlock_getMaxTime(MmsGooseControlBlock self);
bool MmsGooseControlBlock_getFixedOffs(MmsGooseControlBlock self);
bool MmsGooseControlBlock_getNdsCom(MmsGooseControlBlock self);
```
---
## 13. Sampled Values 控制块 (SVCB)
```c
// SVCB 事件回调
typedef void (*SVCBEventHandler)(
SVControlBlock* svcb, // SVCB 实例
int event, // IEC61850_SVCB_EVENT_ENABLE(1) 或 _DISABLE(0)
void* parameter);
// 设置 SVCB 事件处理器
void IedServer_setSVCBHandler(IedServer self,
SVControlBlock* svcb,
SVCBEventHandler handler, void* parameter);
```
---
## 14. 数据访问控制 (Access Control)
### 14.1 写访问处理器 (WriteAccessHandler)
```c
// 回调类型
typedef MmsDataAccessError (*WriteAccessHandler)(
DataAttribute* dataAttribute, // 被写入的数据属性
MmsValue* value, // 客户端想要写入的值
ClientConnection connection, // 发起操作的客户端连接
void* parameter); // 用户参数
// 返回值:
// DATA_ACCESS_ERROR_SUCCESS - 接受写入 (栈自动更新值)
// DATA_ACCESS_ERROR_SUCCESS_NO_UPDATE - 接受但不自动更新 (用户自行更新)
// DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED - 拒绝写入
// 安装写访问处理器 (仅指定属性)
void IedServer_handleWriteAccess(IedServer self,
DataAttribute* dataAttribute,
WriteAccessHandler handler, void* parameter);
// 注意: 如果 dataAttribute 有子属性, 此处理器不会传播到子属性
// 安装写访问处理器 (包含所有子属性)
void IedServer_handleWriteAccessForComplexAttribute(IedServer self,
DataAttribute* dataAttribute,
WriteAccessHandler handler, void* parameter);
```
### 14.2 FC 级写策略
```c
typedef enum {
ACCESS_POLICY_ALLOW, // 允许
ACCESS_POLICY_DENY // 拒绝
} AccessPolicy;
void IedServer_setWriteAccessPolicy(IedServer self,
FunctionalConstraint fc, AccessPolicy policy);
// 默认可对 FC=DC 和 FC=CF 的写访问都是拒绝的
// 如需允许客户端修改描述信息: IedServer_setWriteAccessPolicy(server, IEC61850_FC_DC, ACCESS_POLICY_ALLOW);
```
### 14.3 读访问处理器 (ReadAccessHandler)
```c
typedef MmsDataAccessError (*ReadAccessHandler)(
LogicalDevice* ld, // 被访问的逻辑设备
LogicalNode* ln, // 被访问的逻辑节点
DataObject* dataObject, // 被访问的数据对象
FunctionalConstraint fc, // 功能约束
ClientConnection connection, // 客户端连接
void* parameter); // 用户参数
void IedServer_setReadAccessHandler(IedServer self,
ReadAccessHandler handler, void* parameter);
// 全局读访问处理器: 每次客户端读取前调用
// 可用于实现基于角色的访问控制 (RBAC)
```
---
## 15. 设置组 (Setting Groups)
### 15.1 结构体
```c
struct sSettingGroupControlBlock {
LogicalNode* parent;
uint8_t actSG; // 当前活动设置组号
uint8_t numOfSGs; // 设置组总数
uint8_t editSG; // 当前编辑设置组号 (上电为0)
bool cnfEdit; // 编辑确认标志 (上电为false)
uint64_t timestamp;
uint16_t resvTms;
SettingGroupControlBlock* sibling; // 链表中下一个
};
```
### 15.2 活动设置组操作
```c
// 服务器内部主动切换活动设置组
void IedServer_changeActiveSettingGroup(IedServer self,
SettingGroupControlBlock* sgcb, uint8_t newActiveSg);
// 调用前用户应先更新 FC=SG 的数据属性
// 获取当前活动设置组号
uint8_t IedServer_getActiveSettingGroup(IedServer self,
SettingGroupControlBlock* sgcb);
```
### 15.3 设置组回调处理器
```c
// 活动设置组变化处理器
typedef bool (*ActiveSettingGroupChangedHandler)(
void* parameter,
SettingGroupControlBlock* sgcb,
uint8_t newActSg, // 新的活动设置组
ClientConnection connection); // 请求变更的客户端
// 返回 true 接受变更, false 拒绝
void IedServer_setActiveSettingGroupChangedHandler(IedServer self,
SettingGroupControlBlock* sgcb,
ActiveSettingGroupChangedHandler handler, void* parameter);
// 编辑设置组变化处理器
typedef bool (*EditSettingGroupChangedHandler)(
void* parameter,
SettingGroupControlBlock* sgcb,
uint8_t newEditSg, // 新的编辑设置组
ClientConnection connection);
// 应在此回调中更新 FC=SE 的数据属性
// 返回 true 接受变更, false 拒绝
void IedServer_setEditSettingGroupChangedHandler(IedServer self,
SettingGroupControlBlock* sgcb,
EditSettingGroupChangedHandler handler, void* parameter);
// 编辑设置组确认处理器
typedef void (*EditSettingGroupConfirmationHandler)(
void* parameter,
SettingGroupControlBlock* sgcb,
uint8_t editSg); // 被确认的编辑设置组
// 客户端确认编辑后将 SE 值写入对应的 SG 值
void IedServer_setEditSettingGroupConfirmationHandler(IedServer self,
SettingGroupControlBlock* sgcb,
EditSettingGroupConfirmationHandler handler, void* parameter);
```
---
## 16. 文件服务
### 16.1 基础配置
```c
// 设置文件服务根目录
void IedServer_setFilestoreBasepath(IedServer self, const char* basepath);
// 条件编译: CONFIG_SET_FILESTORE_BASEPATH_AT_RUNTIME
// 安装文件访问处理器 (控制/监控文件访问)
void MmsServer_installFileAccessHandler(MmsServer self,
MmsFileAccessHandler handler, void* parameter);
// 通过 IedServer_getMmsServer() 获取 MmsServer
```
### 16.2 文件访问处理器
```c
typedef enum {
MMS_FILE_ACCESS_TYPE_READ_DIRECTORY, // 读取目录
MMS_FILE_ACCESS_TYPE_OPEN, // 打开文件
MMS_FILE_ACCESS_TYPE_OBTAIN, // 上传文件(ObtainFile)
MMS_FILE_ACCESS_TYPE_DELETE, // 删除文件
MMS_FILE_ACCESS_TYPE_RENAME // 重命名文件
} MmsFileServiceType;
typedef MmsError (*MmsFileAccessHandler)(
void* parameter, // 用户参数
MmsServerConnection connection, // 客户端连接
MmsFileServiceType service, // 服务类型
const char* localFilename, // 服务器端文件名
const char* otherFilename); // 另一个文件名参数
// 返回 MMS_ERROR_NONE 表示接受, 否则用适当的错误码
```
---
## 17. 日志服务 (Log Service)
```c
#include "logging_api.h"
// 关联日志存储到服务器日志对象
void IedServer_setLogStorage(IedServer self,
const char* logRef, // 日志对象引用 ( "GenericIO/LLN0$EventLog")
LogStorage logStorage); // 日志存储实例
// SQLite 日志存储 (需包含 src/logging/drivers/sqlite/log_storage_sqlite.c)
extern LogStorage SqliteLogStorage_createInstance(const char* filename);
// 日志存储 API
void LogStorage_setMaxLogEntries(LogStorage self, int maxEntries);
uint64_t LogStorage_addEntry(LogStorage self, uint64_t timestamp);
void LogStorage_addEntryData(LogStorage self, uint64_t entryID,
const char* dataRef, const uint8_t* data, int dataSize, uint8_t reasonCode);
void LogStorage_getEntries(LogStorage self, uint64_t fromTime, uint64_t toTime,
LogEntryCallback entryCallback, LogEntryDataCallback entryDataCallback, void* parameter);
void LogStorage_destroy(LogStorage self);
```
---
## 18. TLS 安全通信
```c
#include "tls_config.h"
// 创建 TLS 配置
TLSConfiguration tlsConfig = TLSConfiguration_create();
// 加载服务器私钥
bool TLSConfiguration_setOwnKeyFromFile(TLSConfiguration self,
const char* keyFilename, const char* password);
// password: 私钥密码, 无密码时传 NULL
// 加载服务器证书
bool TLSConfiguration_setOwnCertificateFromFile(TLSConfiguration self,
const char* certFilename);
// 加载 CA 证书
bool TLSConfiguration_addCACertificateFromFile(TLSConfiguration self,
const char* certFilename);
// 加载允许的客户端证书 (白名单)
bool TLSConfiguration_addAllowedCertificateFromFile(TLSConfiguration self,
const char* certFilename);
// 证书链验证
void TLSConfiguration_setChainValidation(TLSConfiguration self, bool enable);
// 仅允许已知证书
void TLSConfiguration_setAllowOnlyKnownCertificates(TLSConfiguration self, bool enable);
// 安全事件处理器
void TLSConfiguration_setEventHandler(TLSConfiguration self,
TLSEventHandler handler, void* parameter);
// 使用 TLS 创建服务器
IedServer iedServer = IedServer_createWithTlsSupport(&iedModel, tlsConfig);
// 销毁 TLS 配置 (在 IedServer_destroy 之后)
TLSConfiguration_destroy(tlsConfig);
```
---
## 19. 单线程模式 (Threadless)
适用于资源受限的嵌入式环境,所有操作在单个线程中完成。
```c
// 启动 (不创建后台线程)
void IedServer_startThreadless(IedServer self, int tcpPort);
// 等待连接就绪 (带超时) - 可选
int IedServer_waitReady(IedServer self, unsigned int timeoutMs);
// 返回: 0 = 无连接就绪, !=0 = 至少一个连接就绪
// 等价于 Linux select()
// 处理收到的数据 - 必须周期性调用
void IedServer_processIncomingData(IedServer self);
// 执行周期后台任务 - 必须周期性调用
void IedServer_performPeriodicTasks(IedServer self);
// 停止
void IedServer_stopThreadless(IedServer self);
// 单线程模式主循环示例:
IedServer_startThreadless(iedServer, 102);
while (running) {
uint64_t now = Hal_getTimeInMs();
// 定期更新数据
if (now - lastUpdateTime >= 100) {
IedServer_lockDataModel(iedServer);
IedServer_updateFloatAttributeValue(iedServer, attr, value);
IedServer_unlockDataModel(iedServer);
lastUpdateTime = now;
}
// 处理网络事件
IedServer_processIncomingData(iedServer);
// 处理周期任务 (超时、报告等)
IedServer_performPeriodicTasks(iedServer);
Thread_sleep(1);
}
IedServer_stopThreadless(iedServer);
```
---
## 20. MmsServer 底层接口
通过 `IedServer_getMmsServer()` 获取后可用:
```c
// 设置最大连接数
void MmsServer_setMaxConnections(MmsServer self, int maxConnections);
// 文件服务
void MmsServer_setFilestoreBasepath(MmsServer self, const char* basepath);
void MmsServer_enableFileService(MmsServer self, bool enable);
// 待命名变量列表 (数据集) 服务
void MmsServer_enableDynamicNamedVariableListService(MmsServer self, bool enable);
void MmsServer_setMaxAssociationSpecificDataSets(MmsServer self, int maxDataSets);
void MmsServer_setMaxDomainSpecificDataSets(MmsServer self, int maxDataSets);
void MmsServer_setMaxDataSetEntries(MmsServer self, int maxDataSetEntries);
// 日志服务
void MmsServer_enableJournalService(MmsServer self, bool enable);
// 服务器身份
void MmsServer_setServerIdentity(MmsServer self,
char* vendorName, char* modelName, char* revision);
// VMD 状态
void MmsServer_setVMDStatus(MmsServer self,
int vmdLogicalStatus, int vmdPhysicalStatus);
// LOGICAL: 0=STATE_CHANGES_ALLOWED, 1=NO_CHANGES, 2=LIMITED_SERVICES, 3=SUPPORT_SERVICES
// PHYSICAL: 0=OPERATIONAL, 1=PARTIALLY, 2=INOPERATIONAL, 3=NEEDS_COMMISSIONING
```
---
## 21. 完整示例
### 21.1 最简单服务器
```c
#include "iec61850_server.h"
#include "hal_thread.h"
#include <signal.h>
#include "static_model.h"
static int running = 0;
void sigint_handler(int sig) { running = 0; }
int main(int argc, char** argv)
{
IedServer iedServer = IedServer_create(&iedModel);
IedServer_start(iedServer, 102);
if (!IedServer_isRunning(iedServer)) {
IedServer_destroy(iedServer);
return -1;
}
running = 1;
signal(SIGINT, sigint_handler);
while (running)
Thread_sleep(1);
IedServer_stop(iedServer);
IedServer_destroy(iedServer);
return 0;
}
```
### 21.2 带控制、报告和 GOOSE 的完整服务器
```c
#include "iec61850_server.h"
#include "hal_thread.h"
#include <signal.h>
#include <math.h>
#include "static_model.h"
static int running = 0;
static IedServer iedServer = NULL;
// --- 控制处理器 ---
static ControlHandlerResult
controlHandler(ControlAction action, void* parameter, MmsValue* value, bool test)
{
if (test) return CONTROL_RESULT_FAILED;
if (MmsValue_getType(value) != MMS_BOOLEAN) return CONTROL_RESULT_FAILED;
uint64_t ts = Hal_getTimeInMs();
IedServer_updateUTCTimeAttributeValue(iedServer,
IEDMODEL_GenericIO_GGIO1_SPCSO1_t, ts);
IedServer_updateAttributeValue(iedServer,
IEDMODEL_GenericIO_GGIO1_SPCSO1_stVal, value);
return CONTROL_RESULT_OK;
}
// --- 连接处理器 ---
static void
connectionHandler(IedServer self, ClientConnection conn, bool connected, void* param)
{
printf("Client %s %s\n",
ClientConnection_getPeerAddress(conn),
connected ? "connected" : "disconnected");
}
// --- RCB 事件处理器 ---
static void
rcbHandler(void* param, ReportControlBlock* rcb, ClientConnection conn,
IedServer_RCBEventType event, const char* paramName,
MmsDataAccessError err)
{
printf("RCB %s event: %i\n", ReportControlBlock_getName(rcb), event);
}
// --- GoCB 事件处理器 ---
static void
goCbHandler(MmsGooseControlBlock goCb, int event, void* param)
{
printf("GoCB %s: %s\n",
MmsGooseControlBlock_getName(goCb),
event == IEC61850_GOCB_EVENT_ENABLE ? "ENABLED" : "DISABLED");
}
int main(int argc, char** argv)
{
int port = (argc > 1) ? atoi(argv[1]) : 102;
IedServerConfig cfg = IedServerConfig_create();
IedServerConfig_setReportBufferSize(cfg, 200000);
IedServerConfig_setMaxMmsConnections(cfg, 5);
iedServer = IedServer_createWithConfig(&iedModel, NULL, cfg);
IedServerConfig_destroy(cfg);
// 安装处理器
IedServer_setControlHandler(iedServer,
IEDMODEL_GenericIO_GGIO1_SPCSO1,
(ControlHandler) controlHandler,
IEDMODEL_GenericIO_GGIO1_SPCSO1);
IedServer_setConnectionIndicationHandler(iedServer,
(IedConnectionIndicationHandler) connectionHandler, NULL);
IedServer_setRCBEventHandler(iedServer, rcbHandler, NULL);
IedServer_setGoCBHandler(iedServer, goCbHandler, NULL);
// 允许客户端写 DC/CF
IedServer_setWriteAccessPolicy(iedServer, IEC61850_FC_DC, ACCESS_POLICY_ALLOW);
// 设置 GOOSE 接口并启动发布
IedServer_setGooseInterfaceId(iedServer, "eth0");
IedServer_start(iedServer, port);
if (!IedServer_isRunning(iedServer)) {
printf("Start failed!\n");
IedServer_destroy(iedServer);
return -1;
}
IedServer_enableGoosePublishing(iedServer);
running = 1;
signal(SIGINT, sigint_handler);
float t = 0.f;
while (running) {
uint64_t ts = Hal_getTimeInMs();
// 构建时间戳
Timestamp iecTs;
Timestamp_clearFlags(&iecTs);
Timestamp_setTimeInMilliseconds(&iecTs, ts);
Timestamp_setLeapSecondKnown(&iecTs, true);
IedServer_lockDataModel(iedServer);
IedServer_updateFloatAttributeValue(iedServer,
IEDMODEL_GenericIO_GGIO1_AnIn1_mag_f, sinf(t));
IedServer_updateTimestampAttributeValue(iedServer,
IEDMODEL_GenericIO_GGIO1_AnIn1_t, &iecTs);
IedServer_updateQuality(iedServer,
IEDMODEL_GenericIO_GGIO1_AnIn1_q, QUALITY_VALIDITY_GOOD);
IedServer_unlockDataModel(iedServer);
t += 0.1f;
Thread_sleep(100);
}
IedServer_stop(iedServer);
IedServer_destroy(iedServer);
return 0;
}
```