diff --git a/dotnet/IEC61850forCSharp/Control.cs b/dotnet/IEC61850forCSharp/Control.cs index c629ad90..4fa909cf 100644 --- a/dotnet/IEC61850forCSharp/Control.cs +++ b/dotnet/IEC61850forCSharp/Control.cs @@ -101,6 +101,13 @@ namespace IEC61850 } } + public enum ControlActionType + { + SELECT = 0, + OPERATE = 1, + CANCEL = 2 + } + /// /// Control object. /// @@ -125,6 +132,30 @@ namespace IEC61850 [return: MarshalAs(UnmanagedType.I1)] private static extern bool ControlObjectClient_operate(IntPtr self, IntPtr ctlVal, UInt64 operTime); + /// + /// Handler for asynchronous control actions (select, operate, cancel) + /// + public delegate void ControlActionHandler (UInt32 invokeId, Object parameter, IedClientError error, ControlActionType type, bool success); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate void ControlObjectClient_ControlActionHandler (UInt32 invokeId, IntPtr parameter, int err, int type, [MarshalAs(UnmanagedType.I1)] bool success); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern UInt32 ControlObjectClient_operateAsync(IntPtr self, out int err, IntPtr ctlVal, UInt64 operTime, + ControlObjectClient_ControlActionHandler handler, IntPtr parameter); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern UInt32 ControlObjectClient_selectAsync(IntPtr self, out int err, + ControlObjectClient_ControlActionHandler handler, IntPtr parameter); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern UInt32 ControlObjectClient_selectWithValueAsync(IntPtr self, out int err, IntPtr ctlVal, + ControlObjectClient_ControlActionHandler handler, IntPtr parameter); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern UInt32 ControlObjectClient_cancelAsync(IntPtr self, out int err, + ControlObjectClient_ControlActionHandler handler, IntPtr parameter); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] [return: MarshalAs(UnmanagedType.I1)] private static extern bool ControlObjectClient_select(IntPtr self); @@ -314,6 +345,149 @@ namespace IEC61850 return ControlObjectClient_operate(controlObject, ctlVal.valueReference, operTime); } + private void nativeOperateHandler (UInt32 invokeId, IntPtr parameter, int err, int type, bool success) + { + GCHandle handle = GCHandle.FromIntPtr(parameter); + + Tuple callbackInfo = handle.Target as Tuple; + + ControlActionHandler handler = callbackInfo.Item1; + object handlerParameter = callbackInfo.Item2; + + handle.Free(); + + IedClientError clientError = (IedClientError)err; + + handler(invokeId, handlerParameter, clientError, (ControlActionType) type, success); + } + + + /// + /// Operate the control with the specified control value. + /// + /// the new value of the control + /// Callback function to handle the received response or service timeout + /// User provided callback parameter. Will be passed to the callback function + /// the invoke ID of the sent request + /// This exception is thrown if there is a connection or service error + public UInt32 OperateAsync (bool ctlVal, ControlActionHandler handler, object parameter) + { + return OperateAsync (ctlVal, 0, handler, parameter); + } + + /// + /// Operate the control with the specified control value (time activated control). + /// + /// the new value of the control + /// the time when the operation will be executed + /// Callback function to handle the received response or service timeout + /// User provided callback parameter. Will be passed to the callback function + /// the invoke ID of the sent request + /// This exception is thrown if there is a connection or service error + public UInt32 OperateAsync (bool ctlVal, UInt64 operTime, ControlActionHandler handler, object parameter) + { + MmsValue value = new MmsValue(ctlVal); + + return OperateAsync (value, operTime, handler, parameter); + } + + /// + /// Operate the control with the specified control value. + /// + /// the new value of the control + /// Callback function to handle the received response or service timeout + /// User provided callback parameter. Will be passed to the callback function + /// the invoke ID of the sent request + /// This exception is thrown if there is a connection or service error + public UInt32 OperateAsync (float ctlVal, ControlActionHandler handler, object parameter) + { + return OperateAsync (ctlVal, 0, handler, parameter); + } + + /// + /// Operate the control with the specified control value (time activated control). + /// + /// the new value of the control + /// the time when the operation will be executed + /// Callback function to handle the received response or service timeout + /// User provided callback parameter. Will be passed to the callback function + /// the invoke ID of the sent request + /// This exception is thrown if there is a connection or service error + public UInt32 OperateAsync (float ctlVal, UInt64 operTime, ControlActionHandler handler, object parameter) + { + MmsValue value = new MmsValue(ctlVal); + + return OperateAsync (value, operTime, handler, parameter); + } + + /// + /// Operate the control with the specified control value. + /// + /// the new value of the control + /// Callback function to handle the received response or service timeout + /// User provided callback parameter. Will be passed to the callback function + /// the invoke ID of the sent request + /// This exception is thrown if there is a connection or service error + public UInt32 OperateAsync (int ctlVal, ControlActionHandler handler, object parameter) + { + return OperateAsync (ctlVal, 0, handler, parameter); + } + + /// + /// Operate the control with the specified control value (time activated control). + /// + /// the new value of the control + /// the time when the operation will be executed + /// Callback function to handle the received response or service timeout + /// User provided callback parameter. Will be passed to the callback function + /// the invoke ID of the sent request + /// This exception is thrown if there is a connection or service error + public UInt32 OperateAsync (int ctlVal, UInt64 operTime, ControlActionHandler handler, object parameter) + { + return OperateAsync (ctlVal, operTime, handler, parameter); + } + + /// + /// Operate the control with the specified control value. + /// + /// the new value of the control + /// Callback function to handle the received response or service timeout + /// User provided callback parameter. Will be passed to the callback function + /// the invoke ID of the sent request + /// This exception is thrown if there is a connection or service error + public UInt32 OperateAsync (MmsValue ctlVal, ControlActionHandler handler, object parameter) + { + return OperateAsync (ctlVal, 0, handler, parameter); + } + + /// + /// Operate the control with the specified control value (time activated control). + /// + /// the new value of the control + /// the time when the operation will be executed + /// Callback function to handle the received response or service timeout + /// User provided callback parameter. Will be passed to the callback function + /// the invoke ID of the sent request + /// This exception is thrown if there is a connection or service error + public UInt32 OperateAsync (MmsValue ctlVal, UInt64 operTime, ControlActionHandler handler, object parameter) + { + int error; + + Tuple callbackInfo = Tuple.Create(handler, parameter); + + GCHandle handle = GCHandle.Alloc(callbackInfo); + + UInt32 invokeId = ControlObjectClient_operateAsync(controlObject, out error, ctlVal.valueReference, operTime, nativeOperateHandler, GCHandle.ToIntPtr(handle)); + + if (error != 0) + { + handle.Free(); + throw new IedConnectionException("Operate failed", error); + } + + return invokeId; + } + /// /// Select the control object. /// @@ -323,13 +497,36 @@ namespace IEC61850 return ControlObjectClient_select(controlObject); } + /// + /// Select the control object. + /// + /// Callback function to handle the received response or service timeout + /// User provided callback parameter. Will be passed to the callback function + /// the invoke ID of the sent request + /// This exception is thrown if there is a connection or service error + public UInt32 SelectAsync(ControlActionHandler handler, object parameter) + { + int error; + + Tuple callbackInfo = Tuple.Create(handler, parameter); + + GCHandle handle = GCHandle.Alloc(callbackInfo); + + UInt32 invokeId = ControlObjectClient_selectAsync(controlObject, out error, nativeOperateHandler, GCHandle.ToIntPtr(handle)); + + if (error != 0) + { + handle.Free(); + throw new IedConnectionException("Select failed", error); + } + + return invokeId; + } /// /// Send a select with value command for generic MmsValue instances /// - /// - /// the value to be checked. - /// + /// the value to be checked. /// true when the selection has been successful, false otherwise public bool SelectWithValue (MmsValue ctlVal) { @@ -372,15 +569,107 @@ namespace IEC61850 return SelectWithValue(new MmsValue(ctlVal)); } + /// + /// Send a select with value command for boolean controls - asynchronous version + /// + /// the value to be checked. + /// Callback function to handle the received response or service timeout + /// User provided callback parameter. Will be passed to the callback function + /// the invoke ID of the sent request + /// This exception is thrown if there is a connection or service error + public UInt32 SelectWithValueAsync (bool ctlVal, ControlActionHandler handler, object parameter) + { + return SelectWithValueAsync(new MmsValue(ctlVal), handler, parameter); + } + + /// + /// Send a select with value command for integer controls - asynchronous version + /// + /// the value to be checked. + /// Callback function to handle the received response or service timeout + /// User provided callback parameter. Will be passed to the callback function + /// the invoke ID of the sent request + /// This exception is thrown if there is a connection or service error + public UInt32 SelectWithValueAsync (int ctlVal, ControlActionHandler handler, object parameter) + { + return SelectWithValueAsync(new MmsValue(ctlVal), handler, parameter); + } + + /// + /// Send a select with value command for float controls - asynchronous version + /// + /// the value to be checked. + /// Callback function to handle the received response or service timeout + /// User provided callback parameter. Will be passed to the callback function + /// the invoke ID of the sent request + /// This exception is thrown if there is a connection or service error + public UInt32 SelectWithValueAsync (float ctlVal, ControlActionHandler handler, object parameter) + { + return SelectWithValueAsync(new MmsValue(ctlVal), handler, parameter); + } + + /// + /// Send a select with value command for generic MmsValue instances - asynchronous version + /// + /// the value to be checked. + /// Callback function to handle the received response or service timeout + /// User provided callback parameter. Will be passed to the callback function + /// the invoke ID of the sent request + /// This exception is thrown if there is a connection or service error + public UInt32 SelectWithValueAsync (MmsValue ctlVal, ControlActionHandler handler, object parameter) + { + int error; + + Tuple callbackInfo = Tuple.Create(handler, parameter); + + GCHandle handle = GCHandle.Alloc(callbackInfo); + + UInt32 invokeId = ControlObjectClient_selectWithValueAsync(controlObject, out error, ctlVal.valueReference, nativeOperateHandler, GCHandle.ToIntPtr(handle)); + + if (error != 0) + { + handle.Free(); + throw new IedConnectionException("Select with value failed", error); + } + + return invokeId; + } + /// /// Cancel a selection or time activated operation /// /// true when the cancelation has been successful, false otherwise + /// Callback function to handle the received response or service timeout + /// User provided callback parameter. Will be passed to the callback function + /// the invoke ID of the sent request + /// This exception is thrown if there is a connection or service error public bool Cancel () { return ControlObjectClient_cancel(controlObject); } + /// + /// Cancel a selection or time activated operation + /// + public UInt32 CancelAsync(ControlActionHandler handler, object parameter) + { + int error; + + Tuple callbackInfo = Tuple.Create(handler, parameter); + + GCHandle handle = GCHandle.Alloc(callbackInfo); + + UInt32 invokeId = ControlObjectClient_cancelAsync(controlObject, out error, nativeOperateHandler, GCHandle.ToIntPtr(handle)); + + if (error != 0) + { + handle.Free(); + throw new IedConnectionException("Cancel failed", error); + } + + return invokeId; + } + /// /// Enables the synchro check for operate commands /// diff --git a/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs index b919cfeb..7d251e51 100644 --- a/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs +++ b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs @@ -544,6 +544,23 @@ namespace IEC61850 static extern UInt32 IedConnection_queryLogAfterAsync(IntPtr self, out int error, string logReference, 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); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern UInt32 + IedConnection_getVariableSpecificationAsync(IntPtr self, out int error, string dataAttributeReference, + int fc, IedConnection_GetVariableSpecificationHandler handler, IntPtr parameter); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + 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); + /******************** * FileDirectoryEntry @@ -1330,8 +1347,10 @@ namespace IEC61850 /// Read the content of a file directory. - single request version /// The name of the directory. + /// the filename that defines the continuation point, or null for the first request + /// true, when more files are available, false otherwise /// This exception is thrown if there is a connection or service error - /// The name of the directory. + public List GetFileDirectoryEx(string directoryName, string continueAfter, out bool moreFollows) { int error; @@ -1567,7 +1586,6 @@ namespace IEC61850 /// This function will invoke a readDataSetValues service and return a new DataSet value containing the /// 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) { @@ -1810,6 +1828,119 @@ namespace IEC61850 return invokeId; } + private void nativeGetVariableSpecifcationHandler (UInt32 invokeId, IntPtr parameter, int err, IntPtr spec) + { + GCHandle handle = GCHandle.FromIntPtr(parameter); + + Tuple callbackInfo = handle.Target as Tuple; + + GetVariableSpecifcationHandler handler = callbackInfo.Item1; + object handlerParameter = callbackInfo.Item2; + + handle.Free(); + + IedClientError clientError = (IedClientError)err; + + MmsVariableSpecification varSpec = null; + + if (spec != IntPtr.Zero) + varSpec = new MmsVariableSpecification(spec, true); + + handler(invokeId, handlerParameter, clientError, varSpec); + } + + 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. + /// The functional constraint (FC) of the object + /// Callback function to handle the received response or service timeout + /// User provided callback parameter. Will be passed to the callback function + /// the invoke ID of the sent request + /// This exception is thrown if there is a connection or service error + public UInt32 GetVariableSpecificationAsync(string objectReference, FunctionalConstraint fc, GetVariableSpecifcationHandler handler, object parameter) + { + int error; + + Tuple callbackInfo = Tuple.Create(handler, parameter); + + GCHandle handle = GCHandle.Alloc(callbackInfo); + + UInt32 invokeId = IedConnection_getVariableSpecificationAsync(connection, out error, objectReference, (int)fc, nativeGetVariableSpecifcationHandler, GCHandle.ToIntPtr(handle)); + + if (error != 0) + { + handle.Free(); + throw new IedConnectionException("Reading variable specification failed", error); + } + + return invokeId; + } + + private void nativeReadDataSetHandler (UInt32 invokeId, IntPtr parameter, int err, IntPtr nativeDataSet) + { + GCHandle handle = GCHandle.FromIntPtr(parameter); + + Tuple callbackInfo = handle.Target as Tuple; + + ReadDataSetHandler handler = callbackInfo.Item1; + object handlerParameter = callbackInfo.Item2; + DataSet dataSet = callbackInfo.Item3; + + handle.Free(); + + IedClientError clientError = (IedClientError)err; + + if (nativeDataSet != IntPtr.Zero) + { + if (dataSet == null) + dataSet = new DataSet(nativeDataSet); + } + + + handler(invokeId, handlerParameter, clientError, dataSet); + } + + + public delegate void ReadDataSetHandler(UInt32 invokeId, object parameter, IedClientError err, DataSet dataSet); + + /// + /// Read the values of a data set (GetDataSetValues service) - asynchronous version + /// + /// This function will invoke a readDataSetValues service and in case of success returns a new DataSet value + /// containing the received values by the callback function. 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 + /// Callback function to handle the received response or service timeout + /// User provided callback parameter. Will be passed to the callback function + /// the invoke ID of the sent request + /// This exception is thrown if there is a connection or service error + public UInt32 ReadDataSetValuesAsync(string dataSetReference, DataSet dataSet, ReadDataSetHandler handler, object parameter) + { + int error; + + Tuple callbackInfo = Tuple.Create(handler, parameter, dataSet); + + GCHandle handle = GCHandle.Alloc(callbackInfo); + + IntPtr dataSetPtr = IntPtr.Zero; + + if (dataSet != null) + dataSetPtr = dataSet.getNativeInstance(); + + UInt32 invokeId = IedConnection_readDataSetValuesAsync(connection, out error, dataSetReference, dataSetPtr, nativeReadDataSetHandler, GCHandle.ToIntPtr(handle)); + + if (error != 0) + { + handle.Free(); + throw new IedConnectionException("Reading data set failed", error); + } + + return invokeId; + } + /// /// Write value handler. ///