Skip to content
This repository has been archived by the owner on Sep 1, 2022. It is now read-only.

Commit

Permalink
Merge pull request #357 from dnp3/dnptimesource
Browse files Browse the repository at this point in the history
Provide IDnpTimeSource in Java and C# bindings.
  • Loading branch information
emgre committed Mar 27, 2020
2 parents e3f1b1d + d29d21f commit 84ef898
Show file tree
Hide file tree
Showing 53 changed files with 390 additions and 248 deletions.
60 changes: 29 additions & 31 deletions dotnet/CLRAdapter/src/Conversions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,40 +164,38 @@ namespace DNP3

Binary ^ Conversions::ConvertMeas(opendnp3::Binary meas)
{
return gcnew Binary(meas.value, gcnew Flags(meas.flags.value), TimeStamp::Convert(meas.time.value));
return gcnew Binary(meas.value, gcnew Flags(meas.flags.value), ConvertTime(meas.time));
}

DoubleBitBinary ^ Conversions::ConvertMeas(opendnp3::DoubleBitBinary meas)
{
return gcnew DoubleBitBinary(static_cast<DoubleBit>(meas.value), gcnew Flags(meas.flags.value),
TimeStamp::Convert(meas.time.value));
ConvertTime(meas.time));
}

Analog ^ Conversions::ConvertMeas(opendnp3::Analog meas)
{
return gcnew Analog(meas.value, gcnew Flags(meas.flags.value), TimeStamp::Convert(meas.time.value));
return gcnew Analog(meas.value, gcnew Flags(meas.flags.value), ConvertTime(meas.time));
}

Counter ^ Conversions::ConvertMeas(opendnp3::Counter meas)
{
return gcnew Counter(meas.value, gcnew Flags(meas.flags.value), TimeStamp::Convert(meas.time.value));
return gcnew Counter(meas.value, gcnew Flags(meas.flags.value), ConvertTime(meas.time));
}

FrozenCounter ^ Conversions::ConvertMeas(opendnp3::FrozenCounter meas)
{
return gcnew FrozenCounter(meas.value, gcnew Flags(meas.flags.value), TimeStamp::Convert(meas.time.value));
return gcnew FrozenCounter(meas.value, gcnew Flags(meas.flags.value), ConvertTime(meas.time));
}

AnalogOutputStatus ^ Conversions::ConvertMeas(opendnp3::AnalogOutputStatus meas)
{
return gcnew AnalogOutputStatus(meas.value, gcnew Flags(meas.flags.value),
TimeStamp::Convert(meas.time.value));
return gcnew AnalogOutputStatus(meas.value, gcnew Flags(meas.flags.value), ConvertTime(meas.time));
}

BinaryOutputStatus ^ Conversions::ConvertMeas(opendnp3::BinaryOutputStatus meas)
{
return gcnew BinaryOutputStatus(meas.value, gcnew Flags(meas.flags.value),
TimeStamp::Convert(meas.time.value));
return gcnew BinaryOutputStatus(meas.value, gcnew Flags(meas.flags.value), ConvertTime(meas.time));
}

OctetString ^ Conversions::ConvertMeas(const opendnp3::OctetString& meas)
Expand All @@ -212,61 +210,63 @@ namespace DNP3

BinaryCommandEvent ^ Conversions::ConvertMeas(const opendnp3::BinaryCommandEvent& meas)
{
return gcnew BinaryCommandEvent(meas.value, ConvertCommandStatus(meas.status),
TimeStamp::Convert(meas.time.value));
return gcnew BinaryCommandEvent(meas.value, ConvertCommandStatus(meas.status), ConvertTime(meas.time));
}

AnalogCommandEvent ^ Conversions::ConvertMeas(const opendnp3::AnalogCommandEvent& meas)
{
return gcnew AnalogCommandEvent(meas.value, ConvertCommandStatus(meas.status),
TimeStamp::Convert(meas.time.value));
return gcnew AnalogCommandEvent(meas.value, ConvertCommandStatus(meas.status), ConvertTime(meas.time));
}

SecurityStat ^ Conversions::ConvertMeas(const opendnp3::SecurityStat& meas)
{
return gcnew SecurityStat(meas.value.count, meas.value.assocId, gcnew Flags(meas.quality),
TimeStamp::Convert(meas.time.value));
ConvertTime(meas.time));
}

opendnp3::DNPTime Conversions::ConvertTime(DNPTime^ time)
{
return opendnp3::DNPTime(time->ToEpoch(), (opendnp3::TimestampQuality)time->Quality);
}

DNPTime^ Conversions::ConvertTime(opendnp3::DNPTime time)
{
return DNPTime::FromEpoch(time.value, (TimestampQuality)time.quality);
}

opendnp3::Binary Conversions::ConvertMeas(Binary ^ meas)
{
return opendnp3::Binary(meas->Value, opendnp3::Flags(meas->Quality->Value), opendnp3::DNPTime(TimeStamp::Convert(meas->Timestamp)));
return opendnp3::Binary(meas->Value, opendnp3::Flags(meas->Quality->Value), ConvertTime(meas->Timestamp));
}

opendnp3::DoubleBitBinary Conversions::ConvertMeas(DoubleBitBinary ^ meas)
{
return opendnp3::DoubleBitBinary((opendnp3::DoubleBit)meas->Value, opendnp3::Flags(meas->Quality->Value),
opendnp3::DNPTime(TimeStamp::Convert(meas->Timestamp)));
return opendnp3::DoubleBitBinary((opendnp3::DoubleBit)meas->Value, opendnp3::Flags(meas->Quality->Value), ConvertTime(meas->Timestamp));
}

opendnp3::Analog Conversions::ConvertMeas(Analog ^ meas)
{
return opendnp3::Analog(meas->Value, opendnp3::Flags(meas->Quality->Value),
opendnp3::DNPTime(TimeStamp::Convert(meas->Timestamp)));
return opendnp3::Analog(meas->Value, opendnp3::Flags(meas->Quality->Value), ConvertTime(meas->Timestamp));
}

opendnp3::Counter Conversions::ConvertMeas(Counter ^ meas)
{
return opendnp3::Counter(meas->Value, opendnp3::Flags(meas->Quality->Value),
opendnp3::DNPTime(TimeStamp::Convert(meas->Timestamp)));
return opendnp3::Counter(meas->Value, opendnp3::Flags(meas->Quality->Value), ConvertTime(meas->Timestamp));
}

opendnp3::FrozenCounter Conversions::ConvertMeas(FrozenCounter ^ meas)
{
return opendnp3::FrozenCounter(meas->Value, opendnp3::Flags(meas->Quality->Value),
opendnp3::DNPTime(TimeStamp::Convert(meas->Timestamp)));
return opendnp3::FrozenCounter(meas->Value, opendnp3::Flags(meas->Quality->Value), ConvertTime(meas->Timestamp));
}

opendnp3::BinaryOutputStatus Conversions::ConvertMeas(BinaryOutputStatus ^ meas)
{
return opendnp3::BinaryOutputStatus(meas->Value, opendnp3::Flags(meas->Quality->Value),
opendnp3::DNPTime(TimeStamp::Convert(meas->Timestamp)));
return opendnp3::BinaryOutputStatus(meas->Value, opendnp3::Flags(meas->Quality->Value), ConvertTime(meas->Timestamp));
}

opendnp3::AnalogOutputStatus Conversions::ConvertMeas(AnalogOutputStatus ^ meas)
{
return opendnp3::AnalogOutputStatus(meas->Value, opendnp3::Flags(meas->Quality->Value),
opendnp3::DNPTime(TimeStamp::Convert(meas->Timestamp)));
return opendnp3::AnalogOutputStatus(meas->Value, opendnp3::Flags(meas->Quality->Value), ConvertTime(meas->Timestamp));
}

opendnp3::OctetString Conversions::ConvertMeas(OctetString ^ meas)
Expand All @@ -290,14 +290,12 @@ namespace DNP3

opendnp3::BinaryCommandEvent Conversions::ConvertMeas(BinaryCommandEvent ^ meas)
{
return opendnp3::BinaryCommandEvent(meas->Value, ConvertCommandStatus(meas->Status),
opendnp3::DNPTime(TimeStamp::Convert(meas->Timestamp)));
return opendnp3::BinaryCommandEvent(meas->Value, ConvertCommandStatus(meas->Status), ConvertTime(meas->Timestamp));
}

opendnp3::AnalogCommandEvent Conversions::ConvertMeas(AnalogCommandEvent ^ meas)
{
return opendnp3::AnalogCommandEvent(meas->Value, ConvertCommandStatus(meas->Status),
opendnp3::DNPTime(TimeStamp::Convert(meas->Timestamp)));
return opendnp3::AnalogCommandEvent(meas->Value, ConvertCommandStatus(meas->Status), ConvertTime(meas->Timestamp));
}

LinkHeader ^ Conversions::Convert(const opendnp3::LinkHeaderFields& fields)
Expand Down
2 changes: 2 additions & 0 deletions dotnet/CLRAdapter/src/Conversions.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ namespace Automatak
static AnalogCommandEvent^ Conversions::ConvertMeas(const opendnp3::AnalogCommandEvent& meas);
static SecurityStat^ Conversions::ConvertMeas(const opendnp3::SecurityStat& meas);

static opendnp3::DNPTime ConvertTime(DNPTime^ time);
static DNPTime^ ConvertTime(opendnp3::DNPTime time);

