diff --git a/dotnet/IEC61850forCSharp/GooseSubscriber.cs b/dotnet/IEC61850forCSharp/GooseSubscriber.cs index 9b2c6e69..29b64c01 100644 --- a/dotnet/IEC61850forCSharp/GooseSubscriber.cs +++ b/dotnet/IEC61850forCSharp/GooseSubscriber.cs @@ -22,6 +22,7 @@ */ using System; +using System.Collections.Generic; using System.Runtime.InteropServices; using IEC61850.Common; @@ -69,6 +70,8 @@ namespace IEC61850 private bool isDisposed = false; + private List subscribers = new List(); + public GooseReceiver() { self = GooseReceiver_create (); @@ -79,14 +82,29 @@ namespace IEC61850 GooseReceiver_setInterfaceId (self, interfaceId); } + /// + /// Add the subscriber to be handled by this receiver instance + /// + /// A GooseSubscriber can only be added to one GooseReceiver! + /// public void AddSubscriber(GooseSubscriber subscriber) { - GooseReceiver_addSubscriber (self, subscriber.self); + if (subscriber.attachedToReceiver == false) + { + subscriber.attachedToReceiver = true; + GooseReceiver_addSubscriber(self, subscriber.self); + subscribers.Add(subscriber); + } } public void RemoveSubscriber(GooseSubscriber subscriber) { - GooseReceiver_removeSubscriber (self, subscriber.self); + if (subscriber.attachedToReceiver) + { + GooseReceiver_removeSubscriber(self, subscriber.self); + subscribers.Remove(subscriber); + subscriber.attachedToReceiver = false; + } } public void Start() @@ -175,10 +193,22 @@ namespace IEC61850 [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] private static extern void GooseSubscriber_setListener (IntPtr self, InternalGooseListener listener, IntPtr parameter); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr GooseSubscriber_getGoId(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr GooseSubscriber_getGoCbRef(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr GooseSubscriber_getDataSet(IntPtr self); + internal IntPtr self; private bool isDisposed = false; + // don't call native destructor when attached to a receiver + internal bool attachedToReceiver = false; + private GooseListener listener = null; private object listenerParameter = null; @@ -214,7 +244,6 @@ namespace IEC61850 return GooseSubscriber_isValid (self); } - public void SetListener(GooseListener listener, object parameter) { this.listener = listener; @@ -227,6 +256,21 @@ namespace IEC61850 } } + public string GetGoId() + { + return Marshal.PtrToStringAnsi(GooseSubscriber_getGoId(self)); + } + + public string GetGoCbRef() + { + return Marshal.PtrToStringAnsi(GooseSubscriber_getGoCbRef(self)); + } + + public string GetDataSet() + { + return Marshal.PtrToStringAnsi(GooseSubscriber_getDataSet(self)); + } + public UInt32 GetStNum() { return GooseSubscriber_getStNum (self); @@ -300,12 +344,20 @@ namespace IEC61850 { if (isDisposed == false) { isDisposed = true; - GooseSubscriber_destroy (self); + + if (attachedToReceiver == false) + GooseSubscriber_destroy (self); + self = IntPtr.Zero; } } - } + ~GooseSubscriber() + { + Dispose(); + } + + } } diff --git a/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs index 29315143..58bc9cbd 100644 --- a/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs +++ b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs @@ -886,7 +886,7 @@ namespace IEC61850 /// Creates a new SampledValuesControlBlock instance. /// /// The new GoCB instance - /// The object reference of the GoCB + /// The object reference of the GoCB (e.g. "simpleIOGenericIO/LLN0.gcbAnalogValues") public GooseControlBlock GetGooseControlBlock(string gocbObjectReference) { return new GooseControlBlock(gocbObjectReference, connection); diff --git a/dotnet/IEC61850forCSharp/IEC61850CommonAPI.cs b/dotnet/IEC61850forCSharp/IEC61850CommonAPI.cs index 574d6c82..df4103ed 100644 --- a/dotnet/IEC61850forCSharp/IEC61850CommonAPI.cs +++ b/dotnet/IEC61850forCSharp/IEC61850CommonAPI.cs @@ -86,9 +86,9 @@ namespace IEC61850 public UInt16 vlanId; public UInt16 appId; - [MarshalAs(UnmanagedType.ByValArray, SizeConst=6)] - public byte[] dstAddress = new byte[6]; - } + [MarshalAs(UnmanagedType.ByValArray, SizeConst=6)] + public byte[] dstAddress = new byte[6]; + } /// /// MMS data access error for MmsValue type MMS_DATA_ACCESS_ERROR diff --git a/dotnet/goose_subscriber/Program.cs b/dotnet/goose_subscriber/Program.cs index df84f032..bfcdaff6 100644 --- a/dotnet/goose_subscriber/Program.cs +++ b/dotnet/goose_subscriber/Program.cs @@ -4,6 +4,9 @@ using IEC61850.GOOSE.Subscriber; using System.Threading; using IEC61850.Common; +/// +/// This example is intended to be +/// namespace goose_subscriber { class MainClass @@ -11,9 +14,10 @@ namespace goose_subscriber private static void gooseListener (GooseSubscriber subscriber, object parameter) { Console.WriteLine ("Received GOOSE message:\n-------------------------"); - + Console.WriteLine (" GoID: " + subscriber.GetGoId()); + Console.WriteLine (" GoCbRef: " + subscriber.GetGoCbRef()); + Console.WriteLine (" DatSet: " + subscriber.GetDataSet()); Console.WriteLine (" stNum: " + subscriber.GetStNum ()); - Console.WriteLine (" sqNum: " + subscriber.GetSqNum ()); @@ -33,17 +37,27 @@ namespace goose_subscriber GooseReceiver receiver = new GooseReceiver (); receiver.SetInterfaceId ("eth0"); + //receiver.SetInterfaceId("0"); // on windows use the interface index starting with 0 GooseSubscriber subscriber = new GooseSubscriber ("simpleIOGenericIO/LLN0$GO$gcbAnalogValues"); - subscriber.SetAppId(1000); - + // APP-ID has to match the APP-ID of the publisher + subscriber.SetAppId(4096); subscriber.SetListener (gooseListener, null); receiver.AddSubscriber (subscriber); + GooseSubscriber subscriber2 = new GooseSubscriber("simpleIOGenericIO/LLN0$GO$gcbEvents"); + + subscriber2.SetAppId(4096); + subscriber2.SetListener(gooseListener, null); + + receiver.AddSubscriber(subscriber2); + receiver.Start (); + subscriber = null; + if (receiver.IsRunning ()) { bool running = true; diff --git a/src/goose/goose_subscriber.h b/src/goose/goose_subscriber.h index f88432dd..e58f4f96 100644 --- a/src/goose/goose_subscriber.h +++ b/src/goose/goose_subscriber.h @@ -1,7 +1,7 @@ /* * goose_subscriber.h * - * Copyright 2013-2018 Michael Zillgith + * Copyright 2013-2021 Michael Zillgith * * This file is part of libIEC61850. * @@ -82,12 +82,27 @@ typedef void (*GooseListener)(GooseSubscriber subscriber, void* parameter); LIB61850_API GooseSubscriber GooseSubscriber_create(char* goCbRef, MmsValue* dataSetValues); +/** + * \brief Get the GoId value of the received GOOSE message + * + * \param self GooseSubscriber instance to operate on. + */ LIB61850_API char* GooseSubscriber_getGoId(GooseSubscriber self); +/** + * \brief Get the GOOSE Control Block reference value of the received GOOSE message + * + * \param self GooseSubscriber instance to operate on. + */ LIB61850_API char* GooseSubscriber_getGoCbRef(GooseSubscriber self); +/** + * \brief Get the DatSet value of the received GOOSE message + * + * \param self GooseSubscriber instance to operate on. + */ LIB61850_API char* GooseSubscriber_getDataSet(GooseSubscriber self); @@ -133,6 +148,14 @@ GooseSubscriber_isValid(GooseSubscriber self); LIB61850_API GooseParseError GooseSubscriber_getParseError(GooseSubscriber self); +/** + * \brief Destroy the GooseSubscriber instance + * + * Do not call this function when the GooseSubscriber instance was added to a GooseReceiver. + * The GooseReceiver will call the destructor when \ref GooseReceiver_destroy is called! + * + * \param self GooseSubscriber instance to operate on. + */ LIB61850_API void GooseSubscriber_destroy(GooseSubscriber self); @@ -146,14 +169,32 @@ GooseSubscriber_destroy(GooseSubscriber self); LIB61850_API void GooseSubscriber_setListener(GooseSubscriber self, GooseListener listener, void* parameter); +/** + * \brief Get the APPID value of the received GOOSE message + * + * \param self GooseSubscriber instance to operate on. + */ LIB61850_API int32_t GooseSubscriber_getAppId(GooseSubscriber self); +/** + * \brief Get the source MAC address of the received GOOSE message + * + * \param self GooseSubscriber instance to operate on. + * \param buffer buffer to store the MAC address (at least 6 byte) + */ LIB61850_API void -GooseSubscriber_getSrcMac(GooseSubscriber self, uint8_t *buffer); +GooseSubscriber_getSrcMac(GooseSubscriber self, uint8_t* buffer); +/** + * \brief Get the destination MAC address of the received GOOSE message + * + * \param self GooseSubscriber instance to operate on. + * \param buffer buffer to store the MAC address (at least 6 byte) + */ LIB61850_API void -GooseSubscriber_getDstMac(GooseSubscriber self, uint8_t *buffer); +GooseSubscriber_getDstMac(GooseSubscriber self, uint8_t* buffer); + /** * \brief return the state number (stNum) of the last received GOOSE message. *