diff --git a/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs index 48ec76f0..71d608a7 100644 --- a/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs +++ b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs @@ -37,47 +37,47 @@ namespace IEC61850 /// /// IEC 61850 client API. /// - namespace Client - { + namespace Client + { - [StructLayout(LayoutKind.Sequential)] - public class MmsServerIdentity - { - public string vendorName; - public string modelName; - public string revision; - } + [StructLayout(LayoutKind.Sequential)] + public class MmsServerIdentity + { + public string vendorName; + public string modelName; + public string revision; + } /// /// Represents an MmsConnection object (a single connection to an MMS server) /// - public class MmsConnection - { + public class MmsConnection + { - [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] - private static extern IntPtr MmsConnection_create(); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr MmsConnection_create(); - [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] - private static extern void MmsConnection_destroy(IntPtr self); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern void MmsConnection_destroy(IntPtr self); - [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] - private static extern IntPtr MmsConnection_identify(IntPtr self, out int mmsError); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr MmsConnection_identify(IntPtr self, out int mmsError); - [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] - private static extern void MmsServerIdentity_destroy(IntPtr self); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern void MmsServerIdentity_destroy(IntPtr self); - [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] - private static extern void MmsConnection_setLocalDetail (IntPtr self, Int32 localDetail); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern void MmsConnection_setLocalDetail(IntPtr self, Int32 localDetail); - [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] - private static extern Int32 MmsConnection_getLocalDetail (IntPtr self); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern Int32 MmsConnection_getLocalDetail(IntPtr self); - [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] private static extern IntPtr MmsConnection_readMultipleVariables(IntPtr self, out int mmsError, string domainId, IntPtr items); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] - private static extern void MmsValue_delete (IntPtr self); + private static extern void MmsValue_delete(IntPtr self); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate void LinkedListValueDeleteFunction(IntPtr pointer); @@ -86,33 +86,35 @@ namespace IEC61850 private static extern void LinkedList_destroyDeep(IntPtr list, LinkedListValueDeleteFunction valueDeleteFunction); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr LinkedList_create (); + private static extern IntPtr LinkedList_create(); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] - private static extern void LinkedList_add (IntPtr self, IntPtr data); + private static extern void LinkedList_add(IntPtr self, IntPtr data); - private IntPtr self = IntPtr.Zero; - private bool selfDestroy = false; + private IntPtr self = IntPtr.Zero; + private bool selfDestroy = false; - public MmsConnection() { - selfDestroy = true; + public MmsConnection() + { + selfDestroy = true; - self = MmsConnection_create(); - } + self = MmsConnection_create(); + } - internal MmsConnection(IntPtr mmsConnection) { - self = mmsConnection; - } + internal MmsConnection(IntPtr mmsConnection) + { + self = mmsConnection; + } - ~MmsConnection () + ~MmsConnection () { - if (selfDestroy) - if (self != IntPtr.Zero) - MmsConnection_destroy(self); + if (selfDestroy) + if (self != IntPtr.Zero) + MmsConnection_destroy(self); } - private void FreeHGlobaleDeleteFunction (IntPtr pointer) + private void FreeHGlobaleDeleteFunction(IntPtr pointer) { Marshal.FreeHGlobal(pointer); } @@ -121,15 +123,16 @@ namespace IEC61850 /// Requests the server identity information /// /// The server identity. - public MmsServerIdentity GetServerIdentity () - { - int mmsError; + public MmsServerIdentity GetServerIdentity() + { + int mmsError; - if (self == IntPtr.Zero) { - throw new IedConnectionException("Pointer is Zero!"); - } + if (self == IntPtr.Zero) + { + throw new IedConnectionException("Pointer is Zero!"); + } - IntPtr identity = MmsConnection_identify(self, out mmsError); + IntPtr identity = MmsConnection_identify(self, out mmsError); if (mmsError != 0) throw new IedConnectionException("Failed to read server identity", mmsError); @@ -137,29 +140,31 @@ namespace IEC61850 if (identity == IntPtr.Zero) throw new IedConnectionException("Failed to read server identity"); - MmsServerIdentity serverIdentity = (MmsServerIdentity) + MmsServerIdentity serverIdentity = (MmsServerIdentity) Marshal.PtrToStructure(identity, typeof(MmsServerIdentity)); - MmsServerIdentity_destroy(identity); + MmsServerIdentity_destroy(identity); - return serverIdentity; - } + return serverIdentity; + } /// /// Sets the local detail (maximum MMS PDU size) /// /// maximum accepted MMS PDU size in bytes - public void SetLocalDetail(int localDetail) { - MmsConnection_setLocalDetail (self, localDetail); - } + public void SetLocalDetail(int localDetail) + { + MmsConnection_setLocalDetail(self, localDetail); + } /// /// Gets the local detail (maximum MMS PDU size) /// /// maximum accepted MMS PDU size in bytes - public int GetLocalDetail() { - return MmsConnection_getLocalDetail (self); - } + public int GetLocalDetail() + { + return MmsConnection_getLocalDetail(self); + } /// /// Reads multipe MMS variables from the same domain @@ -169,12 +174,13 @@ namespace IEC61850 /// list of variable names (in MMS notation e.g. "GGIO$ST$Ind1") public MmsValue ReadMultipleVariables(string domainName, List variables) { - IntPtr linkedList = LinkedList_create (); + IntPtr linkedList = LinkedList_create(); - foreach (string variableName in variables) { - IntPtr handle = System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi (variableName); + foreach (string variableName in variables) + { + IntPtr handle = System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(variableName); - LinkedList_add (linkedList, handle); + LinkedList_add(linkedList, handle); } int error; @@ -193,128 +199,131 @@ namespace IEC61850 return new MmsValue(mmsValue, true); } - } + } - public class MmsJournalVariable - { - [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] - static extern IntPtr MmsJournalVariable_getTag(IntPtr self); + public class MmsJournalVariable + { + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr MmsJournalVariable_getTag(IntPtr self); - [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] - static extern IntPtr MmsJournalVariable_getValue(IntPtr self); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr MmsJournalVariable_getValue(IntPtr self); - private IntPtr self; + private IntPtr self; - internal MmsJournalVariable(IntPtr self) - { - this.self = self; - } + internal MmsJournalVariable(IntPtr self) + { + this.self = self; + } - public string GetTag() - { - return Marshal.PtrToStringAnsi (MmsJournalVariable_getTag (self)); - } + public string GetTag() + { + return Marshal.PtrToStringAnsi(MmsJournalVariable_getTag(self)); + } - public MmsValue GetValue() - { - MmsValue mmsValue = new MmsValue (MmsJournalVariable_getValue (self)); + public MmsValue GetValue() + { + MmsValue mmsValue = new MmsValue(MmsJournalVariable_getValue(self)); - return mmsValue; - } + return mmsValue; + } - } + } - /// - /// Represents an entry of a log - /// - public class MmsJournalEntry - { - [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] - static extern void MmsJournalEntry_destroy(IntPtr self); + /// + /// Represents an entry of a log + /// + public class MmsJournalEntry + { + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void MmsJournalEntry_destroy(IntPtr self); - [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] - static extern IntPtr MmsJournalEntry_getEntryID(IntPtr self); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr MmsJournalEntry_getEntryID(IntPtr self); - [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] - static extern IntPtr MmsJournalEntry_getOccurenceTime(IntPtr self); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr MmsJournalEntry_getOccurenceTime(IntPtr self); - [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] - static extern IntPtr MmsJournalEntry_getJournalVariables (IntPtr self); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr MmsJournalEntry_getJournalVariables(IntPtr self); - /**************** + /**************** * LinkedList ***************/ - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] - static extern IntPtr LinkedList_getNext (IntPtr self); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr LinkedList_getNext(IntPtr self); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] - static extern IntPtr LinkedList_getData (IntPtr self); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr LinkedList_getData(IntPtr self); - private IntPtr self; - private List variables = null; + private IntPtr self; + private List variables = null; - internal MmsJournalEntry(IntPtr self) - { - this.self = self; - } + internal MmsJournalEntry(IntPtr self) + { + this.self = self; + } - public List GetJournalVariables() - { - if (variables == null) { + public List GetJournalVariables() + { + if (variables == null) + { - IntPtr linkedList = MmsJournalEntry_getJournalVariables (self); + IntPtr linkedList = MmsJournalEntry_getJournalVariables(self); - IntPtr element = LinkedList_getNext (linkedList); + IntPtr element = LinkedList_getNext(linkedList); - variables = new List (); + variables = new List(); - while (element != IntPtr.Zero) { - MmsJournalVariable journalVariable = new MmsJournalVariable (LinkedList_getData (element)); + while (element != IntPtr.Zero) + { + MmsJournalVariable journalVariable = new MmsJournalVariable(LinkedList_getData(element)); - variables.Add (journalVariable); + variables.Add(journalVariable); - element = LinkedList_getNext (element); - } - } + element = LinkedList_getNext(element); + } + } - return variables; - } + return variables; + } - public byte[] GetEntryID() - { - IntPtr mmsValuePtr = MmsJournalEntry_getEntryID (self); + public byte[] GetEntryID() + { + IntPtr mmsValuePtr = MmsJournalEntry_getEntryID(self); - MmsValue mmsValue = new MmsValue (mmsValuePtr); + MmsValue mmsValue = new MmsValue(mmsValuePtr); - byte[] octetString = mmsValue.getOctetString (); + byte[] octetString = mmsValue.getOctetString(); - return octetString; - } + return octetString; + } - public ulong GetOccurenceTime() - { - IntPtr mmsValuePtr = MmsJournalEntry_getOccurenceTime (self); + public ulong GetOccurenceTime() + { + IntPtr mmsValuePtr = MmsJournalEntry_getOccurenceTime(self); - MmsValue mmsValue = new MmsValue (mmsValuePtr); + MmsValue mmsValue = new MmsValue(mmsValuePtr); - return mmsValue.GetBinaryTimeAsUtcMs (); - } + return mmsValue.GetBinaryTimeAsUtcMs(); + } - public void Dispose() - { - if (self != IntPtr.Zero) { - MmsJournalEntry_destroy (self); - self = IntPtr.Zero; - } - } + public void Dispose() + { + if (self != IntPtr.Zero) + { + MmsJournalEntry_destroy(self); + self = IntPtr.Zero; + } + } - ~MmsJournalEntry () - { - Dispose (); - } - } + ~MmsJournalEntry () + { + Dispose(); + } + } /// /// Asynchonous service handler for the get RCB values service @@ -323,7 +332,7 @@ namespace IEC61850 /// user provided callback parameter /// Error code of response or timeout error in case of a response timeout /// the report control block instance - public delegate void GetRCBValuesHandler(UInt32 invokeId, object parameter, IedClientError err, ReportControlBlock rcb); + public delegate void GetRCBValuesHandler(UInt32 invokeId,object parameter,IedClientError err,ReportControlBlock rcb); /// /// Asynchonous service handler for the set RCB values service @@ -332,7 +341,7 @@ namespace IEC61850 /// user provided callback parameter /// Error code of response or timeout error in case of a response timeout /// the report control block instance - public delegate void SetRCBValuesHandler(UInt32 invokeId, object parameter, IedClientError err, ReportControlBlock rcb); + public delegate void SetRCBValuesHandler(UInt32 invokeId,object parameter,IedClientError err,ReportControlBlock rcb); /// /// Generic asynchonous service handler - used by simple services that have only success or error result @@ -340,129 +349,129 @@ namespace IEC61850 /// The invoke ID of the request triggering this callback /// user provided callback parameter /// Error code of response or timeout error in case of a response timeout - public delegate void GenericServiceHandler(UInt32 invokeId, object parameter, IedClientError err); + public delegate void GenericServiceHandler(UInt32 invokeId,object parameter,IedClientError err); - /// - /// This class acts as the entry point for the IEC 61850 client API. It represents a single - /// (MMS) connection to a server. - /// + /// + /// This class acts as the entry point for the IEC 61850 client API. It represents a single + /// (MMS) connection to a server. + /// public partial class IedConnection : IDisposable - { - /************* + { + /************* * MmsValue *************/ - [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] - static extern IntPtr MmsValue_toString (IntPtr self); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr MmsValue_toString(IntPtr self); - [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] - static extern float MmsValue_toFloat (IntPtr self); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern float MmsValue_toFloat(IntPtr self); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] [return: MarshalAs(UnmanagedType.I1)] - static extern bool MmsValue_getBoolean (IntPtr self); + static extern bool MmsValue_getBoolean(IntPtr self); - [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] - static extern UInt32 MmsValue_getBitStringAsInteger (IntPtr self); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern UInt32 MmsValue_getBitStringAsInteger(IntPtr self); - [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] - static extern int MmsValue_getType (IntPtr self); - - [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] - static extern void MmsValue_delete (IntPtr self); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern int MmsValue_getType(IntPtr self); - [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] - static extern int MmsValue_getDataAccessError(IntPtr self); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void MmsValue_delete(IntPtr self); - /**************** + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern int MmsValue_getDataAccessError(IntPtr self); + + /**************** * IedConnection ***************/ - [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] - static extern IntPtr IedConnection_create (); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr IedConnection_create(); - [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] - static extern IntPtr IedConnection_createWithTlsSupport (IntPtr tlsConfig); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr IedConnection_createWithTlsSupport(IntPtr tlsConfig); - [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] - static extern void IedConnection_destroy (IntPtr self); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void IedConnection_destroy(IntPtr self); - [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern void IedConnection_setConnectTimeout(IntPtr self, UInt32 timeoutInMs); - [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] - static extern void IedConnection_connect (IntPtr self, out int error, string hostname, int tcpPort); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void IedConnection_connect(IntPtr self, out int error, string hostname, int tcpPort); - [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] - static extern void IedConnection_abort (IntPtr self, out int error); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void IedConnection_abort(IntPtr self, out int error); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern void IedConnection_release(IntPtr self, out int error); - [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] - private static extern void IedConnection_release(IntPtr self, out int error); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern void IedConnection_close(IntPtr self); - [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] - private static extern void IedConnection_close(IntPtr self); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr IedConnection_readObject(IntPtr self, out int error, string objectReference, int fc); - [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] - static extern IntPtr IedConnection_readObject (IntPtr self, out int error, string objectReference, int fc); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void IedConnection_writeObject(IntPtr self, out int error, string dataAttributeReference, int fc, IntPtr value); - [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] - static extern void IedConnection_writeObject (IntPtr self, out int error, string dataAttributeReference, int fc, IntPtr value); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr IedConnection_getDataDirectory(IntPtr self, out int error, string dataReference); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] - static extern IntPtr IedConnection_getDataDirectory (IntPtr self, out int error, string dataReference); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr IedConnection_getDataDirectoryByFC(IntPtr self, out int error, string dataReference, FunctionalConstraint fc); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] - static extern IntPtr IedConnection_getDataDirectoryByFC (IntPtr self, out int error, string dataReference, FunctionalConstraint fc); + static extern IntPtr IedConnection_getDataDirectoryFC(IntPtr self, out int error, string dataReference); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] - static extern IntPtr IedConnection_getDataDirectoryFC (IntPtr self, out int error, string dataReference); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr IedConnection_getLogicalNodeDirectory(IntPtr self, out int error, string logicalNodeReference, int acsiClass); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] - static extern IntPtr IedConnection_getLogicalNodeDirectory (IntPtr self, out int error, string logicalNodeReference, int acsiClass); - - [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] - static extern IntPtr IedConnection_getServerDirectory (IntPtr self, out int error, [MarshalAs(UnmanagedType.I1)] bool getFileNames); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr IedConnection_getServerDirectory(IntPtr self, out int error, [MarshalAs(UnmanagedType.I1)] bool getFileNames); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern void IedConnection_getDeviceModelFromServer(IntPtr self, out int error); - [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] - static extern IntPtr IedConnection_getLogicalDeviceDirectory (IntPtr self, out int error, string logicalDeviceName); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr IedConnection_getLogicalDeviceDirectory(IntPtr self, out int error, string logicalDeviceName); - [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] - static extern IntPtr IedConnection_getVariableSpecification(IntPtr self, out int error, string objectReference, int fc); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr IedConnection_getVariableSpecification(IntPtr self, out int error, string objectReference, int fc); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate void InternalConnectionClosedHandler (IntPtr parameter,IntPtr Iedconnection); + private delegate void InternalConnectionClosedHandler(IntPtr parameter,IntPtr Iedconnection); /// /// Called when the connection is closed /// - public delegate void ConnectionClosedHandler (IedConnection connection); + public delegate void ConnectionClosedHandler(IedConnection connection); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] - static extern void IedConnection_installConnectionClosedHandler (IntPtr self, InternalConnectionClosedHandler handler, IntPtr parameter); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void IedConnection_installConnectionClosedHandler(IntPtr self, InternalConnectionClosedHandler handler, IntPtr parameter); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] - static extern IntPtr IedConnection_readDataSetValues (IntPtr self, out int error, [MarshalAs(UnmanagedType.LPStr)] string dataSetReference, IntPtr dataSet); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr IedConnection_readDataSetValues(IntPtr self, out int error, [MarshalAs(UnmanagedType.LPStr)] string dataSetReference, IntPtr dataSet); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] - static extern void IedConnection_writeDataSetValues (IntPtr self, out int error, [MarshalAs(UnmanagedType.LPStr)] string dataSetReference, IntPtr values, out IntPtr accessResults); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void IedConnection_writeDataSetValues(IntPtr self, out int error, [MarshalAs(UnmanagedType.LPStr)] string dataSetReference, IntPtr values, out IntPtr accessResults); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] - static extern IntPtr IedConnection_createDataSet (IntPtr self, out int error, [MarshalAs(UnmanagedType.LPStr)] string dataSetReference, IntPtr dataSet); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr IedConnection_createDataSet(IntPtr self, out int error, [MarshalAs(UnmanagedType.LPStr)] string dataSetReference, IntPtr dataSet); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] - [return: MarshalAs(UnmanagedType.Bool)] - static extern bool IedConnection_deleteDataSet (IntPtr self, out int error, string dataSetReference); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.Bool)] + static extern bool IedConnection_deleteDataSet(IntPtr self, out int error, string dataSetReference); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern IntPtr IedConnection_getDataSetDirectory(IntPtr self, out int error, string dataSetReference, [MarshalAs(UnmanagedType.I1)] out bool isDeletable); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] - static extern IntPtr IedConnection_getMmsConnection (IntPtr self); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr IedConnection_getMmsConnection(IntPtr self); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] - static extern IntPtr MmsConnection_getIsoConnectionParameters(IntPtr mmsConnection); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr MmsConnection_getIsoConnectionParameters(IntPtr mmsConnection); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern IntPtr IedConnection_getFileDirectory(IntPtr self, out int error, string directoryName); @@ -475,38 +484,38 @@ namespace IEC61850 [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern void IedConnection_deleteFile(IntPtr self, out int error, string fileName); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] - static extern IntPtr IedConnection_queryLogAfter(IntPtr self, out int error, string logReference, - IntPtr entryID, ulong timeStamp, [MarshalAs(UnmanagedType.I1)] out bool moreFollows); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr IedConnection_queryLogAfter(IntPtr self, out int error, string logReference, + IntPtr entryID, ulong timeStamp, [MarshalAs(UnmanagedType.I1)] out bool moreFollows); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] - static extern IntPtr IedConnection_queryLogByTime (IntPtr self, out int error, string logReference, - ulong startTime, ulong endTime, [MarshalAs(UnmanagedType.I1)] out bool moreFollows); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr IedConnection_queryLogByTime(IntPtr self, out int error, string logReference, + ulong startTime, ulong endTime, [MarshalAs(UnmanagedType.I1)] out bool moreFollows); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] - static extern IntPtr IedConnection_getRCBValues (IntPtr connection, out int error, string rcbReference, IntPtr updateRcb); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr IedConnection_getRCBValues(IntPtr connection, out int error, string rcbReference, IntPtr updateRcb); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] - static extern void IedConnection_setRCBValues (IntPtr connection, out int error, IntPtr rcb, UInt32 parametersMask, [MarshalAs(UnmanagedType.I1)] bool singleRequest); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void IedConnection_setRCBValues(IntPtr connection, out int error, IntPtr rcb, UInt32 parametersMask, [MarshalAs(UnmanagedType.I1)] bool singleRequest); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] - static extern void IedConnection_installReportHandler (IntPtr connection, string rcbReference, string rptId, InternalReportHandler handler, - IntPtr handlerParameter); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void IedConnection_installReportHandler(IntPtr connection, string rcbReference, string rptId, InternalReportHandler handler, + IntPtr handlerParameter); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] - static extern void IedConnection_uninstallReportHandler(IntPtr connection, string rcbReference); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void IedConnection_uninstallReportHandler(IntPtr connection, string rcbReference); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern int IedConnection_getState(IntPtr connection); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate void InternalStateChangedHandler (IntPtr parameter,IntPtr iedConnection, int newState); + private delegate void InternalStateChangedHandler(IntPtr parameter,IntPtr iedConnection,int newState); /// /// Called when there is a change in the connection state /// - public delegate void StateChangedHandler (IedConnection connection, IedConnectionState newState); + public delegate void StateChangedHandler(IedConnection connection,IedConnectionState newState); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern void IedConnection_installStateChangedHandler(IntPtr connection, InternalStateChangedHandler handler, IntPtr parameter); @@ -515,25 +524,25 @@ namespace IEC61850 * Async functions *********************/ - [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] - static extern void IedConnection_connectAsync (IntPtr self, out int error, string hostname, int tcpPort); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void IedConnection_connectAsync(IntPtr self, out int error, string hostname, int tcpPort); - [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] - static extern void IedConnection_abortAsync (IntPtr self, out int error); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void IedConnection_abortAsync(IntPtr self, out int error); - [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] private static extern void IedConnection_releaseAsync(IntPtr self, out int error); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate void IedConnection_ReadObjectHandler (UInt32 invokeId, IntPtr parameter, int err, IntPtr value); + private delegate void IedConnection_ReadObjectHandler(UInt32 invokeId,IntPtr parameter,int err,IntPtr value); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern UInt32 IedConnection_readObjectAsync(IntPtr self, out int error, string objRef, int fc, - IedConnection_ReadObjectHandler handler, IntPtr parameter); + IedConnection_ReadObjectHandler handler, IntPtr parameter); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate void IedConnection_WriteObjectHandler (UInt32 invokeId, IntPtr parameter, int err); + private delegate void IedConnection_WriteObjectHandler(UInt32 invokeId,IntPtr parameter,int err); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern UInt32 @@ -541,72 +550,72 @@ namespace IEC61850 IntPtr value, IedConnection_WriteObjectHandler handler, IntPtr parameter); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate void IedConnection_GetNameListHandler (UInt32 invokeId, IntPtr parameter, int err, IntPtr nameList, [MarshalAs(UnmanagedType.I1)] bool moreFollows); + private delegate void IedConnection_GetNameListHandler(UInt32 invokeId,IntPtr parameter,int err,IntPtr nameList,[MarshalAs(UnmanagedType.I1)] bool moreFollows); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern UInt32 IedConnection_getServerDirectoryAsync(IntPtr self, out int error, string continueAfter, IntPtr result, - IedConnection_GetNameListHandler handler, IntPtr parameter); + IedConnection_GetNameListHandler handler, IntPtr parameter); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern UInt32 IedConnection_getLogicalDeviceVariablesAsync(IntPtr self, out int error, string ldName, string continueAfter, IntPtr result, - IedConnection_GetNameListHandler handler, IntPtr parameter); + IedConnection_GetNameListHandler handler, IntPtr parameter); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern UInt32 IedConnection_getLogicalDeviceDataSetsAsync(IntPtr self, out int error, string ldName, string continueAfter, IntPtr result, - IedConnection_GetNameListHandler handler, IntPtr parameter); + IedConnection_GetNameListHandler handler, IntPtr parameter); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate void IedConnection_QueryLogHandler (UInt32 invokeId, IntPtr parameter, int err, IntPtr journalEntries, [MarshalAs(UnmanagedType.I1)] bool moreFollows); + private delegate void IedConnection_QueryLogHandler(UInt32 invokeId,IntPtr parameter,int err,IntPtr journalEntries,[MarshalAs(UnmanagedType.I1)] bool moreFollows); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern UInt32 IedConnection_queryLogByTimeAsync(IntPtr self, out int error, string logReference, - UInt64 startTime, UInt64 endTime, IedConnection_QueryLogHandler handler, IntPtr parameter); + UInt64 startTime, UInt64 endTime, IedConnection_QueryLogHandler handler, IntPtr parameter); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern UInt32 IedConnection_queryLogAfterAsync(IntPtr self, out int error, string logReference, - IntPtr entryID, UInt64 timeStamp, IedConnection_QueryLogHandler handler, IntPtr parameter); + IntPtr entryID, UInt64 timeStamp, IedConnection_QueryLogHandler handler, IntPtr parameter); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate void IedConnection_GetVariableSpecificationHandler (UInt32 invokeId, IntPtr parameter, int err, IntPtr spec); + private delegate void IedConnection_GetVariableSpecificationHandler(UInt32 invokeId,IntPtr parameter,int err,IntPtr spec); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern UInt32 IedConnection_getVariableSpecificationAsync(IntPtr self, out int error, string dataAttributeReference, - int fc, IedConnection_GetVariableSpecificationHandler handler, IntPtr parameter); + int fc, IedConnection_GetVariableSpecificationHandler handler, IntPtr parameter); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate void IedConnection_ReadDataSetHandler (UInt32 invokeId, IntPtr parameter, int err, IntPtr dataSet); + private delegate void IedConnection_ReadDataSetHandler(UInt32 invokeId,IntPtr parameter,int err,IntPtr dataSet); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern UInt32 IedConnection_readDataSetValuesAsync(IntPtr self, out int error, string dataSetReference, IntPtr dataSet, - IedConnection_ReadDataSetHandler handler, IntPtr parameter); + IedConnection_ReadDataSetHandler handler, IntPtr parameter); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate void IedConnection_GetRCBValuesHandler (UInt32 invokeId, IntPtr parameter, int err, IntPtr rcb); + private delegate void IedConnection_GetRCBValuesHandler(UInt32 invokeId,IntPtr parameter,int err,IntPtr rcb); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern UInt32 IedConnection_getRCBValuesAsync(IntPtr self, out int error, string rcbReference, IntPtr updateRcb, - IedConnection_GetRCBValuesHandler handler, IntPtr parameter); + IedConnection_GetRCBValuesHandler handler, IntPtr parameter); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate void IedConnection_GenericServiceHandler (UInt32 invokeId, IntPtr parameter, int err); + private delegate void IedConnection_GenericServiceHandler(UInt32 invokeId,IntPtr parameter,int err); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern UInt32 IedConnection_setRCBValuesAsync(IntPtr self, out int error, IntPtr rcb, - UInt32 parametersMask, [MarshalAs(UnmanagedType.I1)] bool singleRequest, IedConnection_GenericServiceHandler handler, IntPtr parameter); + UInt32 parametersMask, [MarshalAs(UnmanagedType.I1)] bool singleRequest, IedConnection_GenericServiceHandler handler, IntPtr parameter); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern UInt32 IedConnection_deleteFileAsync(IntPtr self, out int error, string fileName, - IedConnection_GenericServiceHandler handler, IntPtr parameter); + IedConnection_GenericServiceHandler handler, IntPtr parameter); /******************** @@ -615,17 +624,17 @@ namespace IEC61850 [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern void FileDirectoryEntry_destroy(IntPtr self); - /**************** + /**************** * LinkedList ***************/ - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] - static extern IntPtr LinkedList_getNext (IntPtr self); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr LinkedList_getNext(IntPtr self); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] - static extern IntPtr LinkedList_getData (IntPtr self); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr LinkedList_getData(IntPtr self); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] - static extern void LinkedList_destroy (IntPtr self); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void LinkedList_destroy(IntPtr self); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern void LinkedList_destroyStatic(IntPtr self); @@ -633,70 +642,71 @@ namespace IEC61850 [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate void LinkedListValueDeleteFunction(IntPtr pointer); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] - static extern void LinkedList_destroyDeep(IntPtr list, LinkedListValueDeleteFunction valueDeleteFunction); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void LinkedList_destroyDeep(IntPtr list, LinkedListValueDeleteFunction valueDeleteFunction); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] - static extern IntPtr LinkedList_create (); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr LinkedList_create(); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] - static extern void LinkedList_add (IntPtr self, IntPtr data); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void LinkedList_add(IntPtr self, IntPtr data); - private IntPtr connection = IntPtr.Zero; + private IntPtr connection = IntPtr.Zero; private InternalConnectionClosedHandler connectionClosedHandler = null; - private ConnectionClosedHandler userProvidedConnectionClosedHandler = null; + private ConnectionClosedHandler userProvidedConnectionClosedHandler = null; private InternalStateChangedHandler internalStateChangedHandler = null; private StateChangedHandler stateChangedHandler = null; - /// - /// Initializes a new instance of the class. - /// - public IedConnection () - { - connection = IedConnection_create (); - } - - /// - /// Initializes a new instance of the class. - /// - /// TLS configuration to use - public IedConnection (TLSConfiguration tlsConfig) - { - connection = IedConnection_createWithTlsSupport (tlsConfig.GetNativeInstance ()); - } - - /// - /// Releases all resource used by the object. - /// - /// Call when you are finished using the . The - /// method leaves the in an unusable state. After - /// calling , you must release all references to the - /// so the garbage collector can reclaim the memory that the was occupying. - public void Dispose() - { - if (connection != IntPtr.Zero) { - - IedConnection_destroy (connection); - - connection = IntPtr.Zero; - } - } + /// + /// Initializes a new instance of the class. + /// + public IedConnection() + { + connection = IedConnection_create(); + } + + /// + /// Initializes a new instance of the class. + /// + /// TLS configuration to use + public IedConnection(TLSConfiguration tlsConfig) + { + connection = IedConnection_createWithTlsSupport(tlsConfig.GetNativeInstance()); + } + + /// + /// Releases all resource used by the object. + /// + /// Call when you are finished using the . The + /// method leaves the in an unusable state. After + /// calling , you must release all references to the + /// so the garbage collector can reclaim the memory that the was occupying. + public void Dispose() + { + if (connection != IntPtr.Zero) + { + + IedConnection_destroy(connection); + + connection = IntPtr.Zero; + } + } ~IedConnection () { - Dispose (); + Dispose(); } private IsoConnectionParameters isoConnectionParameters = null; - /// - /// Gets the connection parameters - /// - /// The connection parameters - public IsoConnectionParameters GetConnectionParameters () - { - if (isoConnectionParameters == null) + /// + /// Gets the connection parameters + /// + /// The connection parameters + public IsoConnectionParameters GetConnectionParameters() + { + if (isoConnectionParameters == null) { IntPtr mmsConnection = IedConnection_getMmsConnection(connection); @@ -706,15 +716,15 @@ namespace IEC61850 } return isoConnectionParameters; - } + } - private void FreeHGlobaleDeleteFunction (IntPtr pointer) - { - Marshal.FreeHGlobal(pointer); - } + private void FreeHGlobaleDeleteFunction(IntPtr pointer) + { + Marshal.FreeHGlobal(pointer); + } - private UInt32 connectTimeout = 10000; + private UInt32 connectTimeout = 10000; /// /// Gets or sets the timeout used for connection attempts. @@ -722,10 +732,12 @@ namespace IEC61850 /// The connect timeout in milliseconds public UInt32 ConnectTimeout { - get { + get + { return connectTimeout; } - set { + set + { connectTimeout = value; } } @@ -736,10 +748,12 @@ namespace IEC61850 /// The maximum allowed size of an MMS PDU. public int MaxPduSize { - get { + get + { return GetMmsConnection().GetLocalDetail(); } - set { + set + { GetMmsConnection().SetLocalDetail(value); } } @@ -748,26 +762,26 @@ namespace IEC61850 /// Gets the underlying MmsConnection instance. /// /// The mms connection. - public MmsConnection GetMmsConnection () - { - IntPtr mmsConnectionPtr = IedConnection_getMmsConnection(connection); + public MmsConnection GetMmsConnection() + { + IntPtr mmsConnectionPtr = IedConnection_getMmsConnection(connection); - return new MmsConnection(mmsConnectionPtr); - } + return new MmsConnection(mmsConnectionPtr); + } - /// Establish an MMS connection to a server - /// This exception is thrown if there is a connection or service error - public void Connect (string hostname, int tcpPort) - { - int error; + /// Establish an MMS connection to a server + /// This exception is thrown if there is a connection or service error + public void Connect(string hostname, int tcpPort) + { + int error; IedConnection_setConnectTimeout(connection, connectTimeout); - IedConnection_connect (connection, out error, hostname, tcpPort); + IedConnection_connect(connection, out error, hostname, tcpPort); - if (error != 0) - throw new IedConnectionException ("Connect to " + hostname + ":" + tcpPort + " failed", error); - } + if (error != 0) + throw new IedConnectionException("Connect to " + hostname + ":" + tcpPort + " failed", error); + } public void ConnectAsync(string hostname, int tcpPort) { @@ -775,10 +789,10 @@ namespace IEC61850 IedConnection_setConnectTimeout(connection, connectTimeout); - IedConnection_connectAsync (connection, out error, hostname, tcpPort); + IedConnection_connectAsync(connection, out error, hostname, tcpPort); if (error != 0) - throw new IedConnectionException ("Connect to " + hostname + ":" + tcpPort + " failed", error); + throw new IedConnectionException("Connect to " + hostname + ":" + tcpPort + " failed", error); } @@ -791,578 +805,597 @@ namespace IEC61850 return (IedConnectionState)IedConnection_getState(connection); } - /// Establish an MMS connection to a server. - /// This exception is thrown if there is a connection or service error. - public void Connect (string hostname) - { - Connect (hostname, -1); - } - - /// This exception is thrown if there is a connection or service error - public ControlObject CreateControlObject (string objectReference) - { - ControlObject controlObject = new ControlObject (objectReference, connection, this); - - return controlObject; - } - - /// - /// Creates a new SampledValuesControlBlock instance. - /// - /// > - /// This function will also read the SVCB values from the server. - /// - /// The new SVCB instance - /// The object reference of the SVCB - public SampledValuesControlBlock GetSvControlBlock (string svcbObjectReference) - { - return new SampledValuesControlBlock (connection, svcbObjectReference); - } - - /// - /// Creates a new SampledValuesControlBlock instance. - /// - /// The new GoCB instance - /// The object reference of the GoCB - public GooseControlBlock GetGooseControlBlock (string gocbObjectReference) - { - return new GooseControlBlock (gocbObjectReference, connection); - } - - /// - /// Updates the device model by quering the server. - /// - public void UpdateDeviceModel() + /// Establish an MMS connection to a server. + /// This exception is thrown if there is a connection or service error. + public void Connect(string hostname) + { + Connect(hostname, -1); + } + + /// This exception is thrown if there is a connection or service error + public ControlObject CreateControlObject(string objectReference) + { + ControlObject controlObject = new ControlObject(objectReference, connection, this); + + return controlObject; + } + + /// + /// Creates a new SampledValuesControlBlock instance. + /// + /// > + /// This function will also read the SVCB values from the server. + /// + /// The new SVCB instance + /// The object reference of the SVCB + public SampledValuesControlBlock GetSvControlBlock(string svcbObjectReference) + { + return new SampledValuesControlBlock(connection, svcbObjectReference); + } + + /// + /// Creates a new SampledValuesControlBlock instance. + /// + /// The new GoCB instance + /// The object reference of the GoCB + public GooseControlBlock GetGooseControlBlock(string gocbObjectReference) + { + return new GooseControlBlock(gocbObjectReference, connection); + } + + /// + /// Updates the device model by quering the server. + /// + public void UpdateDeviceModel() { int error; IedConnection_getDeviceModelFromServer(connection, out error); - if (error != 0) + if (error != 0) throw new IedConnectionException("UpdateDeviceModel failed", error); } - /// - /// Gets the server directory (Logical devices or file objects) - /// - /// List of logical devices or files - /// If set to true the file directory is returned, otherwise the LD names - /// This exception is thrown if there is a connection or service error - public List GetServerDirectory (bool fileDirectory = false) - { - int error; + /// + /// Gets the server directory (Logical devices or file objects) + /// + /// List of logical devices or files + /// If set to true the file directory is returned, otherwise the LD names + /// This exception is thrown if there is a connection or service error + public List GetServerDirectory(bool fileDirectory = false) + { + int error; + + IntPtr linkedList = IedConnection_getServerDirectory(connection, out error, fileDirectory); + + if (error != 0) + throw new IedConnectionException("GetDeviceDirectory failed", error); + + List newList = new List(); + + if (fileDirectory == false) + { + + IntPtr element = LinkedList_getNext(linkedList); + + while (element != IntPtr.Zero) + { + string ld = Marshal.PtrToStringAnsi(LinkedList_getData(element)); + + newList.Add(ld); + + element = LinkedList_getNext(element); + } - IntPtr linkedList = IedConnection_getServerDirectory (connection, out error, fileDirectory); + LinkedList_destroy(linkedList); + } + else + { - if (error != 0) - throw new IedConnectionException ("GetDeviceDirectory failed", error); + IntPtr element = LinkedList_getNext(linkedList); - List newList = new List (); + while (element != IntPtr.Zero) + { + IntPtr elementData = LinkedList_getData(element); - if (fileDirectory == false) { + FileDirectoryEntry entry = new FileDirectoryEntry(elementData); - IntPtr element = LinkedList_getNext (linkedList); + newList.Add(entry.GetFileName()); - while (element != IntPtr.Zero) { - string ld = Marshal.PtrToStringAnsi (LinkedList_getData (element)); + FileDirectoryEntry_destroy(elementData); - newList.Add (ld); + element = LinkedList_getNext(element); + } - element = LinkedList_getNext (element); - } + LinkedList_destroyStatic(linkedList); + } - LinkedList_destroy (linkedList); - } - else { + return newList; + } - IntPtr element = LinkedList_getNext(linkedList); + /// This exception is thrown if there is a connection or service error + public List GetLogicalDeviceDirectory(string logicalDeviceName) + { + int error; - while (element != IntPtr.Zero) - { - IntPtr elementData = LinkedList_getData(element); + IntPtr linkedList = IedConnection_getLogicalDeviceDirectory(connection, out error, logicalDeviceName); - FileDirectoryEntry entry = new FileDirectoryEntry(elementData); + if (error != 0) + throw new IedConnectionException("GetLogicalDeviceDirectory failed", error); - newList.Add(entry.GetFileName()); + IntPtr element = LinkedList_getNext(linkedList); - FileDirectoryEntry_destroy(elementData); + List newList = new List(); - element = LinkedList_getNext(element); - } + while (element != IntPtr.Zero) + { + string ln = Marshal.PtrToStringAnsi(LinkedList_getData(element)); - LinkedList_destroyStatic(linkedList); - } + newList.Add(ln); - return newList; - } + element = LinkedList_getNext(element); + } - /// This exception is thrown if there is a connection or service error - public List GetLogicalDeviceDirectory (string logicalDeviceName) - { - int error; + LinkedList_destroy(linkedList); - IntPtr linkedList = IedConnection_getLogicalDeviceDirectory (connection, out error, logicalDeviceName); + return newList; + } - if (error != 0) - throw new IedConnectionException ("GetLogicalDeviceDirectory failed", error); + /// Get the directory of a logical node (LN) + /// This function returns the directory contents of a LN. Depending on the provided ACSI class + /// The function returns either data object references, or references of other objects like data sets, + /// report control blocks, ... + /// The object reference of a DO, SDO, or DA. + /// the ACSI class of the requested directory elements. + /// This exception is thrown if there is a connection or service error + public List GetLogicalNodeDirectory(string logicalNodeName, ACSIClass acsiClass) + { + int error; - IntPtr element = LinkedList_getNext (linkedList); + IntPtr linkedList = IedConnection_getLogicalNodeDirectory(connection, out error, logicalNodeName, (int)acsiClass); - List newList = new List (); + if (error != 0) + throw new IedConnectionException("GetLogicalNodeDirectory failed", error); - while (element != IntPtr.Zero) { - string ln = Marshal.PtrToStringAnsi (LinkedList_getData (element)); + IntPtr element = LinkedList_getNext(linkedList); - newList.Add (ln); + List newList = new List(); - element = LinkedList_getNext (element); - } + while (element != IntPtr.Zero) + { + string dataObject = Marshal.PtrToStringAnsi(LinkedList_getData(element)); - LinkedList_destroy (linkedList); + newList.Add(dataObject); - return newList; - } + element = LinkedList_getNext(element); + } - /// Get the directory of a logical node (LN) - /// This function returns the directory contents of a LN. Depending on the provided ACSI class - /// The function returns either data object references, or references of other objects like data sets, - /// report control blocks, ... - /// The object reference of a DO, SDO, or DA. - /// the ACSI class of the requested directory elements. - /// This exception is thrown if there is a connection or service error - public List GetLogicalNodeDirectory (string logicalNodeName, ACSIClass acsiClass) - { - int error; + LinkedList_destroy(linkedList); - IntPtr linkedList = IedConnection_getLogicalNodeDirectory (connection, out error, logicalNodeName, (int)acsiClass); + return newList; + } - if (error != 0) - throw new IedConnectionException ("GetLogicalNodeDirectory failed", error); + /// Get a list of attributes (with functional constraints) of a DO, SDO, or DA + /// The object reference of a DO, SDO, or DA. + /// This exception is thrown if there is a connection or service error + public List GetDataDirectory(string dataReference) + { + int error; - IntPtr element = LinkedList_getNext (linkedList); + IntPtr linkedList = IedConnection_getDataDirectory(connection, out error, dataReference); - List newList = new List (); + if (error != 0) + throw new IedConnectionException("GetDataDirectory failed", error); - while (element != IntPtr.Zero) { - string dataObject = Marshal.PtrToStringAnsi (LinkedList_getData (element)); + IntPtr element = LinkedList_getNext(linkedList); - newList.Add (dataObject); + List newList = new List(); - element = LinkedList_getNext (element); - } + while (element != IntPtr.Zero) + { + string dataObject = Marshal.PtrToStringAnsi(LinkedList_getData(element)); - LinkedList_destroy (linkedList); + newList.Add(dataObject); - return newList; - } + element = LinkedList_getNext(element); + } + + LinkedList_destroy(linkedList); + + return newList; + } + + /// Get the list of attributes with the specified FC of a DO, SDO, or DA + /// The object reference of a DO, SDO, or DA. + /// Functional constraint + /// This exception is thrown if there is a connection or service error + public List GetDataDirectory(string dataReference, FunctionalConstraint fc) + { + int error; + + IntPtr linkedList = IedConnection_getDataDirectoryByFC(connection, out error, dataReference, fc); + + if (error != 0) + throw new IedConnectionException("GetDataDirectory failed", error); + + IntPtr element = LinkedList_getNext(linkedList); + + List newList = new List(); + + while (element != IntPtr.Zero) + { + string dataObject = Marshal.PtrToStringAnsi(LinkedList_getData(element)); + + newList.Add(dataObject); + + element = LinkedList_getNext(element); + } + + LinkedList_destroy(linkedList); + + return newList; + } + + /// Get a list of attributes (with functional constraints) of a DO, SDO, or DA + /// This function is similar to the GetDataDirectory except that the returned element names + /// have the functional contraint (FC) appended. + /// The object reference of a DO, SDO, or DA. + /// This exception is thrown if there is a connection or service error + public List GetDataDirectoryFC(string dataReference) + { + int error; + + IntPtr linkedList = IedConnection_getDataDirectoryFC(connection, out error, dataReference); + + if (error != 0) + throw new IedConnectionException("GetDataDirectoryFC failed", error); + + IntPtr element = LinkedList_getNext(linkedList); + + List newList = new List(); + + while (element != IntPtr.Zero) + { + string dataObject = Marshal.PtrToStringAnsi(LinkedList_getData(element)); + + newList.Add(dataObject); + + element = LinkedList_getNext(element); + } + + LinkedList_destroy(linkedList); + + return newList; + } + + private static List WrapNativeLogQueryResult(IntPtr linkedList) + { + List journalEntries = new List(); + + IntPtr element = LinkedList_getNext(linkedList); + + while (element != IntPtr.Zero) + { + + MmsJournalEntry journalEntry = new MmsJournalEntry(LinkedList_getData(element)); + + journalEntries.Add(journalEntry); + + element = LinkedList_getNext(element); + } + + LinkedList_destroyStatic(linkedList); + + return journalEntries; + } + + /// + /// Queries all log entries after the entry with the given entryID and timestamp + /// + /// The list of log entries contained in the response + /// The object reference of the log (e.g. "simpleIOGenericIO/LLN0$EventLog") + /// EntryID of the last received MmsJournalEntry + /// Timestamp of the last received MmsJournalEntry + /// Indicates that more log entries are available + /// This exception is thrown if there is a connection or service error + public List QueryLogAfter(string logRef, byte[] entryID, ulong timestamp, out bool moreFollows) + { + int error; + bool moreFollowsVal; + + MmsValue entryIdValue = new MmsValue(entryID); + + IntPtr linkedList = IedConnection_queryLogAfter(connection, out error, logRef, entryIdValue.valueReference, timestamp, out moreFollowsVal); + + if (error != 0) + throw new IedConnectionException("QueryLogAfter failed", error); - /// Get a list of attributes (with functional constraints) of a DO, SDO, or DA - /// The object reference of a DO, SDO, or DA. - /// This exception is thrown if there is a connection or service error - public List GetDataDirectory (string dataReference) - { - int error; + moreFollows = moreFollowsVal; - IntPtr linkedList = IedConnection_getDataDirectory (connection, out error, dataReference); + return WrapNativeLogQueryResult(linkedList); + } - if (error != 0) - throw new IedConnectionException ("GetDataDirectory failed", error); + /// + /// Queries all log entries of the given time range + /// + /// The list of log entries contained in the response + /// The object reference of the log (e.g. "simpleIOGenericIO/LLN0$EventLog") + /// Start time of the time range + /// End time of the time range + /// Indicates that more log entries are available + /// This exception is thrown if there is a connection or service error + public List QueryLogByTime(string logRef, ulong startTime, ulong stopTime, out bool moreFollows) + { + int error; + bool moreFollowsVal; - IntPtr element = LinkedList_getNext (linkedList); + IntPtr linkedList = IedConnection_queryLogByTime(connection, out error, logRef, startTime, stopTime, out moreFollowsVal); - List newList = new List (); + if (error != 0) + throw new IedConnectionException("QueryLogByTime failed", error); - while (element != IntPtr.Zero) { - string dataObject = Marshal.PtrToStringAnsi (LinkedList_getData (element)); + moreFollows = moreFollowsVal; - newList.Add (dataObject); + return WrapNativeLogQueryResult(linkedList); - element = LinkedList_getNext (element); - } + } - LinkedList_destroy (linkedList); + /// + /// Queries all log entries of the given time range + /// + /// The list of log entries contained in the response + /// The object reference of the log (e.g. "simpleIOGenericIO/LLN0$EventLog") + /// Start time of the time range + /// End time of the time range + /// Indicates that more log entries are available + /// This exception is thrown if there is a connection or service error + public List QueryLogByTime(string logRef, DateTime startTime, DateTime stopTime, out bool moreFollows) + { + ulong startTimeMs = LibIEC61850.DateTimeToMsTimestamp(startTime); + ulong stopTimeMs = LibIEC61850.DateTimeToMsTimestamp(stopTime); - return newList; - } + return QueryLogByTime(logRef, startTimeMs, stopTimeMs, out moreFollows); + } - /// Get the list of attributes with the specified FC of a DO, SDO, or DA - /// The object reference of a DO, SDO, or DA. - /// Functional constraint + /// Read the variable specification (type description of a DA or FCDO + /// The object reference of a DA or FCDO. + /// The functional constraint (FC) of the object /// This exception is thrown if there is a connection or service error - public List GetDataDirectory (string dataReference, FunctionalConstraint fc) + public MmsVariableSpecification GetVariableSpecification(string objectReference, FunctionalConstraint fc) { int error; - IntPtr linkedList = IedConnection_getDataDirectoryByFC (connection, out error, dataReference, fc); + IntPtr varSpecPtr = IedConnection_getVariableSpecification(connection, out error, objectReference, (int)fc); if (error != 0) - throw new IedConnectionException ("GetDataDirectory failed", error); - - IntPtr element = LinkedList_getNext (linkedList); + throw new IedConnectionException("GetVariableSpecification failed", error); - List newList = new List (); + return new MmsVariableSpecification(varSpecPtr, true); + } - while (element != IntPtr.Zero) { - string dataObject = Marshal.PtrToStringAnsi (LinkedList_getData (element)); + private IntPtr readObjectInternal(string objectReference, FunctionalConstraint fc) + { + int error; - newList.Add (dataObject); + IntPtr mmsValue = IedConnection_readObject(connection, out error, objectReference, (int)fc); - element = LinkedList_getNext (element); - } + if (error != 0) + throw new IedConnectionException("Reading value failed", error); - LinkedList_destroy (linkedList); + if (mmsValue == IntPtr.Zero) + throw new IedConnectionException("Variable not found on server", error); - return newList; + return mmsValue; } - /// Get a list of attributes (with functional constraints) of a DO, SDO, or DA - /// This function is similar to the GetDataDirectory except that the returned element names - /// have the functional contraint (FC) appended. - /// The object reference of a DO, SDO, or DA. - /// This exception is thrown if there is a connection or service error - public List GetDataDirectoryFC (string dataReference) - { - int error; + /// Read the value of a data attribute (DA) or functional constraint data object (FCDO). + /// The object reference of a DA or FCDO. + /// The functional constraint (FC) of the object + /// the received value as an MmsValue instance + /// This exception is thrown if there is a connection or service error + public MmsValue ReadValue(String objectReference, FunctionalConstraint fc) + { + var value = readObjectInternal(objectReference, fc); + + return new MmsValue(value, true); + } - IntPtr linkedList = IedConnection_getDataDirectoryFC (connection, out error, dataReference); + private IntPtr readObjectInternalAndCheckDataAccessError(string objectReference, FunctionalConstraint fc) + { + IntPtr mmsValue = readObjectInternal(objectReference, fc); - if (error != 0) - throw new IedConnectionException ("GetDataDirectoryFC failed", error); + if (MmsValue_getType(mmsValue) == (int)MmsType.MMS_DATA_ACCESS_ERROR) + { - IntPtr element = LinkedList_getNext (linkedList); + int dataAccessError = MmsValue_getDataAccessError(mmsValue); - List newList = new List (); + MmsValue_delete(mmsValue); - while (element != IntPtr.Zero) { - string dataObject = Marshal.PtrToStringAnsi (LinkedList_getData (element)); + throw new IedConnectionException("Data access error", dataAccessError); + } - newList.Add (dataObject); + return mmsValue; + } - element = LinkedList_getNext (element); - } + /// Read the value of a basic data attribute (BDA) of type boolean. + /// The object reference of a BDA. + /// The functional constraint (FC) of the object + /// the received boolean value + /// This exception is thrown if there is a connection or service error + public bool ReadBooleanValue(string objectReference, FunctionalConstraint fc) + { + IntPtr mmsValue = readObjectInternalAndCheckDataAccessError(objectReference, fc); - LinkedList_destroy (linkedList); + if (MmsValue_getType(mmsValue) != (int)MmsType.MMS_BOOLEAN) + { + MmsValue_delete(mmsValue); + throw new IedConnectionException("Result is not of type boolean (MMS_BOOLEAN)", 0); + } - return newList; - } + bool value = MmsValue_getBoolean(mmsValue); - private static List WrapNativeLogQueryResult(IntPtr linkedList) - { - List journalEntries = new List (); + MmsValue_delete(mmsValue); - IntPtr element = LinkedList_getNext (linkedList); + return value; + } - while (element != IntPtr.Zero) { + /// Read the value of a basic data attribute (BDA) of type float. + /// The object reference of a BDA. + /// The functional constraint (FC) of the object + /// This exception is thrown if there is a connection or service error + public float ReadFloatValue(string objectReference, FunctionalConstraint fc) + { + IntPtr mmsValue = readObjectInternalAndCheckDataAccessError(objectReference, fc); - MmsJournalEntry journalEntry = new MmsJournalEntry(LinkedList_getData (element)); + if (MmsValue_getType(mmsValue) != (int)MmsType.MMS_FLOAT) + { + MmsValue_delete(mmsValue); + throw new IedConnectionException("Result is not of type float (MMS_FLOAT)", 0); + } - journalEntries.Add (journalEntry); + float value = MmsValue_toFloat(mmsValue); - element = LinkedList_getNext (element); - } + MmsValue_delete(mmsValue); - LinkedList_destroyStatic (linkedList); + return value; + } - return journalEntries; - } + /// Read the value of a basic data attribute (BDA) of type string (VisibleString or MmsString). + /// The object reference of a BDA. + /// The functional constraint (FC) of the object + /// This exception is thrown if there is a connection or service error + public string ReadStringValue(string objectReference, FunctionalConstraint fc) + { + IntPtr mmsValue = readObjectInternalAndCheckDataAccessError(objectReference, fc); - /// - /// Queries all log entries after the entry with the given entryID and timestamp - /// - /// The list of log entries contained in the response - /// The object reference of the log (e.g. "simpleIOGenericIO/LLN0$EventLog") - /// EntryID of the last received MmsJournalEntry - /// Timestamp of the last received MmsJournalEntry - /// Indicates that more log entries are available - /// This exception is thrown if there is a connection or service error - public List QueryLogAfter(string logRef, byte[] entryID, ulong timestamp, out bool moreFollows) - { - int error; - bool moreFollowsVal; + if (!((MmsValue_getType(mmsValue) == (int)MmsType.MMS_VISIBLE_STRING) || (MmsValue_getType(mmsValue) == (int)MmsType.MMS_STRING))) + { + MmsValue_delete(mmsValue); + throw new IedConnectionException("Result is not of type string", 0); + } - MmsValue entryIdValue = new MmsValue (entryID); + IntPtr ptr = MmsValue_toString(mmsValue); - IntPtr linkedList = IedConnection_queryLogAfter (connection, out error, logRef, entryIdValue.valueReference, timestamp, out moreFollowsVal); + string returnString = Marshal.PtrToStringAnsi(ptr); - if (error != 0) - throw new IedConnectionException ("QueryLogAfter failed", error); + MmsValue_delete(mmsValue); - moreFollows = moreFollowsVal; + return returnString; + } - return WrapNativeLogQueryResult(linkedList); - } + /// Read the value of a basic data attribute (BDA) of type quality. + /// The object reference of a BDA. + /// The functional constraint (FC) of the object + /// This exception is thrown if there is a connection or service error + public Quality ReadQualityValue(string objectReference, FunctionalConstraint fc) + { + IntPtr mmsValue = readObjectInternalAndCheckDataAccessError(objectReference, fc); - /// - /// Queries all log entries of the given time range - /// - /// The list of log entries contained in the response - /// The object reference of the log (e.g. "simpleIOGenericIO/LLN0$EventLog") - /// Start time of the time range - /// End time of the time range - /// Indicates that more log entries are available - /// This exception is thrown if there is a connection or service error - public List QueryLogByTime(string logRef, ulong startTime, ulong stopTime, out bool moreFollows) - { - int error; - bool moreFollowsVal; + if (MmsValue_getType(mmsValue) == (int)MmsType.MMS_BIT_STRING) + { + int bitStringValue = (int)MmsValue_getBitStringAsInteger(mmsValue); - IntPtr linkedList = IedConnection_queryLogByTime (connection, out error, logRef, startTime, stopTime, out moreFollowsVal); + MmsValue_delete(mmsValue); + return new Quality(bitStringValue); + } + else + { + MmsValue_delete(mmsValue); + throw new IedConnectionException("Result is not of type bit string(Quality)", 0); + } + } - if (error != 0) - throw new IedConnectionException ("QueryLogByTime failed", error); + /// Read the value of a basic data attribute (BDA) of type bit string. + /// The object reference of a BDA. + /// The functional constraint (FC) of the object + /// This exception is thrown if there is a connection or service error + public int ReadBitStringValue(string objectReference, FunctionalConstraint fc) + { + IntPtr mmsValue = readObjectInternalAndCheckDataAccessError(objectReference, fc); - moreFollows = moreFollowsVal; + if (MmsValue_getType(mmsValue) == (int)MmsType.MMS_BIT_STRING) + { + int bitStringValue = (int)MmsValue_getBitStringAsInteger(mmsValue); - return WrapNativeLogQueryResult(linkedList); + MmsValue_delete(mmsValue); + return bitStringValue; + } + else + { + MmsValue_delete(mmsValue); + throw new IedConnectionException("Result is not of type bit string", 0); + } + } - } + /// Read the value of a basic data attribute (BDA) of type timestamp (MMS_UTC_TIME). + /// The object reference of a BDA. + /// The functional constraint (FC) of the object + /// This exception is thrown if there is a connection or service error + public Timestamp ReadTimestampValue(string objectReference, FunctionalConstraint fc) + { + var mmsValuePtr = readObjectInternalAndCheckDataAccessError(objectReference, fc); - /// - /// Queries all log entries of the given time range - /// - /// The list of log entries contained in the response - /// The object reference of the log (e.g. "simpleIOGenericIO/LLN0$EventLog") - /// Start time of the time range - /// End time of the time range - /// Indicates that more log entries are available - /// This exception is thrown if there is a connection or service error - public List QueryLogByTime(string logRef, DateTime startTime, DateTime stopTime, out bool moreFollows) - { - ulong startTimeMs = LibIEC61850.DateTimeToMsTimestamp (startTime); - ulong stopTimeMs = LibIEC61850.DateTimeToMsTimestamp (stopTime); + var mmsValue = new MmsValue(mmsValuePtr, true); - return QueryLogByTime (logRef, startTimeMs, stopTimeMs, out moreFollows); - } + if (mmsValue.GetType() == MmsType.MMS_UTC_TIME) + return new Timestamp(mmsValue); + else + throw new IedConnectionException("Result is not of type timestamp (MMS_UTC_TIME)", 0); + } - /// Read the variable specification (type description of a DA or FCDO - /// The object reference of a DA or FCDO. - /// The functional constraint (FC) of the object - /// This exception is thrown if there is a connection or service error - public MmsVariableSpecification GetVariableSpecification (string objectReference, FunctionalConstraint fc) - { - int error; + /// Read the value of a basic data attribute (BDA) of type integer (MMS_INTEGER). + /// This function should also be used if enumerations are beeing read. Because + /// enumerations are mapped to integer types for the MMS mapping + /// The object reference of a BDA. + /// The functional constraint (FC) of the object + /// This exception is thrown if there is a connection or service error + public Int64 ReadIntegerValue(string objectReference, FunctionalConstraint fc) + { + var mmsValuePtr = readObjectInternalAndCheckDataAccessError(objectReference, fc); - IntPtr varSpecPtr = IedConnection_getVariableSpecification(connection, out error, objectReference, (int) fc); + var mmsValue = new MmsValue(mmsValuePtr, true); - if (error != 0) - throw new IedConnectionException ("GetVariableSpecification failed", error); + if (mmsValue.GetType() == MmsType.MMS_INTEGER) + return mmsValue.ToInt64(); + else + throw new IedConnectionException("Result is not of type integer (MMS_INTEGER)", 0); + } - return new MmsVariableSpecification(varSpecPtr, true); - } + /// Write the value of a data attribute (DA) or functional constraint data object (FCDO). + /// This function can be used to write simple or complex variables (setpoints, parameters, descriptive values...) + /// of the server. + /// The object reference of a BDA. + /// The functional constraint (FC) of the object + /// MmsValue object representing asimple or complex variable data + /// This exception is thrown if there is a connection or service error + public void WriteValue(string objectReference, FunctionalConstraint fc, MmsValue value) + { + int error; - private IntPtr readObjectInternal (string objectReference, FunctionalConstraint fc) - { - int error; + IedConnection_writeObject(connection, out error, objectReference, (int)fc, value.valueReference); - IntPtr mmsValue = IedConnection_readObject (connection, out error, objectReference, (int)fc); + if (error != 0) + throw new IedConnectionException("Write value failed", error); + } - if (error != 0) - throw new IedConnectionException ("Reading value failed", error); + /// Delete file + /// The name of the file. + /// This exception is thrown if there is a connection or service error + public void DeleteFile(string fileName) + { + int error; + IedConnection_deleteFile(connection, out error, fileName); - if (mmsValue == IntPtr.Zero) - throw new IedConnectionException ("Variable not found on server", error); - - return mmsValue; - } - - /// Read the value of a data attribute (DA) or functional constraint data object (FCDO). - /// The object reference of a DA or FCDO. - /// The functional constraint (FC) of the object - /// the received value as an MmsValue instance - /// This exception is thrown if there is a connection or service error - public MmsValue ReadValue (String objectReference, FunctionalConstraint fc) - { - var value = readObjectInternal (objectReference, fc); - - return new MmsValue (value, true); - } + if (error != 0) + throw new IedConnectionException("Deleting file " + fileName + " failed", error); + } - private IntPtr readObjectInternalAndCheckDataAccessError(string objectReference, FunctionalConstraint fc) - { - IntPtr mmsValue = readObjectInternal (objectReference, fc); - - if (MmsValue_getType(mmsValue) == (int) MmsType.MMS_DATA_ACCESS_ERROR) { - - int dataAccessError = MmsValue_getDataAccessError (mmsValue); - - MmsValue_delete (mmsValue); - - throw new IedConnectionException ("Data access error", dataAccessError); - } - - return mmsValue; - } - - /// Read the value of a basic data attribute (BDA) of type boolean. - /// The object reference of a BDA. - /// The functional constraint (FC) of the object - /// the received boolean value - /// This exception is thrown if there is a connection or service error - public bool ReadBooleanValue (string objectReference, FunctionalConstraint fc) - { - IntPtr mmsValue = readObjectInternalAndCheckDataAccessError (objectReference, fc); - - if (MmsValue_getType (mmsValue) != (int) MmsType.MMS_BOOLEAN) { - MmsValue_delete (mmsValue); - throw new IedConnectionException ("Result is not of type boolean (MMS_BOOLEAN)", 0); - } - - bool value = MmsValue_getBoolean (mmsValue); - - MmsValue_delete (mmsValue); - - return value; - } - - /// Read the value of a basic data attribute (BDA) of type float. - /// The object reference of a BDA. - /// The functional constraint (FC) of the object - /// This exception is thrown if there is a connection or service error - public float ReadFloatValue (string objectReference, FunctionalConstraint fc) - { - IntPtr mmsValue = readObjectInternalAndCheckDataAccessError (objectReference, fc); - - if (MmsValue_getType (mmsValue) != (int)MmsType.MMS_FLOAT) { - MmsValue_delete (mmsValue); - throw new IedConnectionException ("Result is not of type float (MMS_FLOAT)", 0); - } - - float value = MmsValue_toFloat (mmsValue); - - MmsValue_delete (mmsValue); - - return value; - } - - /// Read the value of a basic data attribute (BDA) of type string (VisibleString or MmsString). - /// The object reference of a BDA. - /// The functional constraint (FC) of the object - /// This exception is thrown if there is a connection or service error - public string ReadStringValue (string objectReference, FunctionalConstraint fc) - { - IntPtr mmsValue = readObjectInternalAndCheckDataAccessError (objectReference, fc); - - if (!((MmsValue_getType (mmsValue) == (int)MmsType.MMS_VISIBLE_STRING) || (MmsValue_getType (mmsValue) == (int)MmsType.MMS_STRING))) { - MmsValue_delete (mmsValue); - throw new IedConnectionException ("Result is not of type string", 0); - } - - IntPtr ptr = MmsValue_toString (mmsValue); - - string returnString = Marshal.PtrToStringAnsi (ptr); - - MmsValue_delete (mmsValue); - - return returnString; - } - - /// Read the value of a basic data attribute (BDA) of type quality. - /// The object reference of a BDA. - /// The functional constraint (FC) of the object - /// This exception is thrown if there is a connection or service error - public Quality ReadQualityValue (string objectReference, FunctionalConstraint fc) - { - IntPtr mmsValue = readObjectInternalAndCheckDataAccessError (objectReference, fc); - - if (MmsValue_getType (mmsValue) == (int)MmsType.MMS_BIT_STRING) { - int bitStringValue = (int)MmsValue_getBitStringAsInteger (mmsValue); - - MmsValue_delete (mmsValue); - return new Quality (bitStringValue); - } else { - MmsValue_delete (mmsValue); - throw new IedConnectionException ("Result is not of type bit string(Quality)", 0); - } - } - - /// Read the value of a basic data attribute (BDA) of type bit string. - /// The object reference of a BDA. - /// The functional constraint (FC) of the object - /// This exception is thrown if there is a connection or service error - public int ReadBitStringValue (string objectReference, FunctionalConstraint fc) - { - IntPtr mmsValue = readObjectInternalAndCheckDataAccessError (objectReference, fc); - - if (MmsValue_getType (mmsValue) == (int)MmsType.MMS_BIT_STRING) { - int bitStringValue = (int)MmsValue_getBitStringAsInteger (mmsValue); - - MmsValue_delete (mmsValue); - return bitStringValue; - } else { - MmsValue_delete (mmsValue); - throw new IedConnectionException ("Result is not of type bit string", 0); - } - } - - /// Read the value of a basic data attribute (BDA) of type timestamp (MMS_UTC_TIME). - /// The object reference of a BDA. - /// The functional constraint (FC) of the object - /// This exception is thrown if there is a connection or service error - public Timestamp ReadTimestampValue (string objectReference, FunctionalConstraint fc) - { - var mmsValuePtr = readObjectInternalAndCheckDataAccessError (objectReference, fc); - - var mmsValue = new MmsValue (mmsValuePtr, true); - - if (mmsValue.GetType () == MmsType.MMS_UTC_TIME) - return new Timestamp (mmsValue); - else - throw new IedConnectionException ("Result is not of type timestamp (MMS_UTC_TIME)", 0); - } - - /// Read the value of a basic data attribute (BDA) of type integer (MMS_INTEGER). - /// This function should also be used if enumerations are beeing read. Because - /// enumerations are mapped to integer types for the MMS mapping - /// The object reference of a BDA. - /// The functional constraint (FC) of the object - /// This exception is thrown if there is a connection or service error - public Int64 ReadIntegerValue (string objectReference, FunctionalConstraint fc) - { - var mmsValuePtr = readObjectInternalAndCheckDataAccessError (objectReference, fc); - - var mmsValue = new MmsValue (mmsValuePtr, true); - - if (mmsValue.GetType () == MmsType.MMS_INTEGER) - return mmsValue.ToInt64 (); - else - throw new IedConnectionException ("Result is not of type integer (MMS_INTEGER)", 0); - } - - /// Write the value of a data attribute (DA) or functional constraint data object (FCDO). - /// This function can be used to write simple or complex variables (setpoints, parameters, descriptive values...) - /// of the server. - /// The object reference of a BDA. - /// The functional constraint (FC) of the object - /// MmsValue object representing asimple or complex variable data - /// This exception is thrown if there is a connection or service error - public void WriteValue (string objectReference, FunctionalConstraint fc, MmsValue value) - { - int error; - - IedConnection_writeObject (connection, out error, objectReference, (int)fc, value.valueReference); - - if (error != 0) - throw new IedConnectionException ("Write value failed", error); - } - - /// Delete file - /// The name of the file. - /// This exception is thrown if there is a connection or service error - public void DeleteFile (string fileName) - { - int error; - IedConnection_deleteFile (connection, out error, fileName); - - if (error != 0) - throw new IedConnectionException ("Deleting file " + fileName + " failed", error); - } - - private void nativeGenericServiceHandler (UInt32 invokeId, IntPtr parameter, int err) + private void nativeGenericServiceHandler(UInt32 invokeId, IntPtr parameter, int err) { GCHandle handle = GCHandle.FromIntPtr(parameter); - Tuple callbackInfo = handle.Target as Tuple; + Tuple callbackInfo = handle.Target as Tuple; GenericServiceHandler handler = callbackInfo.Item1; object handlerParameter = callbackInfo.Item2; @@ -1399,20 +1432,20 @@ namespace IEC61850 /// Read the content of a file directory. /// The name of the directory. /// This exception is thrown if there is a connection or service error - public List GetFileDirectory(string directoryName) + public List GetFileDirectory(string directoryName) { int error; IntPtr fileEntryList = IedConnection_getFileDirectory(connection, out error, directoryName); - if (error != 0) + if (error != 0) throw new IedConnectionException("Reading file directory failed", error); List fileDirectory = new List(); IntPtr element = LinkedList_getNext(fileEntryList); - while (element != IntPtr.Zero) + while (element != IntPtr.Zero) { IntPtr elementData = LinkedList_getData(element); @@ -1467,33 +1500,33 @@ namespace IEC61850 return fileDirectory; } - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] [return: MarshalAs(UnmanagedType.I1)] - private delegate bool InternalIedClientGetFileHandler(IntPtr parameter, IntPtr buffer, UInt32 bytesRead); + private delegate bool InternalIedClientGetFileHandler(IntPtr parameter,IntPtr buffer,UInt32 bytesRead); - private bool iedClientGetFileHandler(IntPtr parameter, IntPtr buffer, UInt32 bytesRead) + private bool iedClientGetFileHandler(IntPtr parameter, IntPtr buffer, UInt32 bytesRead) { GCHandle handle = GCHandle.FromIntPtr(parameter); - GetFileCallback getFileCallback = (GetFileCallback) handle.Target; + GetFileCallback getFileCallback = (GetFileCallback)handle.Target; byte[] bytes = new byte[bytesRead]; - Marshal.Copy(buffer, bytes, 0, (int) bytesRead); + Marshal.Copy(buffer, bytes, 0, (int)bytesRead); return getFileCallback.handler(getFileCallback.parameter, bytes); } [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern UInt32 IedConnection_getFile(IntPtr self, out int error, string fileName, InternalIedClientGetFileHandler handler, - IntPtr handlerParameter); + IntPtr handlerParameter); - public delegate bool GetFileHandler(object parameter, byte[] data); + public delegate bool GetFileHandler(object parameter,byte[] data); - private class GetFileCallback + private class GetFileCallback { - public GetFileCallback(GetFileHandler handler, object parameter) + public GetFileCallback(GetFileHandler handler, object parameter) { this.handler = handler; this.parameter = parameter; @@ -1503,20 +1536,20 @@ namespace IEC61850 public object parameter; } - /// - /// Download a file from the server. - /// - /// - /// File name of the file (full path) - /// - /// - /// Callback handler that is invoked for each chunk of the file received - /// - /// - /// User provided parameter that is passed to the callback handler - /// + /// + /// Download a file from the server. + /// + /// + /// File name of the file (full path) + /// + /// + /// Callback handler that is invoked for each chunk of the file received + /// + /// + /// User provided parameter that is passed to the callback handler + /// /// This exception is thrown if there is a connection or service error - public void GetFile(string fileName, GetFileHandler handler, object parameter) + public void GetFile(string fileName, GetFileHandler handler, object parameter) { int error; @@ -1527,7 +1560,7 @@ namespace IEC61850 IedConnection_getFile(connection, out error, fileName, new InternalIedClientGetFileHandler(iedClientGetFileHandler), GCHandle.ToIntPtr(handle)); - if (error != 0) + if (error != 0) throw new IedConnectionException("Error reading file", error); handle.Free(); @@ -1535,8 +1568,8 @@ namespace IEC61850 [UnmanagedFunctionPointer(CallingConvention.Cdecl)] [return: MarshalAs(UnmanagedType.I1)] - private delegate bool IedConnection_GetFileAsyncHandler (UInt32 invokeId, IntPtr parameter, int err, UInt32 originalInvokeId, - IntPtr buffer, UInt32 bytesRead, bool moreFollows); + private delegate bool IedConnection_GetFileAsyncHandler(UInt32 invokeId,IntPtr parameter,int err,UInt32 originalInvokeId, + IntPtr buffer,UInt32 bytesRead,bool moreFollows); /// /// Callback handler for the asynchronous get file service. Will be invoked for each chunk of received data @@ -1547,20 +1580,20 @@ namespace IEC61850 /// the invokeId of the first (file open) request /// the file data received with the last response, or null if no file data available /// indicates that more file data follows - public delegate bool GetFileAsyncHandler(UInt32 invokeId, object parameter, IedClientError err, UInt32 originalInvokeId, byte[] buffer, bool moreFollows); + public delegate bool GetFileAsyncHandler(UInt32 invokeId,object parameter,IedClientError err,UInt32 originalInvokeId,byte[] buffer,bool moreFollows); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern UInt32 IedConnection_getFileAsync(IntPtr self, out int error, string fileName, IedConnection_GetFileAsyncHandler handler, - IntPtr parameter); + IntPtr parameter); private bool nativeGetFileAsyncHandler(UInt32 invokeId, IntPtr parameter, int err, UInt32 originalInvokeId, - IntPtr buffer, UInt32 bytesRead, bool moreFollows) + IntPtr buffer, UInt32 bytesRead, bool moreFollows) { GCHandle handle = GCHandle.FromIntPtr(parameter); - Tuple callbackInfo = handle.Target as Tuple; + Tuple callbackInfo = handle.Target as Tuple; GetFileAsyncHandler handler = callbackInfo.Item1; object handlerParameter = callbackInfo.Item2; @@ -1575,7 +1608,7 @@ namespace IEC61850 { bytes = new byte[bytesRead]; - Marshal.Copy(buffer, bytes, 0, (int) bytesRead); + Marshal.Copy(buffer, bytes, 0, (int)bytesRead); } return handler(invokeId, handlerParameter, clientError, originalInvokeId, bytes, moreFollows); @@ -1617,21 +1650,21 @@ namespace IEC61850 - /// - /// Abort (close) the connection. - /// - /// This function will send an abort request to the server. This will immediately interrupt the - /// connection. - /// This exception is thrown if there is a connection or service error - public void Abort () - { - int error; + /// + /// Abort (close) the connection. + /// + /// This function will send an abort request to the server. This will immediately interrupt the + /// connection. + /// This exception is thrown if there is a connection or service error + public void Abort() + { + int error; - IedConnection_abort (connection, out error); + IedConnection_abort(connection, out error); - if (error != 0) - throw new IedConnectionException ("Abort failed", error); - } + if (error != 0) + throw new IedConnectionException("Abort failed", error); + } /// /// Abort (close) the connection - asynchronous version @@ -1639,31 +1672,31 @@ namespace IEC61850 /// This function will send an abort request to the server. This will immediately interrupt the /// connection. /// This exception is thrown if there is a connection or service error - public void AbortAsync () + public void AbortAsync() { int error; - IedConnection_abortAsync (connection, out error); + IedConnection_abortAsync(connection, out error); if (error != 0) - throw new IedConnectionException ("Abort failed", error); + throw new IedConnectionException("Abort failed", error); } - /// - /// Release (close) the connection. - /// - /// This function will send an release request to the server. The function will block until the - /// connection is released or an error occured. - /// This exception is thrown if there is a connection or service error - public void Release () - { - int error; + /// + /// Release (close) the connection. + /// + /// This function will send an release request to the server. The function will block until the + /// connection is released or an error occured. + /// This exception is thrown if there is a connection or service error + public void Release() + { + int error; - IedConnection_release(connection, out error); + IedConnection_release(connection, out error); - if (error != 0) - throw new IedConnectionException ("Release failed", error); - } + if (error != 0) + throw new IedConnectionException("Release failed", error); + } /// /// Release (close) the connection - asynchronous version @@ -1671,52 +1704,52 @@ namespace IEC61850 /// This function will send an release request to the server. The function will block until the /// connection is released or an error occured. /// This exception is thrown if there is a connection or service error - public void ReleaseAsync () + public void ReleaseAsync() { int error; IedConnection_releaseAsync(connection, out error); if (error != 0) - throw new IedConnectionException ("Release failed", error); - } - - /// - /// Immediately close the connection. - /// - /// This function will close the connnection to the server by closing the TCP connection. - /// The client will not send an abort or release request as required by the specification! - /// This exception is thrown if there is a connection or service error - public void Close () - { - IedConnection_close(connection); - } - - private void MyConnectionClosedHandler (IntPtr parameter, IntPtr self) - { - if (userProvidedConnectionClosedHandler != null) - userProvidedConnectionClosedHandler (this); - } - - /// - /// Install a callback handler that will be invoked if the connection is closed. - /// - /// The handler is called when the connection is closed no matter if the connection was closed - /// by the client or by the server. Any new call to this function will replace the callback handler installed - /// by a prior function call. - /// The user provided callback handler - /// This exception is thrown if there is a connection or service error + throw new IedConnectionException("Release failed", error); + } + + /// + /// Immediately close the connection. + /// + /// This function will close the connnection to the server by closing the TCP connection. + /// The client will not send an abort or release request as required by the specification! + /// This exception is thrown if there is a connection or service error + public void Close() + { + IedConnection_close(connection); + } + + private void MyConnectionClosedHandler(IntPtr parameter, IntPtr self) + { + if (userProvidedConnectionClosedHandler != null) + userProvidedConnectionClosedHandler(this); + } + + /// + /// Install a callback handler that will be invoked if the connection is closed. + /// + /// The handler is called when the connection is closed no matter if the connection was closed + /// by the client or by the server. Any new call to this function will replace the callback handler installed + /// by a prior function call. + /// The user provided callback handler + /// This exception is thrown if there is a connection or service error [Obsolete("ConnectionClosedHandler is deprecated, please use ConnectionEventHandler instead")] - public void InstallConnectionClosedHandler (ConnectionClosedHandler handler) - { + public void InstallConnectionClosedHandler(ConnectionClosedHandler handler) + { if (connectionClosedHandler == null) { connectionClosedHandler = new InternalConnectionClosedHandler(MyConnectionClosedHandler); - IedConnection_installConnectionClosedHandler (connection, connectionClosedHandler, connection); + IedConnection_installConnectionClosedHandler(connection, connectionClosedHandler, connection); } - userProvidedConnectionClosedHandler = handler; - } + userProvidedConnectionClosedHandler = handler; + } private void MyStateChangedHandler(IntPtr parameter, IntPtr IedConnection, int newState) { @@ -1728,7 +1761,7 @@ namespace IEC61850 /// Sets the handler for StateChanged events /// /// The state changed event handler - public void InstallStateChangedHandler (StateChangedHandler handler) + public void InstallStateChangedHandler(StateChangedHandler handler) { stateChangedHandler = handler; @@ -1758,139 +1791,143 @@ namespace IEC61850 /// received values. /// The object reference of the data set /// This exception is thrown if there is a connection or service error - public DataSet GetDataSetValues (string dataSetReference) + public DataSet GetDataSetValues(string dataSetReference) { return ReadDataSetValues(dataSetReference, null); } - /// - /// Read the values of a data set (GetDataSetValues service). - /// - /// This function will invoke a readDataSetValues service and return a new DataSet value containing the - /// received values. If an existing instance of DataSet is provided to the function the existing instance will be - /// updated by the new values. - /// The object reference of the data set - /// The object reference of an existing data set instance or null - /// a DataSet instance containing the received values - /// This exception is thrown if there is a connection or service error - public DataSet ReadDataSetValues (string dataSetReference, DataSet dataSet) - { - IntPtr nativeClientDataSet = IntPtr.Zero; - - if (dataSet != null) - nativeClientDataSet = dataSet.getNativeInstance (); + /// + /// Read the values of a data set (GetDataSetValues service). + /// + /// This function will invoke a readDataSetValues service and return a new DataSet value containing the + /// received values. If an existing instance of DataSet is provided to the function the existing instance will be + /// updated by the new values. + /// The object reference of the data set + /// The object reference of an existing data set instance or null + /// a DataSet instance containing the received values + /// This exception is thrown if there is a connection or service error + public DataSet ReadDataSetValues(string dataSetReference, DataSet dataSet) + { + IntPtr nativeClientDataSet = IntPtr.Zero; + + if (dataSet != null) + nativeClientDataSet = dataSet.getNativeInstance(); - int error; + int error; - nativeClientDataSet = IedConnection_readDataSetValues (connection, out error, dataSetReference, nativeClientDataSet); + nativeClientDataSet = IedConnection_readDataSetValues(connection, out error, dataSetReference, nativeClientDataSet); - if (error != 0) - throw new IedConnectionException ("Reading data set failed", error); + if (error != 0) + throw new IedConnectionException("Reading data set failed", error); - if (dataSet == null) - dataSet = new DataSet (nativeClientDataSet); + if (dataSet == null) + dataSet = new DataSet(nativeClientDataSet); - return dataSet; - } + return dataSet; + } - /// - /// Writes the values of a data set (SetDataSetValues service). - /// - /// The list of access results - /// The object reference of the data set - /// The new values for the data set members. The values have to be of the same number and type as the data set members - public List WriteDataSetValues(string dataSetReference, List values) - { - int error; - IntPtr accessResults = IntPtr.Zero; + /// + /// Writes the values of a data set (SetDataSetValues service). + /// + /// The list of access results + /// The object reference of the data set + /// The new values for the data set members. The values have to be of the same number and type as the data set members + public List WriteDataSetValues(string dataSetReference, List values) + { + int error; + IntPtr accessResults = IntPtr.Zero; - IntPtr valueList = LinkedList_create (); + IntPtr valueList = LinkedList_create(); - foreach (MmsValue mmsValue in values) { - LinkedList_add (valueList, mmsValue.valueReference); - } + foreach (MmsValue mmsValue in values) + { + LinkedList_add(valueList, mmsValue.valueReference); + } - IedConnection_writeDataSetValues (connection, out error, dataSetReference, valueList, out accessResults); + IedConnection_writeDataSetValues(connection, out error, dataSetReference, valueList, out accessResults); - LinkedList_destroyStatic (valueList); + LinkedList_destroyStatic(valueList); - /* handle access results */ + /* handle access results */ - List accessResultList = null; + List accessResultList = null; - if (accessResults != IntPtr.Zero) { + if (accessResults != IntPtr.Zero) + { - IntPtr element = LinkedList_getNext (accessResults); + IntPtr element = LinkedList_getNext(accessResults); - while (element != IntPtr.Zero) { - IntPtr elementData = LinkedList_getData (element); + while (element != IntPtr.Zero) + { + IntPtr elementData = LinkedList_getData(element); - MmsValue accessResultValue = new MmsValue (elementData, true); + MmsValue accessResultValue = new MmsValue(elementData, true); - MmsDataAccessError dataAccessError = accessResultValue.GetDataAccessError (); + MmsDataAccessError dataAccessError = accessResultValue.GetDataAccessError(); - accessResultList.Add (dataAccessError); + accessResultList.Add(dataAccessError); - element = LinkedList_getNext (element); - } + element = LinkedList_getNext(element); + } - LinkedList_destroyStatic (accessResults); - } + LinkedList_destroyStatic(accessResults); + } - if (error != 0) - throw new IedConnectionException ("Writing data set failed", error); + if (error != 0) + throw new IedConnectionException("Writing data set failed", error); - return accessResultList; - } + return accessResultList; + } - /// - /// Create a new data set. - /// - /// This function creates a new data set at the server. The data set consists of the members defined - /// by the list of object references provided. - /// The object reference of the data set - /// A list of object references of the data set elements - /// This exception is thrown if there is a connection or service error - public void CreateDataSet (string dataSetReference, List dataSetElements) - { - IntPtr linkedList = LinkedList_create (); + /// + /// Create a new data set. + /// + /// This function creates a new data set at the server. The data set consists of the members defined + /// by the list of object references provided. + /// The object reference of the data set + /// A list of object references of the data set elements + /// This exception is thrown if there is a connection or service error + public void CreateDataSet(string dataSetReference, List dataSetElements) + { + IntPtr linkedList = LinkedList_create(); - foreach (string dataSetElement in dataSetElements) { - IntPtr handle = System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi (dataSetElement); + foreach (string dataSetElement in dataSetElements) + { + IntPtr handle = System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(dataSetElement); - LinkedList_add (linkedList, handle); - } + LinkedList_add(linkedList, handle); + } - int error; + int error; - IedConnection_createDataSet (connection, out error, dataSetReference, linkedList); + IedConnection_createDataSet(connection, out error, dataSetReference, linkedList); - LinkedList_destroyDeep(linkedList, new LinkedListValueDeleteFunction(FreeHGlobaleDeleteFunction)); + LinkedList_destroyDeep(linkedList, new LinkedListValueDeleteFunction(FreeHGlobaleDeleteFunction)); - if (error != 0) - throw new IedConnectionException ("Failed to create data set", error); + if (error != 0) + throw new IedConnectionException("Failed to create data set", error); - } + } - /// - /// Delete a data set. - /// - /// This function will delete a data set at the server. This function may fail if the data set is not - /// deletable. - /// The object reference of the data set - /// true if data set has been deleted, false otherwise - /// This exception is thrown if there is a connection or service error - public bool DeleteDataSet (string dataSetReference) - { - int error; + /// + /// Delete a data set. + /// + /// This function will delete a data set at the server. This function may fail if the data set is not + /// deletable. + /// The object reference of the data set + /// true if data set has been deleted, false otherwise + /// This exception is thrown if there is a connection or service error + public bool DeleteDataSet(string dataSetReference) + { + int error; - bool isDeleted = IedConnection_deleteDataSet (connection, out error, dataSetReference); + bool isDeleted = IedConnection_deleteDataSet(connection, out error, dataSetReference); - if (error != 0) - throw new IedConnectionException ("Failed to delete data set", error); + if (error != 0) + throw new IedConnectionException("Failed to delete data set", error); - return isDeleted; - } + return isDeleted; + } /// /// Get the directory of the data set. @@ -1899,7 +1936,7 @@ namespace IEC61850 /// The object reference of the data set /// the list of object references /// This exception is thrown if there is a connection or service error - public List GetDataSetDirectory(string dataSetReference) + public List GetDataSetDirectory(string dataSetReference) { bool isDeletable; @@ -1913,32 +1950,33 @@ namespace IEC61850 /// The object reference of the data set /// Indication if this data set is permanent or deletable. /// the list of object references - /// This exception is thrown if there is a connection or service error - public List GetDataSetDirectory (string dataSetReference, out bool isDeletable) - { - int error; + /// This exception is thrown if there is a connection or service error + public List GetDataSetDirectory(string dataSetReference, out bool isDeletable) + { + int error; - IntPtr linkedList = IedConnection_getDataSetDirectory (connection, out error, dataSetReference, out isDeletable); + IntPtr linkedList = IedConnection_getDataSetDirectory(connection, out error, dataSetReference, out isDeletable); - if (error != 0) - throw new IedConnectionException ("getDataSetDirectory failed", error); + if (error != 0) + throw new IedConnectionException("getDataSetDirectory failed", error); - IntPtr element = LinkedList_getNext (linkedList); + IntPtr element = LinkedList_getNext(linkedList); - List newList = new List (); + List newList = new List(); - while (element != IntPtr.Zero) { - string dataObject = Marshal.PtrToStringAnsi (LinkedList_getData (element)); + while (element != IntPtr.Zero) + { + string dataObject = Marshal.PtrToStringAnsi(LinkedList_getData(element)); - newList.Add (dataObject); + newList.Add(dataObject); - element = LinkedList_getNext (element); - } + element = LinkedList_getNext(element); + } - LinkedList_destroy (linkedList); + LinkedList_destroy(linkedList); - return newList; - } + return newList; + } /// @@ -1948,13 +1986,13 @@ namespace IEC61850 /// user provided callback parameter /// Error code of response or timeout error in case of a response timeout /// The read result value or null in case of an error - public delegate void ReadValueHandler(UInt32 invokeId, object parameter, IedClientError err, MmsValue value); + public delegate void ReadValueHandler(UInt32 invokeId,object parameter,IedClientError err,MmsValue value); - private void nativeReadObjectHandler (UInt32 invokeId, IntPtr parameter, int err, IntPtr value) + private void nativeReadObjectHandler(UInt32 invokeId, IntPtr parameter, int err, IntPtr value) { GCHandle handle = GCHandle.FromIntPtr(parameter); - Tuple callbackInfo = handle.Target as Tuple; + Tuple callbackInfo = handle.Target as Tuple; ReadValueHandler handler = callbackInfo.Item1; object handlerParameter = callbackInfo.Item2; @@ -1999,11 +2037,11 @@ namespace IEC61850 return invokeId; } - private void nativeGetVariableSpecifcationHandler (UInt32 invokeId, IntPtr parameter, int err, IntPtr spec) + private void nativeGetVariableSpecifcationHandler(UInt32 invokeId, IntPtr parameter, int err, IntPtr spec) { GCHandle handle = GCHandle.FromIntPtr(parameter); - Tuple callbackInfo = handle.Target as Tuple; + Tuple callbackInfo = handle.Target as Tuple; GetVariableSpecifcationHandler handler = callbackInfo.Item1; object handlerParameter = callbackInfo.Item2; @@ -2020,7 +2058,7 @@ namespace IEC61850 handler(invokeId, handlerParameter, clientError, varSpec); } - public delegate void GetVariableSpecifcationHandler(UInt32 invokeId, object parameter, IedClientError err, MmsVariableSpecification spec); + public delegate void GetVariableSpecifcationHandler(UInt32 invokeId,object parameter,IedClientError err,MmsVariableSpecification spec); /// Read the variable specification (type description of a DA or FCDO /// The object reference of a DA or FCDO. @@ -2048,11 +2086,11 @@ namespace IEC61850 return invokeId; } - private void nativeReadDataSetHandler (UInt32 invokeId, IntPtr parameter, int err, IntPtr nativeDataSet) + private void nativeReadDataSetHandler(UInt32 invokeId, IntPtr parameter, int err, IntPtr nativeDataSet) { GCHandle handle = GCHandle.FromIntPtr(parameter); - Tuple callbackInfo = handle.Target as Tuple; + Tuple callbackInfo = handle.Target as Tuple; ReadDataSetHandler handler = callbackInfo.Item1; object handlerParameter = callbackInfo.Item2; @@ -2073,7 +2111,7 @@ namespace IEC61850 } - public delegate void ReadDataSetHandler(UInt32 invokeId, object parameter, IedClientError err, DataSet dataSet); + public delegate void ReadDataSetHandler(UInt32 invokeId,object parameter,IedClientError err,DataSet dataSet); /// /// Read the values of a data set (GetDataSetValues service) - asynchronous version @@ -2118,13 +2156,13 @@ namespace IEC61850 /// The invoke ID of the reqeust triggering this callback /// user provided callback parameter /// Error code of response or timeout error in case of a response timeout - public delegate void WriteValueHandler(UInt32 invokeId, object parameter, IedClientError err); + public delegate void WriteValueHandler(UInt32 invokeId,object parameter,IedClientError err); - private void nativeWriteObjectHandler (UInt32 invokeId, IntPtr parameter, int err) + private void nativeWriteObjectHandler(UInt32 invokeId, IntPtr parameter, int err) { GCHandle handle = GCHandle.FromIntPtr(parameter); - Tuple callbackInfo = handle.Target as Tuple; + Tuple callbackInfo = handle.Target as Tuple; WriteValueHandler handler = callbackInfo.Item1; object handlerParameter = callbackInfo.Item2; @@ -2156,9 +2194,9 @@ namespace IEC61850 return invokeId; } - public delegate void GetNameListHandler(UInt32 invokeId, object parameter, IedClientError err, List nameList, bool moreFollows); + public delegate void GetNameListHandler(UInt32 invokeId,object parameter,IedClientError err,List nameList,bool moreFollows); - private void nativeGetNameListHandler (UInt32 invokeId, IntPtr parameter, int err, IntPtr nameList, [MarshalAs(UnmanagedType.I1)] bool moreFollows) + private void nativeGetNameListHandler(UInt32 invokeId, IntPtr parameter, int err, IntPtr nameList, [MarshalAs(UnmanagedType.I1)] bool moreFollows) { GCHandle handle = GCHandle.FromIntPtr(parameter); @@ -2198,7 +2236,7 @@ namespace IEC61850 } } - + /// /// Gets the server directory (Logical devices or file objects) /// @@ -2276,14 +2314,14 @@ namespace IEC61850 return invokeId; } - public delegate void QueryLogHandler(UInt32 invokeId, object parameter, IedClientError err, List journalEntries, bool moreFollows); + public delegate void QueryLogHandler(UInt32 invokeId,object parameter,IedClientError err,List journalEntries,bool moreFollows); - private void nativeQueryLogHandler (UInt32 invokeId, IntPtr parameter, int err, IntPtr journalEntries, - [MarshalAs(UnmanagedType.I1)] bool moreFollows) + private void nativeQueryLogHandler(UInt32 invokeId, IntPtr parameter, int err, IntPtr journalEntries, + [MarshalAs(UnmanagedType.I1)] bool moreFollows) { GCHandle handle = GCHandle.FromIntPtr(parameter); - Tuple callbackInfo = handle.Target as Tuple; + Tuple callbackInfo = handle.Target as Tuple; QueryLogHandler handler = callbackInfo.Item1; object handlerParameter = callbackInfo.Item2; @@ -2338,10 +2376,10 @@ namespace IEC61850 /// This exception is thrown if there is a connection or service error public UInt32 QueryLogByTimeAsync(string logRef, DateTime startTime, DateTime stopTime, QueryLogHandler handler, object parameter) { - ulong startTimeMs = LibIEC61850.DateTimeToMsTimestamp (startTime); - ulong stopTimeMs = LibIEC61850.DateTimeToMsTimestamp (stopTime); + ulong startTimeMs = LibIEC61850.DateTimeToMsTimestamp(startTime); + ulong stopTimeMs = LibIEC61850.DateTimeToMsTimestamp(stopTime); - return QueryLogByTimeAsync (logRef, startTimeMs, stopTimeMs, handler, parameter); + return QueryLogByTimeAsync(logRef, startTimeMs, stopTimeMs, handler, parameter); } /// @@ -2361,9 +2399,9 @@ namespace IEC61850 GCHandle handle = GCHandle.Alloc(callbackInfo); - MmsValue entryIdValue = new MmsValue (entryID); + MmsValue entryIdValue = new MmsValue(entryID); - UInt32 invokeId = IedConnection_queryLogAfterAsync(connection, out error, logRef, entryIdValue.valueReference, timestamp, nativeQueryLogHandler, GCHandle.ToIntPtr(handle)); + UInt32 invokeId = IedConnection_queryLogAfterAsync(connection, out error, logRef, entryIdValue.valueReference, timestamp, nativeQueryLogHandler, GCHandle.ToIntPtr(handle)); if (error != 0) { @@ -2374,40 +2412,48 @@ namespace IEC61850 return invokeId; } - internal void UninstallReportHandler (string objectReference) - { - if (connection != IntPtr.Zero) { - IedConnection_uninstallReportHandler (connection, objectReference); - } - } - - internal void InstallReportHandler (string objectReference, string reportId, InternalReportHandler internalHandler) - { - if (connection != IntPtr.Zero) { - IedConnection_installReportHandler (connection, objectReference, reportId, internalHandler, IntPtr.Zero); - } - } - - internal void GetRCBValues(out int error, string objectReference, IntPtr updateRcb) - { - if (connection != IntPtr.Zero) { - IedConnection_getRCBValues (connection, out error, objectReference, updateRcb); - } else { - error = 1; /* not connected */ - } - } - - internal void SetRCBValues(out int error, IntPtr rcb, UInt32 parametersMask, bool singleRequest) - { - if (connection != IntPtr.Zero) { - IedConnection_setRCBValues (connection, out error, rcb, parametersMask, singleRequest); - } else { - error = 1; /* not connected */ - } - } - + internal void UninstallReportHandler(string objectReference) + { + if (connection != IntPtr.Zero) + { + IedConnection_uninstallReportHandler(connection, objectReference); + } + } + + internal void InstallReportHandler(string objectReference, string reportId, InternalReportHandler internalHandler) + { + if (connection != IntPtr.Zero) + { + IedConnection_installReportHandler(connection, objectReference, reportId, internalHandler, IntPtr.Zero); + } + } + + internal void GetRCBValues(out int error, string objectReference, IntPtr updateRcb) + { + if (connection != IntPtr.Zero) + { + IedConnection_getRCBValues(connection, out error, objectReference, updateRcb); + } + else + { + error = 1; /* not connected */ + } + } + + internal void SetRCBValues(out int error, IntPtr rcb, UInt32 parametersMask, bool singleRequest) + { + if (connection != IntPtr.Zero) + { + IedConnection_setRCBValues(connection, out error, rcb, parametersMask, singleRequest); + } + else + { + error = 1; /* not connected */ + } + } + - private void nativeGetRCBValuesHandler (UInt32 invokeId, IntPtr parameter, int err, IntPtr rcbPtr) + private void nativeGetRCBValuesHandler(UInt32 invokeId, IntPtr parameter, int err, IntPtr rcbPtr) { GCHandle handle = GCHandle.FromIntPtr(parameter); @@ -2443,7 +2489,7 @@ namespace IEC61850 return invokeId; } - private void nativeSetRcbValuesHandler (UInt32 invokeId, IntPtr parameter, int err) + private void nativeSetRcbValuesHandler(UInt32 invokeId, IntPtr parameter, int err) { GCHandle handle = GCHandle.FromIntPtr(parameter); @@ -2479,35 +2525,37 @@ namespace IEC61850 return invokeId; } - } + } - public class IedConnectionException : Exception - { + public class IedConnectionException : Exception + { - private int errorCode; + private int errorCode; - public IedConnectionException (string message, int errorCode) : base(message) - { - this.errorCode = errorCode; - } + public IedConnectionException(string message, int errorCode) + : base(message) + { + this.errorCode = errorCode; + } - public IedConnectionException (string message) : base(message) - { - this.errorCode = 0; - } + public IedConnectionException(string message) + : base(message) + { + this.errorCode = 0; + } - public int GetErrorCode () - { - return this.errorCode; - } + public int GetErrorCode() + { + return this.errorCode; + } - public IedClientError GetIedClientError () - { - return (IedClientError)this.errorCode; - } - } + public IedClientError GetIedClientError() + { + return (IedClientError)this.errorCode; + } + } - public class FileDirectoryEntry + public class FileDirectoryEntry { [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] private static extern IntPtr FileDirectoryEntry_getFileName(IntPtr self); @@ -2522,24 +2570,24 @@ namespace IEC61850 private UInt32 fileSize; private UInt64 lastModified; - internal FileDirectoryEntry(IntPtr nativeFileDirectoryEntry) + internal FileDirectoryEntry(IntPtr nativeFileDirectoryEntry) { fileName = Marshal.PtrToStringAnsi(FileDirectoryEntry_getFileName(nativeFileDirectoryEntry)); fileSize = FileDirectoryEntry_getFileSize(nativeFileDirectoryEntry); lastModified = FileDirectoryEntry_getLastModified(nativeFileDirectoryEntry); } - public string GetFileName() + public string GetFileName() { return fileName; } - public UInt32 GetFileSize() + public UInt32 GetFileSize() { return fileSize; } - public UInt64 GetLastModified() + public UInt64 GetLastModified() { return lastModified; } @@ -2574,60 +2622,60 @@ namespace IEC61850 /// /// Error codes for client side functions /// - public enum IedClientError - { - /* general errors */ + public enum IedClientError + { + /* general errors */ - /** No error occurred - service request has been successful */ - IED_ERROR_OK = 0, + /** No error occurred - service request has been successful */ + IED_ERROR_OK = 0, - /** The service request can not be executed because the client is not yet connected */ - IED_ERROR_NOT_CONNECTED = 1, + /** The service request can not be executed because the client is not yet connected */ + IED_ERROR_NOT_CONNECTED = 1, - /** Connect service not execute because the client is already connected */ - IED_ERROR_ALREADY_CONNECTED = 2, + /** Connect service not execute because the client is already connected */ + IED_ERROR_ALREADY_CONNECTED = 2, - /** The service request can not be executed caused by a loss of connection */ - IED_ERROR_CONNECTION_LOST = 3, + /** The service request can not be executed caused by a loss of connection */ + IED_ERROR_CONNECTION_LOST = 3, - /** The service or some given parameters are not supported by the client stack or by the server */ - IED_ERROR_SERVICE_NOT_SUPPORTED = 4, + /** The service or some given parameters are not supported by the client stack or by the server */ + IED_ERROR_SERVICE_NOT_SUPPORTED = 4, - /** Connection rejected by server */ - IED_ERROR_CONNECTION_REJECTED = 5, + /** Connection rejected by server */ + IED_ERROR_CONNECTION_REJECTED = 5, - /* client side errors */ + /* client side errors */ - /** API function has been called with an invalid argument */ - IED_ERROR_USER_PROVIDED_INVALID_ARGUMENT = 10, + /** API function has been called with an invalid argument */ + IED_ERROR_USER_PROVIDED_INVALID_ARGUMENT = 10, - IED_ERROR_ENABLE_REPORT_FAILED_DATASET_MISMATCH = 11, + IED_ERROR_ENABLE_REPORT_FAILED_DATASET_MISMATCH = 11, - /** The object provided object reference is invalid (there is a syntactical error). */ - IED_ERROR_OBJECT_REFERENCE_INVALID = 12, + /** The object provided object reference is invalid (there is a syntactical error). */ + IED_ERROR_OBJECT_REFERENCE_INVALID = 12, - /** Received object is of unexpected type */ - IED_ERROR_UNEXPECTED_VALUE_RECEIVED = 13, + /** Received object is of unexpected type */ + IED_ERROR_UNEXPECTED_VALUE_RECEIVED = 13, - /* service error - error reported by server */ + /* service error - error reported by server */ - /** The communication to the server failed with a timeout */ - IED_ERROR_TIMEOUT = 20, + /** The communication to the server failed with a timeout */ + IED_ERROR_TIMEOUT = 20, - /** The server rejected the access to the requested object/service due to access control */ - IED_ERROR_ACCESS_DENIED = 21, + /** The server rejected the access to the requested object/service due to access control */ + IED_ERROR_ACCESS_DENIED = 21, - /** The server reported that the requested object does not exist */ - IED_ERROR_OBJECT_DOES_NOT_EXIST = 22, + /** The server reported that the requested object does not exist */ + IED_ERROR_OBJECT_DOES_NOT_EXIST = 22, - /** The server reported that the requested object already exists */ - IED_ERROR_OBJECT_EXISTS = 23, + /** The server reported that the requested object already exists */ + IED_ERROR_OBJECT_EXISTS = 23, - /** The server does not support the requested access method */ - IED_ERROR_OBJECT_ACCESS_UNSUPPORTED = 24, + /** The server does not support the requested access method */ + IED_ERROR_OBJECT_ACCESS_UNSUPPORTED = 24, - /** The server expected an object of another type */ - IED_ERROR_TYPE_INCONSISTENT = 25, + /** The server expected an object of another type */ + IED_ERROR_TYPE_INCONSISTENT = 25, /** The object or service is temporarily unavailable */ IED_ERROR_TEMPORARILY_UNAVAILABLE = 26, @@ -2653,8 +2701,14 @@ namespace IEC61850 /** The object is invalidated (returned by server) */ IED_ERROR_OBJECT_INVALIDATED = 33, - /* unknown error */ - IED_ERROR_UNKNOWN = 99 - } - } + /** Received an invalid response message from the server */ + IED_ERROR_MALFORMED_MESSAGE = 34, + + /** Service not implemented */ + IED_ERROR_SERVICE_NOT_IMPLEMENTED = 98, + + /* unknown error */ + IED_ERROR_UNKNOWN = 99 + } + } } diff --git a/src/iec61850/client/client_report.c b/src/iec61850/client/client_report.c index 26c670c4..41683a41 100644 --- a/src/iec61850/client/client_report.c +++ b/src/iec61850/client/client_report.c @@ -3,7 +3,7 @@ * * Client implementation for IEC 61850 reporting. * - * Copyright 2013-2018 Michael Zillgith + * Copyright 2013-2019 Michael Zillgith * * This file is part of libIEC61850. * @@ -43,6 +43,8 @@ struct sClientReport char* dataSetName; int dataSetNameSize; /* size of the dataSetName buffer */ + int dataSetSize; + MmsValue* entryId; MmsValue* dataReferences; MmsValue* dataSetValues; @@ -93,6 +95,8 @@ ClientReport_create() { ClientReport self = (ClientReport) GLOBAL_CALLOC(1, sizeof(struct sClientReport)); + self->dataSetSize = -1; + return self; } @@ -607,6 +611,18 @@ iedConnection_handleReport(IedConnection self, MmsValue* value) int dataSetSize = MmsValue_getBitStringSize(inclusion); + if (matchingReport->dataSetSize == -1) { + matchingReport->dataSetSize = dataSetSize; + } + else { + if (dataSetSize != matchingReport->dataSetSize) { + if (DEBUG_IED_CLIENT) + printf("IED_CLIENT: received malformed report (inclusion has no plausible size)\n"); + + goto exit_function; + } + } + int includedElements = MmsValue_getNumberOfSetBits(inclusion); if (DEBUG_IED_CLIENT) @@ -692,7 +708,7 @@ iedConnection_handleReport(IedConnection self, MmsValue* value) MmsValue_update(dataSetElement, newElementValue); if (DEBUG_IED_CLIENT) - printf("IED_CLIENT: update element value type: %i\n", MmsValue_getType(newElementValue)); + printf("IED_CLIENT: update element value type: %i\n", MmsValue_getType(newElementValue)); valueIndex++; diff --git a/src/iec61850/client/ied_connection.c b/src/iec61850/client/ied_connection.c index 9299b42a..8b30c753 100644 --- a/src/iec61850/client/ied_connection.c +++ b/src/iec61850/client/ied_connection.c @@ -1,7 +1,7 @@ /* * ied_connection.c * - * Copyright 2013-2018 Michael Zillgith + * Copyright 2013-2019 Michael Zillgith * * This file is part of libIEC61850. * @@ -96,6 +96,9 @@ iedConnection_mapMmsErrorToIedError(MmsError mmsError) case MMS_ERROR_ACCESS_OBJECT_VALUE_INVALID: return IED_ERROR_OBJECT_VALUE_INVALID; + case MMS_ERROR_PARSING_RESPONSE: + return IED_ERROR_MALFORMED_MESSAGE; + default: return IED_ERROR_UNKNOWN; } @@ -484,42 +487,48 @@ informationReportHandler(void* parameter, char* domainName, { IedConnection self = (IedConnection) parameter; - if (DEBUG_IED_CLIENT) - printf("DEBUG_IED_CLIENT: received information report for %s\n", variableListName); + if (value) { + if (DEBUG_IED_CLIENT) + printf("IED_CLIENT: received information report for %s\n", variableListName); - if (domainName == NULL) { + if (domainName == NULL) { - if (isVariableListName) { - iedConnection_handleReport(self, value); - } - else { - if (strcmp(variableListName, "LastApplError") == 0) - handleLastApplErrorMessage(self, value); + if (isVariableListName) { + iedConnection_handleReport(self, value); + } else { - if (DEBUG_IED_CLIENT) - printf("IED_CLIENT: Received unknown variable list report for list: %s\n", variableListName); + if (strcmp(variableListName, "LastApplError") == 0) + handleLastApplErrorMessage(self, value); + else { + if (DEBUG_IED_CLIENT) + printf("IED_CLIENT: Received unknown variable list report for list: %s\n", variableListName); + } } } - } - else { - if (DEBUG_IED_CLIENT) - printf("IED_CLIENT: RCVD CommandTermination for %s/%s\n", domainName, variableListName); + else { + if (DEBUG_IED_CLIENT) + printf("IED_CLIENT: RCVD CommandTermination for %s/%s\n", domainName, variableListName); - LinkedList control = LinkedList_getNext(self->clientControls); + LinkedList control = LinkedList_getNext(self->clientControls); - while (control != NULL) { - ControlObjectClient object = (ControlObjectClient) control->data; + while (control != NULL) { + ControlObjectClient object = (ControlObjectClient) control->data; - const char* objectRef = ControlObjectClient_getObjectReference(object); + const char* objectRef = ControlObjectClient_getObjectReference(object); - if (doesReportMatchControlObject(domainName, variableListName, objectRef)) - controlObjectClient_invokeCommandTerminationHandler(object); + if (doesReportMatchControlObject(domainName, variableListName, objectRef)) + controlObjectClient_invokeCommandTerminationHandler(object); - control = LinkedList_getNext(control); + control = LinkedList_getNext(control); + } } - } - MmsValue_delete(value); + MmsValue_delete(value); + } + else { + if (DEBUG_IED_CLIENT) + printf("IED_CLIENT: report for %s/%s: value invalid\n", domainName, variableListName); + } } static void diff --git a/src/iec61850/inc/iec61850_client.h b/src/iec61850/inc/iec61850_client.h index 2a673439..de29ff9c 100644 --- a/src/iec61850/inc/iec61850_client.h +++ b/src/iec61850/inc/iec61850_client.h @@ -1,7 +1,7 @@ /* * iec61850_client.h * - * Copyright 2013-2018 Michael Zillgith + * Copyright 2013-2019 Michael Zillgith * * This file is part of libIEC61850. * @@ -159,6 +159,9 @@ typedef enum { /** The object is invalidated (returned by server) */ IED_ERROR_OBJECT_INVALIDATED = 33, + /** Received an invalid response message from the server */ + IED_ERROR_MALFORMED_MESSAGE = 34, + /** Service not implemented */ IED_ERROR_SERVICE_NOT_IMPLEMENTED = 98, diff --git a/src/iec61850/server/mms_mapping/control.c b/src/iec61850/server/mms_mapping/control.c index ec2f3383..9a4548ea 100644 --- a/src/iec61850/server/mms_mapping/control.c +++ b/src/iec61850/server/mms_mapping/control.c @@ -1,7 +1,7 @@ /* * control.c * - * Copyright 2013-2018 Michael Zillgith + * Copyright 2013-2019 Michael Zillgith * * This file is part of libIEC61850. * @@ -316,10 +316,25 @@ ControlObject_create(IedServer iedServer, MmsDomain* domain, char* lnName, char* self->iedServer = iedServer; MmsVariableSpecification* ctlValSpec = MmsVariableSpecification_getChildSpecificationByName(operSpec, "ctlVal", NULL); - self->ctlVal = MmsValue_newDefaultValue(ctlValSpec); + + if (ctlValSpec) { + self->ctlVal = MmsValue_newDefaultValue(ctlValSpec); + } + else { + if (DEBUG_IED_SERVER) + printf("IED_SERVER: control object %s/%s.%s has no ctlVal element!\n", domain->domainName, lnName, name); + } + MmsVariableSpecification* originSpec = MmsVariableSpecification_getChildSpecificationByName(operSpec, "origin", NULL); - self->origin = MmsValue_newDefaultValue(originSpec); + + if (originSpec) { + self->origin = MmsValue_newDefaultValue(originSpec); + } + else { + if (DEBUG_IED_SERVER) + printf("IED_SERVER: control object %s/%s.%s has no origin element!\n", domain->domainName, lnName, name); + } self->ctlNum = MmsValue_newUnsigned(8); diff --git a/src/mms/iso_mms/client/mms_client_connection.c b/src/mms/iso_mms/client/mms_client_connection.c index f27a55a1..7f4bac36 100644 --- a/src/mms/iso_mms/client/mms_client_connection.c +++ b/src/mms/iso_mms/client/mms_client_connection.c @@ -1,7 +1,7 @@ /* * mms_client_connection.c * - * Copyright 2013-2018 Michael Zillgith + * Copyright 2013-2019 Michael Zillgith * * This file is part of libIEC61850. * @@ -657,7 +657,10 @@ handleAsyncResponse(MmsConnection self, ByteBuffer* response, uint32_t bufPos, M if (response) { MmsValue* value = mmsClient_parseReadResponse(response, NULL, false); - handler(outstandingCall->invokeId, outstandingCall->userParameter, MMS_ERROR_NONE, value); + if (value == NULL) + err = MMS_ERROR_PARSING_RESPONSE; + + handler(outstandingCall->invokeId, outstandingCall->userParameter, err, value); } } @@ -673,7 +676,10 @@ handleAsyncResponse(MmsConnection self, ByteBuffer* response, uint32_t bufPos, M if (response) { MmsValue* value = mmsClient_parseReadResponse(response, NULL, true); - handler(outstandingCall->invokeId, outstandingCall->userParameter, MMS_ERROR_NONE, value); + if (value == NULL) + err = MMS_ERROR_PARSING_RESPONSE; + + handler(outstandingCall->invokeId, outstandingCall->userParameter, err, value); } } @@ -726,7 +732,7 @@ handleAsyncResponse(MmsConnection self, ByteBuffer* response, uint32_t bufPos, M LinkedList accessSpec = mmsClient_parseGetNamedVariableListAttributesResponse(response, &deletable); - if (accessSpec == false) + if (accessSpec == NULL) err = MMS_ERROR_PARSING_RESPONSE; handler(outstandingCall->invokeId, outstandingCall->userParameter, err, accessSpec, deletable); @@ -779,6 +785,9 @@ handleAsyncResponse(MmsConnection self, ByteBuffer* response, uint32_t bufPos, M else { MmsVariableSpecification* typeSpec = mmsClient_parseGetVariableAccessAttributesResponse(response, NULL); + if (typeSpec == NULL) + err = MMS_ERROR_PARSING_RESPONSE; + handler(outstandingCall->invokeId, outstandingCall->userParameter, err, typeSpec); } } diff --git a/src/mms/iso_mms/client/mms_client_get_var_access.c b/src/mms/iso_mms/client/mms_client_get_var_access.c index 68d6449d..8c0951e5 100644 --- a/src/mms/iso_mms/client/mms_client_get_var_access.c +++ b/src/mms/iso_mms/client/mms_client_get_var_access.c @@ -138,24 +138,25 @@ mmsClient_parseGetVariableAccessAttributesResponse(ByteBuffer* message, uint32_t asn_dec_rval_t rval = ber_decode(NULL, &asn_DEF_MmsPdu, (void**) &mmsPdu, ByteBuffer_getBuffer(message), ByteBuffer_getSize(message)); - if (rval.code != RC_OK) - return NULL; + if (rval.code == RC_OK) { - if (mmsPdu->present == MmsPdu_PR_confirmedResponsePdu) { + if (mmsPdu->present == MmsPdu_PR_confirmedResponsePdu) { - if (invokeId != NULL) - *invokeId = mmsClient_getInvokeId(&mmsPdu->choice.confirmedResponsePdu); + if (invokeId != NULL) + *invokeId = mmsClient_getInvokeId(&mmsPdu->choice.confirmedResponsePdu); - if (mmsPdu->choice.confirmedResponsePdu.confirmedServiceResponse.present == - ConfirmedServiceResponse_PR_getVariableAccessAttributes) - { - GetVariableAccessAttributesResponse_t* response; + if (mmsPdu->choice.confirmedResponsePdu.confirmedServiceResponse.present == + ConfirmedServiceResponse_PR_getVariableAccessAttributes) + { + GetVariableAccessAttributesResponse_t* response; - response = &(mmsPdu->choice.confirmedResponsePdu.confirmedServiceResponse.choice.getVariableAccessAttributes); - TypeSpecification_t* asnTypeSpec = &response->typeSpecification; + response = &(mmsPdu->choice.confirmedResponsePdu.confirmedServiceResponse.choice.getVariableAccessAttributes); + TypeSpecification_t* asnTypeSpec = &response->typeSpecification; - typeSpec = createTypeSpecification(asnTypeSpec); + typeSpec = createTypeSpecification(asnTypeSpec); + } } + } asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); diff --git a/src/mms/iso_mms/client/mms_client_read.c b/src/mms/iso_mms/client/mms_client_read.c index 4bc82e9e..ceef5885 100644 --- a/src/mms/iso_mms/client/mms_client_read.c +++ b/src/mms/iso_mms/client/mms_client_read.c @@ -1,7 +1,7 @@ /* * mms_client_read.c * - * Copyright 2013-2018 Michael Zillgith + * Copyright 2013-2019 Michael Zillgith * * This file is part of libIEC61850. * @@ -46,11 +46,14 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi int i = 0; for (i = 0; i < elementCount; i++) { + + value = NULL; + AccessResult_PR presentType = accessResultList[i]->present; if (presentType == AccessResult_PR_failure) { if (DEBUG_MMS_CLIENT) - printf("access error!\n"); + printf("MMS CLIENT: received access error!\n"); if (accessResultList[i]->choice.failure.size > 0) { int errorCode = (int) accessResultList[i]->choice.failure.buf[0]; @@ -66,72 +69,138 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi value = MmsValue_newDataAccessError(DATA_ACCESS_ERROR_UNKNOWN); } else if (presentType == AccessResult_PR_array) { - value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); - value->type = MMS_ARRAY; int arrayElementCount = accessResultList[i]->choice.array.list.count; - value->value.structure.size = arrayElementCount; - value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(arrayElementCount, sizeof(MmsValue*)); - - int j; - - for (j = 0; j < arrayElementCount; j++) { - value->value.structure.components[j] = mmsMsg_parseDataElement( - accessResultList[i]->choice.array.list.array[j]); + if (arrayElementCount > 0) { + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + value->type = MMS_ARRAY; + value->value.structure.size = arrayElementCount; + value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(arrayElementCount, sizeof(MmsValue*)); + + int j; + + for (j = 0; j < arrayElementCount; j++) { + value->value.structure.components[j] = mmsMsg_parseDataElement( + accessResultList[i]->choice.array.list.array[j]); + + if (value->value.structure.components[j] == NULL) { + MmsValue_delete(value); + value = NULL; + break; + } + } + } + else { + if (DEBUG_MMS_CLIENT) + printf("MMS CLIENT: error parsing access result (invalid array size)!\n"); } + } else if (presentType == AccessResult_PR_structure) { - value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); - value->type = MMS_STRUCTURE; int componentCount = accessResultList[i]->choice.structure.list.count; - value->value.structure.size = componentCount; - value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(componentCount, sizeof(MmsValue*)); - - int j; - for (j = 0; j < componentCount; j++) { - value->value.structure.components[j] = mmsMsg_parseDataElement( - accessResultList[i]->choice.structure.list.array[j]); + if (componentCount > 0) { + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + value->type = MMS_STRUCTURE; + value->value.structure.size = componentCount; + value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(componentCount, sizeof(MmsValue*)); + + int j; + for (j = 0; j < componentCount; j++) { + value->value.structure.components[j] = mmsMsg_parseDataElement( + accessResultList[i]->choice.structure.list.array[j]); + + if (value->value.structure.components[j] == NULL) { + MmsValue_delete(value); + value = NULL; + break; + } + } + } + else { + if (DEBUG_MMS_CLIENT) + printf("MMS CLIENT: error parsing access result (invalid structure size)!\n"); } + } else if (presentType == AccessResult_PR_bitstring) { - value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); - value->type = MMS_BIT_STRING; + int size = accessResultList[i]->choice.bitstring.size; - value->value.bitString.size = (size * 8) - - accessResultList[i]->choice.bitstring.bits_unused; + if (size > 0) { + + int maxSize = (size * 8); + int bitSize = maxSize - accessResultList[i]->choice.bitstring.bits_unused; + + if ((bitSize > 0) && (maxSize >= bitSize)) { + + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + value->type = MMS_BIT_STRING; - value->value.bitString.buf = (uint8_t*) GLOBAL_MALLOC(size); - memcpy(value->value.bitString.buf, - accessResultList[i]->choice.bitstring.buf, size); + + value->value.bitString.size = (size * 8) + - accessResultList[i]->choice.bitstring.bits_unused; + + value->value.bitString.buf = (uint8_t*) GLOBAL_MALLOC(size); + memcpy(value->value.bitString.buf, + accessResultList[i]->choice.bitstring.buf, size); + } + else { + if (DEBUG_MMS_CLIENT) + printf("MMS CLIENT: error parsing access result (bit string padding problem)!\n"); + } + } + else { + if (DEBUG_MMS_CLIENT) + printf("MMS CLIENT: error parsing access result (bit string size 0 or negative)!\n"); + } } else if (presentType == AccessResult_PR_integer) { - Asn1PrimitiveValue* berInteger = - BerInteger_createFromBuffer(accessResultList[i]->choice.integer.buf, - accessResultList[i]->choice.integer.size); - value = MmsValue_newIntegerFromBerInteger(berInteger); + int size = accessResultList[i]->choice.integer.size; + + if (size > 0) { + Asn1PrimitiveValue* berInteger = + BerInteger_createFromBuffer(accessResultList[i]->choice.integer.buf, size); + + value = MmsValue_newIntegerFromBerInteger(berInteger); + } + else { + if (DEBUG_MMS_CLIENT) + printf("MMS CLIENT: error parsing access result (invalid integer size)!\n"); + } } else if (presentType == AccessResult_PR_unsigned) { - Asn1PrimitiveValue* berInteger = - BerInteger_createFromBuffer(accessResultList[i]->choice.Unsigned.buf, - accessResultList[i]->choice.Unsigned.size); - value = MmsValue_newUnsignedFromBerInteger(berInteger); + int size = accessResultList[i]->choice.Unsigned.size; + + if (size > 0) { + Asn1PrimitiveValue* berInteger = + BerInteger_createFromBuffer(accessResultList[i]->choice.Unsigned.buf, + accessResultList[i]->choice.Unsigned.size); + + value = MmsValue_newUnsignedFromBerInteger(berInteger); + } + else { + if (DEBUG_MMS_CLIENT) + printf("MMS CLIENT: error parsing access result (invalid unsigned size)!\n"); + } + } else if (presentType == AccessResult_PR_floatingpoint) { - int size = accessResultList[i]->choice.floatingpoint.size; - value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); - value->type = MMS_FLOAT; + int size = accessResultList[i]->choice.floatingpoint.size; if (size == 5) { /* FLOAT32 */ + + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + value->type = MMS_FLOAT; + value->value.floatingPoint.formatWidth = 32; value->value.floatingPoint.exponentWidth = accessResultList[i]->choice.floatingpoint.buf[0]; @@ -146,8 +215,11 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi #endif } + else if (size == 9) { /* FLOAT64 */ + + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + value->type = MMS_FLOAT; - if (size == 9) { /* FLOAT64 */ value->value.floatingPoint.formatWidth = 64; value->value.floatingPoint.exponentWidth = accessResultList[i]->choice.floatingpoint.buf[0]; @@ -161,46 +233,70 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi memcpy(value->value.floatingPoint.buf, floatBuf, 8); #endif } + else { + if (DEBUG_MMS_CLIENT) + printf("MMS CLIENT: error parsing float (size must be 5 or 9, is %i)\n", size); + } } else if (presentType == AccessResult_PR_visiblestring) { - value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); - - value->type = MMS_VISIBLE_STRING; int strSize = accessResultList[i]->choice.visiblestring.size; - value->value.visibleString.buf = (char*) GLOBAL_MALLOC(strSize + 1); - value->value.visibleString.size = strSize; + if (strSize >= 0) { + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + + value->type = MMS_VISIBLE_STRING; + value->value.visibleString.buf = (char*) GLOBAL_MALLOC(strSize + 1); + value->value.visibleString.size = strSize; - memcpy(value->value.visibleString.buf, - accessResultList[i]->choice.visiblestring.buf, - strSize); + memcpy(value->value.visibleString.buf, + accessResultList[i]->choice.visiblestring.buf, + strSize); + + value->value.visibleString.buf[strSize] = 0; + } + else { + if (DEBUG_MMS_CLIENT) + printf("MMS CLIENT: error parsing access result (invalid visible-string size)\n"); + } - value->value.visibleString.buf[strSize] = 0; } else if (presentType == AccessResult_PR_mMSString) { - value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); - - value->type = MMS_STRING; int strSize = accessResultList[i]->choice.mMSString.size; - value->value.visibleString.buf = (char*) GLOBAL_MALLOC(strSize + 1); - value->value.visibleString.size = strSize; + if (strSize >= 0) { + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); - memcpy(value->value.visibleString.buf, - accessResultList[i]->choice.mMSString.buf, strSize); + value->type = MMS_STRING; + value->value.visibleString.buf = (char*) GLOBAL_MALLOC(strSize + 1); + value->value.visibleString.size = strSize; - value->value.visibleString.buf[strSize] = 0; + memcpy(value->value.visibleString.buf, + accessResultList[i]->choice.mMSString.buf, strSize); + value->value.visibleString.buf[strSize] = 0; + } + else { + if (DEBUG_MMS_CLIENT) + printf("MMS CLIENT: error parsing access result (invalid mms-string size)\n"); + } } else if (presentType == AccessResult_PR_utctime) { - value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); - value->type = MMS_UTC_TIME; - memcpy(value->value.utcTime, - accessResultList[i]->choice.utctime.buf, 8); + int size = accessResultList[i]->choice.utctime.size; + + if (size == 8) { + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + + value->type = MMS_UTC_TIME; + memcpy(value->value.utcTime, accessResultList[i]->choice.utctime.buf, 8); + } + else { + if (DEBUG_MMS_CLIENT) + printf("MMS CLIENT: error parsing UTC time (size is %i instead of 8\n", size); + } } else if (presentType == AccessResult_PR_boolean) { value = MmsValue_newBoolean(accessResultList[i]->choice.boolean); @@ -208,25 +304,36 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi else if (presentType == AccessResult_PR_binarytime) { int size = accessResultList[i]->choice.binarytime.size; - if (size <= 6) { + if ((size == 4) || (size == 6)) { value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = MMS_BINARY_TIME; value->value.binaryTime.size = size; memcpy(value->value.binaryTime.buf, accessResultList[i]->choice.binarytime.buf, size); } + else { + if (DEBUG_MMS_CLIENT) + printf("MMS CLIENT: error parsing binary time (size must be 4 or 6, is %i\n", size); + } } else if (presentType == AccessResult_PR_octetstring) { int size = accessResultList[i]->choice.octetstring.size; - value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); - value->type = MMS_OCTET_STRING; - value->value.octetString.maxSize = size; - value->value.octetString.size = size; - value->value.octetString.buf = (uint8_t*) GLOBAL_MALLOC(size); - memcpy(value->value.octetString.buf, accessResultList[i]->choice.octetstring.buf, size); + if (size >= 0) { + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + value->type = MMS_OCTET_STRING; + value->value.octetString.maxSize = size; + value->value.octetString.size = size; + value->value.octetString.buf = (uint8_t*) GLOBAL_MALLOC(size); + memcpy(value->value.octetString.buf, accessResultList[i]->choice.octetstring.buf, size); + } + else { + if (DEBUG_MMS_CLIENT) + printf("MMS CLIENT: error parsing access result (invalid octet-string size)\n"); + } } else { - printf("unknown type %i\n", presentType); + if (DEBUG_MMS_CLIENT) + printf("MMS CLIENT: unknown type %i in access result\n", presentType); value = MmsValue_newDataAccessError(DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID); } @@ -254,21 +361,20 @@ mmsClient_parseReadResponse(ByteBuffer* message, uint32_t* invokeId, bool create asn_dec_rval_t rval = ber_decode(NULL, &asn_DEF_MmsPdu, (void**) &mmsPdu, ByteBuffer_getBuffer(message), ByteBuffer_getSize(message)); - if (rval.code != RC_OK) - return NULL; - - if (mmsPdu->present == MmsPdu_PR_confirmedResponsePdu) { + if (rval.code == RC_OK) { + if (mmsPdu->present == MmsPdu_PR_confirmedResponsePdu) { - if (invokeId != NULL) - *invokeId = mmsClient_getInvokeId(&mmsPdu->choice.confirmedResponsePdu); + if (invokeId != NULL) + *invokeId = mmsClient_getInvokeId(&mmsPdu->choice.confirmedResponsePdu); - if (mmsPdu->choice.confirmedResponsePdu.confirmedServiceResponse.present == ConfirmedServiceResponse_PR_read) { - ReadResponse_t* response = &(mmsPdu->choice.confirmedResponsePdu.confirmedServiceResponse.choice.read); + if (mmsPdu->choice.confirmedResponsePdu.confirmedServiceResponse.present == ConfirmedServiceResponse_PR_read) { + ReadResponse_t* response = &(mmsPdu->choice.confirmedResponsePdu.confirmedServiceResponse.choice.read); - int elementCount = response->listOfAccessResult.list.count; + int elementCount = response->listOfAccessResult.list.count; - valueList = mmsClient_parseListOfAccessResults(response->listOfAccessResult.list.array, - elementCount, createArray); + valueList = mmsClient_parseListOfAccessResults(response->listOfAccessResult.list.array, + elementCount, createArray); + } } } diff --git a/src/mms/iso_mms/common/mms_common_msg.c b/src/mms/iso_mms/common/mms_common_msg.c index 33571c86..bb6a90d9 100644 --- a/src/mms/iso_mms/common/mms_common_msg.c +++ b/src/mms/iso_mms/common/mms_common_msg.c @@ -1,7 +1,7 @@ /* * mms_common_msg.c * - * Copyright 2013-2018 Michael Zillgith + * Copyright 2013-2019 Michael Zillgith * * This file is part of libIEC61850. * @@ -185,113 +185,192 @@ mmsMsg_parseDataElement(Data_t* dataElement) { MmsValue* value = NULL; - if (dataElement->present == Data_PR_structure) { - value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + if (dataElement->present == Data_PR_array) { - int componentCount = dataElement->choice.structure->list.count; + int componentCount = dataElement->choice.array->list.count; + + if (componentCount > 0) { + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); - value->type = MMS_STRUCTURE; - value->value.structure.size = componentCount; - value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(componentCount, sizeof(MmsValue*)); + value->type = MMS_ARRAY; + value->value.structure.size = componentCount; + value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(componentCount, sizeof(MmsValue*)); - int i; + int i; + + for (i = 0; i < componentCount; i++) { + value->value.structure.components[i] = + mmsMsg_parseDataElement(dataElement->choice.array->list.array[i]); - for (i = 0; i < componentCount; i++) { - value->value.structure.components[i] = - mmsMsg_parseDataElement(dataElement->choice.structure->list.array[i]); + if (value->value.structure.components[i] == NULL) { + MmsValue_delete(value); + value = NULL; + break; + } + } + } + else { + if (DEBUG_MMS_CLIENT) + printf("MMS CLIENT: error parsing data element (invalid array size)!\n"); } + } - else if (dataElement->present == Data_PR_array) { - value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + else if (dataElement->present == Data_PR_structure) { - int componentCount = dataElement->choice.array->list.count; + int componentCount = dataElement->choice.structure->list.count; + + if (componentCount > 0) { + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + + value->type = MMS_STRUCTURE; + value->value.structure.size = componentCount; + value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(componentCount, sizeof(MmsValue*)); - value->type = MMS_ARRAY; - value->value.structure.size = componentCount; - value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(componentCount, sizeof(MmsValue*)); + int i; - int i; + for (i = 0; i < componentCount; i++) { + value->value.structure.components[i] = + mmsMsg_parseDataElement(dataElement->choice.structure->list.array[i]); - for (i = 0; i < componentCount; i++) { - value->value.structure.components[i] = - mmsMsg_parseDataElement(dataElement->choice.array->list.array[i]); + if (value->value.structure.components[i] == NULL) { + MmsValue_delete(value); + value = NULL; + break; + } + } + } + else { + if (DEBUG_MMS_CLIENT) + printf("MMS CLIENT: error parsing data element (invalid structure size)!\n"); } } - else { - if (dataElement->present == Data_PR_integer) { + else if (dataElement->present == Data_PR_integer) { + + if (dataElement->choice.integer.size > 0) { Asn1PrimitiveValue* berInteger = BerInteger_createFromBuffer( dataElement->choice.integer.buf, dataElement->choice.integer.size); value = MmsValue_newIntegerFromBerInteger(berInteger); } - else if (dataElement->present == Data_PR_unsigned) { + else { + if (DEBUG_MMS_CLIENT) + printf("MMS CLIENT: error parsing data element (invalid integer size)!\n"); + } + } + else if (dataElement->present == Data_PR_unsigned) { + + if (dataElement->choice.Unsigned.size > 0) { Asn1PrimitiveValue* berInteger = BerInteger_createFromBuffer( dataElement->choice.Unsigned.buf, dataElement->choice.Unsigned.size); value = MmsValue_newUnsignedFromBerInteger(berInteger); } - else if (dataElement->present == Data_PR_visiblestring) { + else { + if (DEBUG_MMS_CLIENT) + printf("MMS CLIENT: error parsing data element (invalid unsigned size)!\n"); + } + } + else if (dataElement->present == Data_PR_visiblestring) { + + if (dataElement->choice.visiblestring.size >= 0) { value = MmsValue_newVisibleStringFromByteArray(dataElement->choice.visiblestring.buf, dataElement->choice.visiblestring.size); } - else if (dataElement->present == Data_PR_mMSString) { + } + else if (dataElement->present == Data_PR_mMSString) { + + if ( dataElement->choice.mMSString.size >= 0) { value = MmsValue_newMmsStringFromByteArray(dataElement->choice.mMSString.buf, dataElement->choice.mMSString.size); } - else if (dataElement->present == Data_PR_bitstring) { - value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + } + else if (dataElement->present == Data_PR_bitstring) { + + int size = dataElement->choice.bitstring.size; + + if (size > 0) { - value->type = MMS_BIT_STRING; - int size = dataElement->choice.bitstring.size; + int maxSize = (size * 8); + int bitSize = maxSize - dataElement->choice.bitstring.bits_unused; - value->value.bitString.size = (size * 8) - - dataElement->choice.bitstring.bits_unused; + if ((bitSize > 0) && (maxSize >= bitSize)) { + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + + value->type = MMS_BIT_STRING; - value->value.bitString.buf = (uint8_t*) GLOBAL_MALLOC(size); - memcpy(value->value.bitString.buf, - dataElement->choice.bitstring.buf, size); + value->value.bitString.size = bitSize; + value->value.bitString.buf = (uint8_t*) GLOBAL_MALLOC(size); + memcpy(value->value.bitString.buf, + dataElement->choice.bitstring.buf, size); + } + else { + if (DEBUG_MMS_CLIENT) + printf("MMS CLIENT: error parsing data element (bit string padding problem)!\n"); + } } - else if (dataElement->present == Data_PR_floatingpoint) { - value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); - int size = dataElement->choice.floatingpoint.size; + else { + if (DEBUG_MMS_CLIENT) + printf("MMS CLIENT: error parsing data element (bit string size 0 or negative)!\n"); + } + } + else if (dataElement->present == Data_PR_floatingpoint) { + + int size = dataElement->choice.floatingpoint.size; + if (size == 5) { /* FLOAT32 */ + + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = MMS_FLOAT; - if (size == 5) { /* FLOAT32 */ - value->value.floatingPoint.formatWidth = 32; - value->value.floatingPoint.exponentWidth = dataElement->choice.floatingpoint.buf[0]; + value->value.floatingPoint.formatWidth = 32; + value->value.floatingPoint.exponentWidth = dataElement->choice.floatingpoint.buf[0]; - uint8_t* floatBuf = (dataElement->choice.floatingpoint.buf + 1); + uint8_t* floatBuf = (dataElement->choice.floatingpoint.buf + 1); - value->value.floatingPoint.buf = (uint8_t*) GLOBAL_MALLOC(4); + value->value.floatingPoint.buf = (uint8_t*) GLOBAL_MALLOC(4); #if (ORDER_LITTLE_ENDIAN == 1) - memcpyReverseByteOrder(value->value.floatingPoint.buf, floatBuf, 4); + memcpyReverseByteOrder(value->value.floatingPoint.buf, floatBuf, 4); #else - memcpy(value->value.floatingPoint.buf, floatBuf, 4); + memcpy(value->value.floatingPoint.buf, floatBuf, 4); #endif - } + } + + if (size == 9) { /* FLOAT64 */ + + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + value->type = MMS_FLOAT; - if (size == 9) { /* FLOAT64 */ - value->value.floatingPoint.formatWidth = 64; - value->value.floatingPoint.exponentWidth = dataElement->choice.floatingpoint.buf[0]; + value->value.floatingPoint.formatWidth = 64; + value->value.floatingPoint.exponentWidth = dataElement->choice.floatingpoint.buf[0]; - uint8_t* floatBuf = (dataElement->choice.floatingpoint.buf + 1); + uint8_t* floatBuf = (dataElement->choice.floatingpoint.buf + 1); - value->value.floatingPoint.buf = (uint8_t*) GLOBAL_MALLOC(8); + value->value.floatingPoint.buf = (uint8_t*) GLOBAL_MALLOC(8); #if (ORDER_LITTLE_ENDIAN == 1) - memcpyReverseByteOrder(value->value.floatingPoint.buf, floatBuf, 8); + memcpyReverseByteOrder(value->value.floatingPoint.buf, floatBuf, 8); #else - memcpy(value->value.floatingPoint.buf, floatBuf, 8); + memcpy(value->value.floatingPoint.buf, floatBuf, 8); #endif - } } - else if (dataElement->present == Data_PR_utctime) { + } + else if (dataElement->present == Data_PR_utctime) { + + int size = dataElement->choice.utctime.size; + + if (size == 8) { value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = MMS_UTC_TIME; memcpy(value->value.utcTime, dataElement->choice.utctime.buf, 8); } - else if (dataElement->present == Data_PR_octetstring) { + else { + if (DEBUG_MMS_CLIENT) + printf("MMS CLIENT: error parsing UTC time (size is %i instead of 8\n", size); + } + } + else if (dataElement->present == Data_PR_octetstring) { + + if (dataElement->choice.octetstring.size >= 0) { value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); value->type = MMS_OCTET_STRING; int size = dataElement->choice.octetstring.size; @@ -300,20 +379,33 @@ mmsMsg_parseDataElement(Data_t* dataElement) value->value.octetString.buf = (uint8_t*) GLOBAL_MALLOC(size); memcpy(value->value.octetString.buf, dataElement->choice.octetstring.buf, size); } - else if (dataElement->present == Data_PR_binarytime) { - int size = dataElement->choice.binarytime.size; - if (size <= 6) { - value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); - value->type = MMS_BINARY_TIME; - value->value.binaryTime.size = size; - memcpy(value->value.binaryTime.buf, dataElement->choice.binarytime.buf, size); - } + } + else if (dataElement->present == Data_PR_binarytime) { + int size = dataElement->choice.binarytime.size; + + if ((size == 4) || (size == 6)) { + value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); + value->type = MMS_BINARY_TIME; + value->value.binaryTime.size = size; + memcpy(value->value.binaryTime.buf, dataElement->choice.binarytime.buf, size); } - else if (dataElement->present == Data_PR_boolean) { - value = MmsValue_newBoolean(dataElement->choice.boolean); + else { + if (DEBUG_MMS_CLIENT) + printf("MMS CLIENT: error parsing binary time (size must be 4 or 6, is %i\n", size); } + } + else if (dataElement->present == Data_PR_boolean) { + value = MmsValue_newBoolean(dataElement->choice.boolean); + } + else if (dataElement->present == Data_PR_booleanArray) { + if (DEBUG_MMS_CLIENT) + printf("MMS CLIENT: unsupported type - boolean-array\n"); + } + if (DEBUG_MMS_CLIENT) { + if (value == NULL) + printf("MMS CLIENT: error parsing data element\n"); } return value; diff --git a/src/mms/iso_mms/common/mms_value.c b/src/mms/iso_mms/common/mms_value.c index f6f315cf..72d577ba 100644 --- a/src/mms/iso_mms/common/mms_value.c +++ b/src/mms/iso_mms/common/mms_value.c @@ -1,7 +1,7 @@ /* * mms_value.c * - * Copyright 2013-2018 Michael Zillgith + * Copyright 2013-2019 Michael Zillgith * * This file is part of libIEC61850. * @@ -1076,6 +1076,9 @@ MmsValue_cloneToBuffer(const MmsValue* self, uint8_t* destinationAddress) MmsValue* MmsValue_clone(const MmsValue* self) { + if (self == NULL) + return NULL; + MmsValue* newValue = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); if (newValue == NULL) @@ -1179,6 +1182,9 @@ MmsValue_deleteIfNotNull(MmsValue* self) void MmsValue_delete(MmsValue* self) { + if (self == NULL) + return; + switch (self->type) { case MMS_INTEGER: @@ -1997,6 +2003,16 @@ MmsValue_getTypeString(MmsValue* self) const char* MmsValue_printToBuffer(const MmsValue* self, char* buffer, int bufferSize) { + if (self == NULL) { + strncpy(buffer, "(null)", bufferSize); + + /* Ensure buffer is always 0 terminated */ + if (bufferSize > 0) + buffer[bufferSize - 1] = 0; + + return buffer; + } + switch (MmsValue_getType(self)) { case MMS_STRUCTURE: