diff --git a/CMakeLists.txt b/CMakeLists.txt
index 16994b0..cd880bb 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -12,7 +12,7 @@ ENABLE_TESTING()
set(LIB_VERSION_MAJOR "1")
set(LIB_VERSION_MINOR "0")
-set(LIB_VERSION_PATCH "1")
+set(LIB_VERSION_PATCH "2")
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/third_party/cmake/modules/")
diff --git a/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs
index 70e7b1d..374d3a8 100644
--- a/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs
+++ b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs
@@ -987,14 +987,14 @@ namespace IEC61850
/// 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 UInt64 ReadTimestampValue (string objectReference, FunctionalConstraint fc)
+ 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 mmsValue.GetUtcTimeInMs ();
+ 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);
}
diff --git a/dotnet/IEC61850forCSharp/IEC61850CommonAPI.cs b/dotnet/IEC61850forCSharp/IEC61850CommonAPI.cs
index 6024dc1..0e80071 100644
--- a/dotnet/IEC61850forCSharp/IEC61850CommonAPI.cs
+++ b/dotnet/IEC61850forCSharp/IEC61850CommonAPI.cs
@@ -140,6 +140,203 @@ namespace IEC61850
}
}
+ ///
+ /// Timestamp (represents IEC 61850 timestamps e.g. "t" attribute)
+ ///
+ public class Timestamp
+ {
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern IntPtr Timestamp_create ();
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern void Timestamp_destroy (IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern void Timestamp_clearFlags (IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ [return: MarshalAs(UnmanagedType.I1)]
+ static extern bool Timestamp_isLeapSecondKnown (IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern void Timestamp_setLeapSecondKnown (IntPtr self, bool value);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ [return: MarshalAs(UnmanagedType.I1)]
+ static extern bool Timestamp_hasClockFailure (IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern void Timestamp_setClockFailure (IntPtr self, bool value);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ [return: MarshalAs(UnmanagedType.I1)]
+ static extern bool Timestamp_isClockNotSynchronized (IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern void Timestamp_setClockNotSynchronized (IntPtr self, bool value);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern int Timestamp_getSubsecondPrecision (IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern void Timestamp_setSubsecondPrecision(IntPtr self, int subsecondPrecision);
+
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern void Timestamp_setTimeInSeconds (IntPtr self, UInt32 secondsSinceEpoch);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern void Timestamp_setTimeInMilliseconds (IntPtr self, UInt64 millisSinceEpoch);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern UInt32 Timestamp_getTimeInSeconds (IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern UInt64 Timestamp_getTimeInMs (IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern void Timestamp_setByMmsUtcTime (IntPtr self, IntPtr mmsValue);
+
+ internal IntPtr timestampRef = IntPtr.Zero;
+ private bool responsableForDeletion;
+
+ internal Timestamp(IntPtr timestampRef, bool selfAllocated)
+ {
+ this.timestampRef = timestampRef;
+ this.responsableForDeletion = selfAllocated;
+ }
+
+ public Timestamp (DateTime timestamp) : this ()
+ {
+ SetDateTime (timestamp);
+ }
+
+ public Timestamp (MmsValue mmsUtcTime) : this()
+ {
+ SetByMmsUtcTime (mmsUtcTime);
+ }
+
+ public Timestamp()
+ {
+ timestampRef = Timestamp_create ();
+ LeapSecondKnown = true;
+ responsableForDeletion = true;
+ }
+
+ ~Timestamp ()
+ {
+ if (responsableForDeletion)
+ Timestamp_destroy (timestampRef);
+ }
+
+ public void ClearFlags()
+ {
+ Timestamp_clearFlags (timestampRef);
+ }
+
+ public void SetDateTime(DateTime timestamp)
+ {
+ DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+ DateTime timestampUTC = timestamp.ToUniversalTime();
+
+ TimeSpan timeDiff = timestampUTC - epoch;
+ ulong timeVal = Convert.ToUInt64(timeDiff.TotalMilliseconds);
+
+ SetTimeInMilliseconds (timeVal);
+ }
+
+ public bool LeapSecondKnown {
+ get { return IsLeapSecondKnown ();}
+ set { SetLeapSecondKnow (value);}
+ }
+
+ public bool IsLeapSecondKnown()
+ {
+ return Timestamp_isLeapSecondKnown (timestampRef);
+ }
+
+ public void SetLeapSecondKnow(bool value)
+ {
+ Timestamp_setLeapSecondKnown (timestampRef, value);
+ }
+
+ public bool ClockFailure {
+ get { return HasClockFailure ();}
+ set { SetClockFailure (value);}
+ }
+
+ public bool HasClockFailure()
+ {
+ return Timestamp_hasClockFailure (timestampRef);
+ }
+
+ public void SetClockFailure(bool value)
+ {
+ Timestamp_setClockFailure (timestampRef, value);
+ }
+
+ public bool ClockNotSynchronized {
+ get { return IsClockNotSynchronized (); }
+ set { SetClockNotSynchronized (value); }
+ }
+
+ public bool IsClockNotSynchronized() {
+ return Timestamp_isClockNotSynchronized(timestampRef);
+ }
+
+ public void SetClockNotSynchronized(bool value) {
+ Timestamp_setClockNotSynchronized (timestampRef, value);
+ }
+
+ public int SubsecondPrecision {
+ get { return GetSubsecondPrecision (); }
+ set { SetSubsecondPrecision (value); }
+ }
+
+ public int GetSubsecondPrecision() {
+ return Timestamp_getSubsecondPrecision (timestampRef);
+ }
+
+ public void SetSubsecondPrecision(int subsecondPrecision) {
+ Timestamp_setSubsecondPrecision (timestampRef, subsecondPrecision);
+ }
+
+ public UInt32 TimeInSeconds {
+ get { return GetTimeInSeconds (); }
+ set { SetTimeInSeconds (value); }
+ }
+
+ public UInt32 GetTimeInSeconds()
+ {
+ return Timestamp_getTimeInSeconds (timestampRef);
+ }
+
+ public void SetTimeInSeconds(UInt32 secondsSinceEpoch)
+ {
+ Timestamp_setTimeInSeconds (timestampRef, secondsSinceEpoch);
+ }
+
+ public UInt64 TimeInMilliseconds {
+ get { return GetTimeInMilliseconds (); }
+ set { SetTimeInMilliseconds (value); }
+ }
+
+ public UInt64 GetTimeInMilliseconds()
+ {
+ return Timestamp_getTimeInMs (timestampRef);
+ }
+
+ public void SetTimeInMilliseconds(UInt64 millisSinceEpoch) {
+ Timestamp_setTimeInMilliseconds (timestampRef, millisSinceEpoch);
+ }
+
+ public void SetByMmsUtcTime(MmsValue mmsValue)
+ {
+ Timestamp_setByMmsUtcTime (timestampRef, mmsValue.valueReference);
+ }
+
+ }
+
public enum ACSIClass
{
/** data objects */
diff --git a/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs b/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs
index b19835c..926d008 100644
--- a/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs
+++ b/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs
@@ -227,7 +227,8 @@ namespace IEC61850
GENERIC_BITSTRING = 26,
CONSTRUCTED = 27,
ENTRY_TIME = 28,
- PHYCOMADDR = 29
+ PHYCOMADDR = 29,
+ CURRENCY = 30
}
public enum ModeValues
@@ -246,7 +247,12 @@ namespace IEC61850
ALARM = 3
}
- public class CDC {
+ ///
+ /// The CDC class contains helper functions to create DataObject instances for the
+ /// most common Common Data Classes.
+ ///
+ public class CDC
+ {
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr CDC_SPS_create(string name, IntPtr parent, uint options);
@@ -573,12 +579,18 @@ namespace IEC61850
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void IedServer_unlockDataModel(IntPtr self);
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern void IedServer_updateAttributeValue(IntPtr self, IntPtr DataAttribute, IntPtr MmsValue);
+
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void IedServer_updateBooleanAttributeValue(IntPtr self, IntPtr dataAttribute, bool value);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void IedServer_updateInt32AttributeValue(IntPtr self, IntPtr dataAttribute, int value);
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern void IedServer_updateInt64AttributeValue(IntPtr self, IntPtr dataAttribute, Int64 value);
+
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void IedServer_updateFloatAttributeValue(IntPtr self, IntPtr dataAttribute, float value);
@@ -588,6 +600,9 @@ namespace IEC61850
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void IedServer_updateUTCTimeAttributeValue(IntPtr self, IntPtr dataAttribute, ulong value);
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern void IedServer_updateTimestampAttributeValue(IntPtr self, IntPtr dataAttribute, IntPtr timestamp);
+
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void IedServer_updateQuality(IntPtr self, IntPtr dataAttribute, ushort value);
@@ -892,24 +907,34 @@ namespace IEC61850
IedServer_unlockDataModel(self);
}
- public void UpdateBooleanAttributeValue(DataAttribute dataAttr, bool val)
+ public void UpdateAttributeValue(DataAttribute dataAttr, MmsValue value)
{
- IedServer_updateBooleanAttributeValue(self, dataAttr.self, val);
+ IedServer_updateAttributeValue (self, dataAttr.self, value.valueReference);
}
- public void UpdateFloatAttributeValue(DataAttribute dataAttr, float val)
+ public void UpdateBooleanAttributeValue(DataAttribute dataAttr, bool value)
{
- IedServer_updateFloatAttributeValue(self, dataAttr.self, val);
+ IedServer_updateBooleanAttributeValue(self, dataAttr.self, value);
}
- public void UpdateInt32AttributeValue(DataAttribute dataAttr, int val)
+ public void UpdateFloatAttributeValue(DataAttribute dataAttr, float value)
{
- IedServer_updateInt32AttributeValue(self, dataAttr.self, val);
+ IedServer_updateFloatAttributeValue(self, dataAttr.self, value);
}
- public void UpdateVisibleStringAttributeValue(DataAttribute dataAttr, string val)
+ public void UpdateInt32AttributeValue(DataAttribute dataAttr, int value)
{
- IedServer_updateVisibleStringAttributeValue(self, dataAttr.self, val);
+ IedServer_updateInt32AttributeValue(self, dataAttr.self, value);
+ }
+
+ public void UpdateInt64AttributeValue(DataAttribute dataAttr, Int64 value)
+ {
+ IedServer_updateInt64AttributeValue (self, dataAttr.self, value);
+ }
+
+ public void UpdateVisibleStringAttributeValue(DataAttribute dataAttr, string value)
+ {
+ IedServer_updateVisibleStringAttributeValue(self, dataAttr.self, value);
}
public void UpdateUTCTimeAttributeValue(DataAttribute dataAttr, DateTime timestamp)
@@ -923,6 +948,11 @@ namespace IEC61850
IedServer_updateUTCTimeAttributeValue(self, dataAttr.self, timeVal);
}
+ public void UpdateTimestampAttributeValue(DataAttribute dataAttr, Timestamp timestamp)
+ {
+ IedServer_updateTimestampAttributeValue (self, dataAttr.self, timestamp.timestampRef);
+ }
+
public void UpdateQuality(DataAttribute dataAttr, ushort value)
{
IedServer_updateQuality(self, dataAttr.self, value);
diff --git a/dotnet/server1/Program.cs b/dotnet/server1/Program.cs
index 1776257..1977879 100644
--- a/dotnet/server1/Program.cs
+++ b/dotnet/server1/Program.cs
@@ -44,8 +44,18 @@ namespace server1
GC.Collect ();
+ DataObject ggio1AnIn1 = (DataObject)iedModel.GetModelNodeByShortObjectReference ("GenericIO/GGIO1.AnIn1");
+
+ DataAttribute ggio1AnIn1magF = (DataAttribute)ggio1AnIn1.GetChild ("mag.f");
+ DataAttribute ggio1AnIn1T = (DataAttribute)ggio1AnIn1.GetChild ("t");
+
+ float floatVal = 1.0f;
+
while (running) {
- Thread.Sleep (1);
+ floatVal += 1f;
+ iedServer.UpdateTimestampAttributeValue (ggio1AnIn1T, new Timestamp (DateTime.Now));
+ iedServer.UpdateFloatAttributeValue (ggio1AnIn1magF, floatVal);
+ Thread.Sleep (100);
}
iedServer.Stop ();
diff --git a/dotnet/tests/Test.cs b/dotnet/tests/Test.cs
index 2b9f4e4..8ec403e 100644
--- a/dotnet/tests/Test.cs
+++ b/dotnet/tests/Test.cs
@@ -105,6 +105,30 @@ namespace tests
Assert.AreEqual (val.ToFloat (), (float)0.1234);
}
+ [Test ()]
+ public void Timestamps()
+ {
+ Timestamp timestamp = new Timestamp ();
+
+ Assert.IsTrue (timestamp.LeapSecondKnown);
+ Assert.IsFalse (timestamp.ClockFailure);
+ Assert.IsFalse (timestamp.ClockNotSynchronized);
+
+ timestamp.LeapSecondKnown = false;
+ Assert.IsFalse (timestamp.LeapSecondKnown);
+
+ timestamp.ClockFailure = true;
+ Assert.IsTrue (timestamp.ClockFailure);
+
+ timestamp.ClockNotSynchronized = true;
+ Assert.IsTrue (timestamp.ClockNotSynchronized);
+
+ Assert.AreEqual (0, timestamp.SubsecondPrecision);
+
+ timestamp.SubsecondPrecision = 10;
+ Assert.AreEqual (10, timestamp.SubsecondPrecision);
+ }
+
[Test ()]
public void CreateModelFromNonExistingFile()
{
diff --git a/src/common/inc/libiec61850_platform_includes.h b/src/common/inc/libiec61850_platform_includes.h
index 674b554..4dc01c2 100644
--- a/src/common/inc/libiec61850_platform_includes.h
+++ b/src/common/inc/libiec61850_platform_includes.h
@@ -15,7 +15,7 @@
#include "platform_endian.h"
-#define LIBIEC61850_VERSION "1.0.1"
+#define LIBIEC61850_VERSION "1.0.2"
#ifndef CONFIG_DEFAULT_MMS_VENDOR_NAME
#define CONFIG_DEFAULT_MMS_VENDOR_NAME "libiec61850.com"
diff --git a/src/doxygen.config b/src/doxygen.config
index c53fdd7..f188266 100644
--- a/src/doxygen.config
+++ b/src/doxygen.config
@@ -18,7 +18,7 @@ DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = "libIEC61850"
-PROJECT_NUMBER = 1.0.0
+PROJECT_NUMBER = 1.0.2
PROJECT_BRIEF = "Open-source IEC 61850 MMS/GOOSE/SV server and client library"
diff --git a/src/iec61850/common/iec61850_common.c b/src/iec61850/common/iec61850_common.c
index e16eb9a..3189203 100644
--- a/src/iec61850/common/iec61850_common.c
+++ b/src/iec61850/common/iec61850_common.c
@@ -26,6 +26,7 @@
#include "libiec61850_platform_includes.h"
#include "conversions.h"
+#include "mms_value_internal.h"
Validity
Quality_getValidity(Quality* self)
@@ -223,6 +224,21 @@ FunctionalConstraint_fromString(const char* fcString)
return IEC61850_FC_NONE;
}
+Timestamp*
+Timestamp_create()
+{
+ Timestamp* self = (Timestamp*) GLOBAL_CALLOC(1, sizeof(Timestamp));
+
+ return self;
+}
+
+void
+Timestamp_destroy(Timestamp* self)
+{
+ if (self != NULL)
+ GLOBAL_FREEMEM(self);
+}
+
void
Timestamp_clearFlags(Timestamp* self)
{
@@ -382,6 +398,13 @@ Timestamp_getTimeInMs(Timestamp* self)
return (uint64_t) msVal;
}
+void
+Timestamp_setByMmsUtcTime(Timestamp* self, MmsValue* mmsValue)
+{
+ if (MmsValue_getType(mmsValue) == MMS_UTC_TIME)
+ memcpy(self->val, mmsValue->value.utcTime, 8);
+}
+
char*
LibIEC61850_getVersionString()
{
diff --git a/src/iec61850/inc/iec61850_common.h b/src/iec61850/inc/iec61850_common.h
index 5b73f33..47131c4 100644
--- a/src/iec61850/inc/iec61850_common.h
+++ b/src/iec61850/inc/iec61850_common.h
@@ -353,6 +353,12 @@ typedef union {
uint8_t val[8];
} Timestamp;
+Timestamp*
+Timestamp_create(void);
+
+void
+Timestamp_destroy(Timestamp* self);
+
void
Timestamp_clearFlags(Timestamp* self);
@@ -397,6 +403,9 @@ Timestamp_setTimeInSeconds(Timestamp* self, uint32_t secondsSinceEpoch);
void
Timestamp_setTimeInMilliseconds(Timestamp* self, uint64_t millisSinceEpoch);
+void
+Timestamp_setByMmsUtcTime(Timestamp* self, MmsValue* mmsValue);
+
/**
* \brief Get the version of the library as string
*
diff --git a/src/vs/libiec61850-wo-goose.def b/src/vs/libiec61850-wo-goose.def
index 2fee1d4..065650a 100644
--- a/src/vs/libiec61850-wo-goose.def
+++ b/src/vs/libiec61850-wo-goose.def
@@ -558,3 +558,6 @@ EXPORTS
MmsConnection_obtainFile
IedConnection_setFile
IedConnection_readInt64Value
+ Timestamp_create
+ Timestamp_destroy
+ Timestamp_setByMmsUtcTime
\ No newline at end of file
diff --git a/src/vs/libiec61850.def b/src/vs/libiec61850.def
index 2b4d1a6..3a2ca38 100644
--- a/src/vs/libiec61850.def
+++ b/src/vs/libiec61850.def
@@ -636,3 +636,6 @@ EXPORTS
MmsConnection_obtainFile
IedConnection_setFile
IedConnection_readInt64Value
+ Timestamp_create
+ Timestamp_destroy
+ Timestamp_setByMmsUtcTime
\ No newline at end of file