diff --git a/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs index a6a0adc6..b9e01bcf 100644 --- a/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs +++ b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs @@ -1,7 +1,7 @@ /* * IEC61850ClientAPI.cs * - * Copyright 2014 Michael Zillgith + * Copyright 2014-2016 Michael Zillgith * * This file is part of libIEC61850. * @@ -266,6 +266,10 @@ namespace IEC61850 [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 ***************/ @@ -838,7 +842,7 @@ namespace IEC61850 if (error != 0) throw new IedConnectionException ("Reading value failed", error); - if (mmsValue.ToInt32 () == 0) + if (mmsValue == IntPtr.Zero) throw new IedConnectionException ("Variable not found on server", error); return mmsValue; @@ -856,6 +860,22 @@ namespace IEC61850 return new MmsValue (value, true); } + 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 @@ -863,12 +883,18 @@ namespace IEC61850 /// This exception is thrown if there is a connection or service error public bool ReadBooleanValue (string objectReference, FunctionalConstraint fc) { - var mmsValue = ReadValue (objectReference, fc); + IntPtr mmsValue = readObjectInternalAndCheckDataAccessError (objectReference, fc); - if (mmsValue.GetType () == MmsType.MMS_BOOLEAN) - return mmsValue.GetBoolean (); - else + 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. @@ -877,10 +903,12 @@ namespace IEC61850 /// This exception is thrown if there is a connection or service error public float ReadFloatValue (string objectReference, FunctionalConstraint fc) { - IntPtr mmsValue = readObjectInternal (objectReference, fc); + IntPtr mmsValue = readObjectInternalAndCheckDataAccessError (objectReference, fc); - if (MmsValue_getType (mmsValue) != (int)MmsType.MMS_FLOAT) - throw new IedConnectionException ("Result is not of type float", 0); + 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); @@ -895,7 +923,7 @@ namespace IEC61850 /// This exception is thrown if there is a connection or service error public string ReadStringValue (string objectReference, FunctionalConstraint fc) { - IntPtr mmsValue = readObjectInternal (objectReference, 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); @@ -917,7 +945,7 @@ namespace IEC61850 /// This exception is thrown if there is a connection or service error public Quality ReadQualityValue (string objectReference, FunctionalConstraint fc) { - IntPtr mmsValue = readObjectInternal (objectReference, fc); + IntPtr mmsValue = readObjectInternalAndCheckDataAccessError (objectReference, fc); if (MmsValue_getType (mmsValue) == (int)MmsType.MMS_BIT_STRING) { int bitStringValue = (int)MmsValue_getBitStringAsInteger (mmsValue); @@ -936,7 +964,7 @@ namespace IEC61850 /// This exception is thrown if there is a connection or service error public int ReadBitStringValue (string objectReference, FunctionalConstraint fc) { - IntPtr mmsValue = readObjectInternal (objectReference, fc); + IntPtr mmsValue = readObjectInternalAndCheckDataAccessError (objectReference, fc); if (MmsValue_getType (mmsValue) == (int)MmsType.MMS_BIT_STRING) { int bitStringValue = (int)MmsValue_getBitStringAsInteger (mmsValue); @@ -955,11 +983,11 @@ namespace IEC61850 /// This exception is thrown if there is a connection or service error public UInt64 ReadTimestampValue (string objectReference, FunctionalConstraint fc) { - var mmsValuePtr = readObjectInternal (objectReference, fc); + var mmsValuePtr = readObjectInternalAndCheckDataAccessError (objectReference, fc); var mmsValue = new MmsValue (mmsValuePtr, true); - if (mmsValue.GetType () == MmsType.MMS_UTC_TIME) + if (mmsValue.GetType () == MmsType.MMS_UTC_TIME) return mmsValue.GetUtcTimeInMs (); else throw new IedConnectionException ("Result is not of type timestamp (MMS_UTC_TIME)", 0); @@ -973,7 +1001,7 @@ namespace IEC61850 /// This exception is thrown if there is a connection or service error public Int64 ReadIntegerValue (string objectReference, FunctionalConstraint fc) { - var mmsValuePtr = readObjectInternal (objectReference, fc); + var mmsValuePtr = readObjectInternalAndCheckDataAccessError (objectReference, fc); var mmsValue = new MmsValue (mmsValuePtr, true); diff --git a/dotnet/IEC61850forCSharp/MmsValue.cs b/dotnet/IEC61850forCSharp/MmsValue.cs index 12b6b6d4..08298c22 100644 --- a/dotnet/IEC61850forCSharp/MmsValue.cs +++ b/dotnet/IEC61850forCSharp/MmsValue.cs @@ -174,8 +174,7 @@ namespace IEC61850 valueReference = value; this.responsableForDeletion = false; } - - // TODO make internal + internal MmsValue (IntPtr value, bool responsableForDeletion) { valueReference = value; diff --git a/dotnet/tests/Test.cs b/dotnet/tests/Test.cs index 8925422c..1ff1cce3 100644 --- a/dotnet/tests/Test.cs +++ b/dotnet/tests/Test.cs @@ -165,6 +165,30 @@ namespace tests iedServer.Destroy (); } + [Test ()] + public void ReadNonExistingObject() + { + IedModel iedModel = ConfigFileParser.CreateModelFromConfigFile ("../../model.cfg"); + + IedServer iedServer = new IedServer (iedModel); + + iedServer.Start (10002); + + IedConnection connection = new IedConnection (); + + connection.Connect ("localhost", 10002); + + MmsValue value = connection.ReadValue ("simpleIOGenericIO/GGIO1.SPCSO1.stVal", FunctionalConstraint.MX); + + Assert.IsNotNull (value); + + Assert.AreEqual (MmsType.MMS_DATA_ACCESS_ERROR, value.GetType ()); + + iedServer.Stop (); + + iedServer.Destroy (); + } + [Test ()] public void AccessDataModelServerSide() {