restructured WaterMeter

This commit is contained in:
Thomas Wiedebusch
2023-04-26 10:14:09 +02:00
parent 9c328a057c
commit dc16f86930
51 changed files with 3596 additions and 242 deletions
@@ -0,0 +1,146 @@
using System;
using System.Collections.Concurrent;
using System.Threading;
using Xylem.Common.CommonCore.ThreadWatcher;
using Xylem.Common.Hardware.Interfaces.Ports.PortCore.EventArguments;
using Xylem.Common.Hardware.Interfaces.Protocols.TransmitProtocol;
using Xylem.Common.Hardware.WaterMeter.ProtocolCore.EventArguments;
namespace Xylem.Common.Hardware.WaterMeter.ProtocolCore
{
/// <inheritdoc />
/// <summary>
/// Base for all protocol types
/// </summary>
public abstract class BaseProtocol : IProtocol
{
private readonly CancellationTokenSource _decodingToken = new CancellationTokenSource();
/// <inheritdoc />
public abstract event EventHandler<BaseDataEventArgs> OnRecordIsDecoded;
/// <inheritdoc />
public virtual event EventHandler<BasePortDataEventArgs> OnRecordReadyToSend;
private readonly ConcurrentQueue<IPortDataEventArgs> _decodingFifo = new ConcurrentQueue<IPortDataEventArgs>();
//initially do not signal event
private readonly AutoResetEvent _onSyncDecodingThread = new AutoResetEvent(false);
private readonly Thread _decodingThread;
/// <summary>
/// Ident is a combined string of Slot, Port, Protocol and Type
/// </summary>
public readonly String Ident;
private ITransmitProtocol _transmitProtocol;
/// <summary>
/// Starting decoding thread
/// </summary>
/// <remarks date="2018-Feb-14" author="T.Wiedebusch">
/// - Initial
/// </remarks>
protected BaseProtocol(String ident)
{
Ident = ident;
//assign thread to loop
_decodingThread = new Thread(DecodingThreadLoop) { Name = $"{Ident} Decoding thread" };
//start DecodingThread
ThreadWatcher.Instance.Start(_decodingThread);
}
/// <inheritdoc />
/// <summary>
/// Kill the decoding thread
/// </summary>
/// <remarks date="2018-Feb-14" author="T.Wiedebusch">
/// - Initial
/// </remarks>
public void Dispose()
{
//Cancel receive tokens
_decodingToken.Cancel();
//Run thread again to notice CancellationToken has changed
_onSyncDecodingThread.Set();
//this timeout counter is being used for dispose only
var timeoutCounter = 100;
while (_decodingThread.ThreadState != ThreadState.Stopped && timeoutCounter > 0)
{
Thread.Sleep(1);
timeoutCounter = timeoutCounter - 1;
}
if (_decodingThread.ThreadState != ThreadState.Stopped)
{
//if thread still running, he stuck so try to abort
// try to avoid abort (takes age to run and is not safe)
_decodingThread.Abort();
}
}
/// <summary>
/// Fill FIFO with received data
/// </summary>
/// <remarks date="2018-Feb-14" author="T.Wiedebusch">
/// - Initial
/// </remarks>
public void FillDecodingBuffer(IPortDataEventArgs data)
{
if (_decodingToken.IsCancellationRequested) return;
//put data to FIFO
_decodingFifo.Enqueue(data);
//put DecodingThread state from WaitSleepJoin to Running
_onSyncDecodingThread.Set();
}
/// <summary>
/// Decoding thread loop calling the individual decoding
/// </summary>
/// <remarks date="2018-Feb-14" author="T.Wiedebusch">
/// - Initial
/// </remarks>
private void DecodingThreadLoop()
{
try
{
while (!_decodingToken.IsCancellationRequested)
{
IPortDataEventArgs receivedRecord;
while (_decodingFifo.TryDequeue(out receivedRecord))
{
DecodeRecord(receivedRecord);
}
//put DecodingThread to WaitSleepJoin until next data arrived
_onSyncDecodingThread.WaitOne();
}
}
catch (ThreadAbortException)
{ }
}
/// <summary>
/// The decoding routine
/// </summary>
/// <param name="data"></param>
public abstract void DecodeRecord(IPortDataEventArgs data);
/// <inheritdoc />
public ITransmitProtocol GetTransmitProtocol()
{
return _transmitProtocol;
}
/// <inheritdoc />
public void SetTransmitProtocol(ITransmitProtocol transmitProtocol)
{
_transmitProtocol = transmitProtocol;
}
}
}
@@ -0,0 +1,33 @@
using System;
namespace Xylem.Common.Hardware.WaterMeter.ProtocolCore.EventArguments
{
/// <inheritdoc />
/// <summary>
/// abstract for set structure for BaseDataEventArgs
/// </summary>
public abstract class BaseDataEventArgs : EventArgs
{
/// <summary>
/// 'Base' get event record form real child.
/// </summary>
/// <returns></returns>
public Object GetData()
{
return GetEventData();
}
/// <summary>
/// get real Event record
/// </summary>
/// <returns></returns>
public abstract Object GetEventData();
/// <summary>
/// Holds the record before decoding, for logging
/// </summary>
public String RawData;
}
}
@@ -0,0 +1,20 @@
using System;
using Xylem.Common.Hardware.WaterMeter.Genesis.DataPackages.MeasurementRecords;
namespace Xylem.Common.Hardware.WaterMeter.ProtocolCore.EventArguments
{
/// <inheritdoc />
public class CalibDataEventArgs : BaseDataEventArgs
{
/// <summary>
/// Stream record for calibration on channel
/// </summary>
public CalibrationRecord CalibChl;
/// <inheritdoc />
public override Object GetEventData()
{
return CalibChl;
}
}
}
@@ -0,0 +1,20 @@
using System;
using Xylem.Common.Hardware.WaterMeter.Genesis.DataPackages.MeasurementRecords;
namespace Xylem.Common.Hardware.WaterMeter.ProtocolCore.EventArguments
{
/// <inheritdoc />
public class FlowDataEventArgs : BaseDataEventArgs
{
/// <summary>
/// new record from Stream
/// </summary>
public FlowTestRecord NewData;
/// <inheritdoc />
public override Object GetEventData()
{
return NewData;
}
}
}
@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
namespace Xylem.Common.Hardware.WaterMeter.ProtocolCore.EventArguments
{
/// <inheritdoc />
/// <summary>
/// EventArgs for Request Responses
/// </summary>
public class RequestResponseDataEventArgs : BaseDataEventArgs
{
/// <summary>
/// Request response from meter
/// </summary>
public List<Byte> RequestResponseData;
/// <inheritdoc />
public override Object GetEventData()
{
return RequestResponseData;
}
}
}
@@ -0,0 +1,42 @@
using System;
using Xylem.Common.Hardware.Interfaces.Ports.PortCore.EventArguments;
using Xylem.Common.Hardware.Interfaces.Protocols.TransmitProtocol;
using Xylem.Common.Hardware.WaterMeter.ProtocolCore.EventArguments;
namespace Xylem.Common.Hardware.WaterMeter.ProtocolCore
{
/// <inheritdoc />
/// <summary>
/// Protocol interface
/// </summary>
public interface IProtocol : IDisposable
{
/// <summary>
/// Fill the buffer with data ready for decoding
/// </summary>
/// <param name="rawData"></param>
void FillDecodingBuffer(IPortDataEventArgs rawData );
/// <summary>
/// Record is ready to send including all protocols
/// </summary>
event EventHandler<BasePortDataEventArgs> OnRecordReadyToSend;
/// <summary>
/// Record is successfully decoded and ready for further processing
/// </summary>
event EventHandler<BaseDataEventArgs> OnRecordIsDecoded;
/// <summary>
/// Return of transmit protocol settings
/// </summary>
/// <returns></returns>
ITransmitProtocol GetTransmitProtocol();
/// <summary>
/// Assignment of transmit protocol
/// </summary>
/// <param name="transmitProtocol"></param>
void SetTransmitProtocol(ITransmitProtocol transmitProtocol);
}
}
@@ -0,0 +1,7 @@
using System.Runtime.InteropServices;
using System.Reflection;
[assembly: AssemblyTitle("Xylem.Common.Hardware.WaterMeter.ProtocolCore")]
[assembly: AssemblyDescription("")]
[assembly: Guid("1A402949-095C-4039-8AE3-6594A7FB2242")]
@@ -0,0 +1,219 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{8BDD2789-96D4-43EA-AAD7-0F49D0347998}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Xylem.Common.Hardware.WaterMeter.ProtocolCore</RootNamespace>
<AssemblyName>Xylem.Common.Hardware.WaterMeter.ProtocolCore</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<TargetFrameworkProfile />
<SccProjectName>SAK</SccProjectName>
<SccLocalPath>SAK</SccLocalPath>
<SccAuxPath>SAK</SccAuxPath>
<SccProvider>SAK</SccProvider>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<LangVersion>7.0</LangVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<LangVersion>7.0</LangVersion>
</PropertyGroup>
<PropertyGroup>
<StartupObject />
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<LangVersion>6</LangVersion>
<DocumentationFile>bin\x86\Debug\Xylem.Common.Hardware.WaterMeter.ProtocolCore.xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'XP32bit|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\XP32bit\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<LangVersion>7.0</LangVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'XP32bit|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\XP32bit\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'XP32bit|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\XP32bit\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup>
<SignAssembly>false</SignAssembly>
</PropertyGroup>
<PropertyGroup>
<AssemblyOriginatorKeyFile>
</AssemblyOriginatorKeyFile>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'PerformTest|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\PerformTest\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<LangVersion>7.0</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'PerformTest|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\PerformTest\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'PerformTest|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\PerformTest\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == '_MANUAL_CONTROL|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\_MANUAL_CONTROL\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<LangVersion>7.0</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == '_MANUAL_CONTROL|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\_MANUAL_CONTROL\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DocumentationFile>bin\x86\Debug\Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.ProtocolCore.xml</DocumentationFile>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<LangVersion>6</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == '_MANUAL_CONTROL|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\_MANUAL_CONTROL\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
</ItemGroup>
<ItemGroup>
<Compile Include="BaseProtocol.cs" />
<Compile Include="EventArguments\BaseDataEventArgs.cs" />
<Compile Include="EventArguments\CalibDataEventArgs.cs" />
<Compile Include="EventArguments\FlowDataEventArgs.cs" />
<Compile Include="EventArguments\RequestResponseDataEventArgs.cs" />
<Compile Include="IProtocol.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\CommonCore\ThreadWatcher\ThreadWatcher.csproj">
<Project>{94ca71f3-c5d7-4ec6-ba47-fa8eea3c9406}</Project>
<Name>ThreadWatcher</Name>
</ProjectReference>
<ProjectReference Include="..\..\Interfaces\Ports\PortCore\PortCore.csproj">
<Project>{2e139f63-b6fe-4ea9-a098-85364fe9b26c}</Project>
<Name>PortCore</Name>
</ProjectReference>
<ProjectReference Include="..\..\Interfaces\Protocols\TransmitProtocol\TransmitProtocol.csproj">
<Project>{63E0AC5E-B7C8-4363-A2FE-BE489E648FF0}</Project>
<Name>TransmitProtocol</Name>
</ProjectReference>
<ProjectReference Include="..\Genesis\DataPackages\DataPackages.csproj">
<Project>{0e524d43-7b66-45cd-aa74-41d51afc3d99}</Project>
<Name>DataPackages</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="12.0.3" targetFramework="net40" />
<package id="NLog" version="4.6.7" targetFramework="net40" />
</packages>