From 50fc97734ea5b1a176b29c7d3322b5b04d17e798 Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Mon, 25 Oct 2021 18:12:37 +0200 Subject: [PATCH] - new function IedConnection_setTimeQuality - Added support to set time quality for client generated time stamps (LIB61850-280) --- dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs | 15 +++++++++++++++ src/iec61850/client/client_control.c | 18 +++++++++++++++--- src/iec61850/client/ied_connection.c | 19 +++++++++++++++++++ src/iec61850/inc/iec61850_client.h | 12 ++++++++++++ .../inc_private/ied_connection_private.h | 2 ++ 5 files changed, 63 insertions(+), 3 deletions(-) diff --git a/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs index 4c2a53c4..26221b4d 100644 --- a/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs +++ b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs @@ -431,6 +431,9 @@ namespace IEC61850 [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern UInt32 IedConnection_getRequestTimeout(IntPtr self); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void IedConnection_setTimeQuality(IntPtr self, [MarshalAs(UnmanagedType.I1)] bool leapSecondKnown, [MarshalAs(UnmanagedType.I1)] bool clockFailure, [MarshalAs(UnmanagedType.I1)] bool clockNotSynchronized, int subsecondPrecision); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern void IedConnection_connect(IntPtr self, out int error, string hostname, int tcpPort); @@ -807,6 +810,18 @@ namespace IEC61850 } } + /// + /// Set the time quality for all timestamps generated by this IedConnection instance + /// + /// set or unset leap seconds known flag + /// set or unset clock failure flag + /// set or unset clock not synchronized flag + /// set the subsecond precision (number of significant bits of the fractionOfSecond part of the time stamp) + public void SetTimeQuality(bool leapSecondKnown, bool clockFailure, bool clockNotSynchronized, int subsecondPrecision) + { + IedConnection_setTimeQuality(connection, leapSecondKnown, clockFailure, clockNotSynchronized, subsecondPrecision); + } + /// /// Gets the underlying MmsConnection instance. /// diff --git a/src/iec61850/client/client_control.c b/src/iec61850/client/client_control.c index 5bbfd924..64d98e24 100644 --- a/src/iec61850/client/client_control.c +++ b/src/iec61850/client/client_control.c @@ -441,8 +441,12 @@ prepareOperParameters(ControlObjectClient self, MmsValue* ctlVal, uint64_t operT MmsValue* ctlTime; - if (self->edition == 2) + if (self->edition == 2) { ctlTime = MmsValue_newUtcTimeByMsTime(timestamp); + + if (self->connection) + MmsValue_setUtcTimeQuality(ctlTime, self->connection->timeQuality); + } else { ctlTime = MmsValue_newBinaryTime(false); MmsValue_setBinaryTime(ctlTime, timestamp); @@ -682,8 +686,12 @@ prepareSBOwParameters(ControlObjectClient self, MmsValue* ctlVal) if (self->useConstantT) self->constantT = timestamp; - if (self->edition == 2) + if (self->edition == 2) { ctlTime = MmsValue_newUtcTimeByMsTime(timestamp); + + if (self->connection) + MmsValue_setUtcTimeQuality(ctlTime, self->connection->timeQuality); + } else { ctlTime = MmsValue_newBinaryTime(false); MmsValue_setBinaryTime(ctlTime, timestamp); @@ -1089,8 +1097,12 @@ createCancelParameters(ControlObjectClient self) MmsValue* ctlTime; - if (self->edition == 2) + if (self->edition == 2) { ctlTime = MmsValue_newUtcTimeByMsTime(timestamp); + + if (self->connection) + MmsValue_setUtcTimeQuality(ctlTime, self->connection->timeQuality); + } else { ctlTime = MmsValue_newBinaryTime(false); MmsValue_setBinaryTime(ctlTime, timestamp); diff --git a/src/iec61850/client/ied_connection.c b/src/iec61850/client/ied_connection.c index 3eb1d371..7d31dad5 100644 --- a/src/iec61850/client/ied_connection.c +++ b/src/iec61850/client/ied_connection.c @@ -672,6 +672,25 @@ IedConnection_getRequestTimeout(IedConnection self) return 0; } +void +IedConnection_setTimeQuality(IedConnection self, bool leapSecondKnown, bool clockFailure, bool clockNotSynchronized, int subsecondPrecision) +{ + uint8_t timeQuality = 0; + + if (clockNotSynchronized) + timeQuality += 0x20; + + if (clockFailure) + timeQuality += 0x40; + + if (leapSecondKnown) + timeQuality += 0x80; + + timeQuality += (subsecondPrecision & 0x1f); + + self->timeQuality = timeQuality; +} + IedConnectionState IedConnection_getState(IedConnection self) { diff --git a/src/iec61850/inc/iec61850_client.h b/src/iec61850/inc/iec61850_client.h index 9d1946e9..01a9cb95 100644 --- a/src/iec61850/inc/iec61850_client.h +++ b/src/iec61850/inc/iec61850_client.h @@ -266,6 +266,18 @@ IedConnection_setRequestTimeout(IedConnection self, uint32_t timeoutInMs); LIB61850_API uint32_t IedConnection_getRequestTimeout(IedConnection self); +/** + * \brief Set the time quality for all timestamps generated by this IedConnection instance + * + * \param self the connection object + * \param leapSecondKnown set/unset leap seconds known flag + * \param clockFailure set/unset clock failure flag + * \param clockNotSynchronized set/unset clock not synchronized flag + * \param subsecondPrecision set the subsecond precision (number of significant bits of the fractionOfSecond part of the time stamp) + */ +LIB61850_API void +IedConnection_setTimeQuality(IedConnection self, bool leapSecondKnown, bool clockFailure, bool clockNotSynchronized, int subsecondPrecision); + /** * \brief Perform MMS message handling and house-keeping tasks (for non-thread mode only) * diff --git a/src/iec61850/inc_private/ied_connection_private.h b/src/iec61850/inc_private/ied_connection_private.h index 5b7200ed..aefc2168 100644 --- a/src/iec61850/inc_private/ied_connection_private.h +++ b/src/iec61850/inc_private/ied_connection_private.h @@ -75,6 +75,8 @@ struct sIedConnection void* connectionStateChangedHandlerParameter; uint32_t connectionTimeout; + + uint8_t timeQuality; }; struct sClientReportControlBlock {