# 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 #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 #include #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; } ```