diff --git a/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs
index 7d251e51..48ec76f0 100644
--- a/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs
+++ b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs
@@ -316,6 +316,32 @@ namespace IEC61850
}
}
+ ///
+ /// Asynchonous service handler for the get RCB values service
+ ///
+ /// 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
+ /// the report control block instance
+ public delegate void GetRCBValuesHandler(UInt32 invokeId, object parameter, IedClientError err, ReportControlBlock rcb);
+
+ ///
+ /// Asynchonous service handler for the set RCB values service
+ ///
+ /// 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
+ /// the report control block instance
+ 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
+ ///
+ /// 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);
+
///
/// This class acts as the entry point for the IEC 61850 client API. It represents a single
/// (MMS) connection to a server.
@@ -560,6 +586,27 @@ namespace IEC61850
static extern UInt32
IedConnection_readDataSetValuesAsync(IntPtr self, out int error, string dataSetReference, IntPtr dataSet,
IedConnection_ReadDataSetHandler handler, IntPtr parameter);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ 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);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ 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);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern UInt32
+ IedConnection_deleteFileAsync(IntPtr self, out int error, string fileName,
+ IedConnection_GenericServiceHandler handler, IntPtr parameter);
/********************
@@ -1309,7 +1356,45 @@ namespace IEC61850
if (error != 0)
throw new IedConnectionException ("Deleting file " + fileName + " failed", error);
- }
+ }
+
+ private void nativeGenericServiceHandler (UInt32 invokeId, IntPtr parameter, int err)
+ {
+ GCHandle handle = GCHandle.FromIntPtr(parameter);
+
+ Tuple callbackInfo = handle.Target as Tuple;
+
+ GenericServiceHandler handler = callbackInfo.Item1;
+ object handlerParameter = callbackInfo.Item2;
+
+ handle.Free();
+
+ IedClientError clientError = (IedClientError)err;
+
+ handler(invokeId, handlerParameter, clientError);
+ }
+
+ /// Delete file- asynchronous version
+ /// The name of the file.
+ /// This exception is thrown if there is a connection or service error
+ public UInt32 DeleteFileAsync(string filename, GenericServiceHandler handler, object parameter)
+ {
+ int error;
+
+ Tuple callbackInfo = Tuple.Create(handler, parameter);
+
+ GCHandle handle = GCHandle.Alloc(callbackInfo);
+
+ UInt32 invokeId = IedConnection_deleteFileAsync(connection, out error, filename, nativeGenericServiceHandler, GCHandle.ToIntPtr(handle));
+
+ if (error != 0)
+ {
+ handle.Free();
+ throw new IedConnectionException("Get file failed", error);
+ }
+
+ return invokeId;
+ }
/// Read the content of a file directory.
/// The name of the directory.
@@ -1349,8 +1434,8 @@ namespace IEC61850
/// 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
+ /// list of file directory entries
/// This exception is thrown if there is a connection or service error
-
public List GetFileDirectoryEx(string directoryName, string continueAfter, out bool moreFollows)
{
int error;
@@ -1382,7 +1467,8 @@ 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 bool iedClientGetFileHandler(IntPtr parameter, IntPtr buffer, UInt32 bytesRead)
@@ -1429,6 +1515,7 @@ namespace IEC61850
///
/// 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)
{
int error;
@@ -1446,6 +1533,90 @@ namespace IEC61850
handle.Free();
}
+ [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);
+
+ ///
+ /// Callback handler for the asynchronous get file service. Will be invoked for each chunk of received data
+ ///
+ /// 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
+ /// 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);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern UInt32
+ IedConnection_getFileAsync(IntPtr self, out int error, string fileName, IedConnection_GetFileAsyncHandler handler,
+ IntPtr parameter);
+
+ private bool nativeGetFileAsyncHandler(UInt32 invokeId, IntPtr parameter, int err, UInt32 originalInvokeId,
+ IntPtr buffer, UInt32 bytesRead, bool moreFollows)
+ {
+
+ GCHandle handle = GCHandle.FromIntPtr(parameter);
+
+ Tuple callbackInfo = handle.Target as Tuple;
+
+ GetFileAsyncHandler handler = callbackInfo.Item1;
+ object handlerParameter = callbackInfo.Item2;
+
+ handle.Free();
+
+ IedClientError clientError = (IedClientError)err;
+
+ byte[] bytes = null;
+
+ if (clientError == IedClientError.IED_ERROR_OK)
+ {
+ bytes = new byte[bytesRead];
+
+ Marshal.Copy(buffer, bytes, 0, (int) bytesRead);
+ }
+
+ return handler(invokeId, handlerParameter, clientError, originalInvokeId, bytes, moreFollows);
+ }
+
+ ///
+ /// 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
+ ///
+ /// invoke ID of the request
+ /// This exception is thrown if there is a connection or service error
+ public UInt32 GetFileAsync(string fileName, GetFileAsyncHandler handler, object parameter)
+ {
+ int error;
+
+ Tuple callbackInfo = Tuple.Create(handler, parameter);
+
+ GCHandle handle = GCHandle.Alloc(callbackInfo);
+
+ UInt32 invokeId = IedConnection_getFileAsync(connection, out error, fileName, nativeGetFileAsyncHandler, GCHandle.ToIntPtr(handle));
+
+ if (error != 0)
+ {
+ handle.Free();
+ throw new IedConnectionException("Get file failed", error);
+ }
+
+ return invokeId;
+ }
+
+
+
+
///
/// Abort (close) the connection.
///
@@ -2234,6 +2405,79 @@ namespace IEC61850
error = 1; /* not connected */
}
}
+
+
+ private void nativeGetRCBValuesHandler (UInt32 invokeId, IntPtr parameter, int err, IntPtr rcbPtr)
+ {
+ GCHandle handle = GCHandle.FromIntPtr(parameter);
+
+ Tuple callbackInfo = handle.Target as Tuple;
+
+ GetRCBValuesHandler handler = callbackInfo.Item1;
+ object handlerParameter = callbackInfo.Item2;
+ ReportControlBlock rcb = callbackInfo.Item3;
+
+ handle.Free();
+
+ IedClientError clientError = (IedClientError)err;
+
+ handler(invokeId, handlerParameter, clientError, rcb);
+ }
+
+ internal UInt32 GetRCBValuesAsync(string objectReference, ReportControlBlock updateRcb, GetRCBValuesHandler handler, object parameter)
+ {
+ int error;
+
+ Tuple callbackInfo = Tuple.Create(handler, parameter, updateRcb);
+
+ GCHandle handle = GCHandle.Alloc(callbackInfo);
+
+ UInt32 invokeId = IedConnection_getRCBValuesAsync(connection, out error, objectReference, updateRcb.self, nativeGetRCBValuesHandler, GCHandle.ToIntPtr(handle));
+
+ if (error != 0)
+ {
+ handle.Free();
+ throw new IedConnectionException("GetRCBValues failed", error);
+ }
+
+ return invokeId;
+ }
+
+ private void nativeSetRcbValuesHandler (UInt32 invokeId, IntPtr parameter, int err)
+ {
+ GCHandle handle = GCHandle.FromIntPtr(parameter);
+
+ Tuple callbackInfo = handle.Target as Tuple;
+
+ SetRCBValuesHandler handler = callbackInfo.Item1;
+ object handlerParameter = callbackInfo.Item2;
+ ReportControlBlock rcb = callbackInfo.Item3;
+
+ handle.Free();
+
+ IedClientError clientError = (IedClientError)err;
+
+ handler(invokeId, handlerParameter, clientError, rcb);
+ }
+
+ internal UInt32 SetRCBValuesAsync(ReportControlBlock rcb, UInt32 parametersMask, bool singleRequest, SetRCBValuesHandler handler, object parameter)
+ {
+ int error;
+
+ Tuple callbackInfo = Tuple.Create(handler, parameter, rcb);
+
+ GCHandle handle = GCHandle.Alloc(callbackInfo);
+
+ UInt32 invokeId = IedConnection_setRCBValuesAsync(connection, out error, rcb.self, parametersMask, singleRequest, nativeSetRcbValuesHandler, GCHandle.ToIntPtr(handle));
+
+ if (error != 0)
+ {
+ handle.Free();
+ throw new IedConnectionException("SetRCBValues failed", error);
+ }
+
+ return invokeId;
+ }
}
diff --git a/dotnet/IEC61850forCSharp/ReportControlBlock.cs b/dotnet/IEC61850forCSharp/ReportControlBlock.cs
index 1854480f..e5b0ad2a 100644
--- a/dotnet/IEC61850forCSharp/ReportControlBlock.cs
+++ b/dotnet/IEC61850forCSharp/ReportControlBlock.cs
@@ -149,8 +149,9 @@ namespace IEC61850
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr ClientReportControlBlock_getOwner (IntPtr self);
- private IntPtr self;
- private IedConnection iedConnection = null;
+ internal IntPtr self;
+
+ private IedConnection iedConnection = null;
private string objectReference;
private bool flagRptId = false;
private bool flagRptEna = false;
@@ -302,6 +303,18 @@ namespace IEC61850
throw new IedConnectionException ("getRCBValues service failed", error);
}
+ ///
+ /// Read all RCB values from the server - asynchronous version
+ ///
+ /// the invoke ID of the request
+ /// user provided callback function
+ /// user provided callback parameter
+ /// This exception is thrown if there is a connection or service error
+ public UInt32 GetRCBValuesAsync(GetRCBValuesHandler handler, object parameter)
+ {
+ return iedConnection.GetRCBValuesAsync(GetObjectReference(), this, handler, parameter);
+ }
+
///
/// Write changed RCB values to the server.
///
@@ -315,17 +328,7 @@ namespace IEC61850
SetRCBValues (true);
}
- ///
- /// Write changed RCB values to the server.
- ///
- ///
- /// This function will only write the RCB values that were set by one of the setter methods.
- ///
- /// This exception is thrown if there is a connection or service error
- ///
- /// If true the values are sent by single MMS write request. Otherwise the values are all sent by their own MMS write requests.
- ///
- public void SetRCBValues (bool singleRequest)
+ private UInt32 CreateParametersMask()
{
UInt32 parametersMask = 0;
@@ -371,6 +374,35 @@ namespace IEC61850
if (flagResvTms)
parametersMask += 16384;
+ return parametersMask;
+ }
+
+ public UInt32 SetRCBValuesAsync(SetRCBValuesHandler handler, object parameter)
+ {
+ return SetRCBValuesAsync(true, handler, parameter);
+ }
+
+ public UInt32 SetRCBValuesAsync(bool singleRequest, SetRCBValuesHandler handler, object parameter)
+ {
+ UInt32 parametersMask = CreateParametersMask();
+
+ return iedConnection.SetRCBValuesAsync(this, parametersMask, singleRequest, handler, parameter);
+ }
+
+ ///
+ /// Write changed RCB values to the server.
+ ///
+ ///
+ /// This function will only write the RCB values that were set by one of the setter methods.
+ ///
+ /// This exception is thrown if there is a connection or service error
+ ///
+ /// If true the values are sent by single MMS write request. Otherwise the values are all sent by their own MMS write requests.
+ ///
+ public void SetRCBValues (bool singleRequest)
+ {
+ UInt32 parametersMask = CreateParametersMask();
+
int error;
iedConnection.SetRCBValues (out error, self, parametersMask, singleRequest);
diff --git a/src/iec61850/inc/iec61850_server.h b/src/iec61850/inc/iec61850_server.h
index 6873d636..cc46604f 100644
--- a/src/iec61850/inc/iec61850_server.h
+++ b/src/iec61850/inc/iec61850_server.h
@@ -322,8 +322,8 @@ IedServer_destroy(IedServer self);
/**
* \brief Set the local IP address to listen on
*
- * \param self the IedServer instance
- * \param localIpAddress the local IP address as C string (an internal copy will be created)
+ * \param self the IedServer instance
+ * \param localIpAddress the local IP address as C string (an internal copy will be created)
*/
LIB61850_API void
IedServer_setLocalIpAddress(IedServer self, const char* localIpAddress);