An mbed implementation of IEC 61850-9-2LE Sample Values. Creating using the rapid61850 library, available at: https://github.com/stevenblair/rapid61850.
An mbed implementation of IEC 61850-9-2LE Sample Values. Creating using the rapid61850 library, available at: https://github.com/stevenblair/rapid61850.
Revision 0:f09b7bb8bcce, committed 2012-10-02
- Comitter:
- sblair
- Date:
- Tue Oct 02 21:31:05 2012 +0000
- Commit message:
- converted library to folder
Changed in this revision
diff -r 000000000000 -r f09b7bb8bcce main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Tue Oct 02 21:31:05 2012 +0000 @@ -0,0 +1,145 @@ +/** + * IEC 61850-9-2LE Sampled Values demonstration + * + * Copyright (c) 2012 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 "mbed.h" +#include "iec61850.h" + +#include <stdio.h> + +#define NUMBER_OF_SIGNALS 8 +#define NUMBER_OF_SIGNALS_PHASES 6 +#define NUMBER_OF_SAMPLES 80 + +#define PI 3.1415926535897932384626433832795f +#define TWO_PI 6.283185307179586476925286766559f +#define TWO_PI_OVER_THREE 2.0943951023931954923084289221863f + + +CTYPE_INT32 signal[NUMBER_OF_SIGNALS_PHASES][NUMBER_OF_SAMPLES] = {0}; + +float phi = 0.1 * PI; // phase angle between voltage and current (rad) +float freq = 50.0; // frequency of waveforms (Hz) +float w = 2.0 * PI * freq; +float Ts = 250e-6; // timestep; should equal 1 / (freq * NUMBER_OF_SAMPLES) +float V = 8981.462390205; // voltage magnitude; equals 11 kV * sqrt(2) / sqrt(3) +float Zmag = 15.0; // impedance magnitude - defines the current magnitude +float harmonic = 7; // harmonic number +float harmonicMagPu = 0.03; // harmonic magnitude (p.u.); set to zero to ignore + +unsigned char buf[1024] = {0}; +int len = 0; + +DigitalOut watchdogLED(LED1); +DigitalOut ethLink(p29); +DigitalOut ethAct(p30); +Ethernet eth; +Ticker sv; + +/** + * Pre-calculate all voltage and current samples (only possible if exactly 50 Hz frequency is used). + */ +void preCalculate() { + int t = 0; + for (t = 0; t < NUMBER_OF_SAMPLES; t++) { + double theta = w * (((float) t) * Ts); + + signal[0][t] = (CTYPE_INT32) (V * sin(theta) / ((float) LE_IED.S1.MUnn.IEC_61850_9_2LETVTR_1.Vol.sVC.scaleFactor) + (V * harmonicMagPu * sin(theta * harmonic) / ((float) LE_IED.S1.MUnn.IEC_61850_9_2LETVTR_1.Vol.sVC.scaleFactor))); + signal[1][t] = (CTYPE_INT32) (V * sin(theta - TWO_PI_OVER_THREE) / LE_IED.S1.MUnn.IEC_61850_9_2LETVTR_2.Vol.sVC.scaleFactor) + (V * harmonicMagPu * sin(theta * harmonic - TWO_PI_OVER_THREE) / ((float) LE_IED.S1.MUnn.IEC_61850_9_2LETVTR_1.Vol.sVC.scaleFactor)); + signal[2][t] = (CTYPE_INT32) (V * sin(theta + TWO_PI_OVER_THREE) / LE_IED.S1.MUnn.IEC_61850_9_2LETVTR_3.Vol.sVC.scaleFactor) + (V * harmonicMagPu * sin(theta * harmonic + TWO_PI_OVER_THREE) / ((float) LE_IED.S1.MUnn.IEC_61850_9_2LETVTR_1.Vol.sVC.scaleFactor)); + + signal[3][t] = (CTYPE_INT32) ((V / Zmag) * sin(theta - phi) / LE_IED.S1.MUnn.IEC_61850_9_2LETCTR_1.Amp.sVC.scaleFactor) + ((harmonicMagPu * V / Zmag) * sin(theta * harmonic - phi) / LE_IED.S1.MUnn.IEC_61850_9_2LETCTR_1.Amp.sVC.scaleFactor); + signal[4][t] = (CTYPE_INT32) ((V / Zmag) * sin(theta - phi - TWO_PI_OVER_THREE) / LE_IED.S1.MUnn.IEC_61850_9_2LETCTR_2.Amp.sVC.scaleFactor) + ((harmonicMagPu * V / Zmag) * sin(theta * harmonic - phi - TWO_PI_OVER_THREE) / LE_IED.S1.MUnn.IEC_61850_9_2LETCTR_2.Amp.sVC.scaleFactor); + signal[5][t] = (CTYPE_INT32) ((V / Zmag) * sin(theta - phi + TWO_PI_OVER_THREE) / LE_IED.S1.MUnn.IEC_61850_9_2LETCTR_3.Amp.sVC.scaleFactor) + ((harmonicMagPu * V / Zmag) * sin(theta * harmonic - phi + TWO_PI_OVER_THREE) / LE_IED.S1.MUnn.IEC_61850_9_2LETCTR_3.Amp.sVC.scaleFactor); + } +} + +/** + * Transmit the next set of samples. + */ +void svSnapshot() { + static int t = 0; + + LE_IED.S1.MUnn.IEC_61850_9_2LETVTR_1.Vol.instMag.i = signal[0][t]; + LE_IED.S1.MUnn.IEC_61850_9_2LETVTR_2.Vol.instMag.i = signal[1][t]; + LE_IED.S1.MUnn.IEC_61850_9_2LETVTR_3.Vol.instMag.i = signal[2][t]; + LE_IED.S1.MUnn.IEC_61850_9_2LETVTR_4.Vol.instMag.i = 0; + + LE_IED.S1.MUnn.IEC_61850_9_2LETCTR_1.Amp.instMag.i = signal[3][t]; + LE_IED.S1.MUnn.IEC_61850_9_2LETCTR_2.Amp.instMag.i = signal[4][t]; + LE_IED.S1.MUnn.IEC_61850_9_2LETCTR_3.Amp.instMag.i = signal[5][t]; + LE_IED.S1.MUnn.IEC_61850_9_2LETCTR_4.Amp.instMag.i = 0; + + len = sv_update_LE_IED_MUnn_MSVCB01(buf); + + if (len > 0) { + ethAct = 1; + eth.write((const char *) buf, len); + eth.send(); + ethAct = 0; + } + + if (++t >= NUMBER_OF_SAMPLES) { + t = 0; + } +} + +/** + * Overriding this function sets the MAC address. + * Set to the destination MAC of all received SV or GOOSE packets to simplify hardware MAC filtering. + */ +extern "C" void mbed_mac_address(char *s) { + char mac[6]; + + mac[0] = 0x01; + mac[1] = 0x0C; + mac[2] = 0xCD; + mac[3] = 0x04; + mac[4] = 0x00; + mac[5] = 0x00; + + memcpy(s, mac, 6); +} + +int main() { + initialise_iec61850(); + + // enable hardware MAC address filtering + LPC_EMAC->RxFilterCtrl = 1 << 5; + + eth.set_link(eth.FullDuplex100); + while (!eth.link()) { + wait(1); + } + ethLink = 1; + + wait(1); + + preCalculate(); + + sv.attach_us(&svSnapshot, 250); // create 250 us (for 50 Hz, 80 samples/cycle) periodic timer + + // loop forever, toggling LED + while(1) { + watchdogLED = 1; + wait(0.01); + watchdogLED = 0; + wait(2); + } +}
diff -r 000000000000 -r f09b7bb8bcce mbed.bld --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Tue Oct 02 21:31:05 2012 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/737756e0b479 \ No newline at end of file
diff -r 000000000000 -r f09b7bb8bcce rapid61850/ctypes.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rapid61850/ctypes.c Tue Oct 02 21:31:05 2012 +0000 @@ -0,0 +1,207 @@ +/** + * Rapid-prototyping protection schemes with IEC 61850 + * + * Copyright (c) 2012 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 "ctypes.h" +#include "gse.h" +#include "sv.h" +#if TIMESTAMP_SUPPORTED == 1 +#include <sys\time.h> +#endif + +#define ENDIAN_BUFFER_SIZE 8 + +unsigned char LOCAL_MAC_ADDRESS[] = LOCAL_MAC_ADDRESS_VALUE; + +int ber_integer_length(void *value, int maxLength) { + unsigned char endian_buf[ENDIAN_BUFFER_SIZE] = {0}; + netmemcpy(endian_buf, value, maxLength); // ensure bytes are in big-endian order + + unsigned char *buf = endian_buf; + unsigned char *end1 = buf + maxLength - 1; + int shift = 0; + + /* Compute the number of superfluous leading bytes */ + for(; buf < end1; buf++) { + /* + * If the contents octets of an integer value encoding + * consist of more than one octet, then the bits of the + * first octet and bit 8 of the second octet: + * a) shall not all be ones; and + * b) shall not all be zero. + */ + switch(*buf) { + case 0x00: + if((buf[1] & 0x80) == 0) { + continue; + } + break; + case 0xff: + if((buf[1] & 0x80)) { + continue; + } + break; + } + break; + } + + shift = buf - endian_buf; + + return maxLength - shift; +} + +int ber_encode_integer_fixed_size(unsigned char *bufDst, void *value, int maxLength) { + unsigned char *firstByte = (unsigned char*) value; + unsigned char padding = (firstByte[0] & 0x80) ? 0xFF : 0x00; + + bufDst[0] = padding; + netmemcpy(&bufDst[1], value, maxLength); + + return maxLength + 1; +} + +int ber_encode_integer(unsigned char *bufDst, void *value, int maxLength) { + unsigned char endian_buf[ENDIAN_BUFFER_SIZE] = {0}; + netmemcpy(endian_buf, value, maxLength); // ensure bytes are in big-endian order + + unsigned char *buf = endian_buf; + unsigned char *end1 = buf + maxLength - 1; + int shift = 0; + + /* Compute the number of superfluous leading bytes */ + for(; buf < end1; buf++) { + /* + * If the contents octets of an integer value encoding + * consist of more than one octet, then the bits of the + * first octet and bit 8 of the second octet: + * a) shall not all be ones; and + * b) shall not all be zero. + */ + switch(*buf) { + case 0x00: + if((buf[1] & 0x80) == 0) { + continue; + } + break; + case 0xff: + if((buf[1] & 0x80)) { + continue; + } + break; + } + break; + } + + shift = buf - endian_buf; + + unsigned char *nb = endian_buf; + unsigned char *end; + + maxLength -= shift; /* New size, minus bad bytes */ + end = nb + maxLength; + + int i = 0; + for(; nb < end; nb++, buf++, i++) { + //*nb = *buf; + bufDst[i] = *buf; + } + + return maxLength; +} + +//#if GOOSE_FIXED_SIZE == 1 +//void ber_decode_integer(unsigned char *buf, int length, void *value, int maxLength) { +// ; +//} +//#else +void ber_decode_integer(unsigned char *buf, int length, void *value, int maxLength) { + unsigned char endian_buf[ENDIAN_BUFFER_SIZE] = {0}; + unsigned char padding = (buf[0] & 0x80) ? 0xFF : 0x00; + int i = 0; + unsigned char *dest = (unsigned char *) value; + + for (i = maxLength - 1; i >= 0; i--) { + if ((i + length) < maxLength) { + endian_buf[i] = padding; + } + else { + endian_buf[i] = buf[i - (maxLength - length)]; + } + } + + netmemcpy(dest, endian_buf, maxLength); +} +//#endif + +//TODO need cast to, for example, (unsigned char *) for calls to reversememcpy()? + +// a simple memcpy implementation, that reverses endian-ness +void reversememcpy(unsigned char *dst, const unsigned char *src, unsigned int len) { + while (len--) { + *dst++ = src[len]; + } +} + +void setTimestamp(CTYPE_TIMESTAMP *dest) { +#if TIMESTAMP_SUPPORTED == 1 + unsigned char *buf = (unsigned char *) dest; + struct timeval tv; + CTYPE_INT32U frac = 0; + + gettimeofday(&tv, NULL); + frac = (CTYPE_INT32U) ((float) tv.tv_usec * 4294.967296); // * 2^32 / 1000000; + + netmemcpy(&buf[0], &tv.tv_sec, 4); + netmemcpy(&buf[4], &frac, 4); + + buf[7] = 0x18; // quality: 24 bits of accuracy +#endif +} + +// if the recommended MAC address ranges are used, this function filters GOOSE and SV packets +void gse_sv_packet_filter(unsigned char *buf, int len) { + if (buf[0] == 0x01 && buf[1] == 0x0C && buf[2] == 0xCD) { + if (buf[3] == 0x01) { + //GOOSE: 01-0C-CD-01-00-00 to 01-0C-CD-01-01-FF + gseDecode(buf, len); + } + else if (buf[3] == 0x04) { + //SV: 01-0C-CD-04-00-00 to 01-0C-CD-04-01-FF + svDecode(buf, len); + } + } +} + +// copies bytes to network format (big-endian) +void netmemcpy(void *dst, const void *src, unsigned int len) { +#ifdef LITTLE_ENDIAN + reversememcpy((unsigned char *) dst, (const unsigned char *) src, len); +#else + memcpy((unsigned char *) dst, (const unsigned char *) src, len); +#endif +} + +// copies bytes to host format (little-endian) +void hostmemcpy(void *dst, const void *src, unsigned int len) { +#ifdef LITTLE_ENDIAN + memcpy((unsigned char *) dst, (const unsigned char *) src, len); +#else + reversememcpy((unsigned char *) dst, (const unsigned char *) src, len); +#endif +}
diff -r 000000000000 -r f09b7bb8bcce rapid61850/ctypes.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rapid61850/ctypes.h Tue Oct 02 21:31:05 2012 +0000 @@ -0,0 +1,177 @@ +/** + * Rapid-prototyping protection schemes with IEC 61850 + * + * Copyright (c) 2012 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. + */ + +#ifndef CTYPES_H +#define CTYPES_H + +#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */ +extern "C" { +#endif + +#include <string.h> + +#ifndef LITTLE_ENDIAN + #define LITTLE_ENDIAN 1 +#endif +#define TIMESTAMP_SUPPORTED 0 +#define GOOSE_FIXED_SIZE 0 // set to 1 to enable fixed-sized GOOSE encoding, which is slightly more efficient to encode. +#define HIGH_LEVEL_INTERFACE 0 // + +#define LOCAL_MAC_ADDRESS_VALUE {0x01, 0x0C, 0xCD, 0x01, 0x00, 0x02} + +// platform-specific data types to conform to SV type sizes (Table 14 in IEC 61850-9-2) +#define CTYPE_BOOLEAN unsigned char +#define CTYPE_INT8 char +#define CTYPE_INT16 short +#define CTYPE_INT32 int +#define CTYPE_INT8U unsigned char +#define CTYPE_INT16U unsigned short +#define CTYPE_INT32U unsigned int +#if GOOSE_FIXED_SIZE == 1 +#define CTYPE_ENUM CTYPE_INT8 +#else +#define CTYPE_ENUM CTYPE_INT32 +#endif +#define CTYPE_FLOAT32 float +#define CTYPE_FLOAT64 double +#define CTYPE_VISSTRING255 char * +#define CTYPE_DBPOS int +#define CTYPE_QUALITY CTYPE_INT16U +#define CTYPE_TIMESTAMP long long + +// sampled value dataset type sizes, in bytes +#define SV_GET_LENGTH_FLOAT32 4 +#define SV_GET_LENGTH_FLOAT64 8 +#define SV_GET_LENGTH_TIMESTAMP 8 +#define SV_GET_LENGTH_INT8 1 +#define SV_GET_LENGTH_INT16 2 +#define SV_GET_LENGTH_INT32 4 +#define SV_GET_LENGTH_INT8U 1 +#define SV_GET_LENGTH_INT16U 2 +#define SV_GET_LENGTH_INT32U 4 +#define SV_GET_LENGTH_VISSTRING255 35 +#define SV_GET_LENGTH_BOOLEAN 1 +#define SV_GET_LENGTH_ENUM 4 +#define SV_GET_LENGTH_QUALITY 4 +#define SV_GET_LENGTH_DBPOS 4 + +#if GOOSE_FIXED_SIZE == 1 +#define BER_GET_LENGTH_CTYPE_FLOAT32(x) (SV_GET_LENGTH_FLOAT32 + 1) +#define BER_GET_LENGTH_CTYPE_FLOAT64(x) (SV_GET_LENGTH_FLOAT64 + 1) // fixed-size FLOAT64 not actually specified in -8-1 +#define BER_GET_LENGTH_CTYPE_TIMESTAMP(x) (SV_GET_LENGTH_TIMESTAMP) +#define BER_GET_LENGTH_CTYPE_INT8(x) (2) // 8-bit datatypes are encoded in 16 bits! +#define BER_GET_LENGTH_CTYPE_INT16(x) (3) +#define BER_GET_LENGTH_CTYPE_INT32(x) (5) +#define BER_GET_LENGTH_CTYPE_INT16U(x) (3) +#define BER_GET_LENGTH_CTYPE_INT32U(x) (5) +#define BER_GET_LENGTH_CTYPE_VISSTRING255(x) (SV_GET_LENGTH_VISSTRING255) +#define BER_GET_LENGTH_CTYPE_BOOLEAN(x) (SV_GET_LENGTH_BOOLEAN) +#define BER_GET_LENGTH_CTYPE_ENUM(x) (2) +#define BER_GET_LENGTH_CTYPE_QUALITY(x) (3) +#define BER_GET_LENGTH_CTYPE_DBPOS(x) (SV_GET_LENGTH_DBPOS) +#else +// BER datatype sizes, which are dependent on the actual data +#define BER_GET_LENGTH_CTYPE_FLOAT32(x) (SV_GET_LENGTH_FLOAT32 + 1) // + 1 byte for number of exponent bits +#define BER_GET_LENGTH_CTYPE_FLOAT64(x) (SV_GET_LENGTH_FLOAT64 + 1) // + 1 byte for number of exponent bits +#define BER_GET_LENGTH_CTYPE_TIMESTAMP(x) (SV_GET_LENGTH_TIMESTAMP) +#define BER_GET_LENGTH_CTYPE_INT8(x) (ber_integer_length((x), SV_GET_LENGTH_INT8)) +#define BER_GET_LENGTH_CTYPE_INT16(x) (ber_integer_length((x), SV_GET_LENGTH_INT16)) +#define BER_GET_LENGTH_CTYPE_INT32(x) (ber_integer_length((x), SV_GET_LENGTH_INT32)) +#define BER_GET_LENGTH_CTYPE_INT16U(x) (ber_integer_length((x), SV_GET_LENGTH_INT16U)) +#define BER_GET_LENGTH_CTYPE_INT32U(x) (ber_integer_length((x), SV_GET_LENGTH_INT32U)) +#define BER_GET_LENGTH_CTYPE_VISSTRING255(x) (SV_GET_LENGTH_VISSTRING255) +#define BER_GET_LENGTH_CTYPE_BOOLEAN(x) (SV_GET_LENGTH_BOOLEAN) +#define BER_GET_LENGTH_CTYPE_ENUM(x) (ber_integer_length((x), SV_GET_LENGTH_ENUM)) +#define BER_GET_LENGTH_CTYPE_QUALITY(x) (2 + 1) // + 1 byte for padding +#define BER_GET_LENGTH_CTYPE_DBPOS(x) (SV_GET_LENGTH_DBPOS) +#endif + +#define ASN1_TAG_SEQUENCE 0x61 +#define ASN1_TAG_ARRAY 0x81 +#define ASN1_TAG_STRUCTURE 0x82 +#define ASN1_TAG_BOOLEAN 0x83 +#define ASN1_TAG_BIT_STRING 0x84 +#define ASN1_TAG_INTEGER 0x85 +#define ASN1_TAG_UNSIGNED 0x86 +#define ASN1_TAG_FLOATING_POINT 0x87 +#define ASN1_TAG_REAL 0x88 +#define ASN1_TAG_OCTET_STRING 0x89 +#define ASN1_TAG_VISIBLE_STRING 0x8A + +#define GSE_TAG_GOCBREF 0x80 +#define GSE_TAG_TIME_ALLOWED_TO_LIVE 0x81 +#define GSE_TAG_DATSET 0x82 +#define GSE_TAG_GOID 0x83 +#define GSE_TAG_T 0x84 +#define GSE_TAG_STNUM 0x85 +#define GSE_TAG_SQNUM 0x86 +#define GSE_TAG_SIMULATION 0x87 +#define GSE_TAG_CONFREV 0x88 +#define GSE_TAG_NDSCOM 0x89 +#define GSE_TAG_NUMDATSETENTRIES 0x8A +#define GSE_TAG_ALLDATA 0xAB + +#define SV_TAG_SAVPDU 0x60 +#define SV_TAG_NOASDU 0x80 +#define SV_TAG_SECURITY 0x81 +#define SV_TAG_SEQUENCEOFASDU 0xA2 +#define SV_TAG_ASDU 0x30 +#define SV_TAG_SVID 0x80 +#define SV_TAG_DATSET 0x81 +#define SV_TAG_SMPCNT 0x82 +#define SV_TAG_CONFREV 0x83 +#define SV_TAG_REFRTM 0x84 +#define SV_TAG_SMPSYNCH 0x85 +#define SV_TAG_SMPRATE 0x86 +#define SV_TAG_SEQUENCEOFDATA 0x87 + +#define QUALITY_UNUSED_BITS 3 // total_bits (16) - used_bits (13) = 3 + +int ber_integer_length(void *value, int maxLength); +int ber_encode_integer(unsigned char *bufDst, void *value, int maxLength); +int ber_encode_integer_fixed_size(unsigned char *bufDst, void *value, int maxLength); +void ber_decode_integer(unsigned char *buf, int length, void *value, int maxLength); + +void reversememcpy(unsigned char *dst, const unsigned char *src, unsigned int len); +void netmemcpy(void *dst, const void *src, unsigned int len); +void hostmemcpy(void *dst, const void *src, unsigned int len); + +void setTimestamp(CTYPE_TIMESTAMP *t); +void gse_sv_packet_filter(unsigned char *buf, int len); + +struct UtcTime { + unsigned char bytes[8]; // format: ssssssssssssssssssssssssssssssssffffffffffffffffffffffffqqqqqqqq +}; + +extern unsigned char LOCAL_MAC_ADDRESS[]; + +struct ethHeaderData { + unsigned char destMACAddress[6]; // stored in big-endian format + CTYPE_INT16U APPID; + CTYPE_INT16U VLAN_ID; + CTYPE_INT16U VLAN_PRIORITY; +}; + +#ifdef __cplusplus /* If this is a C++ compiler, end C linkage */ +} +#endif + +#endif +
diff -r 000000000000 -r f09b7bb8bcce rapid61850/datatypes.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rapid61850/datatypes.c Tue Oct 02 21:31:05 2012 +0000 @@ -0,0 +1,64 @@ +/** + * Rapid-prototyping protection schemes with IEC 61850 + * + * Copyright (c) 2012 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 <stdlib.h> +#include "ctypes.h" +#include "datatypes.h" +#include "ied.h" + + + + + +void init_IEC_61850_9_2LEAV(struct IEC_61850_9_2LEAV *IEC_61850_9_2LEAV) { +} +void init_IEC_61850_9_2LEsVCAmp(struct IEC_61850_9_2LEsVCAmp *IEC_61850_9_2LEsVCAmp) { + IEC_61850_9_2LEsVCAmp->scaleFactor = 0.001; + IEC_61850_9_2LEsVCAmp->offset = 0; +} +void init_IEC_61850_9_2LEsVCVol(struct IEC_61850_9_2LEsVCVol *IEC_61850_9_2LEsVCVol) { + IEC_61850_9_2LEsVCVol->scaleFactor = 0.01; + IEC_61850_9_2LEsVCVol->offset = 0; +} +void init_IEC_61850_9_2LESAVAmp(struct IEC_61850_9_2LESAVAmp *IEC_61850_9_2LESAVAmp) { +} +void init_IEC_61850_9_2LESAVVol(struct IEC_61850_9_2LESAVVol *IEC_61850_9_2LESAVVol) { +} +void init_IEC_61850_9_2LEINC(struct IEC_61850_9_2LEINC *IEC_61850_9_2LEINC) { +} +void init_datatypes() { + init_IEC_61850_9_2LEsVCAmp(&LE_IED.S1.MUnn.IEC_61850_9_2LETCTR_1.Amp.sVC); + init_IEC_61850_9_2LEsVCAmp(&LE_IED.S1.MUnn.IEC_61850_9_2LETCTR_2.Amp.sVC); + init_IEC_61850_9_2LEsVCAmp(&LE_IED.S1.MUnn.IEC_61850_9_2LETCTR_3.Amp.sVC); + init_IEC_61850_9_2LEsVCAmp(&LE_IED.S1.MUnn.IEC_61850_9_2LETCTR_4.Amp.sVC); + init_IEC_61850_9_2LEsVCVol(&LE_IED.S1.MUnn.IEC_61850_9_2LETVTR_1.Vol.sVC); + init_IEC_61850_9_2LEsVCVol(&LE_IED.S1.MUnn.IEC_61850_9_2LETVTR_2.Vol.sVC); + init_IEC_61850_9_2LEsVCVol(&LE_IED.S1.MUnn.IEC_61850_9_2LETVTR_3.Vol.sVC); + init_IEC_61850_9_2LEsVCVol(&LE_IED.S1.MUnn.IEC_61850_9_2LETVTR_4.Vol.sVC); + init_IEC_61850_9_2LEsVCAmp(&LE_IED_RECV.S1.MUnn.IEC_61850_9_2LETCTR_1.Amp.sVC); + init_IEC_61850_9_2LEsVCAmp(&LE_IED_RECV.S1.MUnn.IEC_61850_9_2LETCTR_2.Amp.sVC); + init_IEC_61850_9_2LEsVCAmp(&LE_IED_RECV.S1.MUnn.IEC_61850_9_2LETCTR_3.Amp.sVC); + init_IEC_61850_9_2LEsVCAmp(&LE_IED_RECV.S1.MUnn.IEC_61850_9_2LETCTR_4.Amp.sVC); + init_IEC_61850_9_2LEsVCVol(&LE_IED_RECV.S1.MUnn.IEC_61850_9_2LETVTR_1.Vol.sVC); + init_IEC_61850_9_2LEsVCVol(&LE_IED_RECV.S1.MUnn.IEC_61850_9_2LETVTR_2.Vol.sVC); + init_IEC_61850_9_2LEsVCVol(&LE_IED_RECV.S1.MUnn.IEC_61850_9_2LETVTR_3.Vol.sVC); + init_IEC_61850_9_2LEsVCVol(&LE_IED_RECV.S1.MUnn.IEC_61850_9_2LETVTR_4.Vol.sVC); +} +
diff -r 000000000000 -r f09b7bb8bcce rapid61850/datatypes.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rapid61850/datatypes.h Tue Oct 02 21:31:05 2012 +0000 @@ -0,0 +1,109 @@ +/** + * Rapid-prototyping protection schemes with IEC 61850 + * + * Copyright (c) 2012 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. + */ + +#ifndef DATATYPES_H +#define DATATYPES_H + +#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */ +extern "C" { +#endif + +#include "ctypes.h" + + +// enums + +// data attributes +struct IEC_61850_9_2LEAV { + CTYPE_INT32 i; +}; +struct IEC_61850_9_2LEsVCAmp { + CTYPE_FLOAT32 scaleFactor; + CTYPE_FLOAT32 offset; +}; +struct IEC_61850_9_2LEsVCVol { + CTYPE_FLOAT32 scaleFactor; + CTYPE_FLOAT32 offset; +}; + +// data objects +struct IEC_61850_9_2LESAVAmp { + struct IEC_61850_9_2LEAV instMag; + CTYPE_QUALITY q; + struct IEC_61850_9_2LEsVCAmp sVC; +}; +struct IEC_61850_9_2LESAVVol { + struct IEC_61850_9_2LEAV instMag; + CTYPE_QUALITY q; + struct IEC_61850_9_2LEsVCVol sVC; +}; +struct IEC_61850_9_2LEINC { + CTYPE_INT32 ctlVal; + CTYPE_INT32 stVal; + CTYPE_QUALITY q; + CTYPE_TIMESTAMP t; +}; + +// datasets +struct LE_IED_MUnn_PhsMeas1 { + struct IEC_61850_9_2LEAV MUnn_TCTR_1_Amp_instMag; + CTYPE_QUALITY MUnn_TCTR_1_Amp_q; + struct IEC_61850_9_2LEAV MUnn_TCTR_2_Amp_instMag; + CTYPE_QUALITY MUnn_TCTR_2_Amp_q; + struct IEC_61850_9_2LEAV MUnn_TCTR_3_Amp_instMag; + CTYPE_QUALITY MUnn_TCTR_3_Amp_q; + struct IEC_61850_9_2LEAV MUnn_TCTR_4_Amp_instMag; + CTYPE_QUALITY MUnn_TCTR_4_Amp_q; + struct IEC_61850_9_2LEAV MUnn_TVTR_1_Vol_instMag; + CTYPE_QUALITY MUnn_TVTR_1_Vol_q; + struct IEC_61850_9_2LEAV MUnn_TVTR_2_Vol_instMag; + CTYPE_QUALITY MUnn_TVTR_2_Vol_q; + struct IEC_61850_9_2LEAV MUnn_TVTR_3_Vol_instMag; + CTYPE_QUALITY MUnn_TVTR_3_Vol_q; + struct IEC_61850_9_2LEAV MUnn_TVTR_4_Vol_instMag; + CTYPE_QUALITY MUnn_TVTR_4_Vol_q; +}; + +// logical nodes +struct IEC_61850_9_2LELLN0 { + struct IEC_61850_9_2LEINC Mod; +}; +struct IEC_61850_9_2LETCTR { + struct IEC_61850_9_2LESAVAmp Amp; + struct { + struct LE_IED_MUnn_PhsMeas1 LE_IED_MUnn_PhsMeas1; + void (*datasetDecodeDone)(CTYPE_INT16U smpCnt); + CTYPE_INT16U smpCnt; + } sv_inputs_MSVCB01; +}; +struct IEC_61850_9_2LETVTR { + struct IEC_61850_9_2LESAVVol Vol; +}; + +void init_datatypes(void); + + + + +#ifdef __cplusplus /* If this is a C++ compiler, end C linkage */ +} +#endif + +#endif
diff -r 000000000000 -r f09b7bb8bcce rapid61850/decodePacket.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rapid61850/decodePacket.c Tue Oct 02 21:31:05 2012 +0000 @@ -0,0 +1,52 @@ +/** + * Rapid-prototyping protection schemes with IEC 61850 + * + * Copyright (c) 2012 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 "decodePacket.h" +//#include "svEncodeBasic.h" + + +// returns size of length field, from first byte +int getLengthFieldSize(unsigned char byte) { + if (byte <= 126) { + return 1; + } + else { + return 1 + (byte & 0x7F); + } +} + +//TODO check this works for all inputs, e.g., buf[1] = 0xFF +int decodeLength(unsigned char *buf) { + if (buf[0] <= 126) { + return buf[0]; + } + else { + int bytes = (buf[0] & 0x7F); + + if (bytes == 1) { + return buf[1]; + } + else if (bytes == 2) { // assumes max length of 2^15 + return ((buf[1] & 0xFF) << 8) | (buf[2] & 0xFF); + } + } + + return 0; +}
diff -r 000000000000 -r f09b7bb8bcce rapid61850/decodePacket.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rapid61850/decodePacket.h Tue Oct 02 21:31:05 2012 +0000 @@ -0,0 +1,35 @@ +/** + * Rapid-prototyping protection schemes with IEC 61850 + * + * Copyright (c) 2012 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. + */ + +#ifndef DECODE_PACKET_H +#define DECODE_PACKET_H + +#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */ +extern "C" { +#endif + +int getLengthFieldSize(unsigned char byte); +int decodeLength(unsigned char *buf); + +#ifdef __cplusplus /* If this is a C++ compiler, end C linkage */ +} +#endif + +#endif
diff -r 000000000000 -r f09b7bb8bcce rapid61850/encodePacket.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rapid61850/encodePacket.c Tue Oct 02 21:31:05 2012 +0000 @@ -0,0 +1,54 @@ +/** + * Rapid-prototyping protection schemes with IEC 61850 + * + * Copyright (c) 2012 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 "encodePacket.h" +#include "svEncodeBasic.h" + +int getLengthBytes(int len) { + if (len <= 126) { + return 1; + } + else if (len <= 255) { + return 2; + } + else { + return 3; + } +} + +int encodeLength(unsigned char *buf, CTYPE_INT16U len) { + if (len <= 126) { + buf[0] = (unsigned char) len; + return 1; + } + else if (len <= 255) { + buf[0] = (unsigned char) 0x81; // 0x80 specifies larger than one byte; 0x02 is number of length bytes to follow + buf[1] = (unsigned char) len; + + return 2; + } + else { + // assume length is not greater than 2^15 + buf[0] = (unsigned char) 0x82; // 0x80 specifies larger than one byte; 0x02 is number of length bytes to follow + ENCODE_CTYPE_INT16U(&buf[1], &len); + + return 3; + } +}
diff -r 000000000000 -r f09b7bb8bcce rapid61850/encodePacket.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rapid61850/encodePacket.h Tue Oct 02 21:31:05 2012 +0000 @@ -0,0 +1,37 @@ +/** + * Rapid-prototyping protection schemes with IEC 61850 + * + * Copyright (c) 2012 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. + */ + +#ifndef ENCODE_PACKET_H +#define ENCODE_PACKET_H + +#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */ +extern "C" { +#endif + +#include "ctypes.h" + +int getLengthBytes(int len); +int encodeLength(unsigned char *buf, CTYPE_INT16U len); + +#ifdef __cplusplus /* If this is a C++ compiler, end C linkage */ +} +#endif + +#endif
diff -r 000000000000 -r f09b7bb8bcce rapid61850/gse.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rapid61850/gse.c Tue Oct 02 21:31:05 2012 +0000 @@ -0,0 +1,33 @@ +/** + * Rapid-prototyping protection schemes with IEC 61850 + * + * Copyright (c) 2012 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 "ied.h" +#include "gsePacketData.h" +#include "gseDecode.h" +#include "gseEncode.h" + + + + + + +void init_gse() { +} +
diff -r 000000000000 -r f09b7bb8bcce rapid61850/gse.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rapid61850/gse.h Tue Oct 02 21:31:05 2012 +0000 @@ -0,0 +1,45 @@ +/** + * Rapid-prototyping protection schemes with IEC 61850 + * + * Copyright (c) 2012 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. + */ + +#ifndef GSE_H +#define GSE_H + +#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */ +extern "C" { +#endif + +#include "gseEncode.h" +#include "gseDecode.h" +#include "gsePacketData.h" + + + + +void init_gse(void); +void gseDecode(unsigned char *buf, int len); + + + + +#ifdef __cplusplus /* If this is a C++ compiler, end C linkage */ +} +#endif + +#endif
diff -r 000000000000 -r f09b7bb8bcce rapid61850/gseDecode.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rapid61850/gseDecode.c Tue Oct 02 21:31:05 2012 +0000 @@ -0,0 +1,131 @@ +/** + * Rapid-prototyping protection schemes with IEC 61850 + * + * Copyright (c) 2012 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 "gseDecodeBasic.h" +#include "gse.h" +#include "ied.h" +#include "gseDecode.h" + + + + +int ber_decode_IEC_61850_9_2LEAV(unsigned char *buf, struct IEC_61850_9_2LEAV *IEC_61850_9_2LEAV) { + int offset = 0; + + if (buf[offset++] == 0xA2) { + offset += getLengthFieldSize(buf[offset]); + + offset += BER_DECODE_CTYPE_INT32(&buf[offset], &IEC_61850_9_2LEAV->i); + } + + return offset; +} +int ber_decode_IEC_61850_9_2LEsVCAmp(unsigned char *buf, struct IEC_61850_9_2LEsVCAmp *IEC_61850_9_2LEsVCAmp) { + int offset = 0; + + if (buf[offset++] == 0xA2) { + offset += getLengthFieldSize(buf[offset]); + + offset += BER_DECODE_CTYPE_FLOAT32(&buf[offset], &IEC_61850_9_2LEsVCAmp->scaleFactor); + offset += BER_DECODE_CTYPE_FLOAT32(&buf[offset], &IEC_61850_9_2LEsVCAmp->offset); + } + + return offset; +} +int ber_decode_IEC_61850_9_2LEsVCVol(unsigned char *buf, struct IEC_61850_9_2LEsVCVol *IEC_61850_9_2LEsVCVol) { + int offset = 0; + + if (buf[offset++] == 0xA2) { + offset += getLengthFieldSize(buf[offset]); + + offset += BER_DECODE_CTYPE_FLOAT32(&buf[offset], &IEC_61850_9_2LEsVCVol->scaleFactor); + offset += BER_DECODE_CTYPE_FLOAT32(&buf[offset], &IEC_61850_9_2LEsVCVol->offset); + } + + return offset; +} +int ber_decode_IEC_61850_9_2LESAVAmp(unsigned char *buf, struct IEC_61850_9_2LESAVAmp *IEC_61850_9_2LESAVAmp) { + int offset = 0; + + if (buf[offset++] == 0xA2) { + offset += getLengthFieldSize(buf[offset]); + + offset += ber_decode_IEC_61850_9_2LEAV(&buf[offset], &IEC_61850_9_2LESAVAmp->instMag); + offset += BER_DECODE_CTYPE_QUALITY(&buf[offset], &IEC_61850_9_2LESAVAmp->q); + offset += ber_decode_IEC_61850_9_2LEsVCAmp(&buf[offset], &IEC_61850_9_2LESAVAmp->sVC); + } + + return offset; +} +int ber_decode_IEC_61850_9_2LESAVVol(unsigned char *buf, struct IEC_61850_9_2LESAVVol *IEC_61850_9_2LESAVVol) { + int offset = 0; + + if (buf[offset++] == 0xA2) { + offset += getLengthFieldSize(buf[offset]); + + offset += ber_decode_IEC_61850_9_2LEAV(&buf[offset], &IEC_61850_9_2LESAVVol->instMag); + offset += BER_DECODE_CTYPE_QUALITY(&buf[offset], &IEC_61850_9_2LESAVVol->q); + offset += ber_decode_IEC_61850_9_2LEsVCVol(&buf[offset], &IEC_61850_9_2LESAVVol->sVC); + } + + return offset; +} +int ber_decode_IEC_61850_9_2LEINC(unsigned char *buf, struct IEC_61850_9_2LEINC *IEC_61850_9_2LEINC) { + int offset = 0; + + if (buf[offset++] == 0xA2) { + offset += getLengthFieldSize(buf[offset]); + + offset += BER_DECODE_CTYPE_INT32(&buf[offset], &IEC_61850_9_2LEINC->ctlVal); + offset += BER_DECODE_CTYPE_INT32(&buf[offset], &IEC_61850_9_2LEINC->stVal); + offset += BER_DECODE_CTYPE_QUALITY(&buf[offset], &IEC_61850_9_2LEINC->q); + offset += BER_DECODE_CTYPE_TIMESTAMP(&buf[offset], &IEC_61850_9_2LEINC->t); + } + + return offset; +} +int ber_decode_LE_IED_MUnn_PhsMeas1(unsigned char *buf, struct LE_IED_MUnn_PhsMeas1 *LE_IED_MUnn_PhsMeas1) { + int offset = 0; + + offset += ber_decode_IEC_61850_9_2LEAV(&buf[offset], &LE_IED_MUnn_PhsMeas1->MUnn_TCTR_1_Amp_instMag); + offset += BER_DECODE_CTYPE_QUALITY(&buf[offset], &LE_IED_MUnn_PhsMeas1->MUnn_TCTR_1_Amp_q); + offset += ber_decode_IEC_61850_9_2LEAV(&buf[offset], &LE_IED_MUnn_PhsMeas1->MUnn_TCTR_2_Amp_instMag); + offset += BER_DECODE_CTYPE_QUALITY(&buf[offset], &LE_IED_MUnn_PhsMeas1->MUnn_TCTR_2_Amp_q); + offset += ber_decode_IEC_61850_9_2LEAV(&buf[offset], &LE_IED_MUnn_PhsMeas1->MUnn_TCTR_3_Amp_instMag); + offset += BER_DECODE_CTYPE_QUALITY(&buf[offset], &LE_IED_MUnn_PhsMeas1->MUnn_TCTR_3_Amp_q); + offset += ber_decode_IEC_61850_9_2LEAV(&buf[offset], &LE_IED_MUnn_PhsMeas1->MUnn_TCTR_4_Amp_instMag); + offset += BER_DECODE_CTYPE_QUALITY(&buf[offset], &LE_IED_MUnn_PhsMeas1->MUnn_TCTR_4_Amp_q); + offset += ber_decode_IEC_61850_9_2LEAV(&buf[offset], &LE_IED_MUnn_PhsMeas1->MUnn_TVTR_1_Vol_instMag); + offset += BER_DECODE_CTYPE_QUALITY(&buf[offset], &LE_IED_MUnn_PhsMeas1->MUnn_TVTR_1_Vol_q); + offset += ber_decode_IEC_61850_9_2LEAV(&buf[offset], &LE_IED_MUnn_PhsMeas1->MUnn_TVTR_2_Vol_instMag); + offset += BER_DECODE_CTYPE_QUALITY(&buf[offset], &LE_IED_MUnn_PhsMeas1->MUnn_TVTR_2_Vol_q); + offset += ber_decode_IEC_61850_9_2LEAV(&buf[offset], &LE_IED_MUnn_PhsMeas1->MUnn_TVTR_3_Vol_instMag); + offset += BER_DECODE_CTYPE_QUALITY(&buf[offset], &LE_IED_MUnn_PhsMeas1->MUnn_TVTR_3_Vol_q); + offset += ber_decode_IEC_61850_9_2LEAV(&buf[offset], &LE_IED_MUnn_PhsMeas1->MUnn_TVTR_4_Vol_instMag); + offset += BER_DECODE_CTYPE_QUALITY(&buf[offset], &LE_IED_MUnn_PhsMeas1->MUnn_TVTR_4_Vol_q); + + return offset; +} + +void gseDecodeDataset(unsigned char *dataset, CTYPE_INT16U datasetLength, unsigned char *gocbRef, CTYPE_INT16U gocbRefLength, CTYPE_INT32U timeAllowedToLive, CTYPE_TIMESTAMP T, CTYPE_INT32U stNum, CTYPE_INT32U sqNum) { + +} + +
diff -r 000000000000 -r f09b7bb8bcce rapid61850/gseDecode.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rapid61850/gseDecode.h Tue Oct 02 21:31:05 2012 +0000 @@ -0,0 +1,44 @@ +/** + * Rapid-prototyping protection schemes with IEC 61850 + * + * Copyright (c) 2012 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. + */ + +#ifndef GSE_DECODE_H +#define GSE_DECODE_H + +#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */ +extern "C" { +#endif + +#include "gsePacketData.h" +#include "datatypes.h" + + + + +int ber_decode_LE_IED_MUnn_PhsMeas1(unsigned char *buf, struct LE_IED_MUnn_PhsMeas1 *LE_IED_MUnn_PhsMeas1); + +void gseDecodeDataset(unsigned char *dataset, CTYPE_INT16U datasetLength, unsigned char *gocbRef, CTYPE_INT16U gocbRefLength, CTYPE_INT32U timeAllowedToLive, CTYPE_TIMESTAMP T, CTYPE_INT32U stNum, CTYPE_INT32U sqNum); + + + +#ifdef __cplusplus /* If this is a C++ compiler, end C linkage */ +} +#endif + +#endif
diff -r 000000000000 -r f09b7bb8bcce rapid61850/gseDecodeBasic.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rapid61850/gseDecodeBasic.c Tue Oct 02 21:31:05 2012 +0000 @@ -0,0 +1,198 @@ +/** + * Rapid-prototyping protection schemes with IEC 61850 + * + * Copyright (c) 2012 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 "ctypes.h" +#include "datatypes.h" +#include "ied.h" +#include "gseDecodeBasic.h" +#include <string.h> + +// GSE decoding of basic types +int BER_DECODE_CTYPE_FLOAT32(unsigned char *buf, CTYPE_FLOAT32 *value) { + CTYPE_INT16U offset = 0; + CTYPE_INT16U len = 0; + + if (buf[offset++] == 0x87) { + len += decodeLength(&buf[offset]); + offset += getLengthFieldSize(buf[offset]); + + // check for fixed-length GOOSE. If not, check for 8 bits for exponent + if (len == 5 && buf[offset] == 0x08) { + netmemcpy(value, &buf[offset + 1], len - 1); + } + else if (len == 4) { + netmemcpy(value, &buf[offset], len); + } + } + + return offset + len; +} + +int BER_DECODE_CTYPE_FLOAT64(unsigned char *buf, CTYPE_FLOAT64 *value) { + CTYPE_INT16U offset = 0; + CTYPE_INT16U len = 0; + + if (buf[offset++] == 0x87) { + len += decodeLength(&buf[offset]); + offset += getLengthFieldSize(buf[offset]); + + // check for fixed-length GOOSE. If not, check for 11 bits for exponent + if (len == 9 && buf[offset] == 0x0B) { + netmemcpy(value, &buf[offset + 1], len - 1); + } + else if (len == 8) { + netmemcpy(value, &buf[offset], len); + } + } + + return offset + len; +} +int BER_DECODE_CTYPE_QUALITY(unsigned char *buf, CTYPE_QUALITY *value) { + CTYPE_INT16U offset = 0; + CTYPE_INT16U len = 0; + + if (buf[offset] == ASN1_TAG_BIT_STRING) { + offset++; + len += decodeLength(&buf[offset]); + offset += getLengthFieldSize(buf[offset]); + + netmemcpy(value, &buf[offset + 1], len - 1); // skip over one byte (which contains number of unused bits) + } + + return offset + len; +} +int BER_DECODE_CTYPE_TIMESTAMP(unsigned char *buf, CTYPE_TIMESTAMP *value) { + CTYPE_INT16U offset = 0; + CTYPE_INT16U len = 0; + + if (buf[offset++] == 0x89) { + len += decodeLength(&buf[offset]); + offset += getLengthFieldSize(buf[offset]); + + netmemcpy(value, &buf[offset], len); + } + + return offset + len; +} +int BER_DECODE_CTYPE_ENUM(unsigned char *buf, CTYPE_ENUM *value) { // assuming enum is an int - allows any enum type to be used + CTYPE_INT16U offset = 0; + CTYPE_INT16U len = 0; + + if (buf[offset++] == ASN1_TAG_UNSIGNED) { + len += decodeLength(&buf[offset]); + offset += getLengthFieldSize(buf[offset]); + +#if GOOSE_FIXED_SIZE == 1 + ber_decode_integer(&buf[offset], len, value, SV_GET_LENGTH_INT8); +#else + ber_decode_integer(&buf[offset], len, value, SV_GET_LENGTH_INT32U); +#endif + } + + return offset + len; +} +int BER_DECODE_CTYPE_INT8(unsigned char *buf, CTYPE_INT8 *value) { + CTYPE_INT16U offset = 0; + CTYPE_INT16U len = 0; + + if (buf[offset++] == ASN1_TAG_INTEGER) { + len += decodeLength(&buf[offset]); + offset += getLengthFieldSize(buf[offset]); + + ber_decode_integer(&buf[offset], len, value, SV_GET_LENGTH_INT8); + } + + return offset + len; +} +int BER_DECODE_CTYPE_INT16(unsigned char *buf, CTYPE_INT16 *value) { + CTYPE_INT16U offset = 0; + CTYPE_INT16U len = 0; + + if (buf[offset++] == ASN1_TAG_INTEGER) { + len += decodeLength(&buf[offset]); + offset += getLengthFieldSize(buf[offset]); + + ber_decode_integer(&buf[offset], len, value, SV_GET_LENGTH_INT16); + } + + return offset + len; +} +int BER_DECODE_CTYPE_INT32(unsigned char *buf, CTYPE_INT32 *value) { + CTYPE_INT16U offset = 0; + CTYPE_INT16U len = 0; + + if (buf[offset++] == ASN1_TAG_INTEGER) { + len += decodeLength(&buf[offset]); + offset += getLengthFieldSize(buf[offset]); + + ber_decode_integer(&buf[offset], len, value, SV_GET_LENGTH_INT32); + } + + return offset + len; +} +int BER_DECODE_CTYPE_INT16U(unsigned char *buf, CTYPE_INT16U *value) { + CTYPE_INT16U offset = 0; + CTYPE_INT16U len = 0; + + if (buf[offset++] == ASN1_TAG_UNSIGNED) { + len += decodeLength(&buf[offset]); + offset += getLengthFieldSize(buf[offset]); + + ber_decode_integer(&buf[offset], len, value, SV_GET_LENGTH_INT16U); + } + + return offset + len; +} +int BER_DECODE_CTYPE_INT32U(unsigned char *buf, CTYPE_INT32U *value) { + CTYPE_INT16U offset = 0; + CTYPE_INT16U len = 0; + + if (buf[offset++] == ASN1_TAG_UNSIGNED) { + len += decodeLength(&buf[offset]); + offset += getLengthFieldSize(buf[offset]); + + ber_decode_integer(&buf[offset], len, value, SV_GET_LENGTH_INT32U); + } + + return offset + len; +} +int BER_DECODE_CTYPE_VISSTRING255(unsigned char *buf, CTYPE_VISSTRING255 *value) { + netmemcpy(value, buf, SV_GET_LENGTH_VISSTRING255); + + return SV_GET_LENGTH_VISSTRING255; +} +int BER_DECODE_CTYPE_BOOLEAN(unsigned char *buf, CTYPE_BOOLEAN *value) { + CTYPE_INT16U offset = 0; + CTYPE_INT16U len = 0; + + if (buf[offset++] == ASN1_TAG_BOOLEAN) { + len += decodeLength(&buf[offset]); + offset += getLengthFieldSize(buf[offset]); + + netmemcpy(value, &buf[offset], len); + } + + return offset + len; +} +int BER_DECODE_CTYPE_DBPOS(unsigned char *buf, CTYPE_DBPOS *value) { + netmemcpy(value, buf, SV_GET_LENGTH_DBPOS); + + return SV_GET_LENGTH_DBPOS; +}
diff -r 000000000000 -r f09b7bb8bcce rapid61850/gseDecodeBasic.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rapid61850/gseDecodeBasic.h Tue Oct 02 21:31:05 2012 +0000 @@ -0,0 +1,48 @@ +/** + * Rapid-prototyping protection schemes with IEC 61850 + * + * Copyright (c) 2012 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. + */ + +#ifndef GSE_BER_DECODE_BASIC_H +#define GSE_BER_DECODE_BASIC_H + +#include "datatypes.h" +#include "decodePacket.h" + +#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */ +extern "C" { +#endif + +int BER_DECODE_CTYPE_FLOAT32(unsigned char *buf, CTYPE_FLOAT32 *value); +int BER_DECODE_CTYPE_QUALITY(unsigned char *buf, CTYPE_QUALITY *value); +int BER_DECODE_CTYPE_TIMESTAMP(unsigned char *buf, CTYPE_TIMESTAMP *value); +int BER_DECODE_CTYPE_ENUM(unsigned char *buf, CTYPE_ENUM *value); +int BER_DECODE_CTYPE_INT8(unsigned char *buf, CTYPE_INT8 *value); +int BER_DECODE_CTYPE_INT16(unsigned char *buf, CTYPE_INT16 *value); +int BER_DECODE_CTYPE_INT32(unsigned char *buf, CTYPE_INT32 *value); +int BER_DECODE_CTYPE_INT16U(unsigned char *buf, CTYPE_INT16U *value); +int BER_DECODE_CTYPE_INT32U(unsigned char *buf, CTYPE_INT32U *value); +int BER_DECODE_CTYPE_VISSTRING255(unsigned char *buf, CTYPE_VISSTRING255 *value); +int BER_DECODE_CTYPE_BOOLEAN(unsigned char *buf, CTYPE_BOOLEAN *value); +int BER_DECODE_CTYPE_DBPOS(unsigned char *buf, CTYPE_DBPOS *value); + +#ifdef __cplusplus /* If this is a C++ compiler, end C linkage */ +} +#endif + +#endif
diff -r 000000000000 -r f09b7bb8bcce rapid61850/gseDecodePacket.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rapid61850/gseDecodePacket.c Tue Oct 02 21:31:05 2012 +0000 @@ -0,0 +1,98 @@ +/** + * Rapid-prototyping protection schemes with IEC 61850 + * + * Copyright (c) 2012 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 "gseDecodeBasic.h" +#include "ied.h" +#include "gseDecode.h" +#include "gsePacketData.h" +#include "decodePacket.h" +#include <stddef.h> + +void gseDecodePDU(unsigned char *buf) { + unsigned char tag = 0; + CTYPE_INT16U lengthFieldSize = 0; + CTYPE_INT16U lengthValue = 0; + CTYPE_INT16U offsetForSequence = 0; + CTYPE_INT16U offsetForNonSequence = 0; + unsigned char *gocbRef = NULL; + CTYPE_INT16U gocbRefLength = 0; + CTYPE_INT32U timeAllowedToLive = 0; + CTYPE_TIMESTAMP T = 0; + CTYPE_INT32U sqNum = 0; + CTYPE_INT32U stNum = 0; + + while (1) { + tag = (unsigned char) buf[0]; // assumes only one byte is used + lengthFieldSize = getLengthFieldSize((unsigned char) buf[1]); + lengthValue = decodeLength((unsigned char *) &buf[1]); + offsetForSequence = 1 + lengthFieldSize; + offsetForNonSequence = 1 + lengthFieldSize + lengthValue; + + switch (tag) { + case GSE_TAG_GOCBREF: + // save pointer to gocbRef name + gocbRef = &buf[offsetForSequence]; + gocbRefLength = lengthValue; + + buf = &buf[offsetForNonSequence]; + break; + case GSE_TAG_TIME_ALLOWED_TO_LIVE: + ber_decode_integer(&buf[offsetForSequence], lengthValue, &timeAllowedToLive, SV_GET_LENGTH_INT32U); + buf = &buf[offsetForNonSequence]; + break; + case ASN1_TAG_SEQUENCE: + buf = &buf[offsetForSequence]; + break; + case GSE_TAG_DATSET: + buf = &buf[offsetForNonSequence]; + break; + case GSE_TAG_T: + memcpy(&T, &buf[offsetForSequence], BER_GET_LENGTH_CTYPE_TIMESTAMP(&T)); + buf = &buf[offsetForNonSequence]; + break; + case GSE_TAG_STNUM: + ber_decode_integer(&buf[offsetForSequence], lengthValue, &stNum, SV_GET_LENGTH_INT32U); + buf = &buf[offsetForNonSequence]; + break; + case GSE_TAG_SQNUM: + ber_decode_integer(&buf[offsetForSequence], lengthValue, &sqNum, SV_GET_LENGTH_INT32U); + buf = &buf[offsetForNonSequence]; + break; + case GSE_TAG_ALLDATA: + gseDecodeDataset(&buf[offsetForSequence], lengthValue, gocbRef, gocbRefLength, timeAllowedToLive, T, stNum, sqNum); + return; + default: + buf = &buf[offsetForNonSequence]; + break; + } + } +} + +void gseDecode(unsigned char *buf, int len) { + int offset = 22; + + // check for VLAN tag + if (buf[12] == 0x81 && buf[13] == 0x00) { + offset = 26; + } + + gseDecodePDU(&buf[offset]); // cuts out frame header +}
diff -r 000000000000 -r f09b7bb8bcce rapid61850/gseEncode.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rapid61850/gseEncode.c Tue Oct 02 21:31:05 2012 +0000 @@ -0,0 +1,231 @@ +/** + * Rapid-prototyping protection schemes with IEC 61850 + * + * Copyright (c) 2012 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 "gseEncodeBasic.h" +#include "ied.h" +#include "gseEncode.h" + + + + +int ber_get_length_IEC_61850_9_2LEAV(struct IEC_61850_9_2LEAV *IEC_61850_9_2LEAV) { + int total = 0; + int len = 0; + + len = BER_GET_LENGTH_CTYPE_INT32(&IEC_61850_9_2LEAV->i); + total += len + getLengthBytes(len) + 1; + + return total; +} +int ber_encode_IEC_61850_9_2LEAV(unsigned char *buf, struct IEC_61850_9_2LEAV *IEC_61850_9_2LEAV) { + int offset = 0; + + buf[offset++] = 0xA2; + offset += encodeLength(&buf[offset], ber_get_length_IEC_61850_9_2LEAV(IEC_61850_9_2LEAV)); + + offset += BER_ENCODE_CTYPE_INT32(&buf[offset], &IEC_61850_9_2LEAV->i); + + return offset; +} +int ber_get_length_IEC_61850_9_2LEsVCAmp(struct IEC_61850_9_2LEsVCAmp *IEC_61850_9_2LEsVCAmp) { + int total = 0; + int len = 0; + + len = BER_GET_LENGTH_CTYPE_FLOAT32(&IEC_61850_9_2LEsVCAmp->scaleFactor); + total += len + getLengthBytes(len) + 1; + len = BER_GET_LENGTH_CTYPE_FLOAT32(&IEC_61850_9_2LEsVCAmp->offset); + total += len + getLengthBytes(len) + 1; + + return total; +} +int ber_encode_IEC_61850_9_2LEsVCAmp(unsigned char *buf, struct IEC_61850_9_2LEsVCAmp *IEC_61850_9_2LEsVCAmp) { + int offset = 0; + + buf[offset++] = 0xA2; + offset += encodeLength(&buf[offset], ber_get_length_IEC_61850_9_2LEsVCAmp(IEC_61850_9_2LEsVCAmp)); + + offset += BER_ENCODE_CTYPE_FLOAT32(&buf[offset], &IEC_61850_9_2LEsVCAmp->scaleFactor); + offset += BER_ENCODE_CTYPE_FLOAT32(&buf[offset], &IEC_61850_9_2LEsVCAmp->offset); + + return offset; +} +int ber_get_length_IEC_61850_9_2LEsVCVol(struct IEC_61850_9_2LEsVCVol *IEC_61850_9_2LEsVCVol) { + int total = 0; + int len = 0; + + len = BER_GET_LENGTH_CTYPE_FLOAT32(&IEC_61850_9_2LEsVCVol->scaleFactor); + total += len + getLengthBytes(len) + 1; + len = BER_GET_LENGTH_CTYPE_FLOAT32(&IEC_61850_9_2LEsVCVol->offset); + total += len + getLengthBytes(len) + 1; + + return total; +} +int ber_encode_IEC_61850_9_2LEsVCVol(unsigned char *buf, struct IEC_61850_9_2LEsVCVol *IEC_61850_9_2LEsVCVol) { + int offset = 0; + + buf[offset++] = 0xA2; + offset += encodeLength(&buf[offset], ber_get_length_IEC_61850_9_2LEsVCVol(IEC_61850_9_2LEsVCVol)); + + offset += BER_ENCODE_CTYPE_FLOAT32(&buf[offset], &IEC_61850_9_2LEsVCVol->scaleFactor); + offset += BER_ENCODE_CTYPE_FLOAT32(&buf[offset], &IEC_61850_9_2LEsVCVol->offset); + + return offset; +} +int ber_get_length_IEC_61850_9_2LESAVAmp(struct IEC_61850_9_2LESAVAmp *IEC_61850_9_2LESAVAmp) { + int total = 0; + int len = 0; + + len = ber_get_length_IEC_61850_9_2LEAV(&IEC_61850_9_2LESAVAmp->instMag); + total += len + getLengthBytes(len) + 1; + len = BER_GET_LENGTH_CTYPE_QUALITY(&IEC_61850_9_2LESAVAmp->q); + total += len + getLengthBytes(len) + 1; + len = ber_get_length_IEC_61850_9_2LEsVCAmp(&IEC_61850_9_2LESAVAmp->sVC); + total += len + getLengthBytes(len) + 1; + + return total; +} +int ber_encode_IEC_61850_9_2LESAVAmp(unsigned char *buf, struct IEC_61850_9_2LESAVAmp *IEC_61850_9_2LESAVAmp) { + int offset = 0; + + buf[offset++] = 0xA2; + offset += encodeLength(&buf[offset], ber_get_length_IEC_61850_9_2LESAVAmp(IEC_61850_9_2LESAVAmp)); + + offset += ber_encode_IEC_61850_9_2LEAV(&buf[offset], &IEC_61850_9_2LESAVAmp->instMag); + offset += BER_ENCODE_CTYPE_QUALITY(&buf[offset], &IEC_61850_9_2LESAVAmp->q); + offset += ber_encode_IEC_61850_9_2LEsVCAmp(&buf[offset], &IEC_61850_9_2LESAVAmp->sVC); + + return offset; +} +int ber_get_length_IEC_61850_9_2LESAVVol(struct IEC_61850_9_2LESAVVol *IEC_61850_9_2LESAVVol) { + int total = 0; + int len = 0; + + len = ber_get_length_IEC_61850_9_2LEAV(&IEC_61850_9_2LESAVVol->instMag); + total += len + getLengthBytes(len) + 1; + len = BER_GET_LENGTH_CTYPE_QUALITY(&IEC_61850_9_2LESAVVol->q); + total += len + getLengthBytes(len) + 1; + len = ber_get_length_IEC_61850_9_2LEsVCVol(&IEC_61850_9_2LESAVVol->sVC); + total += len + getLengthBytes(len) + 1; + + return total; +} +int ber_encode_IEC_61850_9_2LESAVVol(unsigned char *buf, struct IEC_61850_9_2LESAVVol *IEC_61850_9_2LESAVVol) { + int offset = 0; + + buf[offset++] = 0xA2; + offset += encodeLength(&buf[offset], ber_get_length_IEC_61850_9_2LESAVVol(IEC_61850_9_2LESAVVol)); + + offset += ber_encode_IEC_61850_9_2LEAV(&buf[offset], &IEC_61850_9_2LESAVVol->instMag); + offset += BER_ENCODE_CTYPE_QUALITY(&buf[offset], &IEC_61850_9_2LESAVVol->q); + offset += ber_encode_IEC_61850_9_2LEsVCVol(&buf[offset], &IEC_61850_9_2LESAVVol->sVC); + + return offset; +} +int ber_get_length_IEC_61850_9_2LEINC(struct IEC_61850_9_2LEINC *IEC_61850_9_2LEINC) { + int total = 0; + int len = 0; + + len = BER_GET_LENGTH_CTYPE_INT32(&IEC_61850_9_2LEINC->ctlVal); + total += len + getLengthBytes(len) + 1; + len = BER_GET_LENGTH_CTYPE_INT32(&IEC_61850_9_2LEINC->stVal); + total += len + getLengthBytes(len) + 1; + len = BER_GET_LENGTH_CTYPE_QUALITY(&IEC_61850_9_2LEINC->q); + total += len + getLengthBytes(len) + 1; + len = BER_GET_LENGTH_CTYPE_TIMESTAMP(&IEC_61850_9_2LEINC->t); + total += len + getLengthBytes(len) + 1; + + return total; +} +int ber_encode_IEC_61850_9_2LEINC(unsigned char *buf, struct IEC_61850_9_2LEINC *IEC_61850_9_2LEINC) { + int offset = 0; + + buf[offset++] = 0xA2; + offset += encodeLength(&buf[offset], ber_get_length_IEC_61850_9_2LEINC(IEC_61850_9_2LEINC)); + + offset += BER_ENCODE_CTYPE_INT32(&buf[offset], &IEC_61850_9_2LEINC->ctlVal); + offset += BER_ENCODE_CTYPE_INT32(&buf[offset], &IEC_61850_9_2LEINC->stVal); + offset += BER_ENCODE_CTYPE_QUALITY(&buf[offset], &IEC_61850_9_2LEINC->q); + offset += BER_ENCODE_CTYPE_TIMESTAMP(&buf[offset], &IEC_61850_9_2LEINC->t); + + return offset; +} +int ber_get_length_LE_IED_MUnn_PhsMeas1() { + int total = 0; + int len = 0; + + len = ber_get_length_IEC_61850_9_2LEAV(&LE_IED.S1.MUnn.IEC_61850_9_2LETCTR_1.Amp.instMag); + total += len + getLengthBytes(len) + 1; + len = BER_GET_LENGTH_CTYPE_QUALITY(&LE_IED.S1.MUnn.IEC_61850_9_2LETCTR_1.Amp.q); + total += len + getLengthBytes(len) + 1; + len = ber_get_length_IEC_61850_9_2LEAV(&LE_IED.S1.MUnn.IEC_61850_9_2LETCTR_2.Amp.instMag); + total += len + getLengthBytes(len) + 1; + len = BER_GET_LENGTH_CTYPE_QUALITY(&LE_IED.S1.MUnn.IEC_61850_9_2LETCTR_2.Amp.q); + total += len + getLengthBytes(len) + 1; + len = ber_get_length_IEC_61850_9_2LEAV(&LE_IED.S1.MUnn.IEC_61850_9_2LETCTR_3.Amp.instMag); + total += len + getLengthBytes(len) + 1; + len = BER_GET_LENGTH_CTYPE_QUALITY(&LE_IED.S1.MUnn.IEC_61850_9_2LETCTR_3.Amp.q); + total += len + getLengthBytes(len) + 1; + len = ber_get_length_IEC_61850_9_2LEAV(&LE_IED.S1.MUnn.IEC_61850_9_2LETCTR_4.Amp.instMag); + total += len + getLengthBytes(len) + 1; + len = BER_GET_LENGTH_CTYPE_QUALITY(&LE_IED.S1.MUnn.IEC_61850_9_2LETCTR_4.Amp.q); + total += len + getLengthBytes(len) + 1; + len = ber_get_length_IEC_61850_9_2LEAV(&LE_IED.S1.MUnn.IEC_61850_9_2LETVTR_1.Vol.instMag); + total += len + getLengthBytes(len) + 1; + len = BER_GET_LENGTH_CTYPE_QUALITY(&LE_IED.S1.MUnn.IEC_61850_9_2LETVTR_1.Vol.q); + total += len + getLengthBytes(len) + 1; + len = ber_get_length_IEC_61850_9_2LEAV(&LE_IED.S1.MUnn.IEC_61850_9_2LETVTR_2.Vol.instMag); + total += len + getLengthBytes(len) + 1; + len = BER_GET_LENGTH_CTYPE_QUALITY(&LE_IED.S1.MUnn.IEC_61850_9_2LETVTR_2.Vol.q); + total += len + getLengthBytes(len) + 1; + len = ber_get_length_IEC_61850_9_2LEAV(&LE_IED.S1.MUnn.IEC_61850_9_2LETVTR_3.Vol.instMag); + total += len + getLengthBytes(len) + 1; + len = BER_GET_LENGTH_CTYPE_QUALITY(&LE_IED.S1.MUnn.IEC_61850_9_2LETVTR_3.Vol.q); + total += len + getLengthBytes(len) + 1; + len = ber_get_length_IEC_61850_9_2LEAV(&LE_IED.S1.MUnn.IEC_61850_9_2LETVTR_4.Vol.instMag); + total += len + getLengthBytes(len) + 1; + len = BER_GET_LENGTH_CTYPE_QUALITY(&LE_IED.S1.MUnn.IEC_61850_9_2LETVTR_4.Vol.q); + total += len + getLengthBytes(len) + 1; + + return total; +} +int ber_encode_LE_IED_MUnn_PhsMeas1(unsigned char *buf) { + int offset = 0; + + offset += ber_encode_IEC_61850_9_2LEAV(&buf[offset], &LE_IED.S1.MUnn.IEC_61850_9_2LETCTR_1.Amp.instMag); + offset += BER_ENCODE_CTYPE_QUALITY(&buf[offset], &LE_IED.S1.MUnn.IEC_61850_9_2LETCTR_1.Amp.q); + offset += ber_encode_IEC_61850_9_2LEAV(&buf[offset], &LE_IED.S1.MUnn.IEC_61850_9_2LETCTR_2.Amp.instMag); + offset += BER_ENCODE_CTYPE_QUALITY(&buf[offset], &LE_IED.S1.MUnn.IEC_61850_9_2LETCTR_2.Amp.q); + offset += ber_encode_IEC_61850_9_2LEAV(&buf[offset], &LE_IED.S1.MUnn.IEC_61850_9_2LETCTR_3.Amp.instMag); + offset += BER_ENCODE_CTYPE_QUALITY(&buf[offset], &LE_IED.S1.MUnn.IEC_61850_9_2LETCTR_3.Amp.q); + offset += ber_encode_IEC_61850_9_2LEAV(&buf[offset], &LE_IED.S1.MUnn.IEC_61850_9_2LETCTR_4.Amp.instMag); + offset += BER_ENCODE_CTYPE_QUALITY(&buf[offset], &LE_IED.S1.MUnn.IEC_61850_9_2LETCTR_4.Amp.q); + offset += ber_encode_IEC_61850_9_2LEAV(&buf[offset], &LE_IED.S1.MUnn.IEC_61850_9_2LETVTR_1.Vol.instMag); + offset += BER_ENCODE_CTYPE_QUALITY(&buf[offset], &LE_IED.S1.MUnn.IEC_61850_9_2LETVTR_1.Vol.q); + offset += ber_encode_IEC_61850_9_2LEAV(&buf[offset], &LE_IED.S1.MUnn.IEC_61850_9_2LETVTR_2.Vol.instMag); + offset += BER_ENCODE_CTYPE_QUALITY(&buf[offset], &LE_IED.S1.MUnn.IEC_61850_9_2LETVTR_2.Vol.q); + offset += ber_encode_IEC_61850_9_2LEAV(&buf[offset], &LE_IED.S1.MUnn.IEC_61850_9_2LETVTR_3.Vol.instMag); + offset += BER_ENCODE_CTYPE_QUALITY(&buf[offset], &LE_IED.S1.MUnn.IEC_61850_9_2LETVTR_3.Vol.q); + offset += ber_encode_IEC_61850_9_2LEAV(&buf[offset], &LE_IED.S1.MUnn.IEC_61850_9_2LETVTR_4.Vol.instMag); + offset += BER_ENCODE_CTYPE_QUALITY(&buf[offset], &LE_IED.S1.MUnn.IEC_61850_9_2LETVTR_4.Vol.q); + + return offset; +} + +
diff -r 000000000000 -r f09b7bb8bcce rapid61850/gseEncode.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rapid61850/gseEncode.h Tue Oct 02 21:31:05 2012 +0000 @@ -0,0 +1,44 @@ +/** + * Rapid-prototyping protection schemes with IEC 61850 + * + * Copyright (c) 2012 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. + */ + +#ifndef GSE_ENCODE_H +#define GSE_ENCODE_H + +#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */ +extern "C" { +#endif + +#include "gseEncodeBasic.h" +#include "gsePacketData.h" + + + + +int ber_get_length_LE_IED_MUnn_PhsMeas1(); +int ber_encode_LE_IED_MUnn_PhsMeas1(unsigned char *buf); +int gseEncodePacket(struct gseControl *gseControl, unsigned char *buf); + + + +#ifdef __cplusplus /* If this is a C++ compiler, end C linkage */ +} +#endif + +#endif
diff -r 000000000000 -r f09b7bb8bcce rapid61850/gseEncodeBasic.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rapid61850/gseEncodeBasic.c Tue Oct 02 21:31:05 2012 +0000 @@ -0,0 +1,196 @@ +/** + * Rapid-prototyping protection schemes with IEC 61850 + * + * Copyright (c) 2012 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. + */ + +#ifndef GSE_BER_ENCODE_BASIC_C +#define GSE_BER_ENCODE_BASIC_C + +#include "ctypes.h" +#include "datatypes.h" +#include "ied.h" +#include "gseEncodeBasic.h" + +// BER encoding of basic types +int BER_ENCODE_CTYPE_FLOAT32(unsigned char *buf, CTYPE_FLOAT32 *value) { + CTYPE_INT16U offset = 0; + CTYPE_INT16U len = BER_GET_LENGTH_CTYPE_FLOAT32(value); + + buf[offset++] = ASN1_TAG_FLOATING_POINT; + offset += encodeLength(&buf[offset], len); + + buf[offset++] = 0x08; // bits for exponent + netmemcpy(&buf[offset], value, len - 1); + + return offset + len - 1; +} +int BER_ENCODE_CTYPE_FLOAT64(unsigned char *buf, CTYPE_FLOAT64 *value) { + CTYPE_INT16U offset = 0; + CTYPE_INT16U len = BER_GET_LENGTH_CTYPE_FLOAT64(value); + + buf[offset++] = ASN1_TAG_FLOATING_POINT; + offset += encodeLength(&buf[offset], len); + + buf[offset++] = 0x0B; // bits for exponent + netmemcpy(&buf[offset], value, len - 1); + + return offset + len - 1; +} + +int BER_ENCODE_CTYPE_QUALITY(unsigned char *buf, CTYPE_QUALITY *value) { + CTYPE_INT16U offset = 0; + CTYPE_INT16U len = BER_GET_LENGTH_CTYPE_QUALITY(value); + + buf[offset++] = ASN1_TAG_BIT_STRING; + offset += encodeLength(&buf[offset], len); + + buf[offset++] = QUALITY_UNUSED_BITS; // number of unused bits + netmemcpy(&buf[offset], value, len - 1); + + return offset + len - 1; +} +int BER_ENCODE_CTYPE_TIMESTAMP(unsigned char *buf, CTYPE_TIMESTAMP *value) { + CTYPE_INT16U offset = 0; + CTYPE_INT16U len = BER_GET_LENGTH_CTYPE_TIMESTAMP(value); + + buf[offset++] = ASN1_TAG_OCTET_STRING; + offset += encodeLength(&buf[offset], len); + + memcpy(&buf[offset], value, len); + + return offset + len; +} +int BER_ENCODE_CTYPE_ENUM(unsigned char *buf, CTYPE_ENUM *value) { + CTYPE_INT16U offset = 0; + CTYPE_INT16U len = BER_GET_LENGTH_CTYPE_ENUM(value); + + buf[offset++] = ASN1_TAG_INTEGER; + offset += encodeLength(&buf[offset], len); + +#if GOOSE_FIXED_SIZE == 1 + ber_encode_integer_fixed_size(&buf[offset], value, SV_GET_LENGTH_INT8); +#else + ber_encode_integer(&buf[offset], value, SV_GET_LENGTH_INT32U); // assuming enum is an int - allows any enum type to be used +#endif + + return offset + len; +} +int BER_ENCODE_CTYPE_INT8(unsigned char *buf, CTYPE_INT8 *value) { + CTYPE_INT16U offset = 0; + CTYPE_INT16U len = BER_GET_LENGTH_CTYPE_INT8(value); + + buf[offset++] = ASN1_TAG_INTEGER; + offset += encodeLength(&buf[offset], len); + +#if GOOSE_FIXED_SIZE == 1 + ber_encode_integer_fixed_size(&buf[offset], value, SV_GET_LENGTH_INT8); +#else + ber_encode_integer(&buf[offset], value, SV_GET_LENGTH_INT8); +#endif + + return offset + len; +} +int BER_ENCODE_CTYPE_INT16(unsigned char *buf, CTYPE_INT16 *value) { + CTYPE_INT16U offset = 0; + CTYPE_INT16U len = BER_GET_LENGTH_CTYPE_INT16(value); + + buf[offset++] = ASN1_TAG_INTEGER; + offset += encodeLength(&buf[offset], len); + +#if GOOSE_FIXED_SIZE == 1 + ber_encode_integer_fixed_size(&buf[offset], value, SV_GET_LENGTH_INT16); +#else + ber_encode_integer(&buf[offset], value, SV_GET_LENGTH_INT16); +#endif + + return offset + len; +} +int BER_ENCODE_CTYPE_INT32(unsigned char *buf, CTYPE_INT32 *value) { + CTYPE_INT16U offset = 0; + CTYPE_INT16U len = BER_GET_LENGTH_CTYPE_INT32(value); + + buf[offset++] = ASN1_TAG_INTEGER; + offset += encodeLength(&buf[offset], len); + +#if GOOSE_FIXED_SIZE == 1 + ber_encode_integer_fixed_size(&buf[offset], value, SV_GET_LENGTH_INT32); +#else + ber_encode_integer(&buf[offset], value, SV_GET_LENGTH_INT32); +#endif + + return offset + len; +} +int BER_ENCODE_CTYPE_INT16U(unsigned char *buf, CTYPE_INT16U *value) { + CTYPE_INT16U offset = 0; + CTYPE_INT16U len = BER_GET_LENGTH_CTYPE_INT16U(value); + + buf[offset++] = ASN1_TAG_UNSIGNED; + offset += encodeLength(&buf[offset], len); + +#if GOOSE_FIXED_SIZE == 1 + ber_encode_integer_fixed_size(&buf[offset], value, SV_GET_LENGTH_INT16U); +#else + ber_encode_integer(&buf[offset], value, SV_GET_LENGTH_INT16U); +#endif + + return offset + len; +} +int BER_ENCODE_CTYPE_INT32U(unsigned char *buf, CTYPE_INT32U *value) { + CTYPE_INT16U offset = 0; + CTYPE_INT16U len = BER_GET_LENGTH_CTYPE_INT32U(value); + + buf[offset++] = ASN1_TAG_UNSIGNED; + offset += encodeLength(&buf[offset], len); + +#if GOOSE_FIXED_SIZE == 1 + ber_encode_integer_fixed_size(&buf[offset], value, SV_GET_LENGTH_INT32U); +#else + ber_encode_integer(&buf[offset], value, SV_GET_LENGTH_INT32U); +#endif + + return offset + len; +} +int BER_ENCODE_CTYPE_VISSTRING255(unsigned char *buf, CTYPE_VISSTRING255 *value) { + netmemcpy(buf, value, BER_GET_LENGTH_CTYPE_VISSTRING255(value)); + + return BER_GET_LENGTH_CTYPE_VISSTRING255(value); +} +int BER_ENCODE_CTYPE_BOOLEAN(unsigned char *buf, CTYPE_BOOLEAN *value) { + CTYPE_INT16U offset = 0; + CTYPE_INT16U len = BER_GET_LENGTH_CTYPE_BOOLEAN(value); + + buf[offset++] = ASN1_TAG_BOOLEAN; + offset += encodeLength(&buf[offset], len); + + netmemcpy(&buf[offset], value, len); + + return offset + len; +} +int BER_ENCODE_CTYPE_DBPOS(unsigned char *buf, CTYPE_DBPOS *value) { + CTYPE_INT16U offset = 0; + CTYPE_INT16U len = BER_GET_LENGTH_CTYPE_DBPOS(value); + + buf[offset++] = 0x85; + offset += encodeLength(&buf[offset], len); + + netmemcpy(&buf[offset], value, len); + + return offset + len; +} + +#endif
diff -r 000000000000 -r f09b7bb8bcce rapid61850/gseEncodeBasic.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rapid61850/gseEncodeBasic.h Tue Oct 02 21:31:05 2012 +0000 @@ -0,0 +1,49 @@ +/** + * Rapid-prototyping protection schemes with IEC 61850 + * + * Copyright (c) 2012 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. + */ + +#ifndef GSE_ENCODE_BASIC_H +#define GSE_ENCODE_BASIC_H + +#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */ +extern "C" { +#endif + +#include "datatypes.h" +#include "encodePacket.h" + +int BER_ENCODE_CTYPE_FLOAT32(unsigned char *buf, CTYPE_FLOAT32 *value); +int BER_ENCODE_CTYPE_FLOAT64(unsigned char *buf, CTYPE_FLOAT64 *value); +int BER_ENCODE_CTYPE_QUALITY(unsigned char *buf, CTYPE_QUALITY *value); +int BER_ENCODE_CTYPE_TIMESTAMP(unsigned char *buf, CTYPE_TIMESTAMP *value); +int BER_ENCODE_CTYPE_ENUM(unsigned char *buf, CTYPE_ENUM *value); +int BER_ENCODE_CTYPE_INT8(unsigned char *buf, CTYPE_INT8 *value); +int BER_ENCODE_CTYPE_INT16(unsigned char *buf, CTYPE_INT16 *value); +int BER_ENCODE_CTYPE_INT32(unsigned char *buf, CTYPE_INT32 *value); +int BER_ENCODE_CTYPE_INT16U(unsigned char *buf, CTYPE_INT16U *value); +int BER_ENCODE_CTYPE_INT32U(unsigned char *buf, CTYPE_INT32U *value); +int BER_ENCODE_CTYPE_VISSTRING255(unsigned char *buf, CTYPE_VISSTRING255 *value); +int BER_ENCODE_CTYPE_BOOLEAN(unsigned char *buf, CTYPE_BOOLEAN *value); +int BER_ENCODE_CTYPE_DBPOS(unsigned char *buf, CTYPE_DBPOS *value); + +#ifdef __cplusplus /* If this is a C++ compiler, end C linkage */ +} +#endif + +#endif
diff -r 000000000000 -r f09b7bb8bcce rapid61850/gseEncodePacket.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rapid61850/gseEncodePacket.c Tue Oct 02 21:31:05 2012 +0000 @@ -0,0 +1,187 @@ +/** + * Rapid-prototyping protection schemes with IEC 61850 + * + * Copyright (c) 2012 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 "encodePacket.h" +#include "gsePacketData.h" +#include "gseEncode.h" +#include "svEncode.h" + +int getGseHeaderLength(struct gseControl *gseControl) { + int size = 0; + int len = 0; + + size = strlen((const char *) gseControl->gocbRef); + len += size + getLengthBytes(size) + 1; + + size = BER_GET_LENGTH_CTYPE_INT32U(&gseControl->timeAllowedToLive); + len += size + getLengthBytes(size) + 1; + + size = strlen((const char *) gseControl->datSet); + len += size + getLengthBytes(size) + 1; + + size = strlen((const char *) gseControl->goID); + len += size + getLengthBytes(size) + 1; + + size = BER_GET_LENGTH_CTYPE_TIMESTAMP(&gseControl->t); + len += size + getLengthBytes(size) + 1; + + size = BER_GET_LENGTH_CTYPE_INT32U(&gseControl->stNum); + len += size + getLengthBytes(size) + 1; + + size = BER_GET_LENGTH_CTYPE_INT32U(&gseControl->sqNum); + len += size + getLengthBytes(size) + 1; + + size = BER_GET_LENGTH_CTYPE_BOOLEAN(&gseControl->test); + len += size + getLengthBytes(size) + 1; + + size = BER_GET_LENGTH_CTYPE_INT32U(&gseControl->confRev); + len += size + getLengthBytes(size) + 1; + + size = BER_GET_LENGTH_CTYPE_BOOLEAN(&gseControl->ndsCom); + len += size + getLengthBytes(size) + 1; + + size = BER_GET_LENGTH_CTYPE_INT32U(&gseControl->numDatSetEntries); + len += size + getLengthBytes(size) + 1; + + size = (gseControl->getDatasetLength)(); + len += size + getLengthBytes(size) + 1; + + return len; +} + +// creates a GSE packet, including frame header. returns 0 on fail; number of bytes on success +int gseEncodePacket(struct gseControl *gseControl, unsigned char *buf) { + int offset = 0; + int size = 0; + int ADPULength = getGseHeaderLength(gseControl); + int len = ADPULength + 9 + getLengthBytes(ADPULength); // APDU tag size (1 byte), plus 8 "header" bytes + + //printf("ADPULength: %i, len: %i\n", ADPULength, len); + + // frame header + memcpy(&buf[offset], gseControl->ethHeaderData.destMACAddress, 6); // destination MAC addresses + offset += 6; + memcpy(&buf[offset], LOCAL_MAC_ADDRESS, 6); // source MAC addresses + offset += 6; + + buf[offset++] = 0x81; // TPID + buf[offset++] = 0x00; + + netmemcpy(&buf[offset], &gseControl->ethHeaderData.VLAN_ID, 2); // TCI + buf[offset] |= (gseControl->ethHeaderData.VLAN_PRIORITY << 5); + offset += 2; + + buf[offset++] = 0x88; // EtherType + buf[offset++] = 0xB8; + + netmemcpy(&buf[offset], &gseControl->ethHeaderData.APPID, 2); // APPID + offset += 2; + + netmemcpy(&buf[offset], &len, 2); // length + offset += 2; + + buf[offset++] = 0x00; // reserved 1 + buf[offset++] = 0x00; + buf[offset++] = 0x00; // reserved 2 + buf[offset++] = 0x00; + + buf[offset++] = ASN1_TAG_SEQUENCE; + offset += encodeLength(&buf[offset], ADPULength /*+ getLengthBytes(ADPULength) + 1*/); + + buf[offset++] = GSE_TAG_GOCBREF; + size = strlen((const char *) gseControl->gocbRef); + buf[offset++] = size; + memcpy(&buf[offset], gseControl->gocbRef, size); + offset += size; + + buf[offset++] = GSE_TAG_TIME_ALLOWED_TO_LIVE; + offset += encodeLength(&buf[offset], BER_GET_LENGTH_CTYPE_INT32U(&gseControl->timeAllowedToLive)); +#if GOOSE_FIXED_SIZE == 1 + offset += ber_encode_integer_fixed_size(&buf[offset], &gseControl->timeAllowedToLive, SV_GET_LENGTH_INT32U); +#else + offset += ber_encode_integer(&buf[offset], &gseControl->timeAllowedToLive, SV_GET_LENGTH_INT32U); +#endif + + buf[offset++] = GSE_TAG_DATSET; + size = strlen((const char *) gseControl->datSet); + buf[offset++] = size; + memcpy(&buf[offset], gseControl->datSet, size); + offset += size; + + buf[offset++] = GSE_TAG_GOID; + size = strlen((const char *) gseControl->goID); + buf[offset++] = size; + memcpy(&buf[offset], gseControl->goID, size); + offset += size; + + buf[offset++] = GSE_TAG_T; + offset += encodeLength(&buf[offset], BER_GET_LENGTH_CTYPE_TIMESTAMP(&gseControl->t)); + setTimestamp(&gseControl->t); + memcpy(&buf[offset], &gseControl->t, BER_GET_LENGTH_CTYPE_TIMESTAMP(&gseControl->t)); + offset += BER_GET_LENGTH_CTYPE_TIMESTAMP(&gseControl->t); + + buf[offset++] = GSE_TAG_STNUM; + offset += encodeLength(&buf[offset], BER_GET_LENGTH_CTYPE_INT32U(&gseControl->stNum)); +#if GOOSE_FIXED_SIZE == 1 + offset += ber_encode_integer_fixed_size(&buf[offset], &gseControl->stNum, SV_GET_LENGTH_INT32U); +#else + offset += ber_encode_integer(&buf[offset], &gseControl->stNum, SV_GET_LENGTH_INT32U); +#endif + + buf[offset++] = GSE_TAG_SQNUM; + offset += encodeLength(&buf[offset], BER_GET_LENGTH_CTYPE_INT32U(&gseControl->sqNum)); +#if GOOSE_FIXED_SIZE == 1 + offset += ber_encode_integer_fixed_size(&buf[offset], &gseControl->sqNum, SV_GET_LENGTH_INT32U); +#else + offset += ber_encode_integer(&buf[offset], &gseControl->sqNum, SV_GET_LENGTH_INT32U); +#endif + + buf[offset++] = GSE_TAG_SIMULATION; + offset += encodeLength(&buf[offset], BER_GET_LENGTH_CTYPE_BOOLEAN(&gseControl->test)); + offset += ber_encode_integer(&buf[offset], &gseControl->test, SV_GET_LENGTH_BOOLEAN); + + buf[offset++] = GSE_TAG_CONFREV; + offset += encodeLength(&buf[offset], BER_GET_LENGTH_CTYPE_INT32U(&gseControl->confRev)); +#if GOOSE_FIXED_SIZE == 1 + offset += ber_encode_integer_fixed_size(&buf[offset], &gseControl->confRev, SV_GET_LENGTH_INT32U); +#else + offset += ber_encode_integer(&buf[offset], &gseControl->confRev, SV_GET_LENGTH_INT32U); +#endif + + buf[offset++] = GSE_TAG_NDSCOM; + offset += encodeLength(&buf[offset], BER_GET_LENGTH_CTYPE_BOOLEAN(&gseControl->ndsCom)); + offset += ber_encode_integer(&buf[offset], &gseControl->ndsCom, SV_GET_LENGTH_BOOLEAN); + + buf[offset++] = GSE_TAG_NUMDATSETENTRIES; + offset += encodeLength(&buf[offset], BER_GET_LENGTH_CTYPE_INT32U(&gseControl->numDatSetEntries)); +#if GOOSE_FIXED_SIZE == 1 + offset += ber_encode_integer_fixed_size(&buf[offset], &gseControl->numDatSetEntries, SV_GET_LENGTH_INT32U); +#else + offset += ber_encode_integer(&buf[offset], &gseControl->numDatSetEntries, SV_GET_LENGTH_INT32U); +#endif + + buf[offset++] = GSE_TAG_ALLDATA; + offset += encodeLength(&buf[offset], (gseControl->getDatasetLength)()); + offset += (gseControl->encodeDataset)(&buf[offset]); + + // assume network interface, such as WinPcap, generates CRC bytes + + return offset; +}
diff -r 000000000000 -r f09b7bb8bcce rapid61850/gsePacketData.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rapid61850/gsePacketData.h Tue Oct 02 21:31:05 2012 +0000 @@ -0,0 +1,56 @@ +/** + * Rapid-prototyping protection schemes with IEC 61850 + * + * Copyright (c) 2012 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. + */ + +#ifndef GSE_PACKET_DATA_H +#define GSE_PACKET_DATA_H + +#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */ +extern "C" { +#endif + +#include <stdlib.h> +#include <string.h> +#include "ctypes.h" + +struct gseControl { + struct ethHeaderData ethHeaderData; + unsigned char *gocbRef; // <LDinst>/LLN0$<GSEControl.name> e.g. "C1/LLN0$ItlPositions" + CTYPE_INT32U timeAllowedToLive; + unsigned char *datSet; // <IEDname><LDinst>/LLN0$<DataSet.name> e.g. "E1Q1SB1C1/LLN0$Positions" + unsigned char *goID; // optional + CTYPE_TIMESTAMP t; + CTYPE_INT32U stNum; + CTYPE_INT32U sqNum; + CTYPE_BOOLEAN test; + CTYPE_INT32U confRev; + CTYPE_BOOLEAN ndsCom; + CTYPE_INT32U numDatSetEntries; + CTYPE_INT32U minTime; // stored in milliseconds + CTYPE_INT32U maxTime; // stored in milliseconds + int (*encodeDataset)(unsigned char *buf); // function pointer to dataset-specific encoder + int (*getDatasetLength)(); // function pointer to dataset-specific getLength function + int (*send)(unsigned char *buf, CTYPE_BOOLEAN statusChange, CTYPE_INT32U timeAllowedToLive); // function pointer to send GSE packet +}; + +#ifdef __cplusplus /* If this is a C++ compiler, end C linkage */ +} +#endif + +#endif
diff -r 000000000000 -r f09b7bb8bcce rapid61850/iec61850.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rapid61850/iec61850.c Tue Oct 02 21:31:05 2012 +0000 @@ -0,0 +1,27 @@ +/** + * Rapid-prototyping protection schemes with IEC 61850 + * + * Copyright (c) 2012 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 "iec61850.h" + +void initialise_iec61850() { + init_datatypes(); + init_sv(); + init_gse(); +}
diff -r 000000000000 -r f09b7bb8bcce rapid61850/iec61850.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rapid61850/iec61850.h Tue Oct 02 21:31:05 2012 +0000 @@ -0,0 +1,40 @@ +/** + * Rapid-prototyping protection schemes with IEC 61850 + * + * Copyright (c) 2012 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. + */ + +#ifndef IEC61850_H +#define IEC61850_H + +//#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */ +//extern "C" { +//#endif + + +#include "ied.h" +#include "sv.h" +#include "gse.h" + +void initialise_iec61850(); + + +//#ifdef __cplusplus /* If this is a C++ compiler, end C linkage */ +//} +//#endif + +#endif
diff -r 000000000000 -r f09b7bb8bcce rapid61850/ied.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rapid61850/ied.c Tue Oct 02 21:31:05 2012 +0000 @@ -0,0 +1,30 @@ +/** + * Rapid-prototyping protection schemes with IEC 61850 + * + * Copyright (c) 2012 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 "ied.h" +#include "datatypes.h" + + +struct LE_IED_t LE_IED; +struct LE_IED_RECV_t LE_IED_RECV; + + + +
diff -r 000000000000 -r f09b7bb8bcce rapid61850/ied.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rapid61850/ied.h Tue Oct 02 21:31:05 2012 +0000 @@ -0,0 +1,81 @@ +/** + * Rapid-prototyping protection schemes with IEC 61850 + * + * Copyright (c) 2012 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. + */ + +#ifndef IED_H +#define IED_H + +#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */ +extern "C" { +#endif + +#include "datatypes.h" +#include "sv.h" +#include "gse.h" + + +struct LE_IED_t { + struct { + struct { + struct { + struct IEC_61850_9_2LELLN0 LLN0; + struct svControl MSVCB01; + } LN0; + struct IEC_61850_9_2LETCTR IEC_61850_9_2LETCTR_1; + struct IEC_61850_9_2LETCTR IEC_61850_9_2LETCTR_2; + struct IEC_61850_9_2LETCTR IEC_61850_9_2LETCTR_3; + struct IEC_61850_9_2LETCTR IEC_61850_9_2LETCTR_4; + struct IEC_61850_9_2LETVTR IEC_61850_9_2LETVTR_1; + struct IEC_61850_9_2LETVTR IEC_61850_9_2LETVTR_2; + struct IEC_61850_9_2LETVTR IEC_61850_9_2LETVTR_3; + struct IEC_61850_9_2LETVTR IEC_61850_9_2LETVTR_4; + } MUnn; + } S1; +}; + +struct LE_IED_RECV_t { + struct { + struct { + struct { + struct IEC_61850_9_2LELLN0 LLN0; + } LN0; + struct IEC_61850_9_2LETCTR IEC_61850_9_2LETCTR_1; + struct IEC_61850_9_2LETCTR IEC_61850_9_2LETCTR_2; + struct IEC_61850_9_2LETCTR IEC_61850_9_2LETCTR_3; + struct IEC_61850_9_2LETCTR IEC_61850_9_2LETCTR_4; + struct IEC_61850_9_2LETVTR IEC_61850_9_2LETVTR_1; + struct IEC_61850_9_2LETVTR IEC_61850_9_2LETVTR_2; + struct IEC_61850_9_2LETVTR IEC_61850_9_2LETVTR_3; + struct IEC_61850_9_2LETVTR IEC_61850_9_2LETVTR_4; + } MUnn; + } S1; +}; + + + + +extern struct LE_IED_t LE_IED; +extern struct LE_IED_RECV_t LE_IED_RECV; + + +#ifdef __cplusplus /* If this is a C++ compiler, end C linkage */ +} +#endif + +#endif
diff -r 000000000000 -r f09b7bb8bcce rapid61850/sv.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rapid61850/sv.c Tue Oct 02 21:31:05 2012 +0000 @@ -0,0 +1,83 @@ +/** + * Rapid-prototyping protection schemes with IEC 61850 + * + * Copyright (c) 2012 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 "ied.h" +#include "sv.h" +#include "svPacketData.h" +#include "svDecode.h" +#include "svEncode.h" + + + + + + +// returns 1 if buf contains valid packet data +int sv_update_LE_IED_MUnn_MSVCB01(unsigned char *buf) { + int size = encode_control_LE_IED_MUnn_MSVCB01(LE_IED.S1.MUnn.LN0.MSVCB01.ASDU[LE_IED.S1.MUnn.LN0.MSVCB01.ASDUCount].data.data); + LE_IED.S1.MUnn.LN0.MSVCB01.ASDU[LE_IED.S1.MUnn.LN0.MSVCB01.ASDUCount].data.size = size; + + LE_IED.S1.MUnn.LN0.MSVCB01.ASDU[LE_IED.S1.MUnn.LN0.MSVCB01.ASDUCount].smpCnt = LE_IED.S1.MUnn.LN0.MSVCB01.sampleCountMaster; + LE_IED.S1.MUnn.LN0.MSVCB01.sampleCountMaster++; + + if (LE_IED.S1.MUnn.LN0.MSVCB01.sampleCountMaster == LE_IED.S1.MUnn.LN0.MSVCB01.ASDU[LE_IED.S1.MUnn.LN0.MSVCB01.ASDUCount].smpRate) { + LE_IED.S1.MUnn.LN0.MSVCB01.sampleCountMaster = 0; + } + + if (++LE_IED.S1.MUnn.LN0.MSVCB01.ASDUCount == LE_IED.S1.MUnn.LN0.MSVCB01.noASDU) { + LE_IED.S1.MUnn.LN0.MSVCB01.ASDUCount = 0; + return svEncodePacket(&LE_IED.S1.MUnn.LN0.MSVCB01, buf); + } + + return 0; +} + +void init_sv() { + int i = 0; + + LE_IED.S1.MUnn.LN0.MSVCB01.noASDU = 1; + LE_IED.S1.MUnn.LN0.MSVCB01.ethHeaderData.destMACAddress[0] = 0x01; + LE_IED.S1.MUnn.LN0.MSVCB01.ethHeaderData.destMACAddress[1] = 0x0C; + LE_IED.S1.MUnn.LN0.MSVCB01.ethHeaderData.destMACAddress[2] = 0xCD; + LE_IED.S1.MUnn.LN0.MSVCB01.ethHeaderData.destMACAddress[3] = 0x04; + LE_IED.S1.MUnn.LN0.MSVCB01.ethHeaderData.destMACAddress[4] = 0x00; + LE_IED.S1.MUnn.LN0.MSVCB01.ethHeaderData.destMACAddress[5] = 0x01; + LE_IED.S1.MUnn.LN0.MSVCB01.ethHeaderData.APPID = 0x4000; + LE_IED.S1.MUnn.LN0.MSVCB01.ethHeaderData.VLAN_ID = 0x123; + LE_IED.S1.MUnn.LN0.MSVCB01.ethHeaderData.VLAN_PRIORITY = 0x4; + LE_IED.S1.MUnn.LN0.MSVCB01.ASDU = (struct ASDU *) malloc(1 * sizeof(struct ASDU)); + for (i = 0; i < 1; i++) { + LE_IED.S1.MUnn.LN0.MSVCB01.ASDU[i].svID = (unsigned char *) malloc(11); + strncpy((char *) LE_IED.S1.MUnn.LN0.MSVCB01.ASDU[i].svID, "0000MU0001\0", 11); + LE_IED.S1.MUnn.LN0.MSVCB01.ASDU[i].datset = (unsigned char *) malloc(9); + strncpy((char *) LE_IED.S1.MUnn.LN0.MSVCB01.ASDU[i].datset, "PhsMeas1\0", 9); + LE_IED.S1.MUnn.LN0.MSVCB01.ASDU[i].smpCnt = 0; + LE_IED.S1.MUnn.LN0.MSVCB01.ASDU[i].confRev = 1; + LE_IED.S1.MUnn.LN0.MSVCB01.ASDU[i].smpSynch = 1; + LE_IED.S1.MUnn.LN0.MSVCB01.ASDU[i].showRefrTm = 0; + LE_IED.S1.MUnn.LN0.MSVCB01.ASDU[i].showDatset = 0; + LE_IED.S1.MUnn.LN0.MSVCB01.ASDU[i].showSmpRate = 0; + LE_IED.S1.MUnn.LN0.MSVCB01.ASDU[i].smpRate = 4000; + LE_IED.S1.MUnn.LN0.MSVCB01.ASDU[i].data.size = 0; + } + LE_IED.S1.MUnn.LN0.MSVCB01.ASDUCount = 0; + LE_IED.S1.MUnn.LN0.MSVCB01.update = &sv_update_LE_IED_MUnn_MSVCB01; +} +
diff -r 000000000000 -r f09b7bb8bcce rapid61850/sv.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rapid61850/sv.h Tue Oct 02 21:31:05 2012 +0000 @@ -0,0 +1,46 @@ +/** + * Rapid-prototyping protection schemes with IEC 61850 + * + * Copyright (c) 2012 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. + */ + +#ifndef SV_H +#define SV_H + +#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */ +extern "C" { +#endif + +#include "svEncode.h" +#include "svDecode.h" +#include "svPacketData.h" + + + + +void init_sv(); +int sv_update_LE_IED_MUnn_MSVCB01(unsigned char *buf); +void svDecode(unsigned char *buf, int len); + + + + +#ifdef __cplusplus /* If this is a C++ compiler, end C linkage */ +} +#endif + +#endif
diff -r 000000000000 -r f09b7bb8bcce rapid61850/svDecode.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rapid61850/svDecode.c Tue Oct 02 21:31:05 2012 +0000 @@ -0,0 +1,114 @@ +/** + * Rapid-prototyping protection schemes with IEC 61850 + * + * Copyright (c) 2012 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 "sv.h" +#include "svDecodeBasic.h" +#include "ied.h" +#include "svDecode.h" + + + + +int decode_IEC_61850_9_2LEAV(unsigned char *buf, struct IEC_61850_9_2LEAV *IEC_61850_9_2LEAV) { + int offset = 0; + + offset += DECODE_CTYPE_INT32(&buf[offset], &IEC_61850_9_2LEAV->i); + + return offset; +} +int decode_IEC_61850_9_2LEsVCAmp(unsigned char *buf, struct IEC_61850_9_2LEsVCAmp *IEC_61850_9_2LEsVCAmp) { + int offset = 0; + + offset += DECODE_CTYPE_FLOAT32(&buf[offset], &IEC_61850_9_2LEsVCAmp->scaleFactor); + offset += DECODE_CTYPE_FLOAT32(&buf[offset], &IEC_61850_9_2LEsVCAmp->offset); + + return offset; +} +int decode_IEC_61850_9_2LEsVCVol(unsigned char *buf, struct IEC_61850_9_2LEsVCVol *IEC_61850_9_2LEsVCVol) { + int offset = 0; + + offset += DECODE_CTYPE_FLOAT32(&buf[offset], &IEC_61850_9_2LEsVCVol->scaleFactor); + offset += DECODE_CTYPE_FLOAT32(&buf[offset], &IEC_61850_9_2LEsVCVol->offset); + + return offset; +} +int decode_IEC_61850_9_2LESAVAmp(unsigned char *buf, struct IEC_61850_9_2LESAVAmp *IEC_61850_9_2LESAVAmp) { + int offset = 0; + + offset += decode_IEC_61850_9_2LEAV(&buf[offset], &IEC_61850_9_2LESAVAmp->instMag); + offset += DECODE_CTYPE_QUALITY(&buf[offset], &IEC_61850_9_2LESAVAmp->q); + offset += decode_IEC_61850_9_2LEsVCAmp(&buf[offset], &IEC_61850_9_2LESAVAmp->sVC); + + return offset; +} +int decode_IEC_61850_9_2LESAVVol(unsigned char *buf, struct IEC_61850_9_2LESAVVol *IEC_61850_9_2LESAVVol) { + int offset = 0; + + offset += decode_IEC_61850_9_2LEAV(&buf[offset], &IEC_61850_9_2LESAVVol->instMag); + offset += DECODE_CTYPE_QUALITY(&buf[offset], &IEC_61850_9_2LESAVVol->q); + offset += decode_IEC_61850_9_2LEsVCVol(&buf[offset], &IEC_61850_9_2LESAVVol->sVC); + + return offset; +} +int decode_IEC_61850_9_2LEINC(unsigned char *buf, struct IEC_61850_9_2LEINC *IEC_61850_9_2LEINC) { + int offset = 0; + + offset += DECODE_CTYPE_INT32(&buf[offset], &IEC_61850_9_2LEINC->ctlVal); + offset += DECODE_CTYPE_INT32(&buf[offset], &IEC_61850_9_2LEINC->stVal); + offset += DECODE_CTYPE_QUALITY(&buf[offset], &IEC_61850_9_2LEINC->q); + offset += DECODE_CTYPE_TIMESTAMP(&buf[offset], &IEC_61850_9_2LEINC->t); + + return offset; +} +int decode_LE_IED_MUnn_PhsMeas1(unsigned char *buf, CTYPE_INT16U smpCnt, struct LE_IED_MUnn_PhsMeas1 *LE_IED_MUnn_PhsMeas1) { + int offset = 0; + + offset += decode_IEC_61850_9_2LEAV(&buf[offset], &LE_IED_MUnn_PhsMeas1->MUnn_TCTR_1_Amp_instMag); + offset += DECODE_CTYPE_QUALITY(&buf[offset], &LE_IED_MUnn_PhsMeas1->MUnn_TCTR_1_Amp_q); + offset += decode_IEC_61850_9_2LEAV(&buf[offset], &LE_IED_MUnn_PhsMeas1->MUnn_TCTR_2_Amp_instMag); + offset += DECODE_CTYPE_QUALITY(&buf[offset], &LE_IED_MUnn_PhsMeas1->MUnn_TCTR_2_Amp_q); + offset += decode_IEC_61850_9_2LEAV(&buf[offset], &LE_IED_MUnn_PhsMeas1->MUnn_TCTR_3_Amp_instMag); + offset += DECODE_CTYPE_QUALITY(&buf[offset], &LE_IED_MUnn_PhsMeas1->MUnn_TCTR_3_Amp_q); + offset += decode_IEC_61850_9_2LEAV(&buf[offset], &LE_IED_MUnn_PhsMeas1->MUnn_TCTR_4_Amp_instMag); + offset += DECODE_CTYPE_QUALITY(&buf[offset], &LE_IED_MUnn_PhsMeas1->MUnn_TCTR_4_Amp_q); + offset += decode_IEC_61850_9_2LEAV(&buf[offset], &LE_IED_MUnn_PhsMeas1->MUnn_TVTR_1_Vol_instMag); + offset += DECODE_CTYPE_QUALITY(&buf[offset], &LE_IED_MUnn_PhsMeas1->MUnn_TVTR_1_Vol_q); + offset += decode_IEC_61850_9_2LEAV(&buf[offset], &LE_IED_MUnn_PhsMeas1->MUnn_TVTR_2_Vol_instMag); + offset += DECODE_CTYPE_QUALITY(&buf[offset], &LE_IED_MUnn_PhsMeas1->MUnn_TVTR_2_Vol_q); + offset += decode_IEC_61850_9_2LEAV(&buf[offset], &LE_IED_MUnn_PhsMeas1->MUnn_TVTR_3_Vol_instMag); + offset += DECODE_CTYPE_QUALITY(&buf[offset], &LE_IED_MUnn_PhsMeas1->MUnn_TVTR_3_Vol_q); + offset += decode_IEC_61850_9_2LEAV(&buf[offset], &LE_IED_MUnn_PhsMeas1->MUnn_TVTR_4_Vol_instMag); + offset += DECODE_CTYPE_QUALITY(&buf[offset], &LE_IED_MUnn_PhsMeas1->MUnn_TVTR_4_Vol_q); + + return offset; +} + +void svDecodeDataset(unsigned char *dataset, int datasetLength, int ASDU, unsigned char *svID, int svIDLength, CTYPE_INT16U smpCnt) { + + if (svIDLength == 10 && strncmp((const char *) svID, "0000MU0001", svIDLength) == 0) { + decode_LE_IED_MUnn_PhsMeas1(dataset, smpCnt, &LE_IED_RECV.S1.MUnn.IEC_61850_9_2LETCTR_1.sv_inputs_MSVCB01.LE_IED_MUnn_PhsMeas1); + LE_IED_RECV.S1.MUnn.IEC_61850_9_2LETCTR_1.sv_inputs_MSVCB01.smpCnt = smpCnt; + if (LE_IED_RECV.S1.MUnn.IEC_61850_9_2LETCTR_1.sv_inputs_MSVCB01.datasetDecodeDone != NULL) { + LE_IED_RECV.S1.MUnn.IEC_61850_9_2LETCTR_1.sv_inputs_MSVCB01.datasetDecodeDone(smpCnt); + } + } +} + +
diff -r 000000000000 -r f09b7bb8bcce rapid61850/svDecode.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rapid61850/svDecode.h Tue Oct 02 21:31:05 2012 +0000 @@ -0,0 +1,43 @@ +/** + * Rapid-prototyping protection schemes with IEC 61850 + * + * Copyright (c) 2012 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. + */ + +#ifndef SV_DECODE_H +#define SV_DECODE_H + +#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */ +extern "C" { +#endif + +#include "svPacketData.h" + + + + +int decode_LE_IED_MUnn_PhsMeas1(unsigned char *buf, CTYPE_INT16U smpCnt, struct LE_IED_MUnn_PhsMeas1 *LE_IED_MUnn_PhsMeas1); + +void svDecodeDataset(unsigned char *dataset, int datasetLength, int ASDU, unsigned char *svID, int svIDLength, CTYPE_INT16U smpCnt); + + + +#ifdef __cplusplus /* If this is a C++ compiler, end C linkage */ +} +#endif + +#endif
diff -r 000000000000 -r f09b7bb8bcce rapid61850/svDecodeBasic.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rapid61850/svDecodeBasic.c Tue Oct 02 21:31:05 2012 +0000 @@ -0,0 +1,92 @@ +/** + * Rapid-prototyping protection schemes with IEC 61850 + * + * Copyright (c) 2012 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 "ctypes.h" +#include "datatypes.h" +#include "ied.h" +#include "svDecodeBasic.h" +#include <string.h> + +// SV encoding of basic types +int DECODE_CTYPE_FLOAT32(unsigned char *buf, CTYPE_FLOAT32 *value) { + netmemcpy(value, buf, SV_GET_LENGTH_FLOAT32); + + return SV_GET_LENGTH_FLOAT32; +} +int DECODE_CTYPE_FLOAT64(unsigned char *buf, CTYPE_FLOAT64 *value) { + netmemcpy(value, buf, SV_GET_LENGTH_FLOAT64); + + return SV_GET_LENGTH_FLOAT64; +} +int DECODE_CTYPE_QUALITY(unsigned char *buf, CTYPE_QUALITY *value) { + netmemcpy(value, buf, SV_GET_LENGTH_QUALITY); + + return SV_GET_LENGTH_QUALITY; +} +int DECODE_CTYPE_TIMESTAMP(unsigned char *buf, CTYPE_TIMESTAMP *value) { + netmemcpy(value, buf, SV_GET_LENGTH_TIMESTAMP); + + return SV_GET_LENGTH_TIMESTAMP; +} +int DECODE_CTYPE_ENUM(unsigned char *buf, CTYPE_ENUM *value) { // assuming enum is an int - allows any enum type to be used + netmemcpy(value, buf, SV_GET_LENGTH_ENUM); + + return SV_GET_LENGTH_ENUM; +} +int DECODE_CTYPE_INT8(unsigned char *buf, CTYPE_INT8 *value) { + netmemcpy(value, buf, SV_GET_LENGTH_INT8); + + return SV_GET_LENGTH_INT8; +} +int DECODE_CTYPE_INT16(unsigned char *buf, CTYPE_INT16 *value) { + netmemcpy(value, buf, SV_GET_LENGTH_INT16); + + return SV_GET_LENGTH_INT16; +} +int DECODE_CTYPE_INT32(unsigned char *buf, CTYPE_INT32 *value) { + netmemcpy(value, buf, SV_GET_LENGTH_INT32); + + return SV_GET_LENGTH_INT32; +} +int DECODE_CTYPE_INT16U(unsigned char *buf, CTYPE_INT16U *value) { + netmemcpy(value, buf, SV_GET_LENGTH_INT16U); + + return SV_GET_LENGTH_INT16U; +} +int DECODE_CTYPE_INT32U(unsigned char *buf, CTYPE_INT32U *value) { + netmemcpy(value, buf, SV_GET_LENGTH_INT32U); + + return SV_GET_LENGTH_INT32U; +} +int DECODE_CTYPE_VISSTRING255(unsigned char *buf, CTYPE_VISSTRING255 *value) { + netmemcpy(value, buf, SV_GET_LENGTH_VISSTRING255); + + return SV_GET_LENGTH_VISSTRING255; +} +int DECODE_CTYPE_BOOLEAN(unsigned char *buf, CTYPE_BOOLEAN *value) { + netmemcpy(value, buf, SV_GET_LENGTH_BOOLEAN); + + return SV_GET_LENGTH_BOOLEAN; +} +int DECODE_CTYPE_DBPOS(unsigned char *buf, CTYPE_DBPOS *value) { + netmemcpy(value, buf, SV_GET_LENGTH_DBPOS); + + return SV_GET_LENGTH_DBPOS; +}
diff -r 000000000000 -r f09b7bb8bcce rapid61850/svDecodeBasic.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rapid61850/svDecodeBasic.h Tue Oct 02 21:31:05 2012 +0000 @@ -0,0 +1,48 @@ +/** + * Rapid-prototyping protection schemes with IEC 61850 + * + * Copyright (c) 2012 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. + */ + +#ifndef SV_DECODE_BASIC_H +#define SV_DECODE_BASIC_H + +#include "datatypes.h" + +#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */ +extern "C" { +#endif + +int DECODE_CTYPE_FLOAT32(unsigned char *buf, CTYPE_FLOAT32 *value); +int DECODE_CTYPE_FLOAT64(unsigned char *buf, CTYPE_FLOAT64 *value); +int DECODE_CTYPE_QUALITY(unsigned char *buf, CTYPE_QUALITY *value); +int DECODE_CTYPE_TIMESTAMP(unsigned char *buf, CTYPE_TIMESTAMP *value); +int DECODE_CTYPE_ENUM(unsigned char *buf, CTYPE_ENUM *value); +int DECODE_CTYPE_INT8(unsigned char *buf, CTYPE_INT8 *value) ; +int DECODE_CTYPE_INT16(unsigned char *buf, CTYPE_INT16 *value); +int DECODE_CTYPE_INT32(unsigned char *buf, CTYPE_INT32 *value); +int DECODE_CTYPE_INT16U(unsigned char *buf, CTYPE_INT16U *value); +int DECODE_CTYPE_INT32U(unsigned char *buf, CTYPE_INT32U *value); +int DECODE_CTYPE_VISSTRING255(unsigned char *buf, CTYPE_VISSTRING255 *value); +int DECODE_CTYPE_BOOLEAN(unsigned char *buf, CTYPE_BOOLEAN *value); +int DECODE_CTYPE_DBPOS(unsigned char *buf, CTYPE_DBPOS *value); + +#ifdef __cplusplus /* If this is a C++ compiler, end C linkage */ +} +#endif + +#endif
diff -r 000000000000 -r f09b7bb8bcce rapid61850/svDecodePacket.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rapid61850/svDecodePacket.c Tue Oct 02 21:31:05 2012 +0000 @@ -0,0 +1,132 @@ +/** + * Rapid-prototyping protection schemes with IEC 61850 + * + * Copyright (c) 2012 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" +#include "svPacketData.h" +#include "decodePacket.h" +#include "gseDecodeBasic.h" +#include <stddef.h> + + +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; + CTYPE_INT16U smpCnt = 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; + + //printf("\ttag: %x, noASDU: %u, lengthFieldSize: %i, lengthValue: %i, offset: %i\n", tag, noASDU, lengthFieldSize, lengthValue, offsetForNonSequence); + + switch (tag) { + case SV_TAG_SVID: + svID = &buf[i + 1 + lengthFieldSize]; + svIDLength = lengthValue; + break; + case SV_TAG_DATSET: + + break; + case SV_TAG_SMPCNT: + ber_decode_integer(&buf[i + 1 + lengthFieldSize], lengthValue, &smpCnt, SV_GET_LENGTH_INT16U); + break; + case SV_TAG_CONFREV: + + break; + case SV_TAG_REFRTM: + + break; + case SV_TAG_SMPSYNCH: + + break; + case SV_TAG_SMPRATE: + + break; + case SV_TAG_SEQUENCEOFDATA: + if (svID != NULL) { + svDecodeDataset(&buf[i + 1 + lengthFieldSize], lengthValue, noASDU, svID, svIDLength, smpCnt); + } + break; + default: + break; + } + + i += offsetForNonSequence; + } +} + +void svDecodeAPDU(unsigned char *buf, int len, unsigned int ASDU, unsigned int totalASDUs) { + 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; + unsigned int noASDU = 0; + //static unsigned int ASDU = 0; + + //printf("tag: %x, ASDU: %u, totalASDUs: %u, lengthFieldSize: %i, lengthValue: %i, offset: %i\n", tag, ASDU, totalASDUs, lengthFieldSize, lengthValue, offsetForNonSequence); + + switch (tag) { + case SV_TAG_SAVPDU: + svDecodeAPDU(&buf[offsetForSequence], lengthValue, ASDU, totalASDUs); + break; + case SV_TAG_NOASDU: + noASDU = (unsigned int) buf[1 + lengthFieldSize]; // assuming noASDU is < 126 + //ASDU = 0; + svDecodeAPDU(&buf[offsetForNonSequence], len - offsetForNonSequence, ASDU, noASDU); + break; + case SV_TAG_SEQUENCEOFASDU: + svDecodeAPDU(&buf[offsetForSequence], lengthValue, ASDU, totalASDUs); + break; + case SV_TAG_ASDU: + svDecodeASDU(&buf[offsetForSequence], lengthValue, ASDU); + ASDU++; + + // process any more ASDUs, until max number + if (ASDU < totalASDUs) { + svDecodeAPDU(&buf[offsetForNonSequence], len - offsetForNonSequence, ASDU, totalASDUs); + } + break; + default: + break; + } +} + +void svDecode(unsigned char *buf, int len) { + int offset = 16; // start of 'length' field in payload + + // check for VLAN tag + if (buf[12] == 0x81 && buf[13] == 0x00) { + offset = 20; + } + + unsigned short APDULength = ((buf[offset] << 8) | buf[offset + 1]) - 8; // must use length in PDU because total bytes (len) may contain CRC + + svDecodeAPDU(&buf[offset + 6], APDULength, 0, 0); // cuts out frame header +}
diff -r 000000000000 -r f09b7bb8bcce rapid61850/svEncode.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rapid61850/svEncode.c Tue Oct 02 21:31:05 2012 +0000 @@ -0,0 +1,105 @@ +/** + * Rapid-prototyping protection schemes with IEC 61850 + * + * Copyright (c) 2012 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 "svEncodeBasic.h" +#include "ied.h" +#include "svEncode.h" + + + + +int encode_IEC_61850_9_2LEAV(unsigned char *buf, struct IEC_61850_9_2LEAV *IEC_61850_9_2LEAV) { + int offset = 0; + + offset += ENCODE_CTYPE_INT32(&buf[offset], &IEC_61850_9_2LEAV->i); + + return offset; +} +int encode_IEC_61850_9_2LEsVCAmp(unsigned char *buf, struct IEC_61850_9_2LEsVCAmp *IEC_61850_9_2LEsVCAmp) { + int offset = 0; + + offset += ENCODE_CTYPE_FLOAT32(&buf[offset], &IEC_61850_9_2LEsVCAmp->scaleFactor); + offset += ENCODE_CTYPE_FLOAT32(&buf[offset], &IEC_61850_9_2LEsVCAmp->offset); + + return offset; +} +int encode_IEC_61850_9_2LEsVCVol(unsigned char *buf, struct IEC_61850_9_2LEsVCVol *IEC_61850_9_2LEsVCVol) { + int offset = 0; + + offset += ENCODE_CTYPE_FLOAT32(&buf[offset], &IEC_61850_9_2LEsVCVol->scaleFactor); + offset += ENCODE_CTYPE_FLOAT32(&buf[offset], &IEC_61850_9_2LEsVCVol->offset); + + return offset; +} +int encode_IEC_61850_9_2LESAVAmp(unsigned char *buf, struct IEC_61850_9_2LESAVAmp *IEC_61850_9_2LESAVAmp) { + int offset = 0; + + offset += encode_IEC_61850_9_2LEAV(&buf[offset], &IEC_61850_9_2LESAVAmp->instMag); + offset += ENCODE_CTYPE_QUALITY(&buf[offset], &IEC_61850_9_2LESAVAmp->q); + offset += encode_IEC_61850_9_2LEsVCAmp(&buf[offset], &IEC_61850_9_2LESAVAmp->sVC); + + return offset; +} +int encode_IEC_61850_9_2LESAVVol(unsigned char *buf, struct IEC_61850_9_2LESAVVol *IEC_61850_9_2LESAVVol) { + int offset = 0; + + offset += encode_IEC_61850_9_2LEAV(&buf[offset], &IEC_61850_9_2LESAVVol->instMag); + offset += ENCODE_CTYPE_QUALITY(&buf[offset], &IEC_61850_9_2LESAVVol->q); + offset += encode_IEC_61850_9_2LEsVCVol(&buf[offset], &IEC_61850_9_2LESAVVol->sVC); + + return offset; +} +int encode_IEC_61850_9_2LEINC(unsigned char *buf, struct IEC_61850_9_2LEINC *IEC_61850_9_2LEINC) { + int offset = 0; + + offset += ENCODE_CTYPE_INT32(&buf[offset], &IEC_61850_9_2LEINC->ctlVal); + offset += ENCODE_CTYPE_INT32(&buf[offset], &IEC_61850_9_2LEINC->stVal); + offset += ENCODE_CTYPE_QUALITY(&buf[offset], &IEC_61850_9_2LEINC->q); + offset += ENCODE_CTYPE_TIMESTAMP(&buf[offset], &IEC_61850_9_2LEINC->t); + + return offset; +} +int encode_LE_IED_MUnn_PhsMeas1(unsigned char *buf) { + int offset = 0; + + offset += encode_IEC_61850_9_2LEAV(&buf[offset], &LE_IED.S1.MUnn.IEC_61850_9_2LETCTR_1.Amp.instMag); + offset += ENCODE_CTYPE_QUALITY(&buf[offset], &LE_IED.S1.MUnn.IEC_61850_9_2LETCTR_1.Amp.q); + offset += encode_IEC_61850_9_2LEAV(&buf[offset], &LE_IED.S1.MUnn.IEC_61850_9_2LETCTR_2.Amp.instMag); + offset += ENCODE_CTYPE_QUALITY(&buf[offset], &LE_IED.S1.MUnn.IEC_61850_9_2LETCTR_2.Amp.q); + offset += encode_IEC_61850_9_2LEAV(&buf[offset], &LE_IED.S1.MUnn.IEC_61850_9_2LETCTR_3.Amp.instMag); + offset += ENCODE_CTYPE_QUALITY(&buf[offset], &LE_IED.S1.MUnn.IEC_61850_9_2LETCTR_3.Amp.q); + offset += encode_IEC_61850_9_2LEAV(&buf[offset], &LE_IED.S1.MUnn.IEC_61850_9_2LETCTR_4.Amp.instMag); + offset += ENCODE_CTYPE_QUALITY(&buf[offset], &LE_IED.S1.MUnn.IEC_61850_9_2LETCTR_4.Amp.q); + offset += encode_IEC_61850_9_2LEAV(&buf[offset], &LE_IED.S1.MUnn.IEC_61850_9_2LETVTR_1.Vol.instMag); + offset += ENCODE_CTYPE_QUALITY(&buf[offset], &LE_IED.S1.MUnn.IEC_61850_9_2LETVTR_1.Vol.q); + offset += encode_IEC_61850_9_2LEAV(&buf[offset], &LE_IED.S1.MUnn.IEC_61850_9_2LETVTR_2.Vol.instMag); + offset += ENCODE_CTYPE_QUALITY(&buf[offset], &LE_IED.S1.MUnn.IEC_61850_9_2LETVTR_2.Vol.q); + offset += encode_IEC_61850_9_2LEAV(&buf[offset], &LE_IED.S1.MUnn.IEC_61850_9_2LETVTR_3.Vol.instMag); + offset += ENCODE_CTYPE_QUALITY(&buf[offset], &LE_IED.S1.MUnn.IEC_61850_9_2LETVTR_3.Vol.q); + offset += encode_IEC_61850_9_2LEAV(&buf[offset], &LE_IED.S1.MUnn.IEC_61850_9_2LETVTR_4.Vol.instMag); + offset += ENCODE_CTYPE_QUALITY(&buf[offset], &LE_IED.S1.MUnn.IEC_61850_9_2LETVTR_4.Vol.q); + + return offset; +} +int encode_control_LE_IED_MUnn_MSVCB01(unsigned char *buf) { + return encode_LE_IED_MUnn_PhsMeas1(buf); +} + +
diff -r 000000000000 -r f09b7bb8bcce rapid61850/svEncode.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rapid61850/svEncode.h Tue Oct 02 21:31:05 2012 +0000 @@ -0,0 +1,45 @@ +/** + * Rapid-prototyping protection schemes with IEC 61850 + * + * Copyright (c) 2012 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. + */ + +#ifndef SV_ENCODE_H +#define SV_ENCODE_H + +#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */ +extern "C" { +#endif + +#include "svEncodeBasic.h" +#include "svPacketData.h" + + + + +int encode_LE_IED_MUnn_PhsMeas1(unsigned char *buf); +int encode_control_LE_IED_MUnn_MSVCB01(unsigned char *buf); + +int svEncodePacket(struct svControl *svControl, unsigned char *buf); + + + +#ifdef __cplusplus /* If this is a C++ compiler, end C linkage */ +} +#endif + +#endif
diff -r 000000000000 -r f09b7bb8bcce rapid61850/svEncodeBasic.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rapid61850/svEncodeBasic.c Tue Oct 02 21:31:05 2012 +0000 @@ -0,0 +1,91 @@ +/** + * Rapid-prototyping protection schemes with IEC 61850 + * + * Copyright (c) 2012 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 "ctypes.h" +#include "datatypes.h" +#include "ied.h" +#include "svEncodeBasic.h" + +// SV encoding of basic types +int ENCODE_CTYPE_FLOAT32(unsigned char *buf, CTYPE_FLOAT32 *value) { + netmemcpy(buf, value, SV_GET_LENGTH_FLOAT32); + + return SV_GET_LENGTH_FLOAT32; +} +int ENCODE_CTYPE_FLOAT64(unsigned char *buf, CTYPE_FLOAT64 *value) { + netmemcpy(buf, value, SV_GET_LENGTH_FLOAT64); + + return SV_GET_LENGTH_FLOAT64; +} +int ENCODE_CTYPE_QUALITY(unsigned char *buf, CTYPE_QUALITY *value) { + netmemcpy(&buf[2], value, 2); // assumes Quality is stored as 16-bit, but SV encoding is 32-bit + + return SV_GET_LENGTH_QUALITY; +} +int ENCODE_CTYPE_TIMESTAMP(unsigned char *buf, CTYPE_TIMESTAMP *value) { + netmemcpy(buf, value, SV_GET_LENGTH_TIMESTAMP); + + return SV_GET_LENGTH_TIMESTAMP; +} +int ENCODE_CTYPE_ENUM(unsigned char *buf, CTYPE_ENUM *value) { // assuming enum is an int - allows any enum type to be used + netmemcpy(buf, value, SV_GET_LENGTH_ENUM); + + return SV_GET_LENGTH_ENUM; +} +int ENCODE_CTYPE_INT8(unsigned char *buf, CTYPE_INT8 *value) { + netmemcpy(buf, value, SV_GET_LENGTH_INT8); + + return SV_GET_LENGTH_INT8; +} +int ENCODE_CTYPE_INT16(unsigned char *buf, CTYPE_INT16 *value) { + netmemcpy(buf, value, SV_GET_LENGTH_INT16); + + return SV_GET_LENGTH_INT16; +} +int ENCODE_CTYPE_INT32(unsigned char *buf, CTYPE_INT32 *value) { + netmemcpy(buf, value, SV_GET_LENGTH_INT32); + + return SV_GET_LENGTH_INT32; +} +int ENCODE_CTYPE_INT16U(unsigned char *buf, CTYPE_INT16U *value) { + netmemcpy(buf, value, SV_GET_LENGTH_INT16U); + + return SV_GET_LENGTH_INT16U; +} +int ENCODE_CTYPE_INT32U(unsigned char *buf, CTYPE_INT32U *value) { + netmemcpy(buf, value, SV_GET_LENGTH_INT32U); + + return SV_GET_LENGTH_INT32U; +} +int ENCODE_CTYPE_VISSTRING255(unsigned char *buf, CTYPE_VISSTRING255 *value) { + netmemcpy(buf, value, SV_GET_LENGTH_VISSTRING255); + + return SV_GET_LENGTH_VISSTRING255; +} +int ENCODE_CTYPE_BOOLEAN(unsigned char *buf, CTYPE_BOOLEAN *value) { + netmemcpy(buf, value, SV_GET_LENGTH_BOOLEAN); + + return SV_GET_LENGTH_BOOLEAN; +} +int ENCODE_CTYPE_DBPOS(unsigned char *buf, CTYPE_DBPOS *value) { + netmemcpy(buf, value, SV_GET_LENGTH_DBPOS); + + return SV_GET_LENGTH_DBPOS; +}
diff -r 000000000000 -r f09b7bb8bcce rapid61850/svEncodeBasic.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rapid61850/svEncodeBasic.h Tue Oct 02 21:31:05 2012 +0000 @@ -0,0 +1,48 @@ +/** + * Rapid-prototyping protection schemes with IEC 61850 + * + * Copyright (c) 2012 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. + */ + +#ifndef SV_ENCODE_BASIC_H +#define SV_ENCODE_BASIC_H + +#include "datatypes.h" + +#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */ +extern "C" { +#endif + +int ENCODE_CTYPE_FLOAT32(unsigned char *buf, CTYPE_FLOAT32 *value); +int ENCODE_CTYPE_FLOAT64(unsigned char *buf, CTYPE_FLOAT64 *value); +int ENCODE_CTYPE_QUALITY(unsigned char *buf, CTYPE_QUALITY *value); +int ENCODE_CTYPE_TIMESTAMP(unsigned char *buf, CTYPE_TIMESTAMP *value); +int ENCODE_CTYPE_ENUM(unsigned char *buf, CTYPE_ENUM *value); +int ENCODE_CTYPE_INT8(unsigned char *buf, CTYPE_INT8 *value); +int ENCODE_CTYPE_INT16(unsigned char *buf, CTYPE_INT16 *value); +int ENCODE_CTYPE_INT32(unsigned char *buf, CTYPE_INT32 *value); +int ENCODE_CTYPE_INT16U(unsigned char *buf, CTYPE_INT16U *value); +int ENCODE_CTYPE_INT32U(unsigned char *buf, CTYPE_INT32U *value); +int ENCODE_CTYPE_VISSTRING255(unsigned char *buf, CTYPE_VISSTRING255 *value); +int ENCODE_CTYPE_BOOLEAN(unsigned char *buf, CTYPE_BOOLEAN *value); +int ENCODE_CTYPE_DBPOS(unsigned char *buf, CTYPE_DBPOS *value); + +#ifdef __cplusplus /* If this is a C++ compiler, end C linkage */ +} +#endif + +#endif
diff -r 000000000000 -r f09b7bb8bcce rapid61850/svEncodePacket.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rapid61850/svEncodePacket.c Tue Oct 02 21:31:05 2012 +0000 @@ -0,0 +1,191 @@ +/** + * Rapid-prototyping protection schemes with IEC 61850 + * + * Copyright (c) 2012 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 "svPacketData.h" +#include "svEncode.h" +#include "gseEncode.h" +#include "encodePacket.h" + + +int svASDULength(struct svControl *svControl) { + int len = 0; + + len += strlen((const char *) svControl->ASDU[0].svID) + 2; + //printf("%i, %s\n", strlen(svControl->ASDU[0].svID), svControl->ASDU[0].svID); + //len += strlen((const char *) svControl->ASDU[0].datset) + 2; + +#if SV_FIXED_SMPCNT_CONFREV_SIZE == 1 + len += SV_GET_LENGTH_INT16U + 2; // smpCnt + len += SV_GET_LENGTH_INT32U + 2; // confRev +#else + len += ber_integer_length((&svControl->ASDU[0].smpCnt), SV_GET_LENGTH_INT16U)/*BER_GET_LENGTH_CTYPE_INT16U(&svControl->ASDU[0].smpCnt)*/ + 2; + len += ber_integer_length((&svControl->ASDU[0].confRev), SV_GET_LENGTH_INT32U)/*BER_GET_LENGTH_CTYPE_INT32U(&svControl->ASDU[0].confRev)*/ + 2; +#endif + len += SV_GET_LENGTH_BOOLEAN + 2; + + + + + //len += BER_GET_LENGTH_CTYPE_INT16U(&svControl->ASDU[0].smpRate) + 2; + len += svControl->ASDU[0].data.size + getLengthBytes(svControl->ASDU[0].data.size); + len++; + + return len; +} + +int svSeqLength(struct svControl *svControl) { + int len = svASDULength(svControl); + len += getLengthBytes(len); + len++; + len = len * svControl->noASDU; // assume all ASDUs are the same size + + return len; +} + +int svAPDULength(struct svControl *svControl) { + int len = svSeqLength(svControl); + len += getLengthBytes(len); + len++; + + len += 3; + + return len; +} + +// creates an SV packet, including frame header. returns 0 on fail; number of bytes on success +int svEncodePacket(struct svControl *svControl, unsigned char *buf) { + int offset = 0; + int len = svAPDULength(svControl); + len += getLengthBytes(len); + len += 9; // savPdu tag size (1 byte), plus 8 "header" bytes + + // frame header + memcpy(&buf[offset], svControl->ethHeaderData.destMACAddress, 6); // destination MAC addresses + offset += 6; + memcpy(&buf[offset], LOCAL_MAC_ADDRESS, 6); // source MAC addresses + offset += 6; + +#if SV_USE_VLAN == 1 + buf[offset++] = 0x81; // TPID + buf[offset++] = 0x00; + + netmemcpy(&buf[offset], &svControl->ethHeaderData.VLAN_ID, 2); // TCI + buf[offset] |= (svControl->ethHeaderData.VLAN_PRIORITY << 5); + offset += 2; +#endif + + buf[offset++] = 0x88; // EtherType + buf[offset++] = 0xBA; + + netmemcpy(&buf[offset], &svControl->ethHeaderData.APPID, 2); // APPID + offset += 2; + + netmemcpy(&buf[offset], &len, 2); // length + offset += 2; + + buf[offset++] = 0x00; // reserved 1 + buf[offset++] = 0x00; + buf[offset++] = 0x00; // reserved 2 + buf[offset++] = 0x00; + + buf[offset++] = SV_TAG_SAVPDU; + offset += encodeLength(&buf[offset], svAPDULength(svControl)); + + buf[offset++] = SV_TAG_NOASDU; + offset += encodeLength(&buf[offset], ber_integer_length(&svControl->noASDU, SV_GET_LENGTH_INT16U)); + offset += ber_encode_integer(&buf[offset], &svControl->noASDU, ber_integer_length(&svControl->noASDU, SV_GET_LENGTH_INT16U)); + + buf[offset++] = SV_TAG_SEQUENCEOFASDU; + offset += encodeLength(&buf[offset], svSeqLength(svControl)); + + int i = 0; + int size = 0; + for (i = 0; i < svControl->noASDU; i++) { + buf[offset++] = SV_TAG_ASDU; + offset += encodeLength(&buf[offset], svASDULength(svControl)); + + size = strlen((const char *) svControl->ASDU[i].svID); + buf[offset++] = SV_TAG_SVID; + buf[offset++] = size; + memcpy(&buf[offset], svControl->ASDU[i].svID, size); + offset += size; + +#if SV_OPTIONAL_SUPPORTED == 1 + if (svControl->ASDU[i].showDatset) { + size = strlen(svControl->ASDU[i].datset); + buf[offset++] = SV_TAG_DATSET; + buf[offset++] = size; + memcpy(&buf[offset], svControl->ASDU[i].datset, size); + offset += size; + } +#endif + + buf[offset++] = SV_TAG_SMPCNT; +#if SV_FIXED_SMPCNT_CONFREV_SIZE == 1 + buf[offset++] = SV_GET_LENGTH_INT16U; + netmemcpy(&buf[offset], &svControl->ASDU[i].smpCnt, SV_GET_LENGTH_INT16U); + offset += SV_GET_LENGTH_INT16U; +#else + offset += encodeLength(&buf[offset], ber_integer_length(&svControl->ASDU[i].smpCnt, SV_GET_LENGTH_INT16U)); + offset += ber_encode_integer(&buf[offset], &svControl->ASDU[i].smpCnt, SV_GET_LENGTH_INT16U); +#endif + + buf[offset++] = SV_TAG_CONFREV; +#if SV_FIXED_SMPCNT_CONFREV_SIZE == 1 + buf[offset++] = SV_GET_LENGTH_INT32U; + netmemcpy(&buf[offset], &svControl->ASDU[i].confRev, SV_GET_LENGTH_INT32U); + offset += SV_GET_LENGTH_INT32U; +#else + offset += encodeLength(&buf[offset], ber_integer_length(&svControl->ASDU[i].confRev, SV_GET_LENGTH_INT32U)); + offset += ber_encode_integer(&buf[offset], &svControl->ASDU[i].confRev, SV_GET_LENGTH_INT32U); +#endif + +#if SV_OPTIONAL_SUPPORTED == 1 + if (svControl->ASDU[i].showRefrTm) { + buf[offset++] = SV_TAG_REFRTM; + offset += encodeLength(&buf[offset], BER_GET_LENGTH_CTYPE_TIMESTAMP(&svControl->ASDU[i].refrTm)); + setTimestamp(&svControl->ASDU[i].refrTm); + memcpy(&buf[offset], &svControl->ASDU[i].refrTm, BER_GET_LENGTH_CTYPE_TIMESTAMP(&svControl->ASDU[i].refrTm)); + offset += BER_GET_LENGTH_CTYPE_TIMESTAMP(&svControl->ASDU[i].refrTm); + } +#endif + + buf[offset++] = SV_TAG_SMPSYNCH; + buf[offset++] = SV_GET_LENGTH_BOOLEAN; + offset += ENCODE_CTYPE_BOOLEAN(&buf[offset], &svControl->ASDU[i].smpSynch); + +#if SV_OPTIONAL_SUPPORTED == 1 + if (svControl->ASDU[i].showSmpRate) { + buf[offset++] = SV_TAG_SMPRATE; + buf[offset++] = SV_GET_LENGTH_INT16U; + offset += ENCODE_CTYPE_INT16U(&buf[offset], &svControl->ASDU[i].smpRate); + } +#endif + + buf[offset++] = SV_TAG_SEQUENCEOFDATA; + offset += encodeLength(&buf[offset], svControl->ASDU[i].data.size); + memcpy(&buf[offset], svControl->ASDU[i].data.data, svControl->ASDU[i].data.size); + offset += svControl->ASDU[i].data.size; + } + + // assume network interface, such as WinPcap, generates CRC bytes + + return offset; +}
diff -r 000000000000 -r f09b7bb8bcce rapid61850/svPacketData.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rapid61850/svPacketData.h Tue Oct 02 21:31:05 2012 +0000 @@ -0,0 +1,61 @@ +/** + * Rapid-prototyping protection schemes with IEC 61850 + * + * Copyright (c) 2012 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. + */ + +#ifndef SV_PACKET_DATA_H +#define SV_PACKET_DATA_H + +#include <stdlib.h> +#include <string.h> +#include "ctypes.h" + +#define SV_USE_VLAN 0 // set to "1" to insert VLAN tag into SV packets +#define SV_OPTIONAL_SUPPORTED 0 // set to "1" to enable output of optional items in SV packets (Wireshark does not support these) +#define SV_FIXED_SMPCNT_CONFREV_SIZE 1 // set to "1" to force smpCnt and confRev field to be fixed size, rather than BER encoded + +#define SV_MAX_DATASET_SIZE 512//1024 + +struct ASDU { + unsigned char *svID; + unsigned char *datset; // optional + CTYPE_INT16U smpCnt; + CTYPE_INT32U confRev; + //struct UtcTime refrTm; // optional + CTYPE_TIMESTAMP refrTm; // optional + CTYPE_BOOLEAN smpSynch; + CTYPE_INT16U smpRate; // optional + int showDatset; + int showRefrTm; + int showSmpRate; + struct data { + unsigned char data[SV_MAX_DATASET_SIZE]; + CTYPE_INT32U size; + } data; +}; + +struct svControl { + struct ethHeaderData ethHeaderData; + short noASDU; + struct ASDU *ASDU; + CTYPE_INT16U ASDUCount; // stores present ASDU count; transmit a packet when equals "noASDU" + CTYPE_INT16U sampleCountMaster; + int (*update)(unsigned char *buf); // function pointer to save next ASDU, and possible send SV packet +}; + +#endif