The goal of this software is to automatically generate C/C++ code which reads and writes GOOSE and Sampled Value packets. Any valid IEC 61850 Substation Configuration Description (SCD) file, describing GOOSE and/or SV communications, can be used as the input. The output code is lightweight and platform-independent, so it can run on a variety of devices, including low-cost microcontrollers. It\'s ideal for rapid-prototyping new protection and control systems that require communications. This mbed project is a simple example of this functionality. Other code: https://github.com/stevenblair/rapid61850 Project homepage: http://personal.strath.ac.uk/steven.m.blair/

Committer:
sblair
Date:
Fri Oct 07 13:48:18 2011 +0000
Revision:
1:9399d44c2b1a
Parent:
0:230c10b228ea

        

Who changed what in which revision?

UserRevisionLine numberNew contents of line
sblair 1:9399d44c2b1a 1 /**
sblair 1:9399d44c2b1a 2 * Rapid-prototyping protection schemes with IEC 61850
sblair 1:9399d44c2b1a 3 *
sblair 1:9399d44c2b1a 4 * Copyright (c) 2011 Steven Blair
sblair 1:9399d44c2b1a 5 *
sblair 1:9399d44c2b1a 6 * This program is free software; you can redistribute it and/or
sblair 1:9399d44c2b1a 7 * modify it under the terms of the GNU General Public License
sblair 1:9399d44c2b1a 8 * as published by the Free Software Foundation; either version 2
sblair 1:9399d44c2b1a 9 * of the License, or (at your option) any later version.
sblair 1:9399d44c2b1a 10
sblair 1:9399d44c2b1a 11 * This program is distributed in the hope that it will be useful,
sblair 1:9399d44c2b1a 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
sblair 1:9399d44c2b1a 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
sblair 1:9399d44c2b1a 14 * GNU General Public License for more details.
sblair 1:9399d44c2b1a 15
sblair 1:9399d44c2b1a 16 * You should have received a copy of the GNU General Public License
sblair 1:9399d44c2b1a 17 * along with this program; if not, write to the Free Software
sblair 1:9399d44c2b1a 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
sblair 1:9399d44c2b1a 19 */
sblair 1:9399d44c2b1a 20
sblair 0:230c10b228ea 21 #include "gseDecodeBasic.h"
sblair 0:230c10b228ea 22 #include "ied.h"
sblair 0:230c10b228ea 23 #include "gseDecode.h"
sblair 0:230c10b228ea 24
sblair 0:230c10b228ea 25
sblair 0:230c10b228ea 26
sblair 0:230c10b228ea 27 int ber_decode_myAnalogValue(unsigned char *buf, struct myAnalogValue *myAnalogValue) {
sblair 0:230c10b228ea 28 int offset = 0;
sblair 0:230c10b228ea 29
sblair 0:230c10b228ea 30 if (buf[offset++] == 0xA2) {
sblair 0:230c10b228ea 31 offset += getLengthFieldSize(buf[offset]);
sblair 0:230c10b228ea 32
sblair 0:230c10b228ea 33 offset += BER_DECODE_CTYPE_FLOAT32(&buf[offset], &myAnalogValue->f);
sblair 0:230c10b228ea 34 }
sblair 0:230c10b228ea 35
sblair 0:230c10b228ea 36 return offset;
sblair 0:230c10b228ea 37 }
sblair 0:230c10b228ea 38 int ber_decode_ScaledValueConfig(unsigned char *buf, struct ScaledValueConfig *ScaledValueConfig) {
sblair 0:230c10b228ea 39 int offset = 0;
sblair 0:230c10b228ea 40
sblair 0:230c10b228ea 41 if (buf[offset++] == 0xA2) {
sblair 0:230c10b228ea 42 offset += getLengthFieldSize(buf[offset]);
sblair 0:230c10b228ea 43
sblair 0:230c10b228ea 44 offset += BER_DECODE_CTYPE_FLOAT32(&buf[offset], &ScaledValueConfig->scaleFactor);
sblair 0:230c10b228ea 45 offset += BER_DECODE_CTYPE_FLOAT32(&buf[offset], &ScaledValueConfig->offset);
sblair 0:230c10b228ea 46 }
sblair 0:230c10b228ea 47
sblair 0:230c10b228ea 48 return offset;
sblair 0:230c10b228ea 49 }
sblair 0:230c10b228ea 50 int ber_decode_myVector(unsigned char *buf, struct myVector *myVector) {
sblair 0:230c10b228ea 51 int offset = 0;
sblair 0:230c10b228ea 52
sblair 0:230c10b228ea 53 if (buf[offset++] == 0xA2) {
sblair 0:230c10b228ea 54 offset += getLengthFieldSize(buf[offset]);
sblair 0:230c10b228ea 55
sblair 0:230c10b228ea 56 offset += ber_decode_myAnalogValue(&buf[offset], &myVector->mag);
sblair 0:230c10b228ea 57 offset += ber_decode_myAnalogValue(&buf[offset], &myVector->ang);
sblair 0:230c10b228ea 58 }
sblair 0:230c10b228ea 59
sblair 0:230c10b228ea 60 return offset;
sblair 0:230c10b228ea 61 }
sblair 0:230c10b228ea 62 int ber_decode_simpleVector(unsigned char *buf, struct simpleVector *simpleVector) {
sblair 0:230c10b228ea 63 int offset = 0;
sblair 0:230c10b228ea 64
sblair 0:230c10b228ea 65 if (buf[offset++] == 0xA2) {
sblair 0:230c10b228ea 66 offset += getLengthFieldSize(buf[offset]);
sblair 0:230c10b228ea 67
sblair 0:230c10b228ea 68 offset += ber_decode_myAnalogValue(&buf[offset], &simpleVector->mag);
sblair 0:230c10b228ea 69 offset += ber_decode_myAnalogValue(&buf[offset], &simpleVector->ang);
sblair 0:230c10b228ea 70 }
sblair 0:230c10b228ea 71
sblair 0:230c10b228ea 72 return offset;
sblair 0:230c10b228ea 73 }
sblair 0:230c10b228ea 74 int ber_decode_myMod(unsigned char *buf, struct myMod *myMod) {
sblair 0:230c10b228ea 75 int offset = 0;
sblair 0:230c10b228ea 76
sblair 0:230c10b228ea 77 if (buf[offset++] == 0xA2) {
sblair 0:230c10b228ea 78 offset += getLengthFieldSize(buf[offset]);
sblair 0:230c10b228ea 79
sblair 0:230c10b228ea 80 offset += BER_DECODE_CTYPE_ENUM(&buf[offset], (CTYPE_ENUM *) &myMod->ctlVal);
sblair 0:230c10b228ea 81 offset += BER_DECODE_CTYPE_ENUM(&buf[offset], (CTYPE_ENUM *) &myMod->stVal);
sblair 0:230c10b228ea 82 offset += BER_DECODE_CTYPE_QUALITY(&buf[offset], &myMod->q);
sblair 0:230c10b228ea 83 offset += BER_DECODE_CTYPE_TIMESTAMP(&buf[offset], &myMod->t);
sblair 0:230c10b228ea 84 }
sblair 0:230c10b228ea 85
sblair 0:230c10b228ea 86 return offset;
sblair 0:230c10b228ea 87 }
sblair 0:230c10b228ea 88 int ber_decode_myHealth(unsigned char *buf, struct myHealth *myHealth) {
sblair 0:230c10b228ea 89 int offset = 0;
sblair 0:230c10b228ea 90
sblair 0:230c10b228ea 91 if (buf[offset++] == 0xA2) {
sblair 0:230c10b228ea 92 offset += getLengthFieldSize(buf[offset]);
sblair 0:230c10b228ea 93
sblair 0:230c10b228ea 94 offset += BER_DECODE_CTYPE_ENUM(&buf[offset], (CTYPE_ENUM *) &myHealth->stVal);
sblair 0:230c10b228ea 95 }
sblair 0:230c10b228ea 96
sblair 0:230c10b228ea 97 return offset;
sblair 0:230c10b228ea 98 }
sblair 0:230c10b228ea 99 int ber_decode_myBeh(unsigned char *buf, struct myBeh *myBeh) {
sblair 0:230c10b228ea 100 int offset = 0;
sblair 0:230c10b228ea 101
sblair 0:230c10b228ea 102 if (buf[offset++] == 0xA2) {
sblair 0:230c10b228ea 103 offset += getLengthFieldSize(buf[offset]);
sblair 0:230c10b228ea 104
sblair 0:230c10b228ea 105 offset += BER_DECODE_CTYPE_ENUM(&buf[offset], (CTYPE_ENUM *) &myBeh->stVal);
sblair 0:230c10b228ea 106 }
sblair 0:230c10b228ea 107
sblair 0:230c10b228ea 108 return offset;
sblair 0:230c10b228ea 109 }
sblair 0:230c10b228ea 110 int ber_decode_myINS(unsigned char *buf, struct myINS *myINS) {
sblair 0:230c10b228ea 111 int offset = 0;
sblair 0:230c10b228ea 112
sblair 0:230c10b228ea 113 if (buf[offset++] == 0xA2) {
sblair 0:230c10b228ea 114 offset += getLengthFieldSize(buf[offset]);
sblair 0:230c10b228ea 115
sblair 0:230c10b228ea 116 offset += BER_DECODE_CTYPE_INT32(&buf[offset], &myINS->stVal);
sblair 0:230c10b228ea 117 }
sblair 0:230c10b228ea 118
sblair 0:230c10b228ea 119 return offset;
sblair 0:230c10b228ea 120 }
sblair 0:230c10b228ea 121 int ber_decode_myLPL(unsigned char *buf, struct myLPL *myLPL) {
sblair 0:230c10b228ea 122 int offset = 0;
sblair 0:230c10b228ea 123
sblair 0:230c10b228ea 124 if (buf[offset++] == 0xA2) {
sblair 0:230c10b228ea 125 offset += getLengthFieldSize(buf[offset]);
sblair 0:230c10b228ea 126
sblair 0:230c10b228ea 127 offset += BER_DECODE_CTYPE_VISSTRING255(&buf[offset], &myLPL->ldNs);
sblair 0:230c10b228ea 128 offset += BER_DECODE_CTYPE_VISSTRING255(&buf[offset], &myLPL->configRev);
sblair 0:230c10b228ea 129 }
sblair 0:230c10b228ea 130
sblair 0:230c10b228ea 131 return offset;
sblair 0:230c10b228ea 132 }
sblair 0:230c10b228ea 133 int ber_decode_myDPL(unsigned char *buf, struct myDPL *myDPL) {
sblair 0:230c10b228ea 134 int offset = 0;
sblair 0:230c10b228ea 135
sblair 0:230c10b228ea 136 if (buf[offset++] == 0xA2) {
sblair 0:230c10b228ea 137 offset += getLengthFieldSize(buf[offset]);
sblair 0:230c10b228ea 138
sblair 0:230c10b228ea 139 offset += BER_DECODE_CTYPE_VISSTRING255(&buf[offset], &myDPL->vendor);
sblair 0:230c10b228ea 140 offset += BER_DECODE_CTYPE_VISSTRING255(&buf[offset], &myDPL->hwRev);
sblair 0:230c10b228ea 141 }
sblair 0:230c10b228ea 142
sblair 0:230c10b228ea 143 return offset;
sblair 0:230c10b228ea 144 }
sblair 0:230c10b228ea 145 int ber_decode_myPos(unsigned char *buf, struct myPos *myPos) {
sblair 0:230c10b228ea 146 int offset = 0;
sblair 0:230c10b228ea 147
sblair 0:230c10b228ea 148 if (buf[offset++] == 0xA2) {
sblair 0:230c10b228ea 149 offset += getLengthFieldSize(buf[offset]);
sblair 0:230c10b228ea 150
sblair 0:230c10b228ea 151 offset += BER_DECODE_CTYPE_DBPOS(&buf[offset], &myPos->stVal);
sblair 0:230c10b228ea 152 offset += BER_DECODE_CTYPE_QUALITY(&buf[offset], &myPos->q);
sblair 0:230c10b228ea 153 offset += BER_DECODE_CTYPE_TIMESTAMP(&buf[offset], &myPos->t);
sblair 0:230c10b228ea 154 offset += BER_DECODE_CTYPE_BOOLEAN(&buf[offset], &myPos->ctlVal);
sblair 0:230c10b228ea 155 }
sblair 0:230c10b228ea 156
sblair 0:230c10b228ea 157 return offset;
sblair 0:230c10b228ea 158 }
sblair 0:230c10b228ea 159 int ber_decode_mySPS(unsigned char *buf, struct mySPS *mySPS) {
sblair 0:230c10b228ea 160 int offset = 0;
sblair 0:230c10b228ea 161
sblair 0:230c10b228ea 162 if (buf[offset++] == 0xA2) {
sblair 0:230c10b228ea 163 offset += getLengthFieldSize(buf[offset]);
sblair 0:230c10b228ea 164
sblair 0:230c10b228ea 165 offset += BER_DECODE_CTYPE_INT32(&buf[offset], &mySPS->stVal);
sblair 0:230c10b228ea 166 offset += BER_DECODE_CTYPE_QUALITY(&buf[offset], &mySPS->q);
sblair 0:230c10b228ea 167 offset += BER_DECODE_CTYPE_TIMESTAMP(&buf[offset], &mySPS->t);
sblair 0:230c10b228ea 168 }
sblair 0:230c10b228ea 169
sblair 0:230c10b228ea 170 return offset;
sblair 0:230c10b228ea 171 }
sblair 0:230c10b228ea 172 int ber_decode_myMV(unsigned char *buf, struct myMV *myMV) {
sblair 0:230c10b228ea 173 int offset = 0;
sblair 0:230c10b228ea 174
sblair 0:230c10b228ea 175 if (buf[offset++] == 0xA2) {
sblair 0:230c10b228ea 176 offset += getLengthFieldSize(buf[offset]);
sblair 0:230c10b228ea 177
sblair 0:230c10b228ea 178 offset += ber_decode_myAnalogValue(&buf[offset], &myMV->mag);
sblair 0:230c10b228ea 179 offset += BER_DECODE_CTYPE_QUALITY(&buf[offset], &myMV->q);
sblair 0:230c10b228ea 180 offset += BER_DECODE_CTYPE_TIMESTAMP(&buf[offset], &myMV->t);
sblair 0:230c10b228ea 181 offset += ber_decode_ScaledValueConfig(&buf[offset], &myMV->sVC);
sblair 0:230c10b228ea 182 }
sblair 0:230c10b228ea 183
sblair 0:230c10b228ea 184 return offset;
sblair 0:230c10b228ea 185 }
sblair 0:230c10b228ea 186 int ber_decode_simpleMV(unsigned char *buf, struct simpleMV *simpleMV) {
sblair 0:230c10b228ea 187 int offset = 0;
sblair 0:230c10b228ea 188
sblair 0:230c10b228ea 189 if (buf[offset++] == 0xA2) {
sblair 0:230c10b228ea 190 offset += getLengthFieldSize(buf[offset]);
sblair 0:230c10b228ea 191
sblair 0:230c10b228ea 192 offset += BER_DECODE_CTYPE_FLOAT32(&buf[offset], &simpleMV->mag);
sblair 0:230c10b228ea 193 offset += BER_DECODE_CTYPE_QUALITY(&buf[offset], &simpleMV->q);
sblair 0:230c10b228ea 194 offset += BER_DECODE_CTYPE_TIMESTAMP(&buf[offset], &simpleMV->t);
sblair 0:230c10b228ea 195 offset += ber_decode_ScaledValueConfig(&buf[offset], &simpleMV->sVC);
sblair 0:230c10b228ea 196 }
sblair 0:230c10b228ea 197
sblair 0:230c10b228ea 198 return offset;
sblair 0:230c10b228ea 199 }
sblair 0:230c10b228ea 200 int ber_decode_simpleCMV(unsigned char *buf, struct simpleCMV *simpleCMV) {
sblair 0:230c10b228ea 201 int offset = 0;
sblair 0:230c10b228ea 202
sblair 0:230c10b228ea 203 if (buf[offset++] == 0xA2) {
sblair 0:230c10b228ea 204 offset += getLengthFieldSize(buf[offset]);
sblair 0:230c10b228ea 205
sblair 0:230c10b228ea 206 offset += ber_decode_simpleVector(&buf[offset], &simpleCMV->cVal);
sblair 0:230c10b228ea 207 offset += BER_DECODE_CTYPE_QUALITY(&buf[offset], &simpleCMV->q);
sblair 0:230c10b228ea 208 offset += BER_DECODE_CTYPE_TIMESTAMP(&buf[offset], &simpleCMV->t);
sblair 0:230c10b228ea 209 }
sblair 0:230c10b228ea 210
sblair 0:230c10b228ea 211 return offset;
sblair 0:230c10b228ea 212 }
sblair 0:230c10b228ea 213 int ber_decode_simpleWYE(unsigned char *buf, struct simpleWYE *simpleWYE) {
sblair 0:230c10b228ea 214 int offset = 0;
sblair 0:230c10b228ea 215
sblair 0:230c10b228ea 216 if (buf[offset++] == 0xA2) {
sblair 0:230c10b228ea 217 offset += getLengthFieldSize(buf[offset]);
sblair 0:230c10b228ea 218
sblair 0:230c10b228ea 219 offset += ber_decode_simpleCMV(&buf[offset], &simpleWYE->phsA);
sblair 0:230c10b228ea 220 offset += ber_decode_simpleCMV(&buf[offset], &simpleWYE->phsB);
sblair 0:230c10b228ea 221 offset += ber_decode_simpleCMV(&buf[offset], &simpleWYE->phsC);
sblair 0:230c10b228ea 222 }
sblair 0:230c10b228ea 223
sblair 0:230c10b228ea 224 return offset;
sblair 0:230c10b228ea 225 }
sblair 0:230c10b228ea 226 int ber_decode_myCMV(unsigned char *buf, struct myCMV *myCMV) {
sblair 0:230c10b228ea 227 int offset = 0;
sblair 0:230c10b228ea 228
sblair 0:230c10b228ea 229 if (buf[offset++] == 0xA2) {
sblair 0:230c10b228ea 230 offset += getLengthFieldSize(buf[offset]);
sblair 0:230c10b228ea 231
sblair 0:230c10b228ea 232 offset += ber_decode_myVector(&buf[offset], &myCMV->cVal);
sblair 0:230c10b228ea 233 offset += BER_DECODE_CTYPE_QUALITY(&buf[offset], &myCMV->q);
sblair 0:230c10b228ea 234 offset += BER_DECODE_CTYPE_TIMESTAMP(&buf[offset], &myCMV->t);
sblair 0:230c10b228ea 235 }
sblair 0:230c10b228ea 236
sblair 0:230c10b228ea 237 return offset;
sblair 0:230c10b228ea 238 }
sblair 0:230c10b228ea 239 int ber_decode_mySEQ(unsigned char *buf, struct mySEQ *mySEQ) {
sblair 0:230c10b228ea 240 int offset = 0;
sblair 0:230c10b228ea 241
sblair 0:230c10b228ea 242 if (buf[offset++] == 0xA2) {
sblair 0:230c10b228ea 243 offset += getLengthFieldSize(buf[offset]);
sblair 0:230c10b228ea 244
sblair 0:230c10b228ea 245 offset += ber_decode_myCMV(&buf[offset], &mySEQ->c1);
sblair 0:230c10b228ea 246 offset += ber_decode_myCMV(&buf[offset], &mySEQ->c2);
sblair 0:230c10b228ea 247 offset += ber_decode_myCMV(&buf[offset], &mySEQ->c3);
sblair 0:230c10b228ea 248 offset += BER_DECODE_CTYPE_ENUM(&buf[offset], (CTYPE_ENUM *) &mySEQ->seqT);
sblair 0:230c10b228ea 249 }
sblair 0:230c10b228ea 250
sblair 0:230c10b228ea 251 return offset;
sblair 0:230c10b228ea 252 }
sblair 0:230c10b228ea 253 int ber_decode_mySAV(unsigned char *buf, struct mySAV *mySAV) {
sblair 0:230c10b228ea 254 int offset = 0;
sblair 0:230c10b228ea 255
sblair 0:230c10b228ea 256 if (buf[offset++] == 0xA2) {
sblair 0:230c10b228ea 257 offset += getLengthFieldSize(buf[offset]);
sblair 0:230c10b228ea 258
sblair 0:230c10b228ea 259 offset += ber_decode_myAnalogValue(&buf[offset], &mySAV->instMag);
sblair 0:230c10b228ea 260 offset += BER_DECODE_CTYPE_QUALITY(&buf[offset], &mySAV->q);
sblair 0:230c10b228ea 261 }
sblair 0:230c10b228ea 262
sblair 0:230c10b228ea 263 return offset;
sblair 0:230c10b228ea 264 }
sblair 0:230c10b228ea 265 int ber_decode_simpleSAV(unsigned char *buf, struct simpleSAV *simpleSAV) {
sblair 0:230c10b228ea 266 int offset = 0;
sblair 0:230c10b228ea 267
sblair 0:230c10b228ea 268 if (buf[offset++] == 0xA2) {
sblair 0:230c10b228ea 269 offset += getLengthFieldSize(buf[offset]);
sblair 0:230c10b228ea 270
sblair 0:230c10b228ea 271 offset += ber_decode_myAnalogValue(&buf[offset], &simpleSAV->instMag);
sblair 0:230c10b228ea 272 offset += BER_DECODE_CTYPE_QUALITY(&buf[offset], &simpleSAV->q);
sblair 0:230c10b228ea 273 }
sblair 0:230c10b228ea 274
sblair 0:230c10b228ea 275 return offset;
sblair 0:230c10b228ea 276 }
sblair 0:230c10b228ea 277 int ber_decode_Positions_RSYN_1(unsigned char *buf) {
sblair 0:230c10b228ea 278 int offset = 0;
sblair 0:230c10b228ea 279
sblair 0:230c10b228ea 280 offset += ber_decode_myAnalogValue(&buf[offset], &D1Q1SB4.S1.C1.RSYN_1.gse_inputs.instMag_1);
sblair 0:230c10b228ea 281 offset += ber_decode_myPos(&buf[offset], &D1Q1SB4.S1.C1.RSYN_1.gse_inputs.Pos_1);
sblair 0:230c10b228ea 282 offset += ber_decode_myPos(&buf[offset], &D1Q1SB4.S1.C1.RSYN_1.gse_inputs.Pos_2);
sblair 0:230c10b228ea 283 offset += BER_DECODE_CTYPE_ENUM(&buf[offset], (CTYPE_ENUM *) &D1Q1SB4.S1.C1.RSYN_1.gse_inputs.stVal_1);
sblair 0:230c10b228ea 284 offset += ber_decode_myMV(&buf[offset], &D1Q1SB4.S1.C1.RSYN_1.gse_inputs.Amps_1);
sblair 0:230c10b228ea 285 offset += ber_decode_myMV(&buf[offset], &D1Q1SB4.S1.C1.RSYN_1.gse_inputs.Volts_1);
sblair 0:230c10b228ea 286
sblair 0:230c10b228ea 287 return offset;
sblair 0:230c10b228ea 288 }
sblair 0:230c10b228ea 289
sblair 0:230c10b228ea 290 void gseDecodeDataset(unsigned char *dataset, int datasetLength, unsigned char *datSet, int datSetLength) {
sblair 0:230c10b228ea 291
sblair 0:230c10b228ea 292 if (strncmp((const char *) datSet, "E1Q1SB1C1/LLN0$Positions", datSetLength) == 0) {
sblair 0:230c10b228ea 293 ber_decode_Positions_RSYN_1(dataset);
sblair 0:230c10b228ea 294 }
sblair 0:230c10b228ea 295 }
sblair 0:230c10b228ea 296
sblair 0:230c10b228ea 297