1 /* 2 * 3 * iec61850sv_protocol.h 4 * 5 * iec61850采样协议(9-1、9-2)解析。 6 * 7 * 8 * 本代码支持win32平台和linux平台。 9 * 10 * Copyright (c)2012,lizhi<ibox> 11 * 12 * 2012-10-10 V1.0 lizhi<QQ:252240557,msn:ddgooo@hotmail.com> created 13 * 14 * 15 * ◆ IEC61850-9-2(特定通信服务映射-基于ISO/IEC 8802-3 的模拟量采样值) 16 * 以太网通信帧结构格式(9-1、9-2): 17 * Header MAC 01 目标地址 0xFF 18 * 02 0xFF 19 * 03 0xFF 20 * 04 0xFF 21 * 05 0xFF 22 * 06 0xFF 23 * 07 源地址 0x73 24 * 08 0x61 25 * 09 0x63 26 * 10 0x00 27 * 11 0x00 28 * 12 0x01 29 * Priority Tagged 13 TPID 0x81 30 * 14 0x00 31 * 15 TCI 0x80 32 * 16 0x00 33 * Ether-type PDU 17 Ether-type 0x88 34 * 18 0xBA 35 * 19 APPID 0x40 36 * 20 0x00 37 * 21 Length .... 38 * 22 .... 39 * 23 保留 0x00 40 * 24 0x00 41 * 25 保留 0x00 42 * 26 0x00 43 * APDU 27 ~ N 格式见后面 .... 44 * 45 * 【9-2】APDU的内容定义(第27个字节开始): 46 * 其中Len表示asn1的长度, 注意计算方法. 47 * 长度在[0, 7f], 1个字节表示 48 * 长度在[80, ff], 2个字节表示,第一个字节填0x81 49 * 长度在[100, ffff], 3个字节表示,第一个字节填0x82, 后面用网络字节序 50 * ASDU个数可配,至多12个,采样频率SampleRate范围[1, 255]。SmpCnt前后两报文之间加一,当达到采样率时(或溢出时)归零(归1)。 51 * 52 * APDU的内容定义: 53 * 1 savPdu 0x60 Len 54 * 2 numOfAsdu 0x80 Len=1 AsduNum 55 * 2 SequenceOfAsdu 0xA2 Len 56 * 3 Sequence Asdu1 0x30 Len Asdu1 57 * 3 Sequence Asdu2 0x30 Len Asdu2 58 * .... ... ... ... 59 * 60 * ASDU内容: 61 * 0x80 svID Len=[10, 34] 10~34个字符串 62 * 0x82 smpCnt Len=2 计数, 变化值 63 * 0x83 confRev Len=1 配置版本 64 * 0x85 smpSynch Len=1 同步标识 65 * 0x87 Dataset Len=64 见下面, 变化值 66 * 4bytes UA 67 * 4bytes UA Quality 68 * 4bytes UB 69 * 4bytes UB Quality 70 * 4bytes UC 71 * 4bytes UC Quality 72 * 4bytes UZ 73 * 4bytes UZQuality 74 * 4bytes IA 75 * 4bytes IA Quality 76 * 4bytes IB 77 * 4bytes IB Quality 78 * 4bytes IC 79 * 4bytes IC Quality 80 * 4bytes IZ 81 * 4bytes IZ Quality 82 * 83 *采样质量编码参见 IEC61850-7-3 质量的编码。 84 * 85 * 86 * 【9-1】APDU的内容定义(第27个字节开始): 87 * 1 savPdu 0x80(TAG) ASDU Length(asn1长度) 88 * 2 numOfAsdu No. of ASDUs(asn1长度) 89 * 3 Sequence Asdu1 Asdu1(46字节) 90 * 3 Sequence Asdu2 Asdu2(46字节) 91 * .... ... 92 * 93 * ASDU内容: 94 * ASDU 报头 01 ASDU 长度(44) 0x00 95 * 02 0x2c 96 * ASDU(基本数据集) 03 LNName(逻辑节点名总为02) 0x02 97 * 04 DataSetName(数据集名称为01或者FE) 0x01 98 * 05 LDName(逻辑设备名) ... 99 * 06 ... 100 * 07 额定相电流 ... 101 * 08 ... 102 * 09 额定中线电流 ... 103 * 10 ... 104 * 11 额定相电压 ... 105 * 12 ... 106 * 13 额定时延 ... 107 * 14 ... 108 * 15 A 相电流, 保护用 ... 109 * 16 ... 110 * 17 B 相电流, 保护用 ... 111 * 18 ... 112 * 19 C 相电流, 保护用 ... 113 * 20 ... 114 * 21 中线电流 ... 115 * 22 ... 116 * 23 A 相电流, 仪表用 ... 117 * 24 ... 118 * 25 B 相电流, 仪表用 ... 119 * 26 ... 120 * 27 C 相电流, 仪表用 ... 121 * 28 ... 122 * 29 A 相电压 ... 123 * 30 ... 124 * 31 B 相电压 ... 125 * 32 ... 126 * 33 C 相电压 ... 127 * 34 ... 128 * 35 零序电压 ... 129 * 36 ... 130 * 37 母线电压 ... 131 * 38 ... 132 * 39 状态字#1 ... 133 * 40 ... 134 * 41 状态字#2 ... 135 * 42 ... 136 * 43 采样计数器 ... 137 * 44 ... 138 * 45 采样率 ... 139 * 46 配置版本号 ... 140 * 141 * 142 */ 143 144 145 #ifndef __INCLUDE_SVPDU_PROTOCOL_H 146 #define __INCLUDE_SVPDU_PROTOCOL_H 147 148 149 /* 150 * 头文件 151 */ 152 #include "base_type.h" 153 154 155 #if defined (__cplusplus) 156 extern "C" { 157 #endif /* defined (__cplusplus) */ 158 159 160 /* 161 * 宏开关 162 */ 163 #ifndef SVPDU_IOBUFFER 164 #define SVPDU_IOBUFFER 165 #endif 166 167 /* 168 * 宏定义文件的读写操作,可以根据需要改写该接口,如重定义 169 * 为网口的recv\send、串口r\w等。 170 * 171 * _my_read_svpdu_bufn/_my_read_svpdu_bufn - svpdu的读写操作 172 * @pfd: 读写地址,可以为文件的fd、或者buffer地址等 173 * @buf: 缓冲区地址 174 * @count: 需要读写的字节数 175 * 176 */ 177 #if defined(SVPDU_IOFILE) 178 typedef int _my_svpdu_ioptr; 179 #define _my_read_svpdu_bufn(pfd, buf, count) \ 180 do { \ 181 if (read((pfd), (buf), (count)) <= 0) { \ 182 (pfd) = -1; \ 183 } \ 184 } while(0); 185 #define _my_write_svpdu_bufn(pfd, buf, count) \ 186 do { \ 187 if (write((pfd), (buf), (count)) <= 0) { \ 188 (pfd) = -1; \ 189 } \ 190 } while(0); 191 #define _my_check_svpdu_ptr(pfd) \ 192 (((pfd) != -1) && ((pfd) != 0)) 193 #elif defined(SVPDU_IOBUFFER) 194 typedef u8* _my_svpdu_ioptr; 195 #define _my_read_svpdu_bufn(pfd, buf, count) \ 196 do { \ 197 memcpy((buf), (pfd), (count)); \ 198 (pfd) += (count); \ 199 } while(0); 200 #define _my_write_svpdu_bufn(pfd, buf, count) \ 201 do { \ 202 memcpy((pfd), (buf), (count)); \ 203 (pfd) += (count); \ 204 } while(0); 205 #define _my_check_svpdu_ptr(pfd) \ 206 (((pfd) != -1) && ((pfd) != 0)) 207 #endif 208 209 210 /* 211 * 关于链路层svpdu报文头部信息的宏定义 212 */ 213 /* 214 * SVPDU_LPDU_TPID_VLAN - tpid的宏定义,标记的协议标识(Tag Protocol Identifier),虚拟局域网(Virtual Local 215 * Area Network); 216 */ 217 #define SVPDU_LPDU_TPID_VLAN 0x8100 218 /* 219 * svpdu_tci_get_pri/svpdu_tci_set_pri - 关于tci中PRI的取值/赋值的宏定义, 220 * PRI:User priority(优先权),占前3bit(BS3),如果不配置优先级,则应采用以下的缺省值为4 221 * (即二进制100); 222 */ 223 #define svpdu_tci_get_pri(tci) (((tci) & 0xE000) >> 13) 224 #define svpdu_tci_set_pri(tci,pri) ((((pri) << 13) | 0x1FFF) & ((tci) | 0xE000)) 225 /* 226 * svpdu_lpdu_tci_get_cfi/svpdu_tci_set_cfi - 关于tci中CFI的取值/赋值的宏定义;占PRI后面1bit; 227 * 228 */ 229 #define svpdu_tci_get_cfi(tci) (((tci) & 0x1000) >> 12) 230 #define svpdu_tci_set_cfi(tci,cfi) ((((cfi) << 12) | 0xEFFF) & ((tci) | 0x1000)) 231 /* 232 * svpdu_tci_get_vid/svpdu_tci_set_vid - 关于tci中VID的取值/赋值的宏定义;占之后剩下的12bit; 233 * 234 */ 235 #define svpdu_tci_get_vid(tci) ((tci) & 0x0FFF) 236 #define svpdu_tci_set_vid(tci,vid) (((tci) | 0xF000) & ((tci) | 0x0FFF)) 237 238 /* 239 * SVPDU_ETHER_TYPE_XXX - 关于ether type的宏定义 240 * SVPDU_ETHER_TYPE_81_GOOSE - IEC 61850-8-1 GOOSE 241 * SVPDU_ETHER_TYPE_81_GSE - IEC 61850-8-1 GSE 242 * SVPDU_ETHER_TYPE_91_OR_92 - IEC 61850-9-1/9-2 采样值 243 */ 244 #define SVPDU_ETHER_TYPE_81_GOOSE 0x88B8 245 #define SVPDU_ETHER_TYPE_81_GSE 0x88B9 246 #define SVPDU_ETHER_TYPE_91_OR_92 0x88BA 247 /* 248 * SVPDU_APPID_XXX - 关于appid的宏定义;APPID用以选择采样值信息并区分应用关联。APPID的值是APPID类型 249 * 码和实际标识的组合,APPID类型码被定义为其最高两位;为采样值保留的取值范围为 0x4000 250 * 到0x7fff;如果没有配置APPID,缺省值应为0x4000。缺省值被保留为表明缺少配置; 251 * SVPDU_APPID_TYPE_81_GOOSE_OR_GSE - IEC 61850-8-1 GOOSE/GSE APPID type; 252 * SVPDU_APPID_TYPE_91_OR_92 - IEC 61850-9-1/9-2 APPID type; 253 * SVPDU_APPID_DEFAULT - 缺省值; 254 * svpdu_appid_get_type - 取类型码值; 255 * svpdu_appid_set_type - 赋值类型码; 256 * 257 */ 258 #define SVPDU_APPID_TYPE_81_GOOSE_OR_GSE 0x00 259 #define SVPDU_APPID_TYPE_91_OR_92 0x01 260 #define SVPDU_APPID_DEFAULT 0x4000 261 #define svpdu_appid_get_type(appid) (((appid) & 0xC000) >> 14) 262 #define svpdu_appid_set_type(appid,type) ((((type) << 14) | 0x3FFF) & ((appid) | 0xC000)) 263 264 /* 265 * svpdu_lpdu_head - 9-2/9-1采样值(sample value)链路层(link layer)报文(pdu)头部信息。 266 * @des_mac: 目标地址(为FF:FF:FF:FF:FF:FF表示广播包),ISO/IEC8802-3标准地址; 267 * @src_mac: 源地址,ISO/IEC8802-3标准地址; 268 * @tpid: 标记的协议标识(Tag Protocol Identifier),有些报文没有该字段(非标准的); 269 * @tci: 标记的控制信息(Tag Control Information),有些报文没有该字段(非标准的); 270 * @ether_type: 以太网类型; 271 * @appid: 应用标识,标识不用的应用的采样值,连续几个包取得采样值时需要核对应用标识,否则会导致取得采 272 * 样值混乱; 273 * @epdu_length: 包括以APPID开始的以太网类型PDU在内的八位位组的数目,其值为8+m(m<1480); 274 * @reserve1: 保留字节,为0; 275 * @reserve2: 保留字节,为0; 276 * 277 * TPID 值:0x8100; 278 * TCI 值: 由三部分组成: 279 * PRI:User priority(优先权),占前3bit(BS3),应对user priority值进行配置,以区分采样值和定时苛 280 * 刻的、保护相关的GOOSE信息,或低优先级的总线负载。如果不配置优先级,则应采用缺省值(4); 281 * CFI:占PRI后面1bit,用于标识是否含有RIF信息;在以太网标记帧中长度/类型域后没有嵌入RIF域,值应 282 * 该为0;若值为1,则表明在ISO/IEC8802-3标记帧中,Length/Type域后接着内嵌的路由信息域(RIF); 283 * VID: 占之后剩下的12bit;为支持虚拟局域网是一种可选的机制,如果采用了这种机制,那么配置时应设 284 * 定虚拟局域网标识(VID)。另外,虚拟局域网标识VID 缺省值为0; 285 * 注:IEEE802.1Q允许应用带有一组优先级限制,高优先级帧应设置其优先级为4~7,低优先级帧则为1~3,优 286 * 先级1为未标记的帧,应避免采用优先级0,因为这会引起正常通信下不可预见的传输时延。优先级和虚拟 287 * 网标识(VID)的缺省值表:优先级和虚拟网标识(VID)的缺省值 288 * 服务 VID缺省值 优先级缺省值 289 * 采样值 0 4 290 * ETHER_TYPE 值: 以太网类型码16位表示,下表描述[以太网类型码]取值和[APPID类型码]取值; 291 * 表:分配的以太网类型码取值([APPID类型码]指APPID的最高两位) 292 * 应用 以太网类型码取值(16进制) APPID类型 293 * IEC61850-8-1GOOSE 88-B8 0 0 294 * IEC61850-8-1GSE管理 88-B9 0 0 295 * IEC61850-9-1采样值 88-BA 0 1 296 * IEC61850-9-2采样值 88-BA 0 1 297 * APPID 值:应用标识。APPID 用以选择采样值信息并区分应用关联。APPID的值是[APPID 类型码]和[实际标识] 298 * 的组合,APPID 类型码被定义为其最高两位(如表8 所定义)。因而采样值取如下值: 299 * 为采样值保留的取值范围为 0x4000~0x7fff。如果没有配置APPID,缺省值应为0x4000。缺省值被保留为 300 * 表明缺少配置。强烈推荐在同一系统内采用唯一的、面向数据源的采样值应用标识(SV APPID)。这应当由 301 * 配置系统强迫执行。 302 * 303 */ 304 struct svpdu_lpdu_head { 305 u8 des_mac[6]; 306 u8 src_mac[6]; 307 u16 tpid; 308 u16 tci; 309 u16 ether_type; 310 u16 appid; 311 u16 epdu_length; 312 u16 reserve1; 313 u16 reserve2; 314 }; 315 316 317 /* 318 * SVPDU_APDU_TAG_91/SVPDU_APDU_TAG_92 - 应用层协议标识,可用来区分该数据包类型; 319 */ 320 #define SVPDU_APDU_TAG_91 0x80 321 #define SVPDU_APDU_TAG_92 0x60 322 /* 323 * SVPDU_ASDUNUM_TAG_92 - asdu个数标识(9-2) 324 */ 325 #define SVPDU_ASDUNUM_TAG_92 0x80 326 /* 327 * SVPDU_SECURITY_TAG_92 - 安全信息标识(9-2) 328 */ 329 #define SVPDU_SECURITY_TAG_92 0x81 330 /* 331 * SVPDU_SEQUENCE_TAG_92 - 关于sequence of asdu的宏定义 332 */ 333 #define SVPDU_SEQUENCE_TAG_92 0xA2 334 335 /* 336 * svpdu_apdu_head - 9-2/9-1 svpdu中应用层(Application Layer)apdu头部信息; 337 * @apdu_tag: 应用层协议标识;为0x60时为9-2数据,为0x80时为9-1数据,该标识可以用来区分该数据包类型; 338 * @apdu_length: apdu数据包的长度值(从apdu_length的下一个数据开始计数);该数据本身是变长数据,采用 339 * ASN.1 基本编码规则(ISO/IEC 8825-1),在此约定该值不会超过0xffffff,最长为4字节,采用u32 340 * 类型数据存储; 341 * @asdu_num_tag: asdu个数标识;该值在9-2中为0x80,9-1中没有该标识; 342 * @asdu_num_length: [asdu个数]的长度值;标识num数据本身的长度信息,该值在9-2中一般为0x01,9-1中没有 343 * 该标识;该数据本身是变长数据,采用ASN.1编码;在此约定该值不会超过0xffffff,最长为4 344 * 字节(实际一般为1在字节),采用u32类型数据存储; 345 * @asdu_num_value: asdu个数;该值在9-2中,该数据是变长数据,长度(字节数)由asdu_num_length中的len 346 * 值(不是码)决定;在9-1中,固定采用2字节表示;在此直接用2字节表示,应为其值一般不能 347 * 超过2字节; 348 * @asdu_security_tag: 安全信息标识;该值在9-2中为0x81,为可选数据(一般不选);在9-1中无该数据; 349 * @asdu_security_length: 安全信息长度;采用ASN.1编码,变长,该项在9-2中为可选数据(一般不选),其值一 350 * 般为0;在9-1中无该数据;在此约定该值不会超过0xffffff,最长为4字节,采用u32类型数据存储; 351 * @asdu_sequence_tag: asdu序列信息标识;该值在9-2中为0xA2;在9-1中无该数据; 352 * @asdu_sequence_length: asdu序列信息长度;采用ASN.1编码,变长;在9-1中无该数据;在此约定该值不会超过 353 * 0xffffff,最长为4字节,采用u32类型数据存储; 354 * 355 * 注: 356 * 结构体中的ASN.1长度码统一采用u32表示,计算实际长度值时,需要解码;ASN.1长度计算方法如下: 357 * 长度值在[0x000000, 0x00007f],1个字节表示; 358 * 长度值在[0x000080, 0x0000ff],2个字节表示,第一个字节填0x81; 359 * 长度值在[0x000100, 0x00ffff],3个字节表示,第一个字节填0x82,后面用网络字节序; 360 * 长度值在[0x010000, 0xffffff],4个字节表示,第一个字节填0x83,后面用网络字节序; 361 * 一般情况下,asdu_security_tag、asdu_security_length没有; 362 * 61850编码规则基于ASN.1基本编码规则(BER),传输语法采用8位位组和面向“Big Endian(高字节在前)”的。 363 * 364 */ 365 struct svpdu_apdu_head { 366 u8 apdu_tag; 367 u32 apdu_length; 368 u8 asdu_num_tag; 369 u32 asdu_num_length; 370 u16 asdu_num_value; 371 u8 asdu_security_tag; 372 u32 asdu_security_length; 373 u8 asdu_sequence_tag; 374 u32 asdu_sequence_length; 375 }; 376 377 378 /* 379 * SVPDU_ASDU_TAG_92 - asdu标识(9-2), 380 */ 381 #define SVPDU_ASDU_TAG_92 0x30 382 /* 383 * SVPDU_ASDU_XXX_TAG_92 - 表示9-2中SVID、DATSET、SMPCNT、CONFREV、REFRTM、SMPSYNCH、SMPRATE以及 384 * SMPDATA项的标识; 385 */ 386 #define SVPDU_ASDU_SVID_TAG_92 0x80 387 #define SVPDU_ASDU_DATSET_TAG_92 0x81 388 #define SVPDU_ASDU_SMPCNT_TAG_92 0x82 389 #define SVPDU_ASDU_CONFREV_TAG_92 0x83 390 #define SVPDU_ASDU_REFRTM_TAG_92 0x84 391 #define SVPDU_ASDU_SMPSYNCH_TAG_92 0x85 392 #define SVPDU_ASDU_SMPRATE_TAG_92 0x86 393 #define SVPDU_ASDU_SMPDATA_TAG_92 0x87 394 395 /* 396 * svpdu_asdu_dat92 - IEC61850-9-2中的asdu详细信息;具体可以包括SVID、DATSET、SMPCNT、CONFREV、 397 * REFRTM、SMPSYNCH、SMPRATE以及SMPDATA项标记、长度、值的详细信息; 398 * @asdu_tag: asdu标记,详见宏定义值; 399 * @asdu_length: asdu总的长度信息; 400 * @svid_tag: svid标记,值为0表示不包含该项信息; 401 * @svid_length: svid信息长度; 402 * @svid_value: svid信息值,系统中唯一标识,该值为VisibleString类型; 403 * @datset_tag: datset标记,值为0表示不包含该项信息; 404 * @datset_length: datset信息长度; 405 * @datset_value: datset信息值,来自MSVC或者USVC的值,为ObjectReference类型; 406 * @smpcnt_tag: smpcnt标记,值为0表示不包含该项信息; 407 * @smpcnt_length: smpcnt信息长度; 408 * @smpcnt_value: smpcnt信息值; 409 * @confrev_tag: confrev标记,值为0表示不包含该项信息; 410 * @confrev_length: confrev信息长度; 411 * @confrev_value: confrev信息值; 412 * @refrtm_tag: refrtm标记,值为0表示不包含该项信息; 413 * @refrtm_length: refrtm信息长度; 414 * @refrtm_value: refrtm信息值; 415 * @smpsynch_tag: smpsynch标记,值为0表示不包含该项信息; 416 * @smpsynch_length: smpsynch信息长度; 417 * @smpsynch_value: smpsynch信息值; 418 * @smprate_tag: smprate标记,值为0表示不包含该项信息; 419 * @smprate_length: smprate信息长度; 420 * @smprate_value: smprate信息值; 421 * @smpdata_tag: smpdata标记,值为0表示不包含该项信息; 422 * @smpdata_length: smpdata信息长度; 423 * @smpdata_portnum: 采样值的端口数; 424 * @smpdata_values: 采样值详细; 425 * @smpdata_qualitys: 采样质量详细,为NULL表示没有质量信息; 426 * 427 * 注: 428 * 按照协议上来说,一个asdu包不可同时包含两个相同的项(即同时有两个svid或者smpdata项),在次如果存 429 * 在这种情况,第二个相同项将不再解析; 430 * 需要注意的是,在此程序中默认tag值为0时表示不包含该项信息。 431 * 432 */ 433 struct svpdu_asdu_dat92 { 434 u8 asdu_tag; 435 u32 asdu_length; 436 u8 svid_tag; 437 u32 svid_length; 438 u8 *svid_value; 439 u8 datset_tag; 440 u32 datset_length; 441 u8 *datset_value; 442 u8 smpcnt_tag; 443 u32 smpcnt_length; 444 u16 smpcnt_value; 445 u8 confrev_tag; 446 u32 confrev_length; 447 u32 confrev_value; 448 u8 refrtm_tag; 449 u32 refrtm_length; 450 u32 refrtm_value; 451 u8 smpsynch_tag; 452 u32 smpsynch_length; 453 u8 smpsynch_value; 454 u8 smprate_tag; 455 u32 smprate_length; 456 u16 smprate_value; 457 u8 smpdata_tag; 458 u32 smpdata_length; 459 u32 smpdata_portnum; 460 s32 *smpdata_values; 461 u32 *smpdata_qualitys; 462 }; 463 464 465 /* 466 * svpdu_asdu_dat91 - IEC61850-9-1中的asdu详细信息; 467 * @asdu_length:数据集长度;类型为16位无符号整数,值域为<0..65535>;长度域包含随后的数据集长度; 468 * 这个长度不包括长度域本身。按IEC 60044-8规定,长度总是44(十进制); 469 * 如果是自定义数据集,长度会变; 470 * @ln_name:逻辑节点名称;类型为8位枚举型,值域为<0..255>;逻辑节点名总为2; 471 * @dataset_name: 数据集名(DataSetName) 类型为8枚举型,值域为<0..255>; 472 * 数据集名是唯一的数字,用于标识数据集结构,也就是数据通道的分配; 473 * 这里允许的取值有01或0xFE(十进制254); 474 * 下表(参见表10)通用数据集(=01)中定义了DataSetName为01时数据通道到信号源的分配; 475 * @ld_name:逻辑设备名(LDName) 类型为16位无符号整数,值域为<0..65535>; 476 * 逻辑设备名在一个变电站中是唯一的,用于标志数据集的来源;逻辑设备名可以在安装时设置; 477 * @i_pp: 额定相电流;数据类型为16位无符号整数,值域为<0..65535>;如果不使用,用0替代它; 478 * @i_p0: 额定中线电流(零序电流);数据类型为16位无符号整数,值域为<0..65535>;如果不使用,用0替代它; 479 * @v_pp: 额定相电压;数据类型为16位无符号整数,值域为<0..65535>;如果不使用,用0替代它; 480 * @t_delay: 额定时延;数据类型为16位无符号整数,值域为<0..65535>; 481 * 给出模数转换和数据处理带来的延时的额定值,单位是sµ。 482 * 设发数据帧开始发出时刻为tc,这一帧数据表示的电流电压在一次侧出现的时刻为tp, 483 * 则延迟时间为tc-tp。 互感器额定延迟时间为500sµ,允许误差范围-100%~+10%; 484 * @smpdata_portnum: 采样数据端口数,该参数确定smpdata_values的空间大小; 485 * @smpdata_values:采样值数组;类型为16位整数,值域为<-32768..32767>。 12个数据通道给出各个信号源的瞬时值, 486 * 通道分配由数据集名决定,参见数据集名的说明。保护用相电流的比例因子由保护用电子式电流互感 487 * 器额定输出值确定,测量用相电流的比例因子由测量用电子式电流互感器额定输出值确定(参见表10)。 488 * @status_wordX:类型为16位布尔量集。参见【表11】、【表12】; 489 * 如果某个数据通道未使用,则其响应的状态标志置为无效, 490 * 数据通道内容置为0x0000。 如果一个传感器故障,其相应的状态标志置为无效, 491 * 并将需要维护标志(LPHD.PHHealth)置位。 在唤醒期间数据无效, 492 * 所有的数据无效标志和唤醒指示标志都置位。 同步脉冲丢失或无效标志在下面逻辑满足时置位: 493 * [[同步脉冲丢失 或 同步脉冲无效] 与 [合并器的内部时钟漂移大于额定相位误差限制的二分之1]]。 494 *@smp_cnt:类型为16位无符号整数,值域为<0..65535>。 495 * 这个16位采样计数器用于检查数据内容是否被连续刷新。每发送一个新的采样数据集,计数器增加1, 496 * 溢出后回到0重新开始计数。 当合并器使用同步脉冲时,合并器收到每个同步脉冲都将把采样计数器清零。 497 * 采样计数器为零的数据帧的数据对应同步脉冲发生时刻的一次电流电压。 498 *@smp_rate:数据速率;类型为8位无符号整数,值域为<0..255>;给出额定频率下每周波时间内输出的采样数据集数目,为0时无意义。 499 * 这里采样速率等于互感器的数据速率。 500 *@version:配置版本号;类型为8位无符号整数,值域为<0..255>。 在每次修改逻辑设备配置时增加1,缺省值为0。 501 * 502 * 【表10】:表DataSetName=01(通用应用)的数据通道映射 503 * 信号源 对象路径名 参考值 比例因子(见表 3) 504 * 数据通道1 A相电流.保护用 PhsATCTR.Amps 额定相电流 SCP 505 * 数据通道2 B相电流.保护用 PhsBTCTR.Amps 额定相电流 SCP 506 * 数据通道3 C相电流.保护用 PhsCTCTR.Amps 额定相电流 SCP 507 * 数据通道4 零序电流 NeutTCTR.Amps 额定零序电流 SCM 508 * 数据通道5 A相电流.测量用 PhsA2TCTR.Amps 额定相电流 SCM 509 * 数据通道6 B相电流.测量用 PhsB2TCTR.Amps 额定相电流 SCM 510 * 数据通道7 C相电流.测量用 PhsC2TCTR.Amps 额定相电流 SCM 511 * 数据通道8 A相电压 PhsATVTR.Volts 额定相电压 SV 512 * 数据通道9 B相电压 PhsBTVTR.Volts 额定相电压 SV 513 * 数据通道10 C相电压 PhsCTVTR.Volts 额定相电压 SV 514 * 数据通道11 零序电压 NeutTVTR.Volts 额定相电压 SV 515 * 数据通道12 母线电压 BBTVTR.Volts 额定相电压 SV 516 * 注:对象路径名参见IEC 61850-9-1; DataSetName为0xFE时表示特殊应用数据集,在上表的通道映射 517 * 不能满足应用要求时使用。这时合并器将通过一定形式将数据集定义提供给二次设备;DataSetName 518 * 的值不能在运行时改变,也就时说在出厂前的设计和配置时便确定数据通道的分配。 519 * 520 * 【表11】:状态字1(StatusWord#1) 521 * 解释 备注 522 * 第0位 需要维护(LPHD.PHHealth) 0:正常 523 * 1:告警(需要维护) 524 * 第1位 模式(LLN0.Mode) 0:正常运行 525 * 1:测试 526 * 第2位 唤醒期间指示 唤醒期间数据无效指示 0:正常,数据有效 在唤醒期间被置位 527 * 1:唤醒期间,数据无效 528 * 第3位 合并器同步方式 0:不能使用插值算法同步 529 * 1:可以使用插值算法同步 530 * 第4位 合并器同步标志 0:采样已同步 如果使用插值算法,这个位将总是1 531 * 1:同步丢失或无效 532 * 第5位 数据通道1无效标志 0:数据有效 533 * 1:数据无效 534 * 第6位 数据通道2无效标志 0:数据有效 535 * 1:数据无效 536 * 第7位 数据通道3无效标志 0:数据有效 537 * 1:数据无效 538 * 第8位 数据通道4无效标志 0:数据有效 539 * 1:数据无效 540 * 第9位 数据通道5无效标志 0:数据有效 541 * 1:数据无效 542 * 第10位 数据通道6无效标志 0:数据有效 543 * 1:数据无效 544 * 第11位 数据通道7无效标志 0:数据有效 545 * 1:数据无效 546 * 第12位 电流传感器类型 0:电流值 在使用Rogowski线圈且没有积分环节时置位。 547 * 1:电流的导数 548 * 第13位 量程标志 0:保护电流比例因子SCP=0x01CF 549 * 1:保护电流比例因子SCP=0x00E7 550 * 第14位 备用 551 * 第15位 备用 552 * 553 * 【表12】:状态字2(StatusWord#2) 554 * 解释 备注 555 * 第0位 数据通道8无效标志 0:数据有效 556 * 1:数据无效 557 * 第1位 数据通道9无效标志 0:数据有效 558 * 1:数据无效 559 * 第2位 数据通道10无效标志 0:数据有效 560 * 1:数据无效 561 * 第3位 数据通道11无效标志 0:数据有效 562 * 1:数据无效 563 * 第4位 数据通道12无效标志 0:数据有效 564 * 1:数据无效 565 * 第5-7位 备用 566 * 第8-15位 自定义 567 * 568 * 569 */ 570 struct svpdu_asdu_dat91 { 571 u16 asdu_length; 572 u8 ln_name; 573 u8 dataset_name; 574 u16 ld_name; 575 u16 i_pp; 576 u16 i_p0; 577 u16 u_pp; 578 u16 t_delay; 579 u32 smpdata_portnum; 580 s16 *smpdata_values; 581 u16 status_word1; 582 u16 status_word2; 583 u16 smp_cnt; 584 u8 smp_rate; 585 u8 version; 586 }; 587 588 /* 589 * read_svpdu_lpdu_head - 取得链路层svpdu报文头部信息,没有读到的数据为其原来的值 590 * @pfd: 输入输出参数,地址 591 * @len: 输入参数,数据缓冲区长度; 592 * @head: 输出参数,svpdu_lpdu_head值 593 * @counter: 输出参数,读取的字节计数器; 594 * 595 * 读成功返回当前读pfd地址,否则返回NULL; 596 * 597 */ 598 _my_svpdu_ioptr read_svpdu_lpdu_head(_my_svpdu_ioptr pfd, int len, struct svpdu_lpdu_head *head, int *counter); 599 600 601 /* 602 * read_svpdu_apdu_head - 取得svpdu报文中apdu头部信息,没有读到的数据为其原来的值 603 * @pfd: 输入输出参数,地址 604 * @len: 输入参数,数据缓冲区长度; 605 * @head: 输出参数,svpdu_lpdu_head值 606 * @counter: 输出参数,读取的字节计数器; 607 * 608 * 读成功返回当前读pfd地址,否则返回NULL; 609 * 610 */ 611 _my_svpdu_ioptr read_svpdu_apdu_head(_my_svpdu_ioptr pfd, int len, struct svpdu_apdu_head *head, int *counter); 612 613 /* 614 * read_svpdu_asdu_dat92 - 读取9-2-asdu详细值; 615 * @pfd: 输入输出参数,地址 616 * @len: 输入参数,数据缓冲区长度; 617 * @dat92: 输出参数,asdu详细值; 618 * @smpquality_enable: 是否有质量信息; 619 * @counter: 输出参数,读取的字节计数器; 620 * 621 * 读成功返回当前读pfd地址,否则返回NULL; 622 * 623 * 读取过程中可能会利用动态创建空间以保存svid_value、datset_value、smpdata_values、smpdata_qualitys数据; 624 * 625 */ 626 _my_svpdu_ioptr read_svpdu_asdu_dat92(_my_svpdu_ioptr pfd, int len, struct svpdu_asdu_dat92 *dat92, int smpquality_enable, int *counter); 627 628 629 /* 630 * init_svpdu_asdu_dat92 - 初始化Dat92结构体; 631 * @dat92: 输入输出参数,asdu详细值; 632 * @setdefaultval: 参数是否赋默认值; 633 * 634 * 初始化成功返回当前dat92结构体地址,否则返回NULL; 635 * 636 */ 637 struct svpdu_asdu_dat92 * init_svpdu_asdu_dat92(struct svpdu_asdu_dat92 *dat92, int setdefaultval); 638 /* 639 * free_svpdu_asdu_dat92 - 释放Dat92结构体; 640 * @dat92: 输入输出参数,asdu详细值; 641 * 642 * 初始化成功返回返回NULL,否则返回当前dat92结构体地址; 643 * 644 */ 645 struct svpdu_asdu_dat92 * free_svpdu_asdu_dat92(struct svpdu_asdu_dat92 *dat92); 646 647 /* 648 * read_svpdu_asdu_dat91 - 读取9-1-asdu详细值; 649 * @pfd: 输入输出参数,地址 650 * @len: 输入参数,数据缓冲区长度; 651 * @dat91: 输出参数,asdu详细值; 652 * @counter: 输出参数,读取的字节计数器; 653 * 654 * 读成功返回当前读pfd地址,否则返回NULL; 655 * 656 * 读取过程中可能会利用动态创建空间以保存smpdata_values数据; 657 * 658 */ 659 _my_svpdu_ioptr read_svpdu_asdu_dat91(_my_svpdu_ioptr pfd, int len, struct svpdu_asdu_dat91 *dat91, int *counter); 660 661 /* 662 * init_svpdu_asdu_dat91 - 初始化Dat91结构体; 663 * @dat92: 输入输出参数,asdu详细值; 664 * 665 * 初始化成功返回当前dat91结构体地址,否则返回NULL; 666 * 667 */ 668 struct svpdu_asdu_dat91 * init_svpdu_asdu_dat91(struct svpdu_asdu_dat91 *dat91); 669 /* 670 * free_svpdu_asdu_dat91 - 释放Dat91结构体; 671 * @dat91: 输入输出参数,asdu详细值; 672 * 673 * 初始化成功返回返回NULL,否则返回当前dat91结构体地址; 674 * 675 */ 676 struct svpdu_asdu_dat91 * free_svpdu_asdu_dat91(struct svpdu_asdu_dat91 *dat91); 677 678 679 /* 680 * write_svpdu_lpdu_head - 写svpdu_lpdu_head到文件中 681 * @pfd: 输入参数,写地址; 682 * @head:输入参数,svpdu_lpdu_head结构体; 683 * @counter: 输出参数,成功写入的字节个数; 684 * 685 * 返回当前pfd指针,写失败返回NULL 686 * 687 */ 688 _my_svpdu_ioptr write_svpdu_lpdu_head(_my_svpdu_ioptr pfd, struct svpdu_lpdu_head *head, int *counter); 689 690 691 /* 692 * write_svpdu_apdu_head - 写svpdu_apdu_head到文件中 693 * @pfd: 输入参数,写地址; 694 * @head:输入参数,svpdu_apdu_head结构体; 695 * @counter: 输出参数,成功写入的字节个数; 696 * 697 * 返回当前pfd指针,写失败返回NULL 698 * 699 */ 700 _my_svpdu_ioptr write_svpdu_apdu_head(_my_svpdu_ioptr pfd, struct svpdu_apdu_head *head, int *counter); 701 702 703 /* 704 * write_svpdu_asdu_dat92 - 写svpdu_asdu_dat92到文件中 705 * @pfd: 输入参数,写地址; 706 * @dat92:输入参数,svpdu_asdu_dat92结构体; 707 * @counter: 输出参数,成功写入的字节个数; 708 * 709 * 返回当前pfd指针,写失败返回NULL 710 * 711 */ 712 _my_svpdu_ioptr write_svpdu_asdu_dat92(_my_svpdu_ioptr pfd, struct svpdu_asdu_dat92 *dat92, int *counter); 713 714 715 /* 716 * write_svpdu_asdu_dat91 - 写svpdu_asdu_dat91到文件中 717 * @pfd: 输入参数,写地址; 718 * @dat91:输入参数,svpdu_asdu_dat91结构体; 719 * @counter: 输出参数,成功写入的字节个数; 720 * 721 * 返回当前pfd指针,写失败返回NULL 722 * 723 */ 724 _my_svpdu_ioptr write_svpdu_asdu_dat91(_my_svpdu_ioptr pfd, struct svpdu_asdu_dat91 *dat91, int *counter); 725 726 727 /* 728 * print_svpdu_lpdu_head - 打印数据 729 * @head: 数据包 730 * 731 */ 732 void print_svpdu_lpdu_head(struct svpdu_lpdu_head * head); 733 734 /* 735 * print_svpdu_apdu_head - 打印数据 736 * @head: 数据包 737 * 738 */ 739 void print_svpdu_apdu_head(struct svpdu_apdu_head* head); 740 741 /* 742 * print_svpdu_asdu_dat92 - 打印数据 743 * @dat92: 数据包 744 * @smpquality_enable: 是否包含质量信息 745 * 746 */ 747 void print_svpdu_asdu_dat92(struct svpdu_asdu_dat92* dat92, u8 smpquality_enable); 748 749 /* 750 * print_svpdu_asdu_dat91 - 打印数据 751 * @dat92: 数据包 752 * @smpquality_enable: 是否包含质量信息 753 * 754 */ 755 void print_svpdu_asdu_dat91(struct svpdu_asdu_dat91* dat91); 756 757 758 #pragma pack(pop) 759 760 #if defined (__cplusplus) 761 } 762 #endif /* defined (__cplusplus) */ 763 764 765 #endif /* __INCLUDE_IEC61850SV_PROTOCOL_H */