static opendnp3::Binary ConvertMeas(Binary^ meas);
static opendnp3::DoubleBitBinary ConvertMeas(DoubleBitBinary^ meas);
Expand Down
4 changes: 3 additions & 1 deletion dotnet/CLRInterface/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ add_library(DNP3CLRInterface SHARED
./src/CommandSet.cs
./src/CommandTypes.cs
./src/DefaultListenCallbacks.cs
./src/DNPTime.cs
./src/Extensions.cs
./src/Flags.cs
./src/Header.cs
Expand All @@ -25,6 +26,7 @@ add_library(DNP3CLRInterface SHARED
./src/ICommandHandler.cs
./src/ICommandProcessor.cs
./src/IDNP3Manager.cs
./src/IDnpTimeSource.cs
./src/IDatabase.cs
./src/ILinkListener.cs
./src/IListenCallbacks.cs
Expand Down Expand Up @@ -58,7 +60,7 @@ add_library(DNP3CLRInterface SHARED
./src/TaskConfig.cs
./src/TaskId.cs
./src/TaskInfo.cs
./src/Timestamp.cs
#./src/Timestamp.cs
./src/X509Info.cs

./src/config/DatabaseTemplate.cs
Expand Down
14 changes: 7 additions & 7 deletions dotnet/CLRInterface/src/BaseMeasurementTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public abstract class MeasurementBase
/// </summary>
/// <param name="quality">quality enumeration as a bitfield</param>
/// <param name="time">timestamp</param>
public MeasurementBase(Flags quality, DateTime time)
public MeasurementBase(Flags quality, DNPTime time)
{
this.quality = quality;
this.time = time;
Expand All @@ -42,13 +42,13 @@ public MeasurementBase(Flags quality, DateTime time)
public MeasurementBase(Flags quality)
{
this.quality = quality;
this.time = DateTime.MinValue;
this.time = DNPTime.Unset;
}

public MeasurementBase()
{
this.quality = new Flags();
this.time = DateTime.MinValue;
this.time = DNPTime.Unset;
}

public Flags Quality
Expand All @@ -63,7 +63,7 @@ public Flags Quality
}
}

public DateTime Timestamp
public DNPTime Timestamp
{
get
{
Expand All @@ -73,15 +73,15 @@ public DateTime Timestamp
{
time = value;
}
}
}

public override string ToString()
{
return "quality: " + quality.Value.ToString("X") + " time: " + time.ToString();
}

Flags quality;
DateTime time;
DNPTime time;
}

/// <summary>
Expand All @@ -95,7 +95,7 @@ public abstract class TypedMeasurementBase<T>: MeasurementBase
/// </summary>
/// <param name="quality">quality enumeration as a bitfield</param>
/// <param name="time">timestamp</param>
public TypedMeasurementBase(T value, Flags quality, DateTime time) : base(quality, time)
public TypedMeasurementBase(T value, Flags quality, DNPTime time) : base(quality, time)
{
this.value = value;
}
Expand Down
72 changes: 72 additions & 0 deletions dotnet/CLRInterface/src/DNPTime.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright 2013-2019 Automatak, LLC
//
// Licensed to Green Energy Corp (www.greenenergycorp.com) and Automatak
// LLC (www.automatak.com) under one or more contributor license agreements.
// See the NOTICE file distributed with this work for additional information
// regarding copyright ownership. Green Energy Corp and Automatak LLC license
// this file to you under the Apache License, Version 2.0 (the "License"); you
// may not use this file except in compliance with the License. You may obtain
// a copy of the License at:
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System;

namespace Automatak.DNP3.Interface
{
public class DNPTime
{
public static DNPTime Unset = new DNPTime(DateTime.MinValue, TimestampQuality.INVALID);
public static DNPTime Now = new DNPTime(DateTime.Now, TimestampQuality.INVALID);

private static DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
public static DNPTime FromEpoch(Int64 epochTime, TimestampQuality quality)
{
var ms = TimeSpan.FromMilliseconds(epochTime);
if (ms > DateTime.MaxValue - Epoch)
{
return new DNPTime(DateTime.MaxValue, quality);
}
else
{
return new DNPTime(Epoch.Add(ms), quality);
}
}

public DNPTime(DateTime time)
{
new DNPTime(time, TimestampQuality.INVALID);
}

public DNPTime(DateTime time, TimestampQuality quality)
{
this.value = time;
this.quality = quality;
}

public DateTime Value
{
get { return this.value; }
}

public TimestampQuality Quality
{
get { return this.quality; }
}

public UInt64 ToEpoch()
{
var ticks = (UInt64)this.value.ToUniversalTime().Subtract(Epoch).Ticks;
return ticks / TimeSpan.TicksPerMillisecond;
}

private DateTime value;
private TimestampQuality quality;
}
}
37 changes: 37 additions & 0 deletions dotnet/CLRInterface/src/IDnpTimeSource.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright 2013-2019 Automatak, LLC
//
// Licensed to Green Energy Corp (www.greenenergycorp.com) and Automatak
// LLC (www.automatak.com) under one or more contributor license agreements.
// See the NOTICE file distributed with this work for additional information
// regarding copyright ownership. Green Energy Corp and Automatak LLC license
// this file to you under the Apache License, Version 2.0 (the "License"); you
// may not use this file except in compliance with the License. You may obtain
// a copy of the License at:
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Automatak.DNP3.Interface
{
/// <summary>
/// Interface that defines a method to get DNPTime source
/// </summary>
public interface IDnpTimeSource
{
/// <summary>
/// Returns a DNPTime of the current time.
/// This value is used when freezing counters.
/// </summary>
DNPTime Now();
}
}
2 changes: 1 addition & 1 deletion dotnet/CLRInterface/src/IMasterApplication.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ public static IMasterApplication Instance

UInt64 IMasterApplication.GetMillisecondsSinceEpoch()
{
return (UInt64) TimeStamp.Convert(DateTime.Now);
return DNPTime.Now.ToEpoch();
}

void IMasterApplication.OnReceiveIIN(IINField iin)
Expand Down
7 changes: 6 additions & 1 deletion dotnet/CLRInterface/src/IOutstationApplication.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ namespace Automatak.DNP3.Interface
/// <summary>
/// Outstation application code implements this interface to interface with the stack
/// </summary>
public interface IOutstationApplication : ILinkStatusListener
public interface IOutstationApplication : ILinkStatusListener, IDnpTimeSource
{
/// <summary>
/// true of the outstation should allow absolute time to be written
Expand Down Expand Up @@ -176,5 +176,10 @@ ushort IOutstationApplication.WarmRestart()
{
return UInt16.MaxValue;
}

DNPTime IDnpTimeSource.Now()
{
return DNPTime.Unset;
}
}
}

0 comments on commit 84ef898

Please sign in to comment.