diff --git a/dotnet/IEC61850forCSharp/IEC61850.NET.csproj b/dotnet/IEC61850forCSharp/IEC61850.NET.csproj
index 61829bc6..4ce8fb16 100644
--- a/dotnet/IEC61850forCSharp/IEC61850.NET.csproj
+++ b/dotnet/IEC61850forCSharp/IEC61850.NET.csproj
@@ -49,6 +49,7 @@
+
\ No newline at end of file
diff --git a/dotnet/IEC61850forCSharp/SampledValuesSubscriber.cs b/dotnet/IEC61850forCSharp/SampledValuesSubscriber.cs
new file mode 100644
index 00000000..139bda67
--- /dev/null
+++ b/dotnet/IEC61850forCSharp/SampledValuesSubscriber.cs
@@ -0,0 +1,387 @@
+/*
+ * SampledValuedSubscriber.cs
+ *
+ * Copyright 2017 Michael Zillgith
+ *
+ * This file is part of libIEC61850.
+ *
+ * libIEC61850 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * libIEC61850 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 libIEC61850. If not, see .
+ *
+ * See COPYING file for the complete license text.
+ */
+
+using System;
+using System.Runtime.InteropServices;
+using IEC61850.Common;
+
+namespace IEC61850
+{
+ namespace SV
+ {
+
+ namespace Subscriber
+ {
+ public class SVReceiver : IDisposable
+ {
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern IntPtr SVReceiver_create ();
+
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern void SVReceiver_disableDestAddrCheck(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern void SVReceiver_addSubscriber(IntPtr self, IntPtr subscriber);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern void SVReceiver_removeSubscriber(IntPtr self, IntPtr subscriber);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern void SVReceiver_start(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern void SVReceiver_stop(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ [return: MarshalAs(UnmanagedType.I1)]
+ private static extern bool SVReceiver_isRunning (IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern void SVReceiver_destroy(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern void SVReceiver_setInterfaceId(IntPtr self, string interfaceId);
+
+ private IntPtr self;
+
+ private bool isDisposed = false;
+
+ public SVReceiver()
+ {
+ self = SVReceiver_create ();
+ }
+
+ public void SetInterfaceId(string interfaceId)
+ {
+ SVReceiver_setInterfaceId (self, interfaceId);
+ }
+
+ public void DisableDestAddrCheck()
+ {
+ SVReceiver_disableDestAddrCheck (self);
+ }
+
+ public void AddSubscriber(SVSubscriber subscriber)
+ {
+ SVReceiver_addSubscriber (self, subscriber.self);
+ }
+
+ public void RemoveSubscriber(SVSubscriber subscriber)
+ {
+ SVReceiver_removeSubscriber (self, subscriber.self);
+ }
+
+ public void Start()
+ {
+ SVReceiver_start (self);
+ }
+
+ public void Stop()
+ {
+ SVReceiver_stop (self);
+ }
+
+ public bool IsRunning()
+ {
+ return SVReceiver_isRunning (self);
+ }
+
+ public void Dispose()
+ {
+ if (isDisposed == false) {
+ isDisposed = true;
+ SVReceiver_destroy (self);
+ self = IntPtr.Zero;
+ }
+ }
+
+ ~SVReceiver()
+ {
+ Dispose ();
+ }
+ }
+
+
+ ///
+ /// SV listener.
+ ///
+ public delegate void SVUpdateListener (SVSubscriber report, object parameter, SVSubscriberASDU asdu);
+
+ public class SVSubscriber : IDisposable
+ {
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ private delegate void InternalSVUpdateListener (IntPtr subscriber, IntPtr parameter, IntPtr asdu);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern IntPtr SVSubscriber_create([Out] byte[] ethAddr, UInt16 appID);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern void SVSubscriber_setListener(IntPtr self, InternalSVUpdateListener listener, IntPtr parameter);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern void SVSubscriber_destroy(IntPtr self);
+
+ internal IntPtr self;
+
+ private bool isDisposed = false;
+
+ private SVUpdateListener listener;
+ private object listenerParameter = null;
+
+ private event InternalSVUpdateListener internalListener = null;
+
+ private void internalSVUpdateListener (IntPtr subscriber, IntPtr parameter, IntPtr asdu)
+ {
+ try {
+
+ if (listener != null) {
+ listener(this, listenerParameter, new SVSubscriberASDU(asdu));
+ }
+
+ }
+ catch (Exception e) {
+ // older versions of mono 2.10 (for linux?) cause this exception
+ Console.WriteLine(e.Message);
+ }
+ }
+
+ public SVSubscriber(byte[] ethAddr, UInt16 appID)
+ {
+ if (ethAddr.Length != 6)
+ throw new ArgumentException ("ethAddr argument has to be of 6 byte size");
+
+ self = SVSubscriber_create (ethAddr, appID);
+ }
+
+ public void SetListener(SVUpdateListener listener, object parameter)
+ {
+ this.listener = listener;
+ this.listenerParameter = parameter;
+
+ if (internalListener == null) {
+ internalListener = new InternalSVUpdateListener (internalSVUpdateListener);
+
+ SVSubscriber_setListener (self, internalListener, IntPtr.Zero);
+ }
+ }
+
+ public void Dispose()
+ {
+ if (isDisposed == false) {
+ isDisposed = true;
+ SVSubscriber_destroy (self);
+ self = IntPtr.Zero;
+ }
+ }
+ }
+
+
+ public class SVSubscriberASDU
+ {
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern UInt16 SVSubscriber_ASDU_getSmpCnt(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern IntPtr SVSubscriber_ASDU_getSvId(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern IntPtr SVSubscriber_ASDU_getDatSet(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern UInt32 SVSubscriber_ASDU_getConfRev(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern byte SVSubscriber_ASDU_getSmpMod(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern UInt16 SVSubscriber_ASDU_getSmpRate(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ [return: MarshalAs(UnmanagedType.I1)]
+ private static extern bool SVSubscriber_ASDU_hasDatSet(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ [return: MarshalAs(UnmanagedType.I1)]
+ private static extern bool SVSubscriber_ASDU_hasRefrTm(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ [return: MarshalAs(UnmanagedType.I1)]
+ private static extern bool SVSubscriber_ASDU_hasSmpMod(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ [return: MarshalAs(UnmanagedType.I1)]
+ private static extern bool SVSubscriber_ASDU_hasSmpRate(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern UInt64 SVSubscriber_ASDU_getRefrTmAsMs(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern sbyte SVSubscriber_ASDU_getINT8(IntPtr self, int index);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern Int16 SVSubscriber_ASDU_getINT16(IntPtr self, int index);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern Int32 SVSubscriber_ASDU_getINT32(IntPtr self, int index);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern Int64 SVSubscriber_ASDU_getINT64(IntPtr self, int index);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern byte SVSubscriber_ASDU_getINT8U(IntPtr self, int index);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern UInt16 SVSubscriber_ASDU_getINT16U(IntPtr self, int index);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern UInt32 SVSubscriber_ASDU_getINT32U(IntPtr self, int index);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern UInt64 SVSubscriber_ASDU_getINT64U(IntPtr self, int index);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern float SVSubscriber_ASDU_getFLOAT32(IntPtr self, int index);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern double SVSubscriber_ASDU_getFLOAT64(IntPtr self, int index);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern int SVSubscriber_ASDU_getDataSize(IntPtr self);
+
+ private IntPtr self;
+
+ internal SVSubscriberASDU (IntPtr self)
+ {
+ this.self = self;
+ }
+
+ public UInt16 GetSmpCnt()
+ {
+ return SVSubscriber_ASDU_getSmpCnt (self);
+ }
+
+ public string GetSvId()
+ {
+ return Marshal.PtrToStringAnsi (SVSubscriber_ASDU_getSvId(self));
+ }
+
+ public string GetDatSet()
+ {
+ return Marshal.PtrToStringAnsi (SVSubscriber_ASDU_getDatSet(self));
+ }
+
+ public UInt32 GetConfRev()
+ {
+ return SVSubscriber_ASDU_getConfRev (self);
+ }
+
+ public SmpMod GetSmpMod()
+ {
+ return (SmpMod) SVSubscriber_ASDU_getSmpMod (self);
+ }
+
+ public UInt16 GetSmpRate()
+ {
+ return (UInt16)SVSubscriber_ASDU_getSmpRate (self);
+ }
+
+ public bool HasDatSet()
+ {
+ return SVSubscriber_ASDU_hasDatSet (self);
+ }
+
+ public bool HasRefrRm()
+ {
+ return SVSubscriber_ASDU_hasRefrTm (self);
+ }
+
+ public bool HasSmpMod()
+ {
+ return SVSubscriber_ASDU_hasSmpMod (self);
+ }
+
+ public bool HasSmpRate()
+ {
+ return SVSubscriber_ASDU_hasSmpRate (self);
+ }
+
+ public UInt64 GetRefrTmAsMs()
+ {
+ return SVSubscriber_ASDU_getRefrTmAsMs (self);
+ }
+
+ public sbyte GetINT8(int index)
+ {
+ return SVSubscriber_ASDU_getINT8 (self, index);
+ }
+
+ public Int16 GetINT16(int index)
+ {
+ return SVSubscriber_ASDU_getINT16 (self, index);
+ }
+
+ public Int32 GetINT32(int index)
+ {
+ return SVSubscriber_ASDU_getINT32 (self, index);
+ }
+
+ public Int64 GetINT64(int index)
+ {
+ return SVSubscriber_ASDU_getINT64 (self, index);
+ }
+
+ public byte GetINT8U(int index)
+ {
+ return SVSubscriber_ASDU_getINT8U (self, index);
+ }
+
+ public UInt16 GetINT16U(int index)
+ {
+ return SVSubscriber_ASDU_getINT16U (self, index);
+ }
+
+ public UInt32 GetINT32U(int index)
+ {
+ return SVSubscriber_ASDU_getINT32U (self, index);
+ }
+
+ public UInt64 GetINT64U(int index)
+ {
+ return SVSubscriber_ASDU_getINT64U (self, index);
+ }
+
+ ///
+ /// Gets the size of the payload data in bytes. The payload comprises the data set data.
+ ///
+ /// The payload data size in byte
+ public int GetDataSize()
+ {
+ return SVSubscriber_ASDU_getDataSize (self);
+ }
+ }
+ }
+
+ }
+}
+
diff --git a/src/goose/goose_receiver.h b/src/goose/goose_receiver.h
index 4995daea..7ac661d8 100644
--- a/src/goose/goose_receiver.h
+++ b/src/goose/goose_receiver.h
@@ -103,6 +103,15 @@ GooseReceiver_start(GooseReceiver self);
void
GooseReceiver_stop(GooseReceiver self);
+/**
+ * \brief Check if GOOSE receiver is running
+ *
+ * Can be used to check if \ref GooseReceiver_start has been successful.
+ *
+ * \param self the GooseReceiver instance
+ *
+ * \return true if GOOSE receiver is running, false otherwise
+ */
bool
GooseReceiver_isRunning(GooseReceiver self);
diff --git a/src/hal/ethernet/win32/ethernet_win32.c b/src/hal/ethernet/win32/ethernet_win32.c
index 4b4f10ca..8dca819c 100644
--- a/src/hal/ethernet/win32/ethernet_win32.c
+++ b/src/hal/ethernet/win32/ethernet_win32.c
@@ -215,7 +215,7 @@ getInterfaceName(int interfaceIndex)
interfaceName = (char*) malloc(strlen(device->name) + 1);
strcpy(interfaceName, device->name);
if (DEBUG_HAL_ETHERNET)
- printf("Use interface (%s)\n", interfaceName);
+ printf("Use interface (%s)\n", interfaceName);
ifaceFound = true;
break;
}
@@ -226,7 +226,7 @@ getInterfaceName(int interfaceIndex)
if (!ifaceFound)
{
if (DEBUG_HAL_ETHERNET)
- printf("No ethernet interfaces found! Make sure WinPcap is installed.\n");
+ printf("No ethernet interfaces found! Make sure WinPcap is installed.\n");
return NULL;
}
@@ -269,7 +269,7 @@ getAdapterMacAddress(char* pcapAdapterName, uint8_t* macAddress)
if (strstr(pcapAdapterName, pAddress->AdapterName) != 0) {
if (DEBUG_HAL_ETHERNET)
- printf(" requested found!");
+ printf(" requested found!");
for (i = 0; i < (int) addressLength; i++) {
macAddress[i] = pAddress->PhysicalAddress[i];
diff --git a/src/sampled_values/sv_subscriber.c b/src/sampled_values/sv_subscriber.c
index 39554063..8cefa423 100644
--- a/src/sampled_values/sv_subscriber.c
+++ b/src/sampled_values/sv_subscriber.c
@@ -185,6 +185,13 @@ SVReceiver_start(SVReceiver self)
}
}
+bool
+SVReceiver_isRunning(SVReceiver self)
+{
+ return self->running;
+}
+
+
void
SVReceiver_stop(SVReceiver self)
{
diff --git a/src/sampled_values/sv_subscriber.h b/src/sampled_values/sv_subscriber.h
index 879736a9..04728cc1 100644
--- a/src/sampled_values/sv_subscriber.h
+++ b/src/sampled_values/sv_subscriber.h
@@ -194,6 +194,18 @@ SVReceiver_start(SVReceiver self);
void
SVReceiver_stop(SVReceiver self);
+/**
+ * \brief Check if SV receiver is running
+ *
+ * Can be used to check if \ref SVReceiver_start has been successful.
+ *
+ * \param self the receiver instance reference
+ *
+ * \return true if SV receiver is running, false otherwise
+ */
+bool
+SVReceiver_isRunning(SVReceiver self);
+
/**
* \brief Destroy receiver instance (cleanup resources)
*
diff --git a/src/vs/libiec61850.def b/src/vs/libiec61850.def
index 83cee3bc..98fab54b 100644
--- a/src/vs/libiec61850.def
+++ b/src/vs/libiec61850.def
@@ -697,4 +697,5 @@ EXPORTS
SVSubscriber_ASDU_getFLOAT64
SVSubscriber_ASDU_getDataSize
CDC_VSS_create
- CDC_VSG_create
\ No newline at end of file
+ CDC_VSG_create
+ SVReceiver_isRunning
\ No newline at end of file