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/

Revision:
1:9399d44c2b1a
Parent:
0:230c10b228ea
--- a/svDecodePacket.c	Fri Oct 07 13:41:08 2011 +0000
+++ b/svDecodePacket.c	Fri Oct 07 13:48:18 2011 +0000
@@ -1,3 +1,23 @@
+/**
+ * Rapid-prototyping protection schemes with IEC 61850
+ *
+ * Copyright (c) 2011 Steven Blair
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 #include "svDecodeBasic.h"
 #include "ied.h"
 #include "svDecode.h"
@@ -7,93 +27,93 @@
 
 
 void svDecodeASDU(unsigned char *buf, int len, int noASDU) {
-	unsigned char tag;	// assumes only one byte is used
-	int lengthFieldSize;
-	int lengthValue;
-	int offsetForNonSequence;
-	unsigned char *svID = NULL;
-	int svIDLength = 0;
+    unsigned char tag;    // assumes only one byte is used
+    int lengthFieldSize;
+    int lengthValue;
+    int offsetForNonSequence;
+    unsigned char *svID = NULL;
+    int svIDLength = 0;
 
-	int i = 0;
-	for (i = 0; i < len;) {
-		tag = (unsigned char) buf[i];
-		lengthFieldSize = getLengthFieldSize((unsigned char) buf[i + 1]);
-		lengthValue = decodeLength((unsigned char *) &buf[i + 1]);
-		offsetForNonSequence = 1 + lengthFieldSize + lengthValue;
+    int i = 0;
+    for (i = 0; i < len;) {
+        tag = (unsigned char) buf[i];
+        lengthFieldSize = getLengthFieldSize((unsigned char) buf[i + 1]);
+        lengthValue = decodeLength((unsigned char *) &buf[i + 1]);
+        offsetForNonSequence = 1 + lengthFieldSize + lengthValue;
 
-		//printf("\ttag: %x, noASDU: %u, lengthFieldSize: %i, lengthValue: %i, offset: %i\n", tag, noASDU, lengthFieldSize, lengthValue, offsetForNonSequence);
+        //printf("\ttag: %x, noASDU: %u, lengthFieldSize: %i, lengthValue: %i, offset: %i\n", tag, noASDU, lengthFieldSize, lengthValue, offsetForNonSequence);
 
-		switch (tag) {
-		case 0x80:
-			svID = &buf[i + 1 + lengthFieldSize];
-			svIDLength = lengthValue;
-			break;
-		case 0x81:
+        switch (tag) {
+        case 0x80:
+            svID = &buf[i + 1 + lengthFieldSize];
+            svIDLength = lengthValue;
+            break;
+        case 0x81:
 
-			break;
-		case 0x82:
-			// TODO: may be useful to store smpCnt value
-			break;
-		case 0x83:
+            break;
+        case 0x82:
+            // TODO: may be useful to store smpCnt value
+            break;
+        case 0x83:
 
-			break;
-		case 0x84:
+            break;
+        case 0x84:
 
-			break;
-		case 0x85:
+            break;
+        case 0x85:
 
-			break;
-		case 0x86:
+            break;
+        case 0x86:
 
-			break;
-		case 0x87:
-			if (svID != NULL) {
-				svDecodeDataset(&buf[i + 1 + lengthFieldSize], lengthValue, noASDU, svID, svIDLength);
-			}
-			break;
-		default:
-			break;
-		}
+            break;
+        case 0x87:
+            if (svID != NULL) {
+                svDecodeDataset(&buf[i + 1 + lengthFieldSize], lengthValue, noASDU, svID, svIDLength);
+            }
+            break;
+        default:
+            break;
+        }
 
-		i += offsetForNonSequence;
-	}
+        i += offsetForNonSequence;
+    }
 }
 
 void svDecodeAPDU(unsigned char *buf, int len) {
-	unsigned char tag = (unsigned char) buf[0];	// assumes only one byte is used
-	int lengthFieldSize = getLengthFieldSize((unsigned char) buf[1]);
-	int lengthValue = decodeLength((unsigned char *) &buf[1]);
-	int offsetForSequence = 1 + lengthFieldSize;
-	int offsetForNonSequence = 1 + lengthFieldSize + lengthValue;
-	//static unsigned int noASDU = 0;
-	static unsigned int ASDU = 0;
+    unsigned char tag = (unsigned char) buf[0];    // assumes only one byte is used
+    int lengthFieldSize = getLengthFieldSize((unsigned char) buf[1]);
+    int lengthValue = decodeLength((unsigned char *) &buf[1]);
+    int offsetForSequence = 1 + lengthFieldSize;
+    int offsetForNonSequence = 1 + lengthFieldSize + lengthValue;
+    //static unsigned int noASDU = 0;
+    static unsigned int ASDU = 0;
 
-	//printf("tag: %x, noASDU: %u, lengthFieldSize: %i, lengthValue: %i, offset: %i\n", tag, noASDU, lengthFieldSize, lengthValue, offsetForNonSequence);
+    //printf("tag: %x, noASDU: %u, lengthFieldSize: %i, lengthValue: %i, offset: %i\n", tag, noASDU, lengthFieldSize, lengthValue, offsetForNonSequence);
 
-	switch (tag) {
-	case 0x60:
-		svDecodeAPDU(&buf[offsetForSequence], lengthValue);
-		break;
-	case 0x80:
-		//noASDU = (unsigned int) buf[1 + lengthFieldSize];	// assuming noASDU is < 126
-		ASDU = 0;
-		svDecodeAPDU(&buf[offsetForNonSequence], len - offsetForNonSequence);
-		break;
-	case 0xA2:
-		svDecodeAPDU(&buf[offsetForSequence], lengthValue);
-		break;
-	case 0x30:
-		svDecodeASDU(&buf[offsetForSequence], lengthValue, ASDU++);
+    switch (tag) {
+    case 0x60:
+        svDecodeAPDU(&buf[offsetForSequence], lengthValue);
+        break;
+    case 0x80:
+        //noASDU = (unsigned int) buf[1 + lengthFieldSize];    // assuming noASDU is < 126
+        ASDU = 0;
+        svDecodeAPDU(&buf[offsetForNonSequence], len - offsetForNonSequence);
+        break;
+    case 0xA2:
+        svDecodeAPDU(&buf[offsetForSequence], lengthValue);
+        break;
+    case 0x30:
+        svDecodeASDU(&buf[offsetForSequence], lengthValue, ASDU++);
 
-		svDecodeAPDU(&buf[offsetForNonSequence], len - offsetForNonSequence);
-		break;
-	default:
-		break;
-	}
+        svDecodeAPDU(&buf[offsetForNonSequence], len - offsetForNonSequence);
+        break;
+    default:
+        break;
+    }
 }
 
 void svDecode(unsigned char *buf, int len) {
-	unsigned short APDULength = ((buf[21] << 8) | buf[22]) - 8;	// must use length in PDU because total bytes (len) may contain CRC
+    unsigned short APDULength = ((buf[21] << 8) | buf[22]) - 8;    // must use length in PDU because total bytes (len) may contain CRC
 
-	svDecodeAPDU(&buf[26], APDULength);	// cuts out frame header (fixed size of 26 bytes before start of APDU)
+    svDecodeAPDU(&buf[26], APDULength);    // cuts out frame header (fixed size of 26 bytes before start of APDU)
 }