diff --git a/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs
index 771c1274..4ba47ea9 100644
--- a/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs
+++ b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs
@@ -48,6 +48,9 @@ namespace IEC61850
public string revision;
}
+ ///
+ /// Represents an MmsConnection object (a single connection to an MMS server)
+ ///
public class MmsConnection
{
@@ -69,6 +72,25 @@ namespace IEC61850
[DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)]
private static extern Int32 MmsConnection_getLocalDetail (IntPtr self);
+ [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);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ private delegate void LinkedListValueDeleteFunction(IntPtr pointer);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern void LinkedList_destroyDeep(IntPtr list, LinkedListValueDeleteFunction valueDeleteFunction);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern IntPtr LinkedList_create ();
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern void LinkedList_add (IntPtr self, IntPtr data);
+
private IntPtr self = IntPtr.Zero;
private bool selfDestroy = false;
@@ -90,6 +112,15 @@ namespace IEC61850
MmsConnection_destroy(self);
}
+ private void FreeHGlobaleDeleteFunction (IntPtr pointer)
+ {
+ Marshal.FreeHGlobal(pointer);
+ }
+
+ ///
+ /// Requests the server identity information
+ ///
+ /// The server identity.
public MmsServerIdentity GetServerIdentity ()
{
int mmsError;
@@ -100,6 +131,12 @@ namespace IEC61850
IntPtr identity = MmsConnection_identify(self, out mmsError);
+ if (mmsError != 0)
+ throw new IedConnectionException("Failed to read server identity", mmsError);
+
+ if (identity == IntPtr.Zero)
+ throw new IedConnectionException("Failed to read server identity");
+
MmsServerIdentity serverIdentity = (MmsServerIdentity)
Marshal.PtrToStructure(identity, typeof(MmsServerIdentity));
@@ -108,14 +145,54 @@ namespace IEC61850
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);
}
+ ///
+ /// Gets the local detail (maximum MMS PDU size)
+ ///
+ /// maximum accepted MMS PDU size in bytes
public int GetLocalDetail() {
return MmsConnection_getLocalDetail (self);
}
+ ///
+ /// Reads multipe MMS variables from the same domain
+ ///
+ /// MmsValue of type MMS_ARRAY containing the access results for the requested variables.
+ /// the domain name (logical device)
+ /// list of variable names (in MMS notation e.g. "GGIO$ST$Ind1")
+ public MmsValue ReadMultipleVariables(string domainName, List variables)
+ {
+ IntPtr linkedList = LinkedList_create ();
+
+ foreach (string variableName in variables) {
+ IntPtr handle = System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi (variableName);
+
+ LinkedList_add (linkedList, handle);
+ }
+
+ int error;
+
+ IntPtr mmsValue = MmsConnection_readMultipleVariables(self, out error, domainName, linkedList);
+
+ LinkedList_destroyDeep(linkedList, new LinkedListValueDeleteFunction(FreeHGlobaleDeleteFunction));
+
+ if (error != 0)
+ {
+ if (mmsValue != IntPtr.Zero)
+ MmsValue_delete(mmsValue);
+
+ throw new IedConnectionException("ReadMultipleVariables failed", error);
+ }
+
+ return new MmsValue(mmsValue, true);
+ }
}
diff --git a/dotnet/IEC61850forCSharp/MmsValue.cs b/dotnet/IEC61850forCSharp/MmsValue.cs
index fd00626f..5d9900df 100644
--- a/dotnet/IEC61850forCSharp/MmsValue.cs
+++ b/dotnet/IEC61850forCSharp/MmsValue.cs
@@ -186,8 +186,7 @@ namespace IEC61850
private bool responsableForDeletion; /* if .NET wrapper is responsable for the deletion of the native MmsValue instance */
- // TODO make internal
- public MmsValue (IntPtr value)
+ internal MmsValue (IntPtr value)
{
valueReference = value;
this.responsableForDeletion = false;
@@ -939,9 +938,31 @@ namespace IEC61850
return retString;
}
+ case MmsType.MMS_ARRAY:
+ {
+ string retString = "[";
+
+ bool first = true;
+
+ foreach (MmsValue element in this) {
+ if (first) {
+ retString += element.ToString ();
+
+ first = false;
+ } else {
+ retString += ", " + element.ToString ();
+ }
+ }
+
+ retString += "]";
+
+ return retString;
+ }
+ case MmsType.MMS_DATA_ACCESS_ERROR:
+ return "error: " + GetDataAccessError().ToString();
default:
- return "unknown";
+ return "unknown (type:" + GetType().ToString() + ")";
}
}
diff --git a/dotnet/example1/Main.cs b/dotnet/example1/Main.cs
index 738d839e..b02b312f 100644
--- a/dotnet/example1/Main.cs
+++ b/dotnet/example1/Main.cs
@@ -67,7 +67,18 @@ namespace example1
DataSet dataSet = con.ReadDataSetValues("simpleIOGenericIO/LLN0.Events", null);
- Console.WriteLine("Read data set " + dataSet.GetReference());
+ Console.WriteLine("Read data set " + dataSet.GetReference());
+
+ /* read multiple variables (WARNING: this is not IEC 61850 standard compliant but might
+ * be supported by most servers).
+ */
+ MmsConnection mmsConnection = con.GetMmsConnection();
+
+ MmsValue result = mmsConnection.ReadMultipleVariables("simpleIOGenericIO", new List() {
+ "GGIO1$ST$Ind1", "GGIO1$ST$Ind1", "GGIO1$ST$Ind1","GGIO1$ST$Ind1"
+ });
+
+ Console.WriteLine(result.ToString());
con.Abort();
}