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:41:08 2011 +0000
Revision:
0:230c10b228ea
Child:
1:9399d44c2b1a

        

Who changed what in which revision?

UserRevisionLine numberNew contents of line
sblair 0:230c10b228ea 1 #include "svDecodeBasic.h"
sblair 0:230c10b228ea 2 #include "ied.h"
sblair 0:230c10b228ea 3 #include "svDecode.h"
sblair 0:230c10b228ea 4 #include "svPacketData.h"
sblair 0:230c10b228ea 5 #include "decodePacket.h"
sblair 0:230c10b228ea 6 #include <stddef.h>
sblair 0:230c10b228ea 7
sblair 0:230c10b228ea 8
sblair 0:230c10b228ea 9 void svDecodeASDU(unsigned char *buf, int len, int noASDU) {
sblair 0:230c10b228ea 10 unsigned char tag; // assumes only one byte is used
sblair 0:230c10b228ea 11 int lengthFieldSize;
sblair 0:230c10b228ea 12 int lengthValue;
sblair 0:230c10b228ea 13 int offsetForNonSequence;
sblair 0:230c10b228ea 14 unsigned char *svID = NULL;
sblair 0:230c10b228ea 15 int svIDLength = 0;
sblair 0:230c10b228ea 16
sblair 0:230c10b228ea 17 int i = 0;
sblair 0:230c10b228ea 18 for (i = 0; i < len;) {
sblair 0:230c10b228ea 19 tag = (unsigned char) buf[i];
sblair 0:230c10b228ea 20 lengthFieldSize = getLengthFieldSize((unsigned char) buf[i + 1]);
sblair 0:230c10b228ea 21 lengthValue = decodeLength((unsigned char *) &buf[i + 1]);
sblair 0:230c10b228ea 22 offsetForNonSequence = 1 + lengthFieldSize + lengthValue;
sblair 0:230c10b228ea 23
sblair 0:230c10b228ea 24 //printf("\ttag: %x, noASDU: %u, lengthFieldSize: %i, lengthValue: %i, offset: %i\n", tag, noASDU, lengthFieldSize, lengthValue, offsetForNonSequence);
sblair 0:230c10b228ea 25
sblair 0:230c10b228ea 26 switch (tag) {
sblair 0:230c10b228ea 27 case 0x80:
sblair 0:230c10b228ea 28 svID = &buf[i + 1 + lengthFieldSize];
sblair 0:230c10b228ea 29 svIDLength = lengthValue;
sblair 0:230c10b228ea 30 break;
sblair 0:230c10b228ea 31 case 0x81:
sblair 0:230c10b228ea 32
sblair 0:230c10b228ea 33 break;
sblair 0:230c10b228ea 34 case 0x82:
sblair 0:230c10b228ea 35 // TODO: may be useful to store smpCnt value
sblair 0:230c10b228ea 36 break;
sblair 0:230c10b228ea 37 case 0x83:
sblair 0:230c10b228ea 38
sblair 0:230c10b228ea 39 break;
sblair 0:230c10b228ea 40 case 0x84:
sblair 0:230c10b228ea 41
sblair 0:230c10b228ea 42 break;
sblair 0:230c10b228ea 43 case 0x85:
sblair 0:230c10b228ea 44
sblair 0:230c10b228ea 45 break;
sblair 0:230c10b228ea 46 case 0x86:
sblair 0:230c10b228ea 47
sblair 0:230c10b228ea 48 break;
sblair 0:230c10b228ea 49 case 0x87:
sblair 0:230c10b228ea 50 if (svID != NULL) {
sblair 0:230c10b228ea 51 svDecodeDataset(&buf[i + 1 + lengthFieldSize], lengthValue, noASDU, svID, svIDLength);
sblair 0:230c10b228ea 52 }
sblair 0:230c10b228ea 53 break;
sblair 0:230c10b228ea 54 default:
sblair 0:230c10b228ea 55 break;
sblair 0:230c10b228ea 56 }
sblair 0:230c10b228ea 57
sblair 0:230c10b228ea 58 i += offsetForNonSequence;
sblair 0:230c10b228ea 59 }
sblair 0:230c10b228ea 60 }
sblair 0:230c10b228ea 61
sblair 0:230c10b228ea 62 void svDecodeAPDU(unsigned char *buf, int len) {
sblair 0:230c10b228ea 63 unsigned char tag = (unsigned char) buf[0]; // assumes only one byte is used
sblair 0:230c10b228ea 64 int lengthFieldSize = getLengthFieldSize((unsigned char) buf[1]);
sblair 0:230c10b228ea 65 int lengthValue = decodeLength((unsigned char *) &buf[1]);
sblair 0:230c10b228ea 66 int offsetForSequence = 1 + lengthFieldSize;
sblair 0:230c10b228ea 67 int offsetForNonSequence = 1 + lengthFieldSize + lengthValue;
sblair 0:230c10b228ea 68 //static unsigned int noASDU = 0;
sblair 0:230c10b228ea 69 static unsigned int ASDU = 0;
sblair 0:230c10b228ea 70
sblair 0:230c10b228ea 71 //printf("tag: %x, noASDU: %u, lengthFieldSize: %i, lengthValue: %i, offset: %i\n", tag, noASDU, lengthFieldSize, lengthValue, offsetForNonSequence);
sblair 0:230c10b228ea 72
sblair 0:230c10b228ea 73 switch (tag) {
sblair 0:230c10b228ea 74 case 0x60:
sblair 0:230c10b228ea 75 svDecodeAPDU(&buf[offsetForSequence], lengthValue);
sblair 0:230c10b228ea 76 break;
sblair 0:230c10b228ea 77 case 0x80:
sblair 0:230c10b228ea 78 //noASDU = (unsigned int) buf[1 + lengthFieldSize]; // assuming noASDU is < 126
sblair 0:230c10b228ea 79 ASDU = 0;
sblair 0:230c10b228ea 80 svDecodeAPDU(&buf[offsetForNonSequence], len - offsetForNonSequence);
sblair 0:230c10b228ea 81 break;
sblair 0:230c10b228ea 82 case 0xA2:
sblair 0:230c10b228ea 83 svDecodeAPDU(&buf[offsetForSequence], lengthValue);
sblair 0:230c10b228ea 84 break;
sblair 0:230c10b228ea 85 case 0x30:
sblair 0:230c10b228ea 86 svDecodeASDU(&buf[offsetForSequence], lengthValue, ASDU++);
sblair 0:230c10b228ea 87
sblair 0:230c10b228ea 88 svDecodeAPDU(&buf[offsetForNonSequence], len - offsetForNonSequence);
sblair 0:230c10b228ea 89 break;
sblair 0:230c10b228ea 90 default:
sblair 0:230c10b228ea 91 break;
sblair 0:230c10b228ea 92 }
sblair 0:230c10b228ea 93 }
sblair 0:230c10b228ea 94
sblair 0:230c10b228ea 95 void svDecode(unsigned char *buf, int len) {
sblair 0:230c10b228ea 96 unsigned short APDULength = ((buf[21] << 8) | buf[22]) - 8; // must use length in PDU because total bytes (len) may contain CRC
sblair 0:230c10b228ea 97
sblair 0:230c10b228ea 98 svDecodeAPDU(&buf[26], APDULength); // cuts out frame header (fixed size of 26 bytes before start of APDU)
sblair 0:230c10b228ea 99 }