Compare commits
12
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a1bb1ff079 | ||
|
|
db4ac6a838 | ||
|
|
a0201427ca | ||
|
|
202eef0d46 | ||
|
|
988a8c6642 | ||
|
|
42ee9eaee3 | ||
|
|
3f28051d79 | ||
|
|
65f13cc868 | ||
|
|
cd8ba3cda3 | ||
|
|
a5936c8f19 | ||
|
|
2842425673 | ||
|
|
daad73ff81 |
@@ -34,6 +34,8 @@ MergeResultsDBs/bin/
|
||||
MergeResultsDBs/obj/
|
||||
NfcC7_Dll/bin/
|
||||
NfcC7_Dll/obj/
|
||||
NfcC7_DLL.Tests/bin/
|
||||
NfcC7_DLL.Tests/obj/
|
||||
OrderManagement/bin/
|
||||
OrderManagement/obj/
|
||||
ProductionTracing/bin/
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using SharedComponents;
|
||||
using SharedComponents;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using SharedComponents;
|
||||
using SharedComponents;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
|
||||
Generated
+1
-1
@@ -1,4 +1,4 @@
|
||||
using System.Windows.Forms;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace AppDiagnostic
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using log4net.Config;
|
||||
using log4net.Config;
|
||||
using log4net;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Reflection;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
// <autogenerated />
|
||||
using System;
|
||||
using System.Reflection;
|
||||
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
|
||||
@@ -0,0 +1,4 @@
|
||||
// <autogenerated />
|
||||
using System;
|
||||
using System.Reflection;
|
||||
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
|
||||
+197
-1
@@ -33,6 +33,18 @@
|
||||
<Reference Include="log4net, Version=2.0.15.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\log4net.2.0.15\lib\net45\log4net.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Logic.ProductionToProductMapper, Version=1.0.3.24128, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>Cordonel\Common\Logic.ProductionToProductMapper.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>Cordonel\Common\NLog.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="PdfSharp.resources, Version=1.50.5147.0, Culture=de, PublicKeyToken=f94615aa0424f9eb, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>Cordonel\Common\de\PdfSharp.resources.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Drawing" />
|
||||
@@ -42,6 +54,90 @@
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="Xylem.Common.Hardware.WaterMeter.Genesis.Applications.resources, Version=1.0.3.24125, Culture=de, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>Cordonel\Common\de\Xylem.Common.Hardware.WaterMeter.Genesis.Applications.resources.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore.resources, Version=1.0.3.24134, Culture=de, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>Cordonel\Common\de\Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore.resources.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile.resources, Version=1.0.3.24134, Culture=de, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>Cordonel\Common\de\Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile.resources.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.ProtocolCore, Version=1.0.3.24127, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>Cordonel\Common\Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.ProtocolCore.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.RequestProtocol, Version=1.0.3.24127, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>Cordonel\Common\Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.RequestProtocol.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.StreamingProtocol, Version=1.0.3.24127, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>Cordonel\Common\Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.StreamingProtocol.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Xylem.Common.Hardware.WaterMeter.Genesis.Registers, Version=1.0.3.24126, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>Cordonel\Common\Xylem.Common.Hardware.WaterMeter.Genesis.Registers.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Xylem.Common.Hardware.WaterMeter.WaterMeterCore, Version=1.0.3.24126, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>Cordonel\Common\Xylem.Common.Hardware.WaterMeter.WaterMeterCore.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Xylem.Common.Hardware.WaterMeter.WaterMeterRegisters, Version=1.0.3.24125, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>Cordonel\Common\Xylem.Common.Hardware.WaterMeter.WaterMeterRegisters.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Xylem.Common.Logic.ProductionOrderCore, Version=1.0.3.24128, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>Cordonel\Common\Xylem.Common.Logic.ProductionOrderCore.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Xylem.Common.Logic.RelatePcb, Version=1.0.3.24125, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>Cordonel\Common\Xylem.Common.Logic.RelatePcb.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Xylem.Common.Logic.ServiceCore, Version=1.0.3.24125, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>Cordonel\Common\Xylem.Common.Logic.ServiceCore.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Xylem.Common.Logic.SoftwareAccessHelper, Version=1.0.3.24125, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>Cordonel\Common\Xylem.Common.Logic.SoftwareAccessHelper.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Xylem.Common.Metrology.Measurements, Version=1.0.3.24125, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>Cordonel\Common\Xylem.Common.Metrology.Measurements.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Xylem.Common.Ui.CordonelPreadjustmentUi, Version=2.1.7944.24134, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>Cordonel\Common\Xylem.Common.Ui.CordonelPreadjustmentUi.exe</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Xylem.Common.Ui.GenesisToolBox, Version=1.0.3.24135, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>Cordonel\Common\Xylem.Common.Ui.GenesisToolBox.exe</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Xylem.Common.Utils.ByteArrayStyle, Version=1.0.3.24125, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>Cordonel\Common\Xylem.Common.Utils.ByteArrayStyle.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Xylem.Common.Utils.Crc16Ccitt, Version=1.0.3.24125, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>Cordonel\Common\Xylem.Common.Utils.Crc16Ccitt.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Xylem.Common.Utils.Logging, Version=1.0.3.24125, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>Cordonel\Common\Xylem.Common.Utils.Logging.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Xylem.Common.Utils.ProcessExec, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>Cordonel\Common\Xylem.Common.Utils.ProcessExec.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="XylemCommonUiLegacyGenCtl, Version=1.0.3.24134, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>Cordonel\Common\XylemCommonUiLegacyGenCtl.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="BackgroundBeep.cs" />
|
||||
@@ -90,7 +186,19 @@
|
||||
<Compile Include="Utils.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<ItemGroup>
|
||||
<None Include="Cordonel\Common\configuration.json" />
|
||||
<None Include="Cordonel\Common\Logic.ProductionToProductMapper.dll.config" />
|
||||
<None Include="Cordonel\Common\meterconfig.json" />
|
||||
<None Include="Cordonel\Common\MeterFilesEraseRestore.json" />
|
||||
<None Include="Cordonel\Common\status.json" />
|
||||
<None Include="Cordonel\Common\Xylem.Common.Hardware.WaterMeter.Genesis.Applications.dll.config" />
|
||||
<None Include="Cordonel\Common\Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore.dll.config" />
|
||||
<None Include="Cordonel\Common\Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile.dll.config" />
|
||||
<None Include="Cordonel\Common\Xylem.Common.Ui.CordonelPreadjustmentUi.exe.config" />
|
||||
<None Include="Cordonel\Common\Xylem.Common.Ui.GenesisToolBox.exe.config" />
|
||||
<None Include="Cordonel\Common\XylemCommonUiLegacyGenCtl.dll.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Forms\ListViewEx.resx">
|
||||
<DependentUpon>ListViewEx.cs</DependentUpon>
|
||||
@@ -99,6 +207,94 @@
|
||||
<DependentUpon>ModelessForm.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Cordonel\Common\de\PdfSharp.resources.dll" />
|
||||
<Content Include="Cordonel\Common\de\Xylem.Common.Hardware.WaterMeter.Genesis.Applications.resources.dll" />
|
||||
<Content Include="Cordonel\Common\de\Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore.resources.dll" />
|
||||
<Content Include="Cordonel\Common\de\Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile.resources.dll" />
|
||||
<Content Include="Cordonel\Common\Logic.ProductionToProductMapper.dll" />
|
||||
<Content Include="Cordonel\Common\Logic.ProductionToProductMapper.pdb" />
|
||||
<Content Include="Cordonel\Common\Newtonsoft.Json.dll" />
|
||||
<Content Include="Cordonel\Common\Newtonsoft.Json.xml" />
|
||||
<Content Include="Cordonel\Common\NLog.dll" />
|
||||
<Content Include="Cordonel\Common\NLog.xml" />
|
||||
<Content Include="Cordonel\Common\NlogConfig.xml" />
|
||||
<Content Include="Cordonel\Common\PdfSharp.dll" />
|
||||
<Content Include="Cordonel\Common\PdfSharp.xml" />
|
||||
<Content Include="Cordonel\Common\RestSharp.dll" />
|
||||
<Content Include="Cordonel\Common\RestSharp.xml" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.CommonCore.Configuration.dll" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.CommonCore.Configuration.pdb" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.CommonCore.dll" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.CommonCore.pdb" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.CommonCore.ThreadWatcher.dll" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.CommonCore.ThreadWatcher.pdb" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Hardware.Interfaces.Ports.PortCore.dll" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Hardware.Interfaces.Ports.PortCore.pdb" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Hardware.Interfaces.Ports.PortCore.xml" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Hardware.Interfaces.Ports.SerialPorts.dll" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Hardware.Interfaces.Ports.SerialPorts.pdb" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Hardware.Interfaces.Protocols.TransmitProtocol.dll" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Hardware.Interfaces.Protocols.TransmitProtocol.pdb" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Hardware.WaterMeter.Genesis.Applications.dll" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Hardware.WaterMeter.Genesis.Applications.pdb" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Hardware.WaterMeter.Genesis.DataPackages.dll" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Hardware.WaterMeter.Genesis.DataPackages.pdb" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Hardware.WaterMeter.Genesis.DataPackages.xml" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Hardware.WaterMeter.Genesis.GenesisConfig.dll" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Hardware.WaterMeter.Genesis.GenesisConfig.pdb" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore.dll" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore.pdb" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore.xml" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile.dll" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile.pdb" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Hardware.WaterMeter.Genesis.GenesisPwd.dll" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Hardware.WaterMeter.Genesis.GenesisPwd.pdb" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.ProtocolCore.dll" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.ProtocolCore.pdb" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.RequestProtocol.dll" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.RequestProtocol.pdb" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.RequestProtocol.xml" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.StreamingProtocol.dll" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.StreamingProtocol.pdb" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.StreamingProtocol.xml" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Hardware.WaterMeter.Genesis.Registers.dll" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Hardware.WaterMeter.Genesis.Registers.pdb" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Hardware.WaterMeter.WaterMeterCore.dll" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Hardware.WaterMeter.WaterMeterCore.pdb" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Hardware.WaterMeter.WaterMeterCore.xml" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Hardware.WaterMeter.WaterMeterRegisters.dll" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Hardware.WaterMeter.WaterMeterRegisters.pdb" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Logic.ProductionOrderCore.dll" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Logic.ProductionOrderCore.pdb" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Logic.RelatePcb.dll" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Logic.RelatePcb.pdb" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Logic.ServiceCore.dll" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Logic.ServiceCore.pdb" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Logic.SoftwareAccessHelper.dll" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Logic.SoftwareAccessHelper.pdb" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Metrology.Measurements.dll" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Metrology.Measurements.pdb" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Metrology.Measurements.xml" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Ui.CordonelPreadjustmentUi.exe" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Ui.CordonelPreadjustmentUi.pdb" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Ui.GenesisToolBox.exe" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Ui.GenesisToolBox.pdb" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Utils.ByteArrayStyle.dll" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Utils.ByteArrayStyle.pdb" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Utils.Crc16Ccitt.dll" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Utils.Crc16Ccitt.pdb" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Utils.Logging.dll" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Utils.Logging.pdb" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Utils.ProcessExec.dll" />
|
||||
<Content Include="Cordonel\Common\Xylem.Common.Utils.ProcessExec.pdb" />
|
||||
<Content Include="Cordonel\Common\XylemCommonUiLegacyGenCtl.dll" />
|
||||
<Content Include="Cordonel\Common\XylemCommonUiLegacyGenCtl.pdb" />
|
||||
<Content Include="Cordonel\Greisinger\GMH3x32E.dll" />
|
||||
<Content Include="Cordonel\Greisinger\RegAsm4.exe" />
|
||||
<Content Include="Cordonel\Sirt\SIRTCOM.dll" />
|
||||
<Content Include="Cordonel\Sirt\SIRT_Driver_Win32_PC.dll" />
|
||||
</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.
|
||||
|
||||
@@ -6,10 +6,6 @@
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||
<WarningLevel>0</WarningLevel>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2023.3.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
|
||||
|
||||
+1
-6
@@ -11,7 +11,6 @@ using NHibernate.Cfg;
|
||||
using NHibernate.Tool.hbm2ddl;
|
||||
using Common;
|
||||
using Results.Entities;
|
||||
using Results.Entities.helpers;
|
||||
|
||||
namespace Results
|
||||
{
|
||||
@@ -108,11 +107,7 @@ namespace Results
|
||||
throw new Exception("Connection string was not specified");
|
||||
}
|
||||
|
||||
if (SessionFactory == null)
|
||||
{
|
||||
DatabaseMigrationHelper.EnsureSchema(dbType, connectionString);
|
||||
SessionFactory = CreateSessionFactory();
|
||||
}
|
||||
if (SessionFactory == null) SessionFactory = CreateSessionFactory();
|
||||
|
||||
return SessionFactory.OpenSession();
|
||||
}
|
||||
|
||||
@@ -1,158 +0,0 @@
|
||||
using System;
|
||||
using Common;
|
||||
using log4net;
|
||||
using MySql.Data.MySqlClient;
|
||||
|
||||
namespace Results.Entities.helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Applies explicit, backwards-compatible results DB migrations before the
|
||||
/// first NHibernate session factory is created.
|
||||
/// </summary>
|
||||
public static class DatabaseMigrationHelper
|
||||
{
|
||||
private static readonly ILog log = LogManager.GetLogger(typeof(DatabaseMigrationHelper));
|
||||
|
||||
public static void EnsureSchema(DBType dbType, string connectionString)
|
||||
{
|
||||
switch (dbType)
|
||||
{
|
||||
case DBType.MySql:
|
||||
EnsureMySqlSchema(connectionString);
|
||||
break;
|
||||
case DBType.SQLite:
|
||||
EnsureSQLiteSchema(connectionString);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void EnsureMySqlSchema(string connectionString)
|
||||
{
|
||||
using (var conn = new MySqlConnection(connectionString))
|
||||
{
|
||||
conn.Open();
|
||||
|
||||
// Added by newer MeterTestRslt mapping; older customer DBs do
|
||||
// not contain it and otherwise reject the entire batch insert.
|
||||
EnsureColumnMySql(conn, "MeterTestRslt", "PulsesPerKilogram", "DOUBLE NOT NULL DEFAULT 0");
|
||||
EnsureColumnMySql(conn, "MeterTestRslt", "FlipMode", "INT NULL");
|
||||
EnsureColumnMySql(conn, "MeterTestRslt", "ExtraDataPath", "VARCHAR(255) NULL");
|
||||
EnsureMeterTestResultExtraColumnsMySql(conn);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EnsureMeterTestResultExtraColumnsMySql(MySqlConnection conn)
|
||||
{
|
||||
for (int index = 1; index <= 9; index++)
|
||||
{
|
||||
EnsureColumnMySql(conn, "MeterTestRslt", "X" + index, "FLOAT NOT NULL DEFAULT 0");
|
||||
}
|
||||
}
|
||||
|
||||
private static void EnsureColumnMySql(
|
||||
MySqlConnection conn,
|
||||
string tableName,
|
||||
string columnName,
|
||||
string columnDefinition)
|
||||
{
|
||||
using (var transaction = conn.BeginTransaction())
|
||||
{
|
||||
try
|
||||
{
|
||||
bool exists;
|
||||
using (var cmd = conn.CreateCommand())
|
||||
{
|
||||
cmd.Transaction = transaction;
|
||||
cmd.CommandText = @"
|
||||
SELECT COUNT(*)
|
||||
FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE TABLE_SCHEMA = DATABASE()
|
||||
AND TABLE_NAME = @tableName
|
||||
AND COLUMN_NAME = @columnName";
|
||||
cmd.Parameters.AddWithValue("@tableName", tableName);
|
||||
cmd.Parameters.AddWithValue("@columnName", columnName);
|
||||
exists = Convert.ToInt32(cmd.ExecuteScalar()) > 0;
|
||||
}
|
||||
|
||||
if (!exists)
|
||||
{
|
||||
using (var alter = conn.CreateCommand())
|
||||
{
|
||||
alter.Transaction = transaction;
|
||||
alter.CommandText = "ALTER TABLE `" + tableName + "` ADD COLUMN `" +
|
||||
columnName + "` " + columnDefinition;
|
||||
alter.ExecuteNonQuery();
|
||||
log.WarnFormat("Results DB migration: added {0}.{1} ({2}).",
|
||||
tableName, columnName, columnDefinition);
|
||||
}
|
||||
}
|
||||
|
||||
transaction.Commit();
|
||||
}
|
||||
catch
|
||||
{
|
||||
transaction.Rollback();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void EnsureSQLiteSchema(string databaseFile)
|
||||
{
|
||||
using (var conn = new System.Data.SQLite.SQLiteConnection("Data Source=" + databaseFile))
|
||||
{
|
||||
conn.Open();
|
||||
|
||||
EnsureColumnSQLite(conn, "MeterTestRslt", "PulsesPerKilogram", "REAL NOT NULL DEFAULT 0");
|
||||
EnsureColumnSQLite(conn, "MeterTestRslt", "FlipMode", "INTEGER NULL");
|
||||
EnsureColumnSQLite(conn, "MeterTestRslt", "ExtraDataPath", "TEXT NULL");
|
||||
EnsureMeterTestResultExtraColumnsSQLite(conn);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EnsureMeterTestResultExtraColumnsSQLite(System.Data.SQLite.SQLiteConnection conn)
|
||||
{
|
||||
for (int index = 1; index <= 9; index++)
|
||||
{
|
||||
EnsureColumnSQLite(conn, "MeterTestRslt", "X" + index, "REAL NOT NULL DEFAULT 0");
|
||||
}
|
||||
}
|
||||
|
||||
private static void EnsureColumnSQLite(
|
||||
System.Data.SQLite.SQLiteConnection conn,
|
||||
string tableName,
|
||||
string columnName,
|
||||
string columnDefinition)
|
||||
{
|
||||
bool exists = false;
|
||||
using (var cmd = conn.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = "PRAGMA table_info(" + tableName + ")";
|
||||
using (var reader = cmd.ExecuteReader())
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
if (string.Equals(reader["name"].ToString(), columnName,
|
||||
StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
exists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!exists)
|
||||
{
|
||||
using (var alter = conn.CreateCommand())
|
||||
{
|
||||
alter.CommandText = "ALTER TABLE " + tableName + " ADD COLUMN " +
|
||||
columnName + " " + columnDefinition;
|
||||
alter.ExecuteNonQuery();
|
||||
log.WarnFormat("Results DB migration: added {0}.{1} ({2}).",
|
||||
tableName, columnName, columnDefinition);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -53,9 +53,6 @@
|
||||
<Reference Include="NHibernate">
|
||||
<HintPath>..\packages\NHibernate.4.0.4.4000\lib\net40\NHibernate.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Data.SQLite, Version=2.0.3.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Data.SQLite.2.0.3\lib\net471\System.Data.SQLite.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Drawing" />
|
||||
@@ -72,7 +69,6 @@
|
||||
<Compile Include="DBase.cs" />
|
||||
<Compile Include="Entities\Batch.cs" />
|
||||
<Compile Include="Entities\Components.cs" />
|
||||
<Compile Include="Entities\helpers\DatabaseMigrationHelper.cs" />
|
||||
<Compile Include="Entities\MeterTestRslt.cs" />
|
||||
<Compile Include="Entities\PurchaseBox.cs" />
|
||||
<Compile Include="Entities\PurchaseOrder.cs" />
|
||||
@@ -269,4 +265,4 @@
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.IO.MemoryMappedFiles;
|
||||
using System.IO.MemoryMappedFiles;
|
||||
using System.Text;
|
||||
|
||||
namespace SharedComponents
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
// <autogenerated />
|
||||
using System;
|
||||
using System.Reflection;
|
||||
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
|
||||
@@ -0,0 +1,23 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
[assembly: System.Reflection.AssemblyCompanyAttribute("SharedComponents")]
|
||||
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
||||
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+498fc21412f36768d9ff9d2abd4fd377ea0bf3ae")]
|
||||
[assembly: System.Reflection.AssemblyProductAttribute("SharedComponents")]
|
||||
[assembly: System.Reflection.AssemblyTitleAttribute("SharedComponents")]
|
||||
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||
|
||||
// Generated by the MSBuild WriteCodeFragment class.
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
// <autogenerated />
|
||||
using System;
|
||||
using System.Reflection;
|
||||
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
|
||||
@@ -0,0 +1,23 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
[assembly: System.Reflection.AssemblyCompanyAttribute("SharedComponents")]
|
||||
[assembly: System.Reflection.AssemblyConfigurationAttribute("Release")]
|
||||
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+498fc21412f36768d9ff9d2abd4fd377ea0bf3ae")]
|
||||
[assembly: System.Reflection.AssemblyProductAttribute("SharedComponents")]
|
||||
[assembly: System.Reflection.AssemblyTitleAttribute("SharedComponents")]
|
||||
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||
|
||||
// Generated by the MSBuild WriteCodeFragment class.
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
// <auto-generated/>
|
||||
global using global::System;
|
||||
global using global::System.Collections.Generic;
|
||||
global using global::System.IO;
|
||||
global using global::System.Linq;
|
||||
global using global::System.Threading;
|
||||
global using global::System.Threading.Tasks;
|
||||
@@ -0,0 +1,4 @@
|
||||
// <autogenerated />
|
||||
using System;
|
||||
using System.Reflection;
|
||||
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v8.0", FrameworkDisplayName = ".NET 8.0")]
|
||||
@@ -0,0 +1,23 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
[assembly: System.Reflection.AssemblyCompanyAttribute("SharedComponents")]
|
||||
[assembly: System.Reflection.AssemblyConfigurationAttribute("Release")]
|
||||
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+498fc21412f36768d9ff9d2abd4fd377ea0bf3ae")]
|
||||
[assembly: System.Reflection.AssemblyProductAttribute("SharedComponents")]
|
||||
[assembly: System.Reflection.AssemblyTitleAttribute("SharedComponents")]
|
||||
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||
|
||||
// Generated by the MSBuild WriteCodeFragment class.
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
// <auto-generated/>
|
||||
global using global::System;
|
||||
global using global::System.Collections.Generic;
|
||||
global using global::System.IO;
|
||||
global using global::System.Linq;
|
||||
global using global::System.Net.Http;
|
||||
global using global::System.Threading;
|
||||
global using global::System.Threading.Tasks;
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
||||
<RestoreSuccess Condition=" '$(RestoreSuccess)' == '' ">True</RestoreSuccess>
|
||||
@@ -7,7 +7,7 @@
|
||||
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">$(UserProfile)\.nuget\packages\</NuGetPackageRoot>
|
||||
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">C:\Users\micha\.nuget\packages\</NuGetPackageFolders>
|
||||
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
|
||||
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">6.14.0</NuGetToolVersion>
|
||||
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">7.0.0</NuGetToolVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
||||
<SourceRoot Include="C:\Users\micha\.nuget\packages\" />
|
||||
|
||||
@@ -106,6 +106,13 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LabelPrinting", "LabelPrint
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TBFTests", "TBFTests\TBFTests.csproj", "{77EB589F-C670-4489-AAD6-2A3C02061FD1}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AppDiagnostic", "AppDiagnostic\AppDiagnostic.csproj", "{FA9ABAD1-7184-4295-ADE8-D44F2E3DE6B2}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{8F942729-F454-4C99-BA6C-746962065AE3} = {8F942729-F454-4C99-BA6C-746962065AE3}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharedComponents", "SharedComponents\SharedComponents.csproj", "{8F942729-F454-4C99-BA6C-746962065AE3}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sensus.iPerl.RfidCom", "..\iPerlHead\Sensus.iPerl.RfidCom\Sensus.iPerl.RfidCom.csproj", "{A3E14180-7F00-42E5-94A9-8DB62EAD6EE8}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sensus.iPerl.TestConsole", "..\iPerlHead\Sensus.iPerl.TestConsole\Sensus.iPerl.TestConsole.csproj", "{5025ED8B-A94F-4E58-8BE0-68481B061609}"
|
||||
@@ -114,6 +121,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NfcS5_DLL", "..\NfcS5_DLL\N
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NfcC7_DLL", "NfcC7_DLL\NfcC7_DLL.csproj", "{53E75979-B530-4805-8FC9-B314F14A62BE}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NfcC7_DLL.Tests", "NfcC7_DLL.Tests\NfcC7_DLL.Tests.csproj", "{715605C5-568B-48D6-9C09-2DC5F2E81F66}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -474,6 +483,30 @@ Global
|
||||
{77EB589F-C670-4489-AAD6-2A3C02061FD1}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{77EB589F-C670-4489-AAD6-2A3C02061FD1}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{77EB589F-C670-4489-AAD6-2A3C02061FD1}.Release|x86.Build.0 = Release|Any CPU
|
||||
{FA9ABAD1-7184-4295-ADE8-D44F2E3DE6B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FA9ABAD1-7184-4295-ADE8-D44F2E3DE6B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FA9ABAD1-7184-4295-ADE8-D44F2E3DE6B2}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{FA9ABAD1-7184-4295-ADE8-D44F2E3DE6B2}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{FA9ABAD1-7184-4295-ADE8-D44F2E3DE6B2}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{FA9ABAD1-7184-4295-ADE8-D44F2E3DE6B2}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{FA9ABAD1-7184-4295-ADE8-D44F2E3DE6B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FA9ABAD1-7184-4295-ADE8-D44F2E3DE6B2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{FA9ABAD1-7184-4295-ADE8-D44F2E3DE6B2}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{FA9ABAD1-7184-4295-ADE8-D44F2E3DE6B2}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{FA9ABAD1-7184-4295-ADE8-D44F2E3DE6B2}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{FA9ABAD1-7184-4295-ADE8-D44F2E3DE6B2}.Release|x86.Build.0 = Release|Any CPU
|
||||
{8F942729-F454-4C99-BA6C-746962065AE3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8F942729-F454-4C99-BA6C-746962065AE3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8F942729-F454-4C99-BA6C-746962065AE3}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{8F942729-F454-4C99-BA6C-746962065AE3}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{8F942729-F454-4C99-BA6C-746962065AE3}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{8F942729-F454-4C99-BA6C-746962065AE3}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{8F942729-F454-4C99-BA6C-746962065AE3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8F942729-F454-4C99-BA6C-746962065AE3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8F942729-F454-4C99-BA6C-746962065AE3}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{8F942729-F454-4C99-BA6C-746962065AE3}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{8F942729-F454-4C99-BA6C-746962065AE3}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{8F942729-F454-4C99-BA6C-746962065AE3}.Release|x86.Build.0 = Release|Any CPU
|
||||
{A3E14180-7F00-42E5-94A9-8DB62EAD6EE8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A3E14180-7F00-42E5-94A9-8DB62EAD6EE8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A3E14180-7F00-42E5-94A9-8DB62EAD6EE8}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
@@ -522,6 +555,18 @@ Global
|
||||
{53E75979-B530-4805-8FC9-B314F14A62BE}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{53E75979-B530-4805-8FC9-B314F14A62BE}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{53E75979-B530-4805-8FC9-B314F14A62BE}.Release|x86.Build.0 = Release|Any CPU
|
||||
{715605C5-568B-48D6-9C09-2DC5F2E81F66}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{715605C5-568B-48D6-9C09-2DC5F2E81F66}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{715605C5-568B-48D6-9C09-2DC5F2E81F66}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{715605C5-568B-48D6-9C09-2DC5F2E81F66}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{715605C5-568B-48D6-9C09-2DC5F2E81F66}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{715605C5-568B-48D6-9C09-2DC5F2E81F66}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{715605C5-568B-48D6-9C09-2DC5F2E81F66}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{715605C5-568B-48D6-9C09-2DC5F2E81F66}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{715605C5-568B-48D6-9C09-2DC5F2E81F66}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{715605C5-568B-48D6-9C09-2DC5F2E81F66}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{715605C5-568B-48D6-9C09-2DC5F2E81F66}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{715605C5-568B-48D6-9C09-2DC5F2E81F66}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -19,9 +19,6 @@ using System.Runtime.InteropServices;
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
//Visibility to TBFTests internal classes
|
||||
[assembly: InternalsVisibleTo("TBFTests")]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("2c13538e-15ee-48b2-af0f-2c95afb67186")]
|
||||
|
||||
@@ -32,5 +29,5 @@ using System.Runtime.InteropServices;
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("3.9.2206.0")]
|
||||
[assembly: AssemblyFileVersion("3.9.2206.0")]
|
||||
[assembly: AssemblyVersion("3.9.2149.4")]
|
||||
[assembly: AssemblyFileVersion("3.9.2149.4")]
|
||||
|
||||
+3
-13
@@ -1,15 +1,5 @@
|
||||
## Version History
|
||||
|
||||
| Version | Target Environment | Title | Description |
|
||||
|------------|--------------------------------------------------------------|-----------------------------------------------------|------------------------------------|
|
||||
| 3.9.2149.0 | HeatMeters, Heat meter sensors, Procedure Dilog, Tab Process | Excanged columns value 'Sensor' and 'Heat meter sensor' | Fix in code ProcedureDlg, row 1851 |
|
||||
| 3.9.2149.1 | General release | Version iteration | Assembly and file version increment. |
|
||||
| 3.9.2149.2 | Poseidon register reader | Poseidon pulse and timing handling | Added reference-pulse reading in `Run()` and improved Poseidon timing/task tracking. |
|
||||
| 3.9.2149.4 | Mass collection / Poseidon start-stop | Mass collection update | Refactored standing-start mass collection, extended Poseidon start/end data-entry configuration and improved dialog/task handling. |
|
||||
| 3.9.2200.1 | Test infrastructure | TBF test assembly access | Added `InternalsVisibleTo` support for `TBFTests`. |
|
||||
| 3.9.2201.1 | Poseidon CLI | Poseidon CLI configuration | Added macro descriptions, refined serial-port/CLI argument configuration and extended CLI test coverage. |
|
||||
| 3.9.2202.1 | Poseidon CLI | CLI release iteration | Assembly and file version increment for the Poseidon CLI workstream. |
|
||||
| 3.9.2203.1 | Poseidon CLI / smart-meter sequence | CLI test and configuration update | Updated CLI executable test setup, serial-port default responses and smart-meter component-name handling. |
|
||||
| 3.9.2204.1 | Morrisville / Poseidon CLI | Morrisville CLI diagnostics | Restored lost 2204 versioning, added detailed CLI command/response logging and used a fixed CLI directory for deployment. |
|
||||
| 3.9.2205.1 | Morrisville / Poseidon CLI / Results DB | Poseidon read diagnostics and results DB migration | Improved Poseidon CLI execution and diagnostics (fixed CLI working directory, exit code/stdout/stderr capture, JSON/NFC/reading validation and culture-independent decimal parsing). Added reader-cycle and fake-CLI test coverage. Prevented a device/CLI error while changing the legacy optical-head mode from crashing the UI. Results DB now creates missing `MeterTestRslt` compatibility columns (`FlipMode`, `ExtraDataPath`, `X1`-`X9`) automatically for MySQL and SQLite before results are saved. |
|
||||
| 3.9.2206.0 | Morrisville / Poseidon CLI / Results DB | Poseidon start/end rearm and simulation isolation | Fixed the Poseidon start/end read cycle so a completed START reader is armed again once for END, preventing reused START values or skipped END CLI calls. Added trace logging for CLI response, dialog prefill and confirmed dialog values. In `Simulate` mode, `PoseidonCmdStartStop` now always runs the fixed `C:\TBF\Cli\cmdSleepTest.exe` instead of the configured physical Hat CLI. Added regression tests for customer CLI JSON responses, decimal comma/dot and non-zero readings, start/end dialog transfer, full/reduced reader cycles and simulation CLI selection. Extended results-schema migration with `MeterTestRslt.PulsesPerKilogram`. |
|
||||
| Version | Source of change | Target Environment | Title | Description |
|
||||
|------------|----------------------|--------------------------------------------------------------|-----------------------------------------------------|------------------------------------|
|
||||
| 3.9.2149.0 | Michal databse error | HeatMeters, Heat meter sensors, Procedure Dilog, Tab Process | Excanged columns value 'Sensor' and 'Heat meter sensor' | Fix in code ProcedureDlg, row 1851 |
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
/// Copyright (c) 2021-2023 Sensus Slovensko a.s.
|
||||
///
|
||||
using System;
|
||||
using Common;
|
||||
using log4net;
|
||||
using TBF.Rig.Sequences;
|
||||
|
||||
@@ -11,6 +12,10 @@ namespace TBF.Rig.ControlBoard.Uni
|
||||
{
|
||||
private static readonly ILog log = LogManager.GetLogger(typeof(FlyingStartStopTestOp));
|
||||
public override string ToString() { return string.Format("FlyingStartStopTestOp()"); }
|
||||
|
||||
private DateTime startTimeForSimulation;
|
||||
private bool simulationTimerStarted = false;
|
||||
|
||||
|
||||
/// Arguments of the constructor
|
||||
readonly UniCB uniCB;
|
||||
@@ -123,6 +128,28 @@ namespace TBF.Rig.ControlBoard.Uni
|
||||
{
|
||||
log.DebugFormat("Op.Run() opState={0}", opState);
|
||||
|
||||
//Simulation of processing time 25 seconds
|
||||
if (uniCB.DebugLevel == DebugMode.Simulate)
|
||||
{
|
||||
if (opState == OpState.StartingTest)
|
||||
{
|
||||
startTimeForSimulation = DateTime.Now;
|
||||
simulationTimerStarted = false;
|
||||
}
|
||||
if (opState == OpState.TestInProgress)
|
||||
{
|
||||
if (!simulationTimerStarted)
|
||||
{
|
||||
startTimeForSimulation = DateTime.Now;
|
||||
simulationTimerStarted = true;
|
||||
}
|
||||
else if (DateTime.Now - startTimeForSimulation > TimeSpan.FromSeconds(25))
|
||||
{
|
||||
return Event.TestCompleted;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (opState)
|
||||
{
|
||||
case OpState.StartingTest:
|
||||
|
||||
@@ -17,7 +17,8 @@ using TBF.Boxes;
|
||||
using TBF.Rig.GenericDevices;
|
||||
using TBF.Rig.Sequences;
|
||||
using TBF.UiBridge;
|
||||
|
||||
using AppDiagnostic;
|
||||
using SharedComponents;
|
||||
|
||||
namespace TBF.Rig.ControlBoard.Uni
|
||||
{
|
||||
|
||||
@@ -268,16 +268,10 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
{
|
||||
dlg.WMStartState[item] = poseidonReader.BeginWMState;
|
||||
dlg.WMStartStateStr[item] = poseidonReader.BeginWMState.ToString();
|
||||
log.InfoFormat("Poseidon dialog prefill: phase=Start, WM{0}, reader={1}, value={2}",
|
||||
item + 1, poseidonReader.Name, dlg.WMStartState[item]);
|
||||
}
|
||||
|
||||
if (currentOp == CurrentOp.ReadDatastream_EndStates)
|
||||
{
|
||||
dlg.WMEndState[item] = poseidonReader.EndWMState;
|
||||
log.InfoFormat("Poseidon dialog prefill: phase=End, WM{0}, reader={1}, value={2}",
|
||||
item + 1, poseidonReader.Name, dlg.WMEndState[item]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -332,10 +326,31 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (modelessDlg is TestStartEndForm)
|
||||
else if (modelessDlg is TestStartEndForm && currentOp == CurrentOp.ReadDatastream_StartStates)
|
||||
{
|
||||
StoreAcceptedDialogValues((TestStartEndForm)modelessDlg);
|
||||
}
|
||||
/// Fixed start test - start
|
||||
TestStartEndForm dlg = (modelessDlg as TestStartEndForm);
|
||||
if (dlg != null)
|
||||
{
|
||||
for (int i = 0; i < dlg.WaterMetersCount; i++)
|
||||
{
|
||||
wmStartState[i] = dlg.WMStartState[i];
|
||||
wmStartStateStr[i] = dlg.WMStartStateStr[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (modelessDlg is TestStartEndForm && currentOp == CurrentOp.ReadDatastream_EndStates)
|
||||
{
|
||||
/// Fixed start test - end
|
||||
TestStartEndForm dlg = (modelessDlg as TestStartEndForm);
|
||||
if (dlg != null)
|
||||
{
|
||||
for (int i = 0; i < dlg.WaterMetersCount; i++)
|
||||
{
|
||||
wmEndState[i] = dlg.WMEndState[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
resultSaved = true;
|
||||
modelessDlg = null;
|
||||
}
|
||||
@@ -343,36 +358,6 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
return Event.ModelessFormClosed; /// Form closed
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies values confirmed by the Poseidon start/end dialog into the
|
||||
/// data-entry state used later by the result calculation.
|
||||
/// </summary>
|
||||
private void StoreAcceptedDialogValues(TestStartEndForm dlg)
|
||||
{
|
||||
if (dlg == null)
|
||||
return;
|
||||
|
||||
if (currentOp == CurrentOp.ReadDatastream_StartStates)
|
||||
{
|
||||
for (int i = 0; i < dlg.WaterMetersCount; i++)
|
||||
{
|
||||
wmStartState[i] = dlg.WMStartState[i];
|
||||
wmStartStateStr[i] = dlg.WMStartStateStr[i];
|
||||
log.InfoFormat("Poseidon dialog accepted: phase=Start, WM{0}, text='{1}', value={2}",
|
||||
i + 1, wmStartStateStr[i], wmStartState[i]);
|
||||
}
|
||||
}
|
||||
else if (currentOp == CurrentOp.ReadDatastream_EndStates)
|
||||
{
|
||||
for (int i = 0; i < dlg.WaterMetersCount; i++)
|
||||
{
|
||||
wmEndState[i] = dlg.WMEndState[i];
|
||||
log.InfoFormat("Poseidon dialog accepted: phase=End, WM{0}, value={1}",
|
||||
i + 1, wmEndState[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Stop this operation</summary>
|
||||
public void Stop()
|
||||
{
|
||||
@@ -448,45 +433,35 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
|| (currentOp == CurrentOp.ReadDatastream_EndStates))
|
||||
{
|
||||
bool finishedReading = regReaders == null; // we can work only with register readers
|
||||
List<IPoseidonReadOperation> poseidonReaders = new List<IPoseidonReadOperation>();
|
||||
if (regReaders != null)
|
||||
{
|
||||
foreach (var iRegReader in regReaders)
|
||||
{
|
||||
PoseidonReader poseidonReader = iRegReader as PoseidonReader;
|
||||
if (poseidonReader != null)
|
||||
{
|
||||
poseidonReader.SetCliLogging(CliLogging);
|
||||
poseidonReaders.Add(new PoseidonReaderOperation(poseidonReader));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var phaseRunner = new PoseidonReadPhaseRunner(
|
||||
currentOp == CurrentOp.ReadDatastream_StartStates);
|
||||
while (!finishedReading) //TODO BUMI lock - fuck ?
|
||||
{
|
||||
foreach (IPoseidonReadOperation poseidonReader in poseidonReaders)
|
||||
bool bAllReadersFinished = true;
|
||||
foreach (var iRegReader in regReaders )
|
||||
{
|
||||
if (poseidonReader.IsNotStarted || poseidonReader.IsFinished)
|
||||
log.DebugFormat("Poseidon read: arming {0} for {1}, previous state finished={2}",
|
||||
currentOp, poseidonReader.Name, poseidonReader.IsFinished);
|
||||
}
|
||||
|
||||
bool bAllReadersFinished = phaseRunner.RunIteration(poseidonReaders);
|
||||
foreach (IPoseidonReadOperation poseidonReader in poseidonReaders)
|
||||
{
|
||||
if (poseidonReader.IsFinished)
|
||||
if (iRegReader is PoseidonReader)
|
||||
{
|
||||
if (poseidonReader.HasError)
|
||||
log.ErrorFormat("Poseidon read: {0} completed with Error during {1}", poseidonReader.Name, currentOp);
|
||||
else
|
||||
log.DebugFormat("Poseidon read: {0} completed during {1}", poseidonReader.Name, currentOp);
|
||||
PoseidonReader poseidonReader = (iRegReader as PoseidonReader);
|
||||
if(poseidonReader == null)
|
||||
continue;
|
||||
poseidonReader.SetCliLogging(CliLogging);
|
||||
if (!(poseidonReader.CurrentOp == PoseidonReader.CurrentPoseidonOp.ReadDatastream_Done
|
||||
|| poseidonReader.CurrentOp == PoseidonReader.CurrentPoseidonOp.ReadDatastream_Running))
|
||||
{
|
||||
poseidonReader.SetCurrentOp((currentOp == CurrentOp.ReadDatastream_StartStates)?
|
||||
PoseidonReader.CurrentPoseidonOp.ReadDataStream_Start :
|
||||
PoseidonReader.CurrentPoseidonOp.ReadDataStream_End);
|
||||
}
|
||||
/// Send start data stream
|
||||
poseidonReader.Run();
|
||||
if (!(poseidonReader.CurrentOp == PoseidonReader.CurrentPoseidonOp.Done
|
||||
|| poseidonReader.CurrentOp == PoseidonReader.CurrentPoseidonOp.Error))
|
||||
{
|
||||
bAllReadersFinished = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bAllReadersFinished)
|
||||
{
|
||||
log.DebugFormat("Poseidon read: all readers finished for {0}", currentOp);
|
||||
finishedReading = true;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -144,9 +144,6 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
|
||||
private void SetUiBusy(bool busy, long deltaTime = -1)
|
||||
{
|
||||
log.DebugFormat("Poseidon UI: SetUiBusy busy={0}, deltaTime={1}, enabledTextBoxes={2}",
|
||||
busy, deltaTime, enabledTextBoxes.Count);
|
||||
|
||||
// show wait cursor for form and children
|
||||
this.UseWaitCursor = busy;
|
||||
|
||||
@@ -293,15 +290,10 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
// Ensure we are on the UI thread
|
||||
if (InvokeRequired)
|
||||
{
|
||||
log.DebugFormat("Poseidon UI: queue UpdateValues startValue={0}, enableEdit={1}, deltaTime={2}",
|
||||
stratValue, enableEdit, deltaTime);
|
||||
BeginInvoke(new Action(() => UpdateValues(stratValue, enableEdit)));
|
||||
return;
|
||||
}
|
||||
|
||||
log.DebugFormat("Poseidon UI: UpdateValues on UI thread startValue={0}, enableEdit={1}, deltaTime={2}",
|
||||
stratValue, enableEdit, deltaTime);
|
||||
|
||||
for (int i = 0; i < TextBoxesCount; i++)
|
||||
{
|
||||
if (stratValue)
|
||||
@@ -325,7 +317,6 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
if (enableEdit)
|
||||
{
|
||||
SetUiBusy(false, deltaTime);
|
||||
log.Debug("Poseidon UI: values applied and dialog released from Loading...");
|
||||
}
|
||||
// if you also need to enable/disable editing, do it here,
|
||||
// it's now safely on the UI thread.
|
||||
@@ -354,8 +345,6 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
if (endTextBoxes[i].Visible && endTextBoxes[i].Enabled)
|
||||
{
|
||||
WMEndState[i] = Utils.ParseUDouble(endTextBoxes[i].Text);
|
||||
log.InfoFormat("Poseidon dialog OK: phase=End, WM{0}, enteredText='{1}', parsedValue={2}",
|
||||
i + 1, endTextBoxes[i].Text, WMEndState[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -367,8 +356,6 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
{
|
||||
WMStartStateStr[i] = startTextBoxes[i].Text;
|
||||
WMStartState[i] = Utils.ParseUDouble(startTextBoxes[i].Text);
|
||||
log.InfoFormat("Poseidon dialog OK: phase=Start, WM{0}, enteredText='{1}', parsedValue={2}",
|
||||
i + 1, startTextBoxes[i].Text, WMStartState[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
///
|
||||
/// Copyright (c) 2018 Sensus Slovensko a.s.
|
||||
///
|
||||
|
||||
using System.Collections.Generic;
|
||||
using TBF.Rig.Generic;
|
||||
|
||||
namespace TBF.Rig.Output.DB.DatabaseWriter
|
||||
{
|
||||
/// <summary>
|
||||
/// Factory component 'DatabaseWriter' implements more storing modules
|
||||
/// Mosules:
|
||||
/// * store whole results in database
|
||||
/// * store to specific mexico database structure - not implemented yet
|
||||
/// * store configurable data SQL template to a specific database - not implemented yet
|
||||
/// </summary>
|
||||
public class Factory : IComponentFactory
|
||||
{
|
||||
public string ClassName { get { return GetType().Namespace.Substring(8); } } /// For backward compatibility
|
||||
public override string ToString() { return ClassName; }
|
||||
|
||||
public IComponent DummyComponent() { return new WritingToDb(); }
|
||||
|
||||
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components) { return new WritingToDb(cfg); }
|
||||
|
||||
public IComponentCfg DefaultConfig() { return new WriterCfg("DatabaseWriter", this); }
|
||||
|
||||
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
|
||||
{
|
||||
return ComponentCfgBase.CreateFromDbEntity(WriterCfg.Serializer, component, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
///
|
||||
/// Copyright (c) 2018-2019 Sensus Slovensko a.s.
|
||||
///
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using Common;
|
||||
using TBF.Rig.Generic;
|
||||
|
||||
|
||||
namespace TBF.Rig.Output.DB.DatabaseWriter
|
||||
{
|
||||
public partial class WriteDbCfgCtrl : Configs.ConfigCtrlUtils, IComponentCfgCtrl
|
||||
{
|
||||
public bool ShowMore { get { return false; } }
|
||||
|
||||
WriterCfg config;
|
||||
public IComponentCfg Config
|
||||
{
|
||||
get { return config as IComponentCfg; }
|
||||
set
|
||||
{
|
||||
config = value as WriterCfg;
|
||||
Redraw();
|
||||
}
|
||||
}
|
||||
|
||||
public WriteDbCfgCtrl()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void WriterCfgCtrl_Load(object sender, EventArgs e)
|
||||
{
|
||||
if (config == null) return;
|
||||
Redraw();
|
||||
}
|
||||
|
||||
public void Closing()
|
||||
{
|
||||
}
|
||||
|
||||
void Redraw()
|
||||
{
|
||||
if (config == null) return; /// Control was not loaded, settings were not changed
|
||||
|
||||
classNameLabel.Text = config.Factory.ClassName;
|
||||
nameTextBox.Text = config.Name;
|
||||
connStrTextBox.Text = config.ConnStr;
|
||||
connStr2TextBox.Text = config.ConnStr2;
|
||||
checkPreviousRecordsCheckBox.Checked = config.CheckPreviousRecords;
|
||||
saveTracingRecordsCheckBox.Checked = config.SaveTracingRecords;
|
||||
|
||||
Network.AdapterInfo.RefreshNetAdaptersInfo();
|
||||
IList<Network.AdapterInfo> adapters = Network.AdapterInfo.NetAdapters;
|
||||
|
||||
string cfgAdapter = string.Empty;
|
||||
foreach (Network.AdapterInfo ai in adapters)
|
||||
{
|
||||
string record;
|
||||
|
||||
if (ai.IPAddress == null)
|
||||
{
|
||||
/// This happens with network adapters that currently have no IP address,
|
||||
/// for instance not connected wireless or dial-up adapters
|
||||
record = "???.???.???.???";
|
||||
}
|
||||
else
|
||||
{
|
||||
/// Do not consider IPv6 adapters as well as "Any", "Broadcast", "Loopback" or "None" addresses
|
||||
if ((ai.IPAddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6) ||
|
||||
ai.IPAddress.Equals(IPAddress.Any) ||
|
||||
ai.IPAddress.Equals(IPAddress.Broadcast) ||
|
||||
ai.IPAddress.Equals(IPAddress.IPv6Any) ||
|
||||
ai.IPAddress.Equals(IPAddress.IPv6Loopback) ||
|
||||
ai.IPAddress.Equals(IPAddress.IPv6None) ||
|
||||
ai.IPAddress.Equals(IPAddress.Loopback) ||
|
||||
ai.IPAddress.Equals(IPAddress.None))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
record = ai.IPAddress.ToString();
|
||||
}
|
||||
|
||||
record += " - " + ai.Description;
|
||||
int i = netAdapterComboBox.Items.Add(record);
|
||||
if (ai.Description == config.NetAdapter)
|
||||
{
|
||||
/// Select the adapter currently in the configuration
|
||||
netAdapterComboBox.SelectedIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
/// Select the first one if the adapter from the configuration does not exist on the system
|
||||
if (netAdapterComboBox.SelectedIndex < 0 && netAdapterComboBox.Items.Count > 0)
|
||||
{
|
||||
netAdapterComboBox.SelectedIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void Unlock()
|
||||
{
|
||||
nameTextBox.Enabled = true;
|
||||
connStrTextBox.Enabled = true;
|
||||
connStr2TextBox.Enabled = true;
|
||||
netAdapterComboBox.Enabled = true;
|
||||
checkPreviousRecordsCheckBox.Enabled = true;
|
||||
saveTracingRecordsCheckBox.Enabled = true;
|
||||
}
|
||||
|
||||
public CfgUpdateFlags VerifyCfg(ref string message)
|
||||
{
|
||||
return CfgUpdateFlags.None;
|
||||
}
|
||||
|
||||
public CfgUpdateFlags UpdateCfg()
|
||||
{
|
||||
CfgUpdateFlags flags = CfgUpdateFlags.None;
|
||||
|
||||
if (config == null) return CfgUpdateFlags.Error; /// Control was not loaded, settings were not changed
|
||||
|
||||
if (config.Name != nameTextBox.Text)
|
||||
{
|
||||
config.Name = nameTextBox.Text;
|
||||
flags |= (CfgUpdateFlags.AnyChange | CfgUpdateFlags.RestartRqrd);
|
||||
}
|
||||
|
||||
flags |= UpdateDifferent(ref config.ConnStr, connStrTextBox.Text, CfgUpdateFlags.AnyChange | CfgUpdateFlags.RestartRqrd);
|
||||
flags |= UpdateDifferent(ref config.ConnStr2, connStr2TextBox.Text, CfgUpdateFlags.AnyChange | CfgUpdateFlags.RestartRqrd);
|
||||
flags |= UpdateDifferent(ref config.CheckPreviousRecords, checkPreviousRecordsCheckBox.Checked, CfgUpdateFlags.AnyChange | CfgUpdateFlags.RestartRqrd);
|
||||
flags |= UpdateDifferent(ref config.SaveTracingRecords, saveTracingRecordsCheckBox.Checked, CfgUpdateFlags.AnyChange | CfgUpdateFlags.RestartRqrd);
|
||||
|
||||
/// Network adapter
|
||||
string strAdapter = netAdapterComboBox.Text;
|
||||
int iDash = strAdapter.IndexOf(" - ");
|
||||
string netAdapter = (iDash < 0) ? "" : strAdapter.Substring(iDash + 3);
|
||||
if (config.NetAdapter != netAdapter)
|
||||
{
|
||||
config.NetAdapter = netAdapter;
|
||||
flags |= (CfgUpdateFlags.AnyChange | CfgUpdateFlags.RestartRqrd);
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
///
|
||||
/// Copyright (c) 2018 Sensus Slovensko a.s.
|
||||
///
|
||||
namespace TBF.Rig.Output.DB.DatabaseWriter
|
||||
{
|
||||
partial class WriteDbCfgCtrl
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.nameTextBox = new System.Windows.Forms.TextBox();
|
||||
this.nameLabel = new System.Windows.Forms.Label();
|
||||
this.classNameLabel = new System.Windows.Forms.Label();
|
||||
this.connStrTextBox = new System.Windows.Forms.TextBox();
|
||||
this.connStrLabel = new System.Windows.Forms.Label();
|
||||
this.saveTracingRecordsCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.checkPreviousRecordsCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.netAdapterLabel = new System.Windows.Forms.Label();
|
||||
this.netAdapterComboBox = new System.Windows.Forms.ComboBox();
|
||||
this.connStr2TextBox = new System.Windows.Forms.TextBox();
|
||||
this.connStr2Label = new System.Windows.Forms.Label();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// nameTextBox
|
||||
//
|
||||
this.nameTextBox.Enabled = false;
|
||||
this.nameTextBox.Location = new System.Drawing.Point(117, 32);
|
||||
this.nameTextBox.Name = "nameTextBox";
|
||||
this.nameTextBox.Size = new System.Drawing.Size(326, 20);
|
||||
this.nameTextBox.TabIndex = 2;
|
||||
//
|
||||
// nameLabel
|
||||
//
|
||||
this.nameLabel.AutoSize = true;
|
||||
this.nameLabel.Location = new System.Drawing.Point(5, 35);
|
||||
this.nameLabel.Name = "nameLabel";
|
||||
this.nameLabel.Size = new System.Drawing.Size(38, 13);
|
||||
this.nameLabel.TabIndex = 1;
|
||||
this.nameLabel.Text = "Name:";
|
||||
//
|
||||
// classNameLabel
|
||||
//
|
||||
this.classNameLabel.AutoSize = true;
|
||||
this.classNameLabel.Location = new System.Drawing.Point(114, 10);
|
||||
this.classNameLabel.Name = "classNameLabel";
|
||||
this.classNameLabel.Size = new System.Drawing.Size(83, 13);
|
||||
this.classNameLabel.TabIndex = 0;
|
||||
this.classNameLabel.Text = "ComonentName";
|
||||
//
|
||||
// connStrTextBox
|
||||
//
|
||||
this.connStrTextBox.Enabled = false;
|
||||
this.connStrTextBox.Location = new System.Drawing.Point(8, 74);
|
||||
this.connStrTextBox.Name = "connStrTextBox";
|
||||
this.connStrTextBox.Size = new System.Drawing.Size(435, 20);
|
||||
this.connStrTextBox.TabIndex = 4;
|
||||
//
|
||||
// connStrLabel
|
||||
//
|
||||
this.connStrLabel.AutoSize = true;
|
||||
this.connStrLabel.Location = new System.Drawing.Point(5, 58);
|
||||
this.connStrLabel.Name = "connStrLabel";
|
||||
this.connStrLabel.Size = new System.Drawing.Size(92, 13);
|
||||
this.connStrLabel.TabIndex = 3;
|
||||
this.connStrLabel.Text = "Connection string:";
|
||||
//
|
||||
// saveTracingRecordsCheckBox
|
||||
//
|
||||
this.saveTracingRecordsCheckBox.AutoSize = true;
|
||||
this.saveTracingRecordsCheckBox.Enabled = false;
|
||||
this.saveTracingRecordsCheckBox.Location = new System.Drawing.Point(117, 221);
|
||||
this.saveTracingRecordsCheckBox.Name = "saveTracingRecordsCheckBox";
|
||||
this.saveTracingRecordsCheckBox.Size = new System.Drawing.Size(177, 17);
|
||||
this.saveTracingRecordsCheckBox.TabIndex = 10;
|
||||
this.saveTracingRecordsCheckBox.Text = "Save production tracing records";
|
||||
this.saveTracingRecordsCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// checkPreviousRecordsCheckBox
|
||||
//
|
||||
this.checkPreviousRecordsCheckBox.AutoSize = true;
|
||||
this.checkPreviousRecordsCheckBox.Enabled = false;
|
||||
this.checkPreviousRecordsCheckBox.Location = new System.Drawing.Point(117, 199);
|
||||
this.checkPreviousRecordsCheckBox.Name = "checkPreviousRecordsCheckBox";
|
||||
this.checkPreviousRecordsCheckBox.Size = new System.Drawing.Size(138, 17);
|
||||
this.checkPreviousRecordsCheckBox.TabIndex = 9;
|
||||
this.checkPreviousRecordsCheckBox.Text = "Check previous records";
|
||||
this.checkPreviousRecordsCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// netAdapterLabel
|
||||
//
|
||||
this.netAdapterLabel.AutoSize = true;
|
||||
this.netAdapterLabel.Location = new System.Drawing.Point(5, 147);
|
||||
this.netAdapterLabel.Name = "netAdapterLabel";
|
||||
this.netAdapterLabel.Size = new System.Drawing.Size(89, 13);
|
||||
this.netAdapterLabel.TabIndex = 7;
|
||||
this.netAdapterLabel.Text = "Network adapter:";
|
||||
//
|
||||
// netAdapterComboBox
|
||||
//
|
||||
this.netAdapterComboBox.Enabled = false;
|
||||
this.netAdapterComboBox.FormattingEnabled = true;
|
||||
this.netAdapterComboBox.Location = new System.Drawing.Point(8, 163);
|
||||
this.netAdapterComboBox.Name = "netAdapterComboBox";
|
||||
this.netAdapterComboBox.Size = new System.Drawing.Size(435, 21);
|
||||
this.netAdapterComboBox.TabIndex = 8;
|
||||
//
|
||||
// connStr2TextBox
|
||||
//
|
||||
this.connStr2TextBox.Enabled = false;
|
||||
this.connStr2TextBox.Location = new System.Drawing.Point(8, 118);
|
||||
this.connStr2TextBox.Name = "connStr2TextBox";
|
||||
this.connStr2TextBox.Size = new System.Drawing.Size(434, 20);
|
||||
this.connStr2TextBox.TabIndex = 6;
|
||||
//
|
||||
// connStr2Label
|
||||
//
|
||||
this.connStr2Label.AutoSize = true;
|
||||
this.connStr2Label.Location = new System.Drawing.Point(5, 102);
|
||||
this.connStr2Label.Name = "connStr2Label";
|
||||
this.connStr2Label.Size = new System.Drawing.Size(101, 13);
|
||||
this.connStr2Label.TabIndex = 5;
|
||||
this.connStr2Label.Text = "Connection string 2:";
|
||||
//
|
||||
// TracingCfgCtrl
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.Controls.Add(this.connStr2TextBox);
|
||||
this.Controls.Add(this.connStr2Label);
|
||||
this.Controls.Add(this.netAdapterComboBox);
|
||||
this.Controls.Add(this.netAdapterLabel);
|
||||
this.Controls.Add(this.saveTracingRecordsCheckBox);
|
||||
this.Controls.Add(this.checkPreviousRecordsCheckBox);
|
||||
this.Controls.Add(this.connStrTextBox);
|
||||
this.Controls.Add(this.connStrLabel);
|
||||
this.Controls.Add(this.nameTextBox);
|
||||
this.Controls.Add(this.nameLabel);
|
||||
this.Controls.Add(this.classNameLabel);
|
||||
this.Name = "WriteDbCfgCtrl";
|
||||
this.Size = new System.Drawing.Size(450, 250);
|
||||
this.Load += new System.EventHandler(this.WriterCfgCtrl_Load);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.TextBox nameTextBox;
|
||||
private System.Windows.Forms.Label nameLabel;
|
||||
private System.Windows.Forms.Label classNameLabel;
|
||||
private System.Windows.Forms.TextBox connStrTextBox;
|
||||
private System.Windows.Forms.Label connStrLabel;
|
||||
private System.Windows.Forms.CheckBox saveTracingRecordsCheckBox;
|
||||
private System.Windows.Forms.CheckBox checkPreviousRecordsCheckBox;
|
||||
private System.Windows.Forms.Label netAdapterLabel;
|
||||
private System.Windows.Forms.ComboBox netAdapterComboBox;
|
||||
private System.Windows.Forms.TextBox connStr2TextBox;
|
||||
private System.Windows.Forms.Label connStr2Label;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
@@ -0,0 +1,57 @@
|
||||
///
|
||||
/// Copyright (c) 2018 Sensus Slovensko a.s.
|
||||
///
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Serialization;
|
||||
using TBF.Rig.Generic;
|
||||
|
||||
namespace TBF.Rig.Output.DB.DatabaseWriter
|
||||
{
|
||||
///
|
||||
/// Class and file name is preserved for backward compatibility
|
||||
///
|
||||
public class WriterCfg : ComponentCfgBase, Generic.IComponentCfg
|
||||
{
|
||||
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(WriterCfg) })[0];
|
||||
public override XmlSerializer GetSerializer() { return Serializer; }
|
||||
|
||||
public IComponentCfgCtrl GetControl(IList<Config.Entities.Component> cmpntEntities) { return new WriteDbCfgCtrl(); }
|
||||
|
||||
|
||||
public string ConnStr;
|
||||
public string ConnStr2;
|
||||
public string NetAdapter;
|
||||
public bool CheckPreviousRecords;
|
||||
public bool SaveTracingRecords;
|
||||
|
||||
|
||||
/// Private parameterless constructor invoked by all other (public) constructors
|
||||
WriterCfg()
|
||||
{
|
||||
ParentName = string.Empty;
|
||||
NetAdapter = string.Empty;
|
||||
ConnStr = "server=10.42.128.24; database=sledovanie2020; uid=vyroba2020; pwd=qwerty; charset=utf8;";
|
||||
ConnStr2 = "server=10.42.128.24; database=sledovanie2019; uid=vyroba2019; pwd=qwerty; charset=utf8;";
|
||||
CheckPreviousRecords = true;
|
||||
SaveTracingRecords = true;
|
||||
}
|
||||
|
||||
public WriterCfg(string name, IComponentFactory factory)
|
||||
: this()
|
||||
{
|
||||
this.Name = name;
|
||||
this.Factory = factory;
|
||||
}
|
||||
|
||||
public string ToString(int i)
|
||||
{
|
||||
return string.Format("Name={0}, CheckPrev.={1}, SaveRecords={2}, ConnStr={3}, , ConnStr2={4}",
|
||||
Name,
|
||||
CheckPreviousRecords,
|
||||
SaveTracingRecords,
|
||||
ConnStr,
|
||||
ConnStr2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,577 @@
|
||||
///
|
||||
/// Copyright (c) 2018-2023 Sensus Slovensko a.s.
|
||||
///
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using Common;
|
||||
using log4net;
|
||||
using NHibernate;
|
||||
using SharedDatabase;
|
||||
using SharedDatabase.Entities;
|
||||
using TBF.Rig.Sequences;
|
||||
|
||||
namespace TBF.Rig.Output.DB.DatabaseWriter
|
||||
{
|
||||
public enum Retv
|
||||
{
|
||||
OK,
|
||||
Error,
|
||||
}
|
||||
|
||||
class DateTimeComparer : IComparer<DateTime>
|
||||
{
|
||||
public int Compare(DateTime x, DateTime y)
|
||||
{
|
||||
return DateTime.Compare(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
public class WritingToDb : ComponentBase, IOperation, GenericDevices.IResultsWriter, GenericDevices.IStartInfoReader, Generic.IDevice
|
||||
{
|
||||
private static readonly ILog log = LogManager.GetLogger(typeof(WritingToDb));
|
||||
public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); }
|
||||
|
||||
public const string WorkstepName = "Test_bench";
|
||||
|
||||
public OrderInfo DefaultOrder;
|
||||
|
||||
WriterCfg tracingCfg;
|
||||
string workplace
|
||||
{
|
||||
get
|
||||
{
|
||||
TBF.Rig.GenericDevices.IBenchInfo benchInfo = TBF.Rig.Sequences.ProcessData.BenchInfo;
|
||||
return (benchInfo != null) ? benchInfo.TestBenchName : "TestBench";
|
||||
}
|
||||
}
|
||||
|
||||
IPAddress ipAddress;
|
||||
IPAddress netMask;
|
||||
public IPAddress IPAddress { get { return ipAddress; } }
|
||||
public IPAddress NetMask { get { return netMask; } }
|
||||
|
||||
enum OpState
|
||||
{
|
||||
None,
|
||||
CheckPreviousRecordsScheduled,
|
||||
CheckPreviousRecordsRunning,
|
||||
SaveTracingRecordsScheduled,
|
||||
SaveTracingRecordsRunning,
|
||||
}
|
||||
///
|
||||
OpState currentOpState;
|
||||
bool opCompleted;
|
||||
bool anyError;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Watermeters to check at the beginning of the cycle
|
||||
/// </summary>
|
||||
IList<Results.Entities.WaterMeter> waterMeters;
|
||||
|
||||
/// <summary>
|
||||
/// Data (tracing records) to write at the end of cycle
|
||||
/// </summary>
|
||||
Results.Entities.Batch batch;
|
||||
|
||||
public ISessionFactory SessionFactory; /// Factory to create database sessions that is initialized in the constructor
|
||||
|
||||
|
||||
public WritingToDb() {}
|
||||
|
||||
public WritingToDb(Generic.IComponentCfg cfg)
|
||||
: base(cfg)
|
||||
{
|
||||
tracingCfg = cfg as WriterCfg;
|
||||
if (tracingCfg == null) throw new ArgumentException("tracingCfg");
|
||||
|
||||
Network.AdapterInfo.RefreshNetAdaptersInfo();
|
||||
Network.AdapterInfo netadapter = Network.AdapterInfo.GetNetAdapter(tracingCfg.NetAdapter);
|
||||
ipAddress = netadapter.IPAddress;
|
||||
|
||||
netMask = netadapter.NetMask;
|
||||
currentOpState = OpState.None;
|
||||
log.Warn(this.ToString());
|
||||
|
||||
DefaultOrder = null;
|
||||
}
|
||||
|
||||
///
|
||||
/// IDevice interface implementation
|
||||
///
|
||||
public override void Initialize()
|
||||
{
|
||||
if (tracingCfg.DebugLevel == DebugMode.Simulate) return;
|
||||
|
||||
string ipAddress = GetIPAddress();
|
||||
|
||||
///
|
||||
/// Session factory is used to create database sessions
|
||||
///
|
||||
SharedDatabase.TracingDB.SessionFactory = this.SessionFactory =
|
||||
FluentNHibernate.Cfg.Fluently.Configure()
|
||||
.Database(FluentNHibernate.Cfg.Db.MySQLConfiguration.Standard.ConnectionString(tracingCfg.ConnStr))
|
||||
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<Process>())
|
||||
.ExposeConfiguration(SharedDatabase.TracingDB.BuildSchema)
|
||||
.BuildSessionFactory();
|
||||
|
||||
try
|
||||
{
|
||||
using (var session = SessionFactory.OpenSession())
|
||||
{
|
||||
///
|
||||
/// Initialize DefaultOrder
|
||||
///
|
||||
var dfltOrders = session.QueryOver<OrderInfo>()
|
||||
.Where(x => x.POName == "0000001")
|
||||
.And(x => (x.POState == (sbyte)OrderState.New || x.POState == (sbyte)OrderState.Active))
|
||||
.List();
|
||||
if (dfltOrders.Count > 0) DefaultOrder = dfltOrders[0];
|
||||
|
||||
#if !DEBUG
|
||||
///
|
||||
/// Register this test bench in the tracing DB for approx. 2 weeks (RELEASE version only)
|
||||
///
|
||||
SharedDatabase.TracingDB.RegisterWorkplaceObsolete(session,
|
||||
workplace,
|
||||
CurrentUser.UserName(),
|
||||
GetIPAddress(),
|
||||
"<multiple>",
|
||||
WorkstepName,
|
||||
DateTime.Now + new TimeSpan(15, 0, 0, 0));
|
||||
session.Flush();
|
||||
#endif
|
||||
session.Close();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.ErrorFormat("Cannot load a default order from a database or regster this workplace: {0}", ex);
|
||||
DefaultOrder = null;
|
||||
}
|
||||
}
|
||||
///
|
||||
string GetIPAddress()
|
||||
{
|
||||
return (ipAddress != null) ? ipAddress.ToString() : "1.2.3.4";
|
||||
}
|
||||
///
|
||||
public void RunDeviceBefore() { }
|
||||
public void RunDeviceAfter() { }
|
||||
///
|
||||
public void StopDevice()
|
||||
{
|
||||
if (tracingCfg.DebugLevel != DebugMode.Normal) return;
|
||||
|
||||
using (ISession session = SessionFactory.OpenSession())
|
||||
{
|
||||
SharedDatabase.TracingDB.UnregisterWorkplaceObsolete(session, workplace);
|
||||
session.Flush();
|
||||
}
|
||||
}
|
||||
public void StopDevice2() {}
|
||||
|
||||
public IList<OrderInfo> ReadOrders()
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var session = SessionFactory.OpenSession())
|
||||
{
|
||||
var result = session.QueryOver<OrderInfo>()
|
||||
.Where(x => (x.POState == (sbyte)OrderState.New || x.POState == (sbyte)OrderState.Active))
|
||||
.List();
|
||||
session.Close();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.ErrorFormat("ReadOrders() failed: {0}", ex.Message);
|
||||
return new List<OrderInfo>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read reference records belonging to a specified order.
|
||||
/// Used when retrieving housing S/N-s belonging to obtained eRegister numbers.
|
||||
/// </summary>
|
||||
/// <param name="session">DB sesson</param>
|
||||
/// <param name="order">Order</param>
|
||||
/// <returns>List of reference records-s</returns>
|
||||
public IList<ReferenceRecord> ReadRefRecords(ISession session, OrderInfo order, OrderInfo dfltOrder = null, Process dfltWFlow = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var refRecords = session.QueryOver<ReferenceRecord>()
|
||||
.Where(x => (x.POName == order.POName))
|
||||
.List();
|
||||
refRecords.Reverse();
|
||||
|
||||
if (dfltOrder != null && dfltWFlow != null)
|
||||
{
|
||||
var moreRecords = session.QueryOver<ReferenceRecord>()
|
||||
.Where(x => (x.POName == dfltOrder.POName))
|
||||
.And(x => (x.Workflow == dfltWFlow.Name))
|
||||
.List();
|
||||
for (int i = moreRecords.Count - 1; i >= 0; i--) refRecords.Add(moreRecords[i]);
|
||||
}
|
||||
|
||||
return refRecords;
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
log.ErrorFormat("Cannot read ref.records from the tracing DB: {0}", exc.Message);
|
||||
return new List<ReferenceRecord>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Read records belonging to a specified order
|
||||
/// </summary>
|
||||
/// <param name="session">DB sesson</param>
|
||||
/// <param name="order">Order</param>
|
||||
/// <returns>List of records</returns>
|
||||
public IList<Record> ReadRecords(ISession session, OrderInfo order, OrderInfo dfltOrder = null, Process dfltWFlow = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var records = session.QueryOver<Record>()
|
||||
.JoinQueryOver<ReferenceRecord>(rec => rec.ReferenceRecord)
|
||||
.Where(rr => rr.POName == order.POName)
|
||||
.List();
|
||||
records.Reverse();
|
||||
|
||||
if (dfltOrder != null && dfltWFlow != null)
|
||||
{
|
||||
var moreRecords = session.QueryOver<Record>()
|
||||
.JoinQueryOver<ReferenceRecord>(rec => rec.ReferenceRecord)
|
||||
.Where(rr => (rr.POName == dfltOrder.POName))
|
||||
.And(rr => (rr.Workflow == dfltWFlow.Name))
|
||||
.List();
|
||||
for (int i = moreRecords.Count - 1; i >= 0; i--) records.Add(moreRecords[i]);
|
||||
}
|
||||
|
||||
return records;
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
log.ErrorFormat("Cannot read records from the tracing DB: {0}", exc.Message);
|
||||
return new List<Record>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Reads information on start of a cycle, Events: Event.InfoRead
|
||||
/// </summary>
|
||||
/// <param name="waterMeters">Results of water meters</param>
|
||||
/// <returns>Reference to the operation</returns>
|
||||
public IOperation ReadStartInfoOp(IList<Results.Entities.WaterMeter> waterMeters)
|
||||
{
|
||||
if (!tracingCfg.CheckPreviousRecords)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else if ((currentOpState == OpState.CheckPreviousRecordsRunning) || (currentOpState == OpState.SaveTracingRecordsRunning))
|
||||
{
|
||||
throw new Exception("Sequence error");
|
||||
}
|
||||
else
|
||||
{
|
||||
this.waterMeters = waterMeters;
|
||||
currentOpState = OpState.CheckPreviousRecordsScheduled;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the test cycle results into a file, Events: Event.ResultsWritten
|
||||
/// </summary>
|
||||
/// <param name="procedure">Procedure to print the results of</param>
|
||||
/// <param name="unsortedResults">Results to write into the file</param>
|
||||
/// <returns>Reference to the operation</returns>
|
||||
public IOperation ProcessResultsOp(Results.Entities.Batch batch)
|
||||
{
|
||||
if (!tracingCfg.SaveTracingRecords)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else if ((currentOpState == OpState.CheckPreviousRecordsRunning) || (currentOpState == OpState.SaveTracingRecordsRunning))
|
||||
{
|
||||
throw new Exception("Sequence error");
|
||||
}
|
||||
else
|
||||
{
|
||||
this.batch = batch;
|
||||
currentOpState = OpState.SaveTracingRecordsScheduled;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>Start this operation</summary>
|
||||
public void Start()
|
||||
{
|
||||
if (currentOpState == OpState.CheckPreviousRecordsScheduled)
|
||||
{
|
||||
currentOpState = OpState.CheckPreviousRecordsRunning;
|
||||
}
|
||||
else if (currentOpState == OpState.SaveTracingRecordsScheduled)
|
||||
{
|
||||
currentOpState = OpState.SaveTracingRecordsRunning;
|
||||
}
|
||||
|
||||
opCompleted = false;
|
||||
anyError = false;
|
||||
}
|
||||
|
||||
/// <summary>Run this operation</summary>
|
||||
/// <returns>Event.ResultsWritten or Event.Error</returns>
|
||||
public Event Run()
|
||||
{
|
||||
log.WarnFormat("{0} : Run() : currentOp = {1}", Name, currentOpState);
|
||||
|
||||
if (currentOpState == OpState.CheckPreviousRecordsRunning)
|
||||
{
|
||||
if (tracingCfg.DebugLevel == DebugMode.Simulate) return Event.InfoRead;
|
||||
if (opCompleted) return anyError ? Event.InfoNotRead : Event.InfoRead;
|
||||
|
||||
/// Run once
|
||||
opCompleted = true;
|
||||
if (CheckPreviousRecords(waterMeters) != Retv.OK) anyError = true;
|
||||
return anyError ? Event.InfoNotRead : Event.InfoRead;
|
||||
}
|
||||
|
||||
if (currentOpState == OpState.SaveTracingRecordsRunning)
|
||||
{
|
||||
if (tracingCfg.DebugLevel == DebugMode.Simulate || batch.WaterMeters.Count == 0) return Event.ResultsWritten;
|
||||
if (opCompleted) return anyError ? Event.ErrorProcessingResults : Event.ResultsWritten;
|
||||
|
||||
/// Run once
|
||||
opCompleted = true;
|
||||
if (SaveTracingRecords(batch) != Retv.OK) anyError = true;
|
||||
|
||||
if (anyError && !string.IsNullOrEmpty(SharedDatabase.EventsDB.ConnectionString))
|
||||
{
|
||||
try
|
||||
{
|
||||
NHibernate.ISession session = SharedDatabase.EventsDB.CreateSession();
|
||||
SharedDatabase.EventsDB.LoadSubscribers(session);
|
||||
|
||||
TBF.UiBridge.Bridge.TriggerEvent(session, Name, EventClass.ComputerResources, Severity.Error,
|
||||
string.Format("Nepodarilo sa uložiť výsledky do sledovacej DB: Číslo dávky={0}", batch.BatchNr),
|
||||
string.Format("Nepodarilo sa uložiť výsledky do sledovacej DB\r\nČíslo dávky = {0}", batch.BatchNr),
|
||||
SubscriberGroup.Metrology | SubscriberGroup.Maintenance | SubscriberGroup.Production);
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
log.ErrorFormat("Triggering event(s) failed: {0}", exc.Message);
|
||||
}
|
||||
}
|
||||
|
||||
return anyError ? Event.ErrorProcessingResults : Event.ResultsWritten;
|
||||
}
|
||||
|
||||
return Event.None;
|
||||
}
|
||||
|
||||
/// <summary>Stop this operation</summary>
|
||||
public void Stop()
|
||||
{
|
||||
currentOpState = OpState.None;
|
||||
}
|
||||
|
||||
|
||||
Retv CheckPreviousRecords(IList<Results.Entities.WaterMeter> waterMeters)
|
||||
{
|
||||
Retv retVal = Retv.Error;
|
||||
|
||||
var sampleWM = waterMeters.FirstOrDefault<Results.Entities.WaterMeter>(x => x != null && x.Disabled == false);
|
||||
if (sampleWM != null)
|
||||
{
|
||||
using (ISession session = SessionFactory.OpenSession())
|
||||
{
|
||||
for (int i = 0; i < waterMeters.Count; i++)
|
||||
{
|
||||
Results.Entities.WaterMeter wm = waterMeters[i];
|
||||
|
||||
if ((wm != null) && !wm.Disabled)
|
||||
{
|
||||
CheckPreviousRecordOfSingleWM(session, wm);
|
||||
}
|
||||
}
|
||||
|
||||
retVal = Retv.OK; /// Successfully completed (regardless of wm.LastRecordIsNok)
|
||||
}
|
||||
}
|
||||
|
||||
return retVal; /// Returns Retv.Error if checking not completed successfully
|
||||
}
|
||||
|
||||
|
||||
Retv CheckPreviousRecordOfSingleWM(ISession session, Results.Entities.WaterMeter wm)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(wm.SerialNr) && ProcessData.WorkflowSummary != null)
|
||||
{
|
||||
/// Get all reference records with Code == SerialNr from all worksteps different from 'Test_bench'
|
||||
var refRecords = session.QueryOver<ReferenceRecord>()
|
||||
.Where(rr => (rr.Code1 == wm.SerialNr))
|
||||
.List();
|
||||
|
||||
if (refRecords.Count == 1)
|
||||
{
|
||||
ReferenceRecord refRecord = refRecords[0];
|
||||
StepRecord previousStep = string.IsNullOrEmpty(ProcessData.WorkflowSummary.PreviousWorkstepName) ? null
|
||||
: refRecord.StepRecords.FirstOrDefault(x => x.Workstep == ProcessData.WorkflowSummary.PreviousWorkstepName);
|
||||
|
||||
if (refRecord.Name1 == ProcessData.WorkflowSummary.Part1Name &&
|
||||
refRecord.Name2 == ProcessData.WorkflowSummary.Part2Name &&
|
||||
(ProcessData.WorkflowSummary.PreviousWorkstepName == null ||
|
||||
(previousStep != null && previousStep.Workstep == ProcessData.WorkflowSummary.PreviousWorkstepName)))
|
||||
{
|
||||
wm.Workflow = ProcessData.WorkflowSummary.Workflow.Name;
|
||||
wm.LastRecordIsNok = false; /// OK
|
||||
return Retv.OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// S/N is missing OR no records found OR workflows do not match OR previous StepRecord is missing
|
||||
wm.Workflow = string.Empty;
|
||||
wm.LastRecordIsNok = true; /// NOK
|
||||
return Retv.OK;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Write results of a batch of water meters to the DB
|
||||
/// </summary>
|
||||
/// <param name="session">DB session</param>
|
||||
/// <param name="batch">Batch entity</param>
|
||||
Retv SaveTracingRecords(Results.Entities.Batch batch)
|
||||
{
|
||||
ITransaction transaction = null;
|
||||
ISession session = null;
|
||||
|
||||
var order = ProcessData.OrderInfo as SharedDatabase.Entities.OrderInfo;
|
||||
if (order != null && ProcessData.WorkflowSummary != null && !string.IsNullOrEmpty(ProcessData.WorkflowSummary.WorkstepName))
|
||||
{
|
||||
///
|
||||
/// Save to regular tracing DB
|
||||
///
|
||||
try
|
||||
{
|
||||
session = SessionFactory.OpenSession();
|
||||
transaction = session.BeginTransaction();
|
||||
|
||||
string workplace = (ProcessData.BenchInfo != null) ? ProcessData.BenchInfo.TestBenchName : "TestBench";
|
||||
int writtenRecordsCount = 0;
|
||||
foreach (var wm in batch.WaterMeters)
|
||||
{
|
||||
if (!wm.Disabled && !string.IsNullOrEmpty(wm.SerialNr))
|
||||
{
|
||||
writtenRecordsCount += SaveSingleWM2DB(session, wm, order.POName, ProcessData.WorkflowSummary, workplace);
|
||||
}
|
||||
}
|
||||
|
||||
transaction.Commit();
|
||||
session.Flush();
|
||||
|
||||
log.WarnFormat("Batch {0}: {1} of {2} watermeters written to the regular production tracing DB",
|
||||
batch.BatchNr, writtenRecordsCount, batch.WaterMeters.Count);
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
if (transaction != null && !transaction.WasCommitted) transaction.Rollback();
|
||||
|
||||
log.ErrorFormat("Failed to write results of batch {0} to production tracing DB: {1}",
|
||||
batch.BatchNr, exc.Message);
|
||||
|
||||
return Retv.Error;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (session != null)
|
||||
{
|
||||
session.Close();
|
||||
session.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Retv.OK;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write one meter results to the DB
|
||||
/// </summary>
|
||||
/// <param name="session">DB session</param>
|
||||
/// <param name="wm">Watermeter entity</param>
|
||||
int SaveSingleWM2DB(ISession session, Results.Entities.WaterMeter wm, string poName, WorkflowSummary wflowSummary, string worplace)
|
||||
{
|
||||
if (string.IsNullOrEmpty(wflowSummary.WorkstepName)) return 0;
|
||||
|
||||
IList<ReferenceRecord> existingRecords = session.QueryOver<ReferenceRecord>()
|
||||
.Where(x => (x.Code1 == wm.SerialNr))
|
||||
.List();
|
||||
if (existingRecords.Count > 1)
|
||||
{
|
||||
/// Unexpected error
|
||||
log.ErrorFormat("Multiple reference records exist: Code1 = {0}", wm.SerialNr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
///
|
||||
/// Reference record
|
||||
///
|
||||
ReferenceRecord refRecord = null;
|
||||
if (existingRecords.Count == 1)
|
||||
{
|
||||
/// TODO: Check if the selected worflow is the same as in the found record
|
||||
refRecord = existingRecords[0];
|
||||
|
||||
refRecord.POName = poName;
|
||||
refRecord.Workflow = wflowSummary.Workflow.Name;
|
||||
refRecord.Code2 = wm.SerialNrAux;
|
||||
refRecord.Code3 = wm.CompleteSerialNr;
|
||||
refRecord.Code4 = wm.RadioAddress;
|
||||
}
|
||||
else
|
||||
{
|
||||
refRecord = new ReferenceRecord(poName,
|
||||
wflowSummary.Workflow.Name,
|
||||
wflowSummary.Part1Name, /// PCB (iPERL) or housing (620/640) SAP number
|
||||
wm.SerialNr, /// PcbNumber (iPERL) or housing S/N (620/640)
|
||||
wflowSummary.Part2Name, /// Flowtube SAP nummber (iPERL) or "eRegister#" (640) or empty
|
||||
wm.SerialNrAux, /// Flowtube S/N (iPERL) or eRegister number (640) or empty
|
||||
wm.CompleteSerialNr, /// Complete assigned S/N
|
||||
wm.RadioAddress); /// Radio address (iPERL and 640)
|
||||
}
|
||||
|
||||
///
|
||||
/// Step record
|
||||
///
|
||||
StepRecord stepRecord = new StepRecord(refRecord,
|
||||
wflowSummary.WorkstepName,
|
||||
workplace,
|
||||
Common.CurrentUser.UserName(),
|
||||
wm.PassedFromTests() ? 0 : 1);
|
||||
if (refRecord.StepRecords == null)
|
||||
{
|
||||
refRecord.StepRecords = new List<StepRecord> { stepRecord };
|
||||
}
|
||||
else
|
||||
{
|
||||
refRecord.StepRecords.Add(stepRecord);
|
||||
}
|
||||
|
||||
session.SaveOrUpdate(refRecord);
|
||||
session.SaveOrUpdate(stepRecord);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,16 +3,42 @@
|
||||
///
|
||||
|
||||
using System;
|
||||
using TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Protocols;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.CommonRR.IPerl.communication
|
||||
{
|
||||
public class OptoReceivedEventArgs : EventArgs
|
||||
{
|
||||
public string Data;
|
||||
public WaterMetrologyData WaterMetrologyData;
|
||||
public byte[] RawData;
|
||||
|
||||
public OptoReceivedEventArgs(string data)
|
||||
{
|
||||
this.Data = data;
|
||||
WaterMetrologyData = null;
|
||||
RawData = null;
|
||||
}
|
||||
|
||||
public OptoReceivedEventArgs(string data, WaterMetrologyData waterMetrologyData)
|
||||
{
|
||||
this.Data = data;
|
||||
this.WaterMetrologyData = waterMetrologyData;
|
||||
RawData = null;
|
||||
}
|
||||
|
||||
public OptoReceivedEventArgs(byte[] data)
|
||||
{
|
||||
this.RawData = data;
|
||||
Data = null;
|
||||
WaterMetrologyData = null;
|
||||
}
|
||||
|
||||
public OptoReceivedEventArgs(WaterMetrologyData data)
|
||||
{
|
||||
WaterMetrologyData = data;
|
||||
Data = null;
|
||||
RawData = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,29 +13,46 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
{
|
||||
public class CliRunner
|
||||
{
|
||||
//static readonly ILog log = LogManager.GetLogger(typeof(CliRunner));
|
||||
private readonly ILog log;
|
||||
private readonly List<CliTaskInfo> taskPool = new List<CliTaskInfo>();
|
||||
private long startTimeMs;
|
||||
private long incommingTimeMs;
|
||||
private List<Task> taskPool = new List<Task>();
|
||||
private long startTime;
|
||||
private long incommingTime;
|
||||
|
||||
public List<Task> TaskPool { get { return taskPool; } }
|
||||
public void AddTask(Task task) { taskPool.Add(task); }
|
||||
public void WaitAll() { Task.WaitAll(taskPool.ToArray()); }
|
||||
public void Clear() { taskPool.Clear(); }
|
||||
public void CancelAll() { Task.WhenAll(taskPool).ContinueWith(t => { }); }
|
||||
|
||||
public List<CliTaskInfo> TaskPool
|
||||
public void StartAll()
|
||||
{
|
||||
get { return taskPool; }
|
||||
taskPool.ForEach(t => t.Start());
|
||||
}
|
||||
|
||||
public bool AreTasksDone()
|
||||
{
|
||||
return taskPool.All(task => task.IsCompleted);
|
||||
}
|
||||
|
||||
public long StartTime
|
||||
{
|
||||
get { return startTimeMs; }
|
||||
get => startTime;
|
||||
}
|
||||
|
||||
public long IncommingTime
|
||||
{
|
||||
get { return incommingTimeMs; }
|
||||
get => incommingTime;
|
||||
}
|
||||
|
||||
public bool TimeOutReceived(long timeout)
|
||||
{
|
||||
return (DateTime.Now.Ticks - startTime) > timeout;
|
||||
}
|
||||
|
||||
public CliRunner(bool isCliLogging)
|
||||
{
|
||||
ResetStartTime();
|
||||
startTime = DateTime.Now.Ticks;
|
||||
|
||||
if (isCliLogging)
|
||||
{
|
||||
@@ -43,432 +60,173 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
{
|
||||
log = new ScopedLoggerFactory().CreateLogger<CliRunner>(
|
||||
@"C:\TBF\Logs\CliRunner.txt",
|
||||
10,
|
||||
7,
|
||||
10, // maxFileSizeMB
|
||||
7, // maxBackups
|
||||
log4net.Core.Level.Debug,
|
||||
true,
|
||||
true,
|
||||
TimeSpan.FromMinutes(2)
|
||||
true, // zipRolledFiles
|
||||
true, // singleZipPerDay
|
||||
TimeSpan.FromMinutes(2) // zipScanInterval
|
||||
);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Fallback to console or handle gracefully
|
||||
Console.WriteLine($"Failed to initialize logger: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ResetStartTime()
|
||||
{
|
||||
startTimeMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
foreach (var item in taskPool)
|
||||
{
|
||||
try
|
||||
{
|
||||
item?.Cts?.Dispose();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (item?.Process != null)
|
||||
{
|
||||
item.Process.Dispose();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
taskPool.Clear();
|
||||
}
|
||||
|
||||
public void WaitAll()
|
||||
{
|
||||
var tasks = taskPool
|
||||
.Where(t => t != null && t.Task != null)
|
||||
.Select(t => t.Task)
|
||||
.ToArray();
|
||||
|
||||
if (tasks.Length == 0)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
Task.WaitAll(tasks);
|
||||
}
|
||||
catch (AggregateException)
|
||||
{
|
||||
RefreshTaskStates();
|
||||
}
|
||||
}
|
||||
|
||||
public bool AreTasksDone()
|
||||
{
|
||||
RefreshTaskStates();
|
||||
return taskPool.Count > 0 && taskPool.All(t => t.State != CliTaskState.Running);
|
||||
}
|
||||
|
||||
public bool TimeOutReceived(long timeoutMs)
|
||||
{
|
||||
long nowMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||
return (nowMs - startTimeMs) > timeoutMs;
|
||||
}
|
||||
|
||||
public void RefreshTaskStates()
|
||||
{
|
||||
foreach (var item in taskPool)
|
||||
{
|
||||
if (item == null || item.Task == null)
|
||||
continue;
|
||||
|
||||
if (item.State == CliTaskState.TimedOut)
|
||||
continue;
|
||||
|
||||
if (!item.Task.IsCompleted)
|
||||
{
|
||||
item.State = CliTaskState.Running;
|
||||
}
|
||||
else if (item.Task.IsCanceled)
|
||||
{
|
||||
item.State = CliTaskState.Canceled;
|
||||
}
|
||||
else if (item.Task.IsFaulted)
|
||||
{
|
||||
item.State = CliTaskState.Faulted;
|
||||
}
|
||||
else
|
||||
{
|
||||
item.State = CliTaskState.Completed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void CancelUndoneTasksAsTimedOut()
|
||||
{
|
||||
foreach (var item in taskPool)
|
||||
{
|
||||
if (item == null || item.Task == null)
|
||||
continue;
|
||||
|
||||
if (item.Task.IsCompleted)
|
||||
{
|
||||
if (item.Task.IsCanceled)
|
||||
item.State = CliTaskState.Canceled;
|
||||
else if (item.Task.IsFaulted)
|
||||
item.State = CliTaskState.Faulted;
|
||||
else
|
||||
item.State = CliTaskState.Completed;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
item.State = CliTaskState.TimedOut;
|
||||
|
||||
try
|
||||
{
|
||||
item.Cts?.Cancel();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log?.Warn("Cancel token failed", ex);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (item.Process != null && !item.Process.HasExited)
|
||||
{
|
||||
item.Process.Kill();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log?.Warn("Kill process failed", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="fileName"></param>
|
||||
/// <param name="args"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public void AddSendAsync(SerialPortData data, SerialPortData.EMeterArg eMeterArg)
|
||||
{
|
||||
AddSendAsync(data.SerialPortCmdClientPath, data.DefaultArgSettings(eMeterArg));
|
||||
var task = SendAsync(data.SerialPortCmdClientPath, data.DefaultArgSettings(eMeterArg));
|
||||
taskPool.Add(task);
|
||||
}
|
||||
|
||||
|
||||
public void AddSendAsync(string fileName, string args)
|
||||
{
|
||||
ResetStartTime();
|
||||
|
||||
var cts = new CancellationTokenSource();
|
||||
var info = new CliTaskInfo
|
||||
{
|
||||
Cts = cts,
|
||||
Name = "SendAsync"
|
||||
};
|
||||
|
||||
var task = SendAsync(fileName, args, info, cts.Token);
|
||||
info.Task = task;
|
||||
taskPool.Add(info);
|
||||
var task = SendAsync(fileName, args);
|
||||
taskPool.Add(task);
|
||||
}
|
||||
|
||||
public async Task<string> SendAsync(string fileName, string args, CliTaskInfo info, CancellationToken ct = default)
|
||||
|
||||
|
||||
public async Task<string> SendAsync(string fileName, string args, CancellationToken ct = default)
|
||||
{
|
||||
var psi = new ProcessStartInfo
|
||||
{
|
||||
FileName = fileName,
|
||||
Arguments = args,
|
||||
WorkingDirectory = System.IO.Path.GetDirectoryName(System.IO.Path.GetFullPath(fileName)),
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true
|
||||
};
|
||||
|
||||
using (var process = new Process { StartInfo = psi, EnableRaisingEvents = true })
|
||||
using var process = new Process { StartInfo = psi, EnableRaisingEvents = true };
|
||||
process.Start();
|
||||
|
||||
Task<string> stdOutTask = process.StandardOutput.ReadToEndAsync();
|
||||
Task<string> stdErrTask = process.StandardError.ReadToEndAsync();
|
||||
|
||||
try
|
||||
{
|
||||
info.Process = process;
|
||||
|
||||
try
|
||||
{
|
||||
process.Start();
|
||||
|
||||
Task<string> stdOutTask = process.StandardOutput.ReadToEndAsync();
|
||||
Task<string> stdErrTask = process.StandardError.ReadToEndAsync();
|
||||
|
||||
try
|
||||
{
|
||||
await Task.WhenAll(stdOutTask, stdErrTask, process.WaitForExitAsync(ct));
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
if (info.State != CliTaskState.TimedOut)
|
||||
info.State = CliTaskState.Canceled;
|
||||
|
||||
if (!process.HasExited)
|
||||
{
|
||||
process.Kill();
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
incommingTimeMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||
|
||||
info.ExitCode = process.ExitCode;
|
||||
info.StandardOutput = stdOutTask.Result ?? "";
|
||||
info.StandardError = stdErrTask.Result ?? "";
|
||||
string allOutput = info.StandardOutput + info.StandardError;
|
||||
log?.Debug(allOutput);
|
||||
|
||||
if (info.ExitCode != 0)
|
||||
{
|
||||
info.FailureReason = $"CLI exited with exit code {info.ExitCode}.";
|
||||
log?.Error($"{info.Name}: {info.FailureReason} stderr='{info.StandardError}'");
|
||||
}
|
||||
|
||||
info.State = CliTaskState.Completed;
|
||||
return allOutput;
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
info.State = CliTaskState.Faulted;
|
||||
log?.Error("SendAsync failed", ex);
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
info.Process = null;
|
||||
}
|
||||
await Task.WhenAll(stdOutTask, stdErrTask, process.WaitForExitAsync(ct));
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
if (!process.HasExited)
|
||||
{
|
||||
process.Kill();
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
//comming answer from serial port - good place for time stamp
|
||||
incommingTime = DateTime.Now.Ticks;
|
||||
string allOutput = (stdOutTask.Result ?? "") + (stdErrTask.Result ?? "");
|
||||
log?.Debug(allOutput);
|
||||
return allOutput;
|
||||
}
|
||||
|
||||
|
||||
public void AddRunAndCaptureJsonAsync<T>(SerialPortData data, SerialPortData.EMeterArg eMeterArg) where T : new()
|
||||
{
|
||||
AddRunAndCaptureJsonAsync<T>(
|
||||
data.SerialPortCmdClientPath,
|
||||
data.DefaultArgSettings(eMeterArg));
|
||||
var task = RunAndCaptureJsonAsync<T>(data.SerialPortCmdClientPath, data.DefaultArgSettings(eMeterArg));
|
||||
taskPool.Add(task);
|
||||
}
|
||||
|
||||
public void AddRunAndCaptureJsonAsync<T>(string fileName, string args) where T : new()
|
||||
{
|
||||
// Tests deliberately create CliRunner without a logger. Starting a CLI task
|
||||
// must not depend on diagnostics being configured.
|
||||
log?.Debug($"CLI: {fileName}");
|
||||
log?.Debug($"ARGS: {args}");
|
||||
|
||||
ResetStartTime();
|
||||
|
||||
var cts = new CancellationTokenSource();
|
||||
var info = new CliTaskInfo
|
||||
{
|
||||
Cts = cts,
|
||||
Name = $"RunAndCaptureJsonAsync<{typeof(T).Name}>"
|
||||
};
|
||||
|
||||
var task = RunAndCaptureJsonAsync<T>(fileName, args, info, cts.Token);
|
||||
|
||||
info.Task = task;
|
||||
taskPool.Add(info);
|
||||
}
|
||||
|
||||
public async Task<T> RunAndCaptureJsonAsync<T>(string fileName, string args, CliTaskInfo info, CancellationToken ct = default) where T : new()
|
||||
|
||||
public async Task<T> RunAndCaptureJsonAsync<T>(string fileName, string args, CancellationToken ct = default) where T : new()
|
||||
{
|
||||
var psi = new ProcessStartInfo
|
||||
{
|
||||
FileName = fileName,
|
||||
Arguments = args,
|
||||
WorkingDirectory = System.IO.Path.GetDirectoryName(System.IO.Path.GetFullPath(fileName)),
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true
|
||||
};
|
||||
|
||||
using (var process = new Process { StartInfo = psi, EnableRaisingEvents = true })
|
||||
{
|
||||
info.Process = process;
|
||||
using var process = new Process { StartInfo = psi, EnableRaisingEvents = true };
|
||||
process.Start();
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
log?.Debug($"FileName = '{psi.FileName}'");
|
||||
log?.Debug($"Arguments = '{psi.Arguments}'");
|
||||
log?.Debug($"WorkingDirectory = '{psi.WorkingDirectory}'");
|
||||
log?.Debug($"Exists = {System.IO.File.Exists(psi.FileName)}");
|
||||
|
||||
process.Start();
|
||||
var stdoutTask = process.StandardOutput.ReadToEndAsync();
|
||||
var stderrTask = process.StandardError.ReadToEndAsync();
|
||||
|
||||
var stdoutTask = process.StandardOutput.ReadToEndAsync();
|
||||
var stderrTask = process.StandardError.ReadToEndAsync();
|
||||
await Task.WhenAll(stdoutTask, stderrTask, process.WaitForExitAsync(ct));
|
||||
|
||||
try
|
||||
{
|
||||
await Task.WhenAll(stdoutTask, stderrTask, process.WaitForExitAsync(ct));
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
if (info.State != CliTaskState.TimedOut)
|
||||
info.State = CliTaskState.Canceled;
|
||||
string allOutput = (stdoutTask.Result ?? "") + (stderrTask.Result ?? "");
|
||||
log?.Debug(allOutput);
|
||||
|
||||
if (!process.HasExited)
|
||||
{
|
||||
process.Kill();
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
incommingTimeMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||
|
||||
info.ExitCode = process.ExitCode;
|
||||
info.StandardOutput = stdoutTask.Result ?? "";
|
||||
info.StandardError = stderrTask.Result ?? "";
|
||||
string allOutput = info.StandardOutput + info.StandardError;
|
||||
log?.Debug(allOutput);
|
||||
|
||||
if (info.ExitCode != 0)
|
||||
{
|
||||
info.FailureReason = $"CLI exited with exit code {info.ExitCode}.";
|
||||
log?.Error($"{info.Name}: {info.FailureReason} stderr='{info.StandardError}'");
|
||||
info.State = CliTaskState.Completed;
|
||||
return default(T);
|
||||
}
|
||||
|
||||
string json = ExtractJson(allOutput);
|
||||
T result;
|
||||
if (TryJsonStringDeserialize(json, out result))
|
||||
{
|
||||
info.State = CliTaskState.Completed;
|
||||
return result;
|
||||
}
|
||||
|
||||
info.FailureReason = "CLI completed without a valid JSON response.";
|
||||
log?.Error($"{info.Name}: {info.FailureReason} stdout='{info.StandardOutput}' stderr='{info.StandardError}'");
|
||||
info.State = CliTaskState.Completed;
|
||||
return default(T);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
info.State = CliTaskState.Faulted;
|
||||
log?.Error("RunAndCaptureJsonAsync failed", ex);
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
info.Process = null;
|
||||
}
|
||||
}
|
||||
string json = ExtractJson(allOutput);
|
||||
if (TryJsonStringDeserialize(json, out T result)) return result;
|
||||
return default;
|
||||
}
|
||||
|
||||
public bool TryJsonStringDeserialize<T>(string json, out T value) where T : new()
|
||||
public bool TryJsonStringDeserialize<T>(string json, out T runAndCaptureJsonAsync) where T : new()
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(json))
|
||||
if (json != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
value = JsonConvert.DeserializeObject<T>(json);
|
||||
return value != null;
|
||||
runAndCaptureJsonAsync = JsonConvert.DeserializeObject<T>(json);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log?.Debug(ex.Message);
|
||||
return TryConvert(json, out value);
|
||||
log.Debug(ex.Message);
|
||||
runAndCaptureJsonAsync = TryConvert<T>(json);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
value = default(T);
|
||||
runAndCaptureJsonAsync = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool TryConvert<T>(string json, out T value) where T : new()
|
||||
|
||||
private static T TryConvert<T>(string json) where T : new()
|
||||
{
|
||||
T obj = new T();
|
||||
|
||||
T obj = new T();
|
||||
|
||||
try
|
||||
{
|
||||
JObject jObject = JObject.Parse(json);
|
||||
|
||||
foreach (PropertyInfo prop in typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance))
|
||||
try
|
||||
{
|
||||
if (!prop.CanWrite)
|
||||
continue;
|
||||
JObject jObject = JObject.Parse(json);
|
||||
|
||||
JToken token;
|
||||
if (jObject.TryGetValue(prop.Name, StringComparison.OrdinalIgnoreCase, out token))
|
||||
foreach (PropertyInfo prop in typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance))
|
||||
{
|
||||
try
|
||||
{
|
||||
object propertyValue = token.ToObject(prop.PropertyType);
|
||||
prop.SetValue(obj, propertyValue);
|
||||
}
|
||||
catch
|
||||
if (!prop.CanWrite) continue;
|
||||
|
||||
JToken token;
|
||||
if (jObject.TryGetValue(prop.Name, StringComparison.OrdinalIgnoreCase, out token))
|
||||
{
|
||||
try
|
||||
{
|
||||
object value = token.ToObject(prop.PropertyType);
|
||||
prop.SetValue(obj, value);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// leave default if conversion fails
|
||||
}
|
||||
}
|
||||
// else → keep default value
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"TryConvert failed: {ex.Message}");
|
||||
}
|
||||
|
||||
value = obj;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"TryConvert failed: {ex.Message}");
|
||||
value = default(T);
|
||||
return false;
|
||||
}
|
||||
return obj;
|
||||
|
||||
}
|
||||
|
||||
public string ExtractJson(string text)
|
||||
@@ -483,20 +241,6 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
internal void AddTaskForTest(Task task, string name = "TestTask", CancellationTokenSource cts = null)
|
||||
{
|
||||
taskPool.Add(new CliTaskInfo
|
||||
{
|
||||
Task = task,
|
||||
Cts = cts,
|
||||
Name = name,
|
||||
State = task.IsCompleted
|
||||
? (task.IsCanceled ? CliTaskState.Canceled :
|
||||
task.IsFaulted ? CliTaskState.Faulted :
|
||||
CliTaskState.Completed)
|
||||
: CliTaskState.Running
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
{
|
||||
public class CliTaskInfo
|
||||
{
|
||||
public Task Task { get; set; }
|
||||
public CancellationTokenSource Cts { get; set; }
|
||||
public Process Process { get; set; }
|
||||
public CliTaskState State { get; set; } = CliTaskState.Running;
|
||||
public string Name { get; set; }
|
||||
public int? ExitCode { get; set; }
|
||||
public string StandardOutput { get; set; }
|
||||
public string StandardError { get; set; }
|
||||
public string FailureReason { get; set; }
|
||||
|
||||
public bool UseResult
|
||||
{
|
||||
get
|
||||
{
|
||||
return State == CliTaskState.Completed
|
||||
&& Task != null
|
||||
&& Task.Status == TaskStatus.RanToCompletion;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
{
|
||||
public enum CliTaskState
|
||||
{
|
||||
Running,
|
||||
Completed,
|
||||
TimedOut,
|
||||
Canceled,
|
||||
Faulted
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Reflection;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
{
|
||||
public static class GetDescription
|
||||
{
|
||||
public static string ToDescription(this Enum en)
|
||||
{
|
||||
Type type = en.GetType();
|
||||
MemberInfo[] memInfo = type.GetMember(en.ToString());
|
||||
|
||||
if (memInfo != null && memInfo.Length > 0)
|
||||
{
|
||||
object[] attrs = memInfo[0].GetCustomAttributes(
|
||||
typeof(DescriptionAttribute),
|
||||
false);
|
||||
|
||||
if (attrs != null && attrs.Length > 0)
|
||||
return ((DescriptionAttribute)attrs[0]).Description;
|
||||
}
|
||||
|
||||
return en.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,53 +1,22 @@
|
||||
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
{
|
||||
public class JsonDataFromPoseidon
|
||||
{
|
||||
public bool NfcTagDetected { get; set; }
|
||||
public bool ReadingComplete { get; set; }
|
||||
|
||||
public string DeviceId { get; set; }
|
||||
public string ProductType { get; set; }
|
||||
public bool? NfcTagDetected { get; set; }
|
||||
public int? ProductType { get; set; }
|
||||
public string ProductTypeVersion { get; set; }
|
||||
public string CliVersion { get; set; }
|
||||
|
||||
public string DeviceId { get; set; }
|
||||
public string Reading { get; set; }
|
||||
|
||||
public object Reading_Totalizer { get; set; }
|
||||
public object Reading_FlowRate { get; set; }
|
||||
public object Reading_FlowDirection { get; set; }
|
||||
public object Reading_Digits { get; set; }
|
||||
public object Reading_Shift { get; set; }
|
||||
public object Reading_Resolution { get; set; }
|
||||
public string Reading_Totalizer { get; set; }
|
||||
public string Reading_Digits { get; set; }
|
||||
public string Reading_Shift { get; set; }
|
||||
public string Reading_Resolution { get; set; }
|
||||
public string Reading_Units { get; set; }
|
||||
|
||||
public string MeterState { get; set; }
|
||||
public string Reading_FlowDirection { get; set; }
|
||||
public string Reading_FlowRate { get; set; }
|
||||
public string CalibrationFactor { get; set; }
|
||||
public string OpticalDataMode { get; set; }
|
||||
|
||||
public string BuildInformation { get; set; }
|
||||
public string ManufactureDate { get; set; }
|
||||
public string MeterSize { get; set; }
|
||||
public string FactoryId { get; set; }
|
||||
public string CustomerText { get; set; }
|
||||
|
||||
public string TestTotalizer { get; set; }
|
||||
public string FlowUnits { get; set; }
|
||||
public string ReadingUnits { get; set; }
|
||||
|
||||
public string SpreadSpectrumParameters { get; set; }
|
||||
|
||||
public string SpreadSpect_DisableSpreadSpectrum { get; set; }
|
||||
public string SpreadSpect_AlwaysUseFullRateBags { get; set; }
|
||||
public string SpreadSpect_PowerUp { get; set; }
|
||||
public string SpreadSpect_HighNoise { get; set; }
|
||||
public string SpreadSpect_EmptyPipe { get; set; }
|
||||
public string SpreadSpect_BadAdc { get; set; }
|
||||
public string SpreadSpect_InitLearningCompleteCount { get; set; }
|
||||
public string SpreadSpect_MinOffsetLearningSampleCount { get; set; }
|
||||
public string SpreadSpect_AdcShiftUpdateInterval { get; set; }
|
||||
public string SpreadSpect_MaxPreviousAdcAge { get; set; }
|
||||
public string SpreadSpect_AdcOffsetLearningGuard { get; set; }
|
||||
public string SpreadSpect_DisplacementCorrectionCount { get; set; }
|
||||
public bool? ReadingComplete { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -3,12 +3,10 @@
|
||||
///
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.IO.Ports;
|
||||
using System.Xml.Serialization;
|
||||
using TBF.Rig.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Common;
|
||||
using TBF.Rig.Generic;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
{
|
||||
@@ -24,22 +22,7 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
///
|
||||
public int ComPortNr;
|
||||
public string CliFileName;
|
||||
|
||||
[XmlIgnore]
|
||||
public SerialPortData.MeterProduct MeterType = SerialPortData.MeterProduct.Poseidon;
|
||||
|
||||
[XmlElement("MeterProduct")]
|
||||
public string MeterProductXml
|
||||
{
|
||||
get { return SerialPortData.MeterToString(MeterType); }
|
||||
set { MeterType = SerialPortData.StringToMeter(value); }
|
||||
}
|
||||
|
||||
public SerialPortData.HatType HatType = SerialPortData.HatType.Mth;
|
||||
public int TimeOut = 30;
|
||||
public string MainMacro = SerialPortData.MacroTypes.readall.ToDescription();
|
||||
|
||||
|
||||
public int MeterType;
|
||||
|
||||
|
||||
/// <summary> Procedure parameters </summary>
|
||||
@@ -48,68 +31,14 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
public override IParamsProvider GetRuntimeProcParamsProvider() { return ProcParams; }
|
||||
public override IParamsProvider CreateProcParamsProvider() { return new PoseidonProcParams(true); }
|
||||
|
||||
public static bool TryParseMeter(
|
||||
string description,
|
||||
out SerialPortData.MeterProduct meter)
|
||||
{
|
||||
var found = Enum.GetValues(typeof(SerialPortData.MeterProduct))
|
||||
.Cast<SerialPortData.MeterProduct>()
|
||||
.FirstOrDefault(e =>
|
||||
string.Equals(
|
||||
e.GetType()
|
||||
.GetField(e.ToString())
|
||||
.GetCustomAttribute<DescriptionAttribute>()
|
||||
?.Description,
|
||||
description,
|
||||
StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (!Equals(found, default(SerialPortData.MeterProduct)) ||
|
||||
string.Equals(description, "Poseidon", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
meter = found;
|
||||
return true;
|
||||
}
|
||||
|
||||
meter = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool TryParseMacro(
|
||||
string description,
|
||||
out string macro)
|
||||
{
|
||||
var found = Enum.GetValues(typeof(SerialPortData.MacroTypes))
|
||||
.Cast<SerialPortData.MacroTypes>()
|
||||
.FirstOrDefault(e =>
|
||||
string.Equals(
|
||||
e.GetType()
|
||||
.GetField(e.ToString())
|
||||
.GetCustomAttribute<DescriptionAttribute>()
|
||||
?.Description,
|
||||
description,
|
||||
StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (!Equals(found, default(SerialPortData.MacroTypes)) ||
|
||||
string.Equals(description, "readall", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
macro = found.ToDescription();
|
||||
return true;
|
||||
}
|
||||
|
||||
macro = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
string[] paramNames = new string[]
|
||||
{
|
||||
"Serial port number", /// 0
|
||||
"CLI program name", /// 1
|
||||
"Meter Type", /// 2
|
||||
"Hat Type", /// 3
|
||||
"TimeOut [s]", /// 4
|
||||
"Main Macro" /// 5
|
||||
};
|
||||
|
||||
public string ParamName(int i) { return paramNames[i]; }
|
||||
public int ParamsCount() { return paramNames.Length; }
|
||||
|
||||
@@ -122,27 +51,8 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
case 1:
|
||||
return new string[] { "HatCLI.exe"};
|
||||
case 2:
|
||||
return new string[] {
|
||||
SerialPortData.MeterProduct.Poseidon.ToDescription() ,
|
||||
SerialPortData.MeterProduct.Ally.ToDescription(),
|
||||
SerialPortData.MeterProduct.IperlPlus.ToDescription(),
|
||||
SerialPortData.MeterProduct.IperlLegacy.ToDescription()
|
||||
};
|
||||
case 3:
|
||||
return new string[]
|
||||
{
|
||||
SerialPortData.HatType.Mth.ToDescription(),
|
||||
SerialPortData.HatType.Harry.ToDescription()
|
||||
};
|
||||
case 4:
|
||||
return new string[] { "30", "60", "90"};
|
||||
case 5:
|
||||
string macro0 = SerialPortData.MacroTypes.readall.ToDescription();
|
||||
string macro1 = SerialPortData.MacroTypes.macro1.ToDescription();
|
||||
string macro2 = SerialPortData.MacroTypes.macro2.ToDescription();
|
||||
string macro3 = SerialPortData.MacroTypes.macro3.ToDescription();
|
||||
|
||||
return new string[] { macro0, macro1, macro2, macro3 };
|
||||
return new string[] { "74" };
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
@@ -150,15 +60,12 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
|
||||
public IComponentCfgCtrl GetControl(IList<Config.Entities.Component> cmpntEntities) { return new Configs.ParamsProvider.ComponentCfgCtrl(this, null); }
|
||||
|
||||
|
||||
|
||||
public void InitializeAll()
|
||||
{
|
||||
ComPortNr = 3;
|
||||
CliFileName = "HatCLI.exe";
|
||||
MeterType = SerialPortData.MeterProduct.Poseidon;
|
||||
HatType = SerialPortData.HatType.Mth;
|
||||
TimeOut = 30;
|
||||
MainMacro = SerialPortData.MacroTypes.readall.ToDescription();
|
||||
CliFileName = "HatCLI.exe";
|
||||
MeterType = 74;
|
||||
}
|
||||
|
||||
public bool ValidateParam(int i, string strValue, out string message)
|
||||
@@ -176,17 +83,8 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
if(System.Text.RegularExpressions.Regex.IsMatch(strValue, @"^[a-zA-Z0-9_-]+\.exe$")) return true; //validate exe file name
|
||||
break;
|
||||
case 2:
|
||||
if (TryParseMeter(strValue, out var meter)) return true;
|
||||
break;
|
||||
case 3:
|
||||
if (TryParseHatType(strValue, out var hatType)) return true;
|
||||
break;
|
||||
case 4:
|
||||
if (int.TryParse(strValue, out idummy) && idummy > 0) return true;
|
||||
break;
|
||||
case 5:
|
||||
if (TryParseMacro(strValue, out string macroType)) return true;
|
||||
break;
|
||||
default:
|
||||
message = "Invalid index";
|
||||
return false;
|
||||
@@ -202,38 +100,11 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
{
|
||||
case 0: ComPortNr = int.Parse(str); return CfgUpdateFlags.RestartRqrd;
|
||||
case 1: CliFileName = str; return CfgUpdateFlags.RestartRqrd;
|
||||
case 2: TryParseMeter(str, out MeterType); return CfgUpdateFlags.RestartRqrd;
|
||||
case 3: TryParseHatType(str, out HatType); return CfgUpdateFlags.RestartRqrd;
|
||||
case 4: TimeOut = int.Parse(str); return CfgUpdateFlags.RestartRqrd;
|
||||
case 5: MainMacro = str; return CfgUpdateFlags.RestartRqrd;
|
||||
case 2: MeterType = int.Parse(str); return CfgUpdateFlags.RestartRqrd;
|
||||
default: return CfgUpdateFlags.None;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool TryParseHatType(string description, out SerialPortData.HatType hatType)
|
||||
{
|
||||
var found = Enum.GetValues(typeof(SerialPortData.HatType))
|
||||
.Cast<SerialPortData.HatType>()
|
||||
.FirstOrDefault(e =>
|
||||
string.Equals(
|
||||
e.GetType()
|
||||
.GetField(e.ToString())
|
||||
.GetCustomAttribute<DescriptionAttribute>()
|
||||
?.Description,
|
||||
description,
|
||||
StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (!Equals(found, default(SerialPortData.HatType)) ||
|
||||
string.Equals(description, "Mth", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
hatType = found;
|
||||
return true;
|
||||
}
|
||||
|
||||
hatType = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool UpdateEmbeddedDbEntity()
|
||||
{
|
||||
return true; /// =OK, do nothing
|
||||
@@ -268,12 +139,9 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
case 0: return ComPortNr.ToString();
|
||||
case 1: return CliFileName;
|
||||
case 2: return MeterType.ToString();
|
||||
case 3: return HatType.ToString();
|
||||
case 4: return TimeOut.ToString();
|
||||
case 5: return MainMacro;
|
||||
default:
|
||||
return string.Format("{0}: Com{1}, CliName =`{2}`, MeterType = {3}, HatType = {4}, TimeOut = {5}",
|
||||
Name, ComPortNr, CliFileName, MeterType, HatType, TimeOut);
|
||||
return string.Format("{0}: Com{1}, CliName =`{2}`, MeterType = {3}",
|
||||
Name, ComPortNr, CliFileName, MeterType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -282,9 +150,6 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
prms.ComPortNr = this.ComPortNr;
|
||||
prms.CliFileName = this.CliFileName;
|
||||
prms.MeterType = this.MeterType;
|
||||
prms.HatType = this.HatType;
|
||||
prms.TimeOut = this.TimeOut;
|
||||
prms.MainMacro = this.MainMacro;
|
||||
prms.ProcParams = this.ProcParams;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,120 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using TBF.Rig;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
{
|
||||
/// <summary>
|
||||
/// A single polling step for the Poseidon start/end read dialog.
|
||||
///
|
||||
/// A reader is armed only from None. In particular, a terminal reader
|
||||
/// must not be armed again: doing so starts a new CLI process on every
|
||||
/// polling iteration and leaves the dialog in Loading.
|
||||
/// </summary>
|
||||
public interface IPoseidonReadOperation
|
||||
{
|
||||
string Name { get; }
|
||||
bool IsNotStarted { get; }
|
||||
bool IsFinished { get; }
|
||||
bool HasError { get; }
|
||||
void Start(bool readStart);
|
||||
Event Run();
|
||||
}
|
||||
|
||||
public sealed class PoseidonReaderOperation : IPoseidonReadOperation
|
||||
{
|
||||
private readonly PoseidonReader reader;
|
||||
|
||||
public PoseidonReaderOperation(PoseidonReader reader)
|
||||
{
|
||||
if (reader == null) throw new ArgumentNullException(nameof(reader));
|
||||
this.reader = reader;
|
||||
}
|
||||
|
||||
public string Name { get { return reader.Name; } }
|
||||
public bool IsNotStarted { get { return reader.CurrentOp == PoseidonReader.CurrentPoseidonOp.None; } }
|
||||
public bool IsFinished
|
||||
{
|
||||
get
|
||||
{
|
||||
return reader.CurrentOp == PoseidonReader.CurrentPoseidonOp.Done ||
|
||||
reader.CurrentOp == PoseidonReader.CurrentPoseidonOp.Error;
|
||||
}
|
||||
}
|
||||
public bool HasError { get { return reader.CurrentOp == PoseidonReader.CurrentPoseidonOp.Error; } }
|
||||
public void Start(bool readStart)
|
||||
{
|
||||
reader.SetCurrentOp(readStart
|
||||
? PoseidonReader.CurrentPoseidonOp.ReadDataStream_Start
|
||||
: PoseidonReader.CurrentPoseidonOp.ReadDataStream_End);
|
||||
}
|
||||
public Event Run() { return reader.Run(); }
|
||||
}
|
||||
|
||||
public static class PoseidonReadCycle
|
||||
{
|
||||
public static bool RunIteration(IEnumerable<IPoseidonReadOperation> readers, bool readStart)
|
||||
{
|
||||
if (readers == null)
|
||||
return true;
|
||||
|
||||
bool allReadersFinished = true;
|
||||
foreach (IPoseidonReadOperation reader in readers)
|
||||
{
|
||||
if (reader == null)
|
||||
continue;
|
||||
|
||||
// None means that this dialog operation has not been started yet.
|
||||
// Done/Error are terminal and deliberately remain terminal.
|
||||
if (reader.IsNotStarted)
|
||||
reader.Start(readStart);
|
||||
|
||||
reader.Run();
|
||||
|
||||
if (!reader.IsFinished)
|
||||
allReadersFinished = false;
|
||||
}
|
||||
|
||||
return allReadersFinished;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Owns one logical dialog phase. A new phase must arm a reader even when
|
||||
/// the preceding phase left it in Done/Error; within this phase it is armed
|
||||
/// only once.
|
||||
/// </summary>
|
||||
public sealed class PoseidonReadPhaseRunner
|
||||
{
|
||||
private readonly bool readStart;
|
||||
private readonly HashSet<IPoseidonReadOperation> startedReaders =
|
||||
new HashSet<IPoseidonReadOperation>();
|
||||
|
||||
public PoseidonReadPhaseRunner(bool readStart)
|
||||
{
|
||||
this.readStart = readStart;
|
||||
}
|
||||
|
||||
public bool RunIteration(IEnumerable<IPoseidonReadOperation> readers)
|
||||
{
|
||||
if (readers == null)
|
||||
return true;
|
||||
|
||||
bool allReadersFinished = true;
|
||||
foreach (IPoseidonReadOperation reader in readers)
|
||||
{
|
||||
if (reader == null)
|
||||
continue;
|
||||
|
||||
if (startedReaders.Add(reader))
|
||||
reader.Start(readStart);
|
||||
|
||||
reader.Run();
|
||||
if (!reader.IsFinished)
|
||||
allReadersFinished = false;
|
||||
}
|
||||
|
||||
return allReadersFinished;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@
|
||||
///
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.IO.Ports;
|
||||
using System.Text.RegularExpressions;
|
||||
@@ -25,15 +24,14 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
public class PoseidonReader : ComponentBase, IDevice, IRegReaderDatastream, ISessionDataMngmnt, IOperation, ICommonRegReader
|
||||
{
|
||||
private static readonly ILog log = LogManager.GetLogger(typeof(PoseidonReader));
|
||||
// The simulator must never open the configured physical Hat CLI. The
|
||||
// deterministic test CLI returns a valid Poseidon JSON response instead.
|
||||
internal const string SimulatedCliFileName = "cmdSleepTest.exe";
|
||||
public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); }
|
||||
|
||||
readonly PoseidonCfg registerReaderCfg;
|
||||
readonly ControlBoard.IControlBoard controlBoard;
|
||||
|
||||
|
||||
|
||||
public int ComPortNr => registerReaderCfg?.ComPortNr ?? -1;
|
||||
public PoseidonCfg RegPoseidonCfg => registerReaderCfg;
|
||||
|
||||
private bool activeHandlerSessioEnabled = false;
|
||||
private CliRunner _cliRunner;
|
||||
|
||||
@@ -284,23 +282,11 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
if ((DebugLevel == DebugMode.Normal)||(DebugLevel == DebugMode.Simulate))
|
||||
{
|
||||
/// Prepare serial port
|
||||
string cliFileName = GetCliFileNameForMode(DebugLevel, registerReaderCfg.CliFileName);
|
||||
serialPort = new SerialPortData(string.Format("COM{0}", registerReaderCfg.ComPortNr),
|
||||
cliFileName,
|
||||
registerReaderCfg.MeterType, //registerReaderCfg.MeterType, //MeterProduct.Poseidon
|
||||
registerReaderCfg.HatType,//HatType.Mth
|
||||
registerReaderCfg.TimeOut, //timeoutSeconds
|
||||
registerReaderCfg.MainMacro
|
||||
);
|
||||
registerReaderCfg.CliFileName,
|
||||
registerReaderCfg.MeterType);
|
||||
|
||||
|
||||
if (DebugLevel == DebugMode.Simulate)
|
||||
{
|
||||
log.WarnFormat(
|
||||
"{0}: simulation mode enabled; overriding configured CLI '{1}' with '{2}'.",
|
||||
Name, registerReaderCfg.CliFileName, serialPort.SerialPortCmdClientPath);
|
||||
}
|
||||
|
||||
//TODO BUMI prepare serial port - for us do nothing
|
||||
//serialPort.Open();
|
||||
//we can check file program if exists
|
||||
@@ -321,13 +307,6 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
}
|
||||
}
|
||||
|
||||
internal static string GetCliFileNameForMode(DebugMode debugMode, string configuredCliFileName)
|
||||
{
|
||||
return debugMode == DebugMode.Simulate
|
||||
? SimulatedCliFileName
|
||||
: configuredCliFileName;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
log.DebugFormat("{0}:Clear()", Name);
|
||||
@@ -353,21 +332,13 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
/// for debug purposes what time will consume answer
|
||||
/// </summary>
|
||||
private long startTimeInMilis = -1, fullTimeInMilis = -1;
|
||||
/// 30 seconds
|
||||
private static long SafetyTimeOut = 30 * 1000;
|
||||
private long incommingTime = -1;
|
||||
private bool _lastOpTimedOut;
|
||||
private bool lastCliReadingParsed;
|
||||
private string lastCliReadFailureReason;
|
||||
private bool lastCliReadSucceeded;
|
||||
|
||||
|
||||
/// 30 seconds
|
||||
|
||||
public long DeltaTime { get{return fullTimeInMilis;}}
|
||||
public long IncommingTime { get{return incommingTime;}}
|
||||
public bool LastCliReadingParsed { get { return lastCliReadingParsed; } }
|
||||
public string LastCliReadFailureReason { get { return lastCliReadFailureReason; } }
|
||||
public bool LastCliReadSucceeded { get { return lastCliReadSucceeded; } }
|
||||
|
||||
/// <summary>Run this operation</summary>
|
||||
/// <returns>eventDone</returns>
|
||||
@@ -381,262 +352,108 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
|
||||
if (_currentOp == CurrentPoseidonOp.SendStartDataStream)
|
||||
{
|
||||
CliRunner.Clear();
|
||||
_lastOpTimedOut = false;
|
||||
CliRunner.AddSendAsync(serialPort, SerialPortData.EMeterArg.AllParams);
|
||||
_currentOp = CurrentPoseidonOp.SendStartDataStream_Runing;
|
||||
return Event.Busy;
|
||||
return Event.Busy;
|
||||
}
|
||||
else if (_currentOp == CurrentPoseidonOp.SendStartDataStream_Runing)
|
||||
{
|
||||
if (CliRunner.AreTasksDone())
|
||||
if (CliRunner.AreTasksDone()
|
||||
|| CliRunner.TimeOutReceived(SafetyTimeOut))
|
||||
{
|
||||
_currentOp = CurrentPoseidonOp.SendStartDataStream_Done;
|
||||
}
|
||||
else if (CliRunner.TimeOutReceived(SafetyTimeOut))
|
||||
{
|
||||
_lastOpTimedOut = true;
|
||||
CliRunner.CancelUndoneTasksAsTimedOut();
|
||||
_currentOp = CurrentPoseidonOp.SendStartDataStream_Done;
|
||||
}
|
||||
|
||||
return Event.Busy;
|
||||
return Event.Busy;
|
||||
}
|
||||
else if (_currentOp == CurrentPoseidonOp.SendStartDataStream_Done)
|
||||
{
|
||||
var firstTaskInfo = CliRunner.TaskPool
|
||||
.FindLast(t => t.Task is Task<string> && t.UseResult);
|
||||
var firstTask = CliRunner.TaskPool.FindLast(t => t is Task<string>);
|
||||
|
||||
if (firstTaskInfo != null)
|
||||
|
||||
if (firstTask != null && firstTask is Task<string>)
|
||||
{
|
||||
var task = (Task<string>)firstTaskInfo.Task;
|
||||
string data = task.Result;
|
||||
string data = null;
|
||||
data = (firstTask as Task<string>).Result;
|
||||
|
||||
if (!string.IsNullOrEmpty(data))
|
||||
if (data != null && TryGetDeviceId(data, out wmSerialNr))
|
||||
{
|
||||
TryGetDeviceId(data, out wmSerialNr);
|
||||
|
||||
}
|
||||
}
|
||||
else if (_lastOpTimedOut)
|
||||
{
|
||||
log.Warn(
|
||||
$"PoseidonReader {Name}: SendStartDataStream timed out, no completed result will be used.");
|
||||
}
|
||||
|
||||
CliRunner.Clear();
|
||||
_currentOp = _lastOpTimedOut ? CurrentPoseidonOp.Error : CurrentPoseidonOp.Done;
|
||||
_currentOp = CurrentPoseidonOp.Done;
|
||||
return Event.Done;
|
||||
}
|
||||
else if (_currentOp == CurrentPoseidonOp.ReadDataStream_Start
|
||||
else if (_currentOp == CurrentPoseidonOp.ReadDataStream_Start
|
||||
|| _currentOp == CurrentPoseidonOp.ReadDataStream_End)
|
||||
{
|
||||
lastCliReadingParsed = false;
|
||||
lastCliReadFailureReason = null;
|
||||
lastCliReadSucceeded = false;
|
||||
startTimeInMilis = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||
startTimeInMilis = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
|
||||
incommingTime = -1;
|
||||
_isReadingStart = (_currentOp == CurrentPoseidonOp.ReadDataStream_Start);
|
||||
|
||||
CliRunner.Clear();
|
||||
_lastOpTimedOut = false;
|
||||
log.DebugFormat("{0}: starting CLI read, direction={1}, path='{2}', args='{3}'",
|
||||
Name,
|
||||
_isReadingStart ? "start" : "end",
|
||||
serialPort == null ? "<not initialized>" : serialPort.SerialPortCmdClientPath,
|
||||
serialPort == null ? "<not initialized>" : serialPort.DefaultArgSettings(SerialPortData.EMeterArg.AllParams));
|
||||
CliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(serialPort,
|
||||
SerialPortData.EMeterArg.AllParams);
|
||||
CliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(serialPort, SerialPortData.EMeterArg.AllParams);
|
||||
_currentOp = CurrentPoseidonOp.ReadDatastream_Running;
|
||||
return Event.Busy;
|
||||
}
|
||||
else if (_currentOp == CurrentPoseidonOp.ReadDatastream_Running)
|
||||
}else if (_currentOp == CurrentPoseidonOp.ReadDatastream_Running)
|
||||
{
|
||||
if (CliRunner.AreTasksDone())
|
||||
if (CliRunner.AreTasksDone()
|
||||
|| CliRunner.TimeOutReceived(SafetyTimeOut))
|
||||
{
|
||||
_currentOp = CurrentPoseidonOp.ReadDatastream_Done;
|
||||
incommingTime = CliRunner.IncommingTime;
|
||||
log.DebugFormat("{0}: CLI read task finished, taskCount={1}, incomingTime={2}",
|
||||
Name, CliRunner.TaskPool.Count, incommingTime);
|
||||
}
|
||||
else if (CliRunner.TimeOutReceived(SafetyTimeOut))
|
||||
{
|
||||
_lastOpTimedOut = true;
|
||||
CliRunner.CancelUndoneTasksAsTimedOut();
|
||||
_currentOp = CurrentPoseidonOp.ReadDatastream_Done;
|
||||
//set time stamp - end of reading
|
||||
incommingTime = CliRunner.IncommingTime;
|
||||
}
|
||||
|
||||
return Event.Busy;
|
||||
}
|
||||
else if (_currentOp == CurrentPoseidonOp.ReadDatastream_Done)
|
||||
{
|
||||
fullTimeInMilis = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() - startTimeInMilis;
|
||||
log.Debug($"PoseidonReader.Run() Name= {Cfg.Name} fullTimeInMilis = {fullTimeInMilis}");
|
||||
|
||||
fullTimeInMilis = (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - startTimeInMilis;
|
||||
log.Debug($"PoseidonReader.Run() Name= {Cfg.Name} fullTimeInMilis = {fullTimeInMilis} ");
|
||||
JsonDataFromPoseidon data = null;
|
||||
var first = CliRunner.TaskPool.FindLast(t => t is Task<JsonDataFromPoseidon>);
|
||||
if (first != null && first is Task<JsonDataFromPoseidon>)
|
||||
{
|
||||
data = (first as Task<JsonDataFromPoseidon>).Result;
|
||||
|
||||
var firstTaskInfo = CliRunner.TaskPool
|
||||
.FindLast(t => t.Task is Task<JsonDataFromPoseidon> && t.UseResult);
|
||||
|
||||
if (firstTaskInfo != null)
|
||||
{
|
||||
var task = (Task<JsonDataFromPoseidon>)firstTaskInfo.Task;
|
||||
data = task.Result;
|
||||
if (data == null)
|
||||
{
|
||||
lastCliReadFailureReason = firstTaskInfo.FailureReason ?? "CLI returned no Poseidon JSON data.";
|
||||
log.ErrorFormat("{0}: Poseidon {1} read failed. reason='{2}', exitCode={3}, stderr='{4}'",
|
||||
Name,
|
||||
_isReadingStart ? "Begin" : "End",
|
||||
lastCliReadFailureReason,
|
||||
firstTaskInfo.ExitCode,
|
||||
firstTaskInfo.StandardError);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var lastTaskInfo = CliRunner.TaskPool.FindLast(t => t.Task is Task<JsonDataFromPoseidon>);
|
||||
lastCliReadFailureReason = lastTaskInfo == null
|
||||
? "No CLI task was created."
|
||||
: lastTaskInfo.FailureReason ?? "CLI task was not usable, state=" + lastTaskInfo.State + ".";
|
||||
if (_lastOpTimedOut)
|
||||
{
|
||||
log.Warn($"PoseidonReader {Name}: ReadDatastream timed out, no completed result available. {lastCliReadFailureReason}");
|
||||
}
|
||||
else
|
||||
{
|
||||
log.Error($"PoseidonReader {Name}: no usable JsonDataFromPoseidon task. {lastCliReadFailureReason}");
|
||||
}
|
||||
}
|
||||
|
||||
if (data != null)
|
||||
{
|
||||
log.DebugFormat("{0}: CLI read result deviceId={1}, reading={2}, readingComplete={3}, nfcTagDetected={4}",
|
||||
Name, data.DeviceId, data.Reading, data.ReadingComplete, data.NfcTagDetected);
|
||||
string validationError;
|
||||
if (!TryValidateCliReadResponse(data, out validationError))
|
||||
{
|
||||
lastCliReadFailureReason = validationError;
|
||||
log.ErrorFormat("{0}: Poseidon {1} read rejected. {2}. Begin={3}, End={4}",
|
||||
Name, _isReadingStart ? "Begin" : "End", validationError, beginWMState, endWMState);
|
||||
}
|
||||
else
|
||||
{
|
||||
//GET serial number
|
||||
if (string.IsNullOrEmpty(wmSerialNr))
|
||||
{
|
||||
try
|
||||
{
|
||||
wmSerialNr = data.DeviceId ?? wmSerialNr;
|
||||
wmSerialNr = data?.DeviceId ?? wmSerialNr;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.Error("Serial Nr - parse error!", e);
|
||||
log.Error("Serial Nr - parse error!");
|
||||
}
|
||||
}
|
||||
|
||||
double volumeLi;
|
||||
string dialogValueFailureReason;
|
||||
if (TryGetDialogValue(data, out volumeLi, out dialogValueFailureReason))
|
||||
//GET volume
|
||||
if (data != null && Double.TryParse(data.Reading, out double Volume))
|
||||
{
|
||||
lastCliReadingParsed = true;
|
||||
lastCliReadSucceeded = true;
|
||||
double volume;
|
||||
TryParseCliReading(data.Reading, out volume);
|
||||
|
||||
double VolumeLi = Units.ConvertFrom(Unit.USgal, Volume);
|
||||
//double VolumeM3 = Units.ConvertTo(Unit.m3, VolumeLi);
|
||||
if (_isReadingStart)
|
||||
beginWMState = volumeLi;
|
||||
{
|
||||
//volume
|
||||
beginWMState = VolumeLi;
|
||||
}
|
||||
else
|
||||
endWMState = volumeLi;
|
||||
{
|
||||
//volume
|
||||
endWMState = VolumeLi;
|
||||
}
|
||||
}
|
||||
|
||||
log.InfoFormat("{0}: Poseidon {1} value stored. deviceId={2}, rawReading='{3}', gallons={4}, litres={5}, Begin={6}, End={7}",
|
||||
Name, _isReadingStart ? "Begin" : "End", data.DeviceId, data.Reading, volume, volumeLi, beginWMState, endWMState);
|
||||
}
|
||||
else
|
||||
{
|
||||
lastCliReadFailureReason = dialogValueFailureReason;
|
||||
log.ErrorFormat("{0}: cannot parse CLI reading '{1}' using invariant or current culture.",
|
||||
Name, data.Reading);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CliRunner.Clear();
|
||||
_currentOp = _lastOpTimedOut ? CurrentPoseidonOp.Error : CurrentPoseidonOp.Done;
|
||||
|
||||
//Finish reading and loop
|
||||
_currentOp = CurrentPoseidonOp.Done;
|
||||
return Event.Done;
|
||||
}
|
||||
|
||||
return Event.None;
|
||||
|
||||
return Event.None;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// CLI values must not depend on the Windows UI culture. Both dot and comma
|
||||
/// are accepted as a decimal separator and normalized before parsing.
|
||||
/// </summary>
|
||||
public static bool TryParseCliReading(string reading, out double value)
|
||||
{
|
||||
value = 0;
|
||||
if (String.IsNullOrWhiteSpace(reading))
|
||||
return false;
|
||||
|
||||
string normalizedReading = reading.Trim().Replace(',', '.');
|
||||
return Double.TryParse(normalizedReading, NumberStyles.Float, CultureInfo.InvariantCulture, out value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a validated CLI response to the value written into the
|
||||
/// start/end dialog. Poseidon reports US gallons; TBF stores litres.
|
||||
/// </summary>
|
||||
public static bool TryGetDialogValue(JsonDataFromPoseidon data, out double valueLitres,
|
||||
out string failureReason)
|
||||
{
|
||||
valueLitres = 0;
|
||||
if (!TryValidateCliReadResponse(data, out failureReason))
|
||||
return false;
|
||||
|
||||
double valueGallons;
|
||||
if (!TryParseCliReading(data.Reading, out valueGallons))
|
||||
{
|
||||
failureReason = "Reading could not be parsed: '" + data.Reading + "'.";
|
||||
return false;
|
||||
}
|
||||
|
||||
valueLitres = Units.ConvertFrom(Unit.USgal, valueGallons);
|
||||
failureReason = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool TryValidateCliReadResponse(JsonDataFromPoseidon data, out string failureReason)
|
||||
{
|
||||
if (data == null)
|
||||
{
|
||||
failureReason = "CLI returned no JSON data.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!data.NfcTagDetected)
|
||||
{
|
||||
failureReason = "NfcTagDetected=false.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!data.ReadingComplete)
|
||||
{
|
||||
failureReason = "ReadingComplete=false.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (String.IsNullOrWhiteSpace(data.Reading))
|
||||
{
|
||||
failureReason = "Reading is empty.";
|
||||
return false;
|
||||
}
|
||||
|
||||
failureReason = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>Stop this operation</summary>
|
||||
public void Stop()
|
||||
{
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.ComponentModel;
|
||||
using System.Reflection;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
{
|
||||
public class SerialPortData
|
||||
{
|
||||
public const string CliDirectory = @"C:\TBF\Cli";
|
||||
|
||||
private Boolean? _cliExists;
|
||||
public bool CliExists { get {
|
||||
if (_cliExists == null || !_cliExists.HasValue)
|
||||
@@ -18,245 +13,39 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
}
|
||||
return _cliExists.Value;
|
||||
} }
|
||||
public string SerialPortCmdClientPath
|
||||
{
|
||||
get
|
||||
{
|
||||
// The configured value is a file name, not an executable path.
|
||||
// Keeping the CLI directory fixed prevents a bench configuration
|
||||
// from starting an unintended executable or failing due to a
|
||||
// relative path/current-directory change.
|
||||
string cliFileName = Path.GetFileName(CmdClientName);
|
||||
if (string.IsNullOrWhiteSpace(cliFileName))
|
||||
cliFileName = "HalCli.exe";
|
||||
|
||||
return Path.Combine(CliDirectory, cliFileName);
|
||||
}
|
||||
}
|
||||
public string SerialPortCmdClientPath {
|
||||
#if DEBUG
|
||||
get { return Path.Combine("C:\\","TBF","Cli", CmdClientName);}
|
||||
#else
|
||||
get { return Path.Combine("..","Cli", CmdClientName);}
|
||||
#endif
|
||||
}
|
||||
public string CmdClientName { get; set; } = "HalCli.exe";
|
||||
public string PortName { get; set; }
|
||||
// Backward compatibility: old numeric meter type
|
||||
public int? OldMeterType { get; set; }
|
||||
public int MeterType { get; set; }
|
||||
|
||||
// New v2.0 parameters
|
||||
public HatType Hat { get; set; } = HatType.Mth;
|
||||
public int TimeoutSeconds { get; set; } = 10;
|
||||
public string Macro { get; set; } = "readall";
|
||||
|
||||
[XmlIgnore]
|
||||
public MeterProduct Meter { get; set; } = MeterProduct.Poseidon;
|
||||
|
||||
[XmlElement("MeterProduct")]
|
||||
public string MeterXml
|
||||
{
|
||||
get { return MeterToString(Meter); }
|
||||
set { Meter = StringToMeter(value); }
|
||||
}
|
||||
|
||||
public static string MeterToString(MeterProduct meter)
|
||||
{
|
||||
switch (meter)
|
||||
{
|
||||
case MeterProduct.Poseidon:
|
||||
return "Poseidon"; //Poseidon
|
||||
case MeterProduct.Ally:
|
||||
return "ally";
|
||||
case MeterProduct.IperlPlus:
|
||||
return "iperlplus";
|
||||
case MeterProduct.IperlLegacy:
|
||||
return "iperllegacy";
|
||||
default:
|
||||
return "74";
|
||||
}
|
||||
}
|
||||
|
||||
public static MeterProduct StringToMeter(string value)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
return MeterProduct.Poseidon;
|
||||
|
||||
// old numeric values: 74, 7889, etc.
|
||||
if (int.TryParse(value, out _))
|
||||
return MeterProduct.Poseidon;
|
||||
|
||||
if (string.Equals(value, "cTouchRead", StringComparison.OrdinalIgnoreCase))
|
||||
return MeterProduct.Poseidon;
|
||||
|
||||
if (string.Equals(value, "Poseidon", StringComparison.OrdinalIgnoreCase))
|
||||
return MeterProduct.Poseidon;
|
||||
|
||||
if (string.Equals(value, "ally", StringComparison.OrdinalIgnoreCase))
|
||||
return MeterProduct.Ally;
|
||||
|
||||
if (string.Equals(value, "iperlplus", StringComparison.OrdinalIgnoreCase))
|
||||
return MeterProduct.IperlPlus;
|
||||
|
||||
if (string.Equals(value, "iperllegacy", StringComparison.OrdinalIgnoreCase))
|
||||
return MeterProduct.IperlLegacy;
|
||||
|
||||
return MeterProduct.Poseidon;
|
||||
}
|
||||
|
||||
public static bool TryParseMeter(
|
||||
string description,
|
||||
out SerialPortData.MeterProduct meter)
|
||||
{
|
||||
foreach (SerialPortData.MeterProduct value in
|
||||
Enum.GetValues(typeof(SerialPortData.MeterProduct)))
|
||||
{
|
||||
var attr = value.GetType()
|
||||
.GetField(value.ToString())
|
||||
.GetCustomAttribute<DescriptionAttribute>();
|
||||
|
||||
if (string.Equals(attr?.Description, description, StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(value.ToString(), description, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
meter = value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
meter = SerialPortData.MeterProduct.Poseidon;
|
||||
return false;
|
||||
}
|
||||
|
||||
public enum MacroTypes
|
||||
{
|
||||
[Description("readall")]
|
||||
readall = 0,
|
||||
[Description("readmacro1")]
|
||||
macro1 = 1,
|
||||
[Description("readmacro2")]
|
||||
macro2 = 2,
|
||||
[Description("readmacro3")]
|
||||
macro3 = 3
|
||||
}
|
||||
|
||||
public enum HatType
|
||||
{
|
||||
[Description("Mth")]
|
||||
Mth = 0,
|
||||
[Description("Harry")]
|
||||
Harry = 1
|
||||
}
|
||||
|
||||
public enum MeterProduct
|
||||
{
|
||||
[Description("Poseidon")]
|
||||
[XmlEnum("74")]
|
||||
Poseidon = 74,
|
||||
|
||||
[Description("ally")]
|
||||
[XmlEnum("ally")]
|
||||
Ally = 75,
|
||||
|
||||
[Description("iperlplus")]
|
||||
[XmlEnum("iperlplus")]
|
||||
IperlPlus = 76,
|
||||
|
||||
[Description("iperllegacy")]
|
||||
[XmlEnum("iperllegacy")]
|
||||
IperlLegacy = 77
|
||||
}
|
||||
|
||||
public enum EMeterArg
|
||||
{
|
||||
public enum EMeterArg {
|
||||
Calibration = 0,
|
||||
AllParams = 2,
|
||||
DeviceId = 3,
|
||||
|
||||
// New macro operations - just waste
|
||||
ReadMacro1 = 10,
|
||||
ReadMacro2 = 11,
|
||||
ReadMacro3 = 12
|
||||
}
|
||||
}
|
||||
EMeterArg _eMeterArg = EMeterArg.AllParams;
|
||||
|
||||
public string DefaultArgSettings(EMeterArg eMeterArg)
|
||||
public string DefaultArgSettings(EMeterArg eMeterArg)
|
||||
{
|
||||
string commonArgs = BuildCommonArgs();
|
||||
|
||||
switch (eMeterArg)
|
||||
{
|
||||
case EMeterArg.Calibration:
|
||||
return $"{commonArgs} --operation write --parameter Calibration --value 1";
|
||||
|
||||
case EMeterArg.DeviceId:
|
||||
return $"{commonArgs} --operation read --parameter DeviceId";
|
||||
|
||||
return $"-p {PortName} -m {MeterType} --operation write --parameter Calibration --value 1";
|
||||
case EMeterArg.AllParams:
|
||||
case EMeterArg.ReadMacro1:
|
||||
case EMeterArg.ReadMacro2:
|
||||
case EMeterArg.ReadMacro3:
|
||||
return $"{commonArgs} --operation {Macro}";
|
||||
return $"-p {PortName} -m {MeterType} --operation readall";
|
||||
case EMeterArg.DeviceId:
|
||||
return $"-p {PortName} -m {MeterType} --operation read --parameter DeviceId";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private string BuildCommonArgs()
|
||||
{
|
||||
return $"-p {PortName} " +
|
||||
$"-m {GetMeterArgument()} " +
|
||||
$"--hat {GetHatArgument()} " +
|
||||
$"--timeout {TimeoutSeconds}";
|
||||
}
|
||||
|
||||
private string GetMeterArgument()
|
||||
{
|
||||
// Old compatibility mode
|
||||
if (OldMeterType.HasValue)
|
||||
return OldMeterType.Value.ToString();
|
||||
|
||||
switch (Meter)
|
||||
{
|
||||
case MeterProduct.Poseidon:
|
||||
return "74"; //return "Poseidon";
|
||||
|
||||
case MeterProduct.Ally:
|
||||
return "ally";
|
||||
|
||||
case MeterProduct.IperlPlus:
|
||||
return "iperlplus";
|
||||
|
||||
case MeterProduct.IperlLegacy:
|
||||
return "iperllegacy";
|
||||
|
||||
default:
|
||||
return "74"; //return "Poseidon";
|
||||
}
|
||||
}
|
||||
|
||||
private string GetHatArgument()
|
||||
{
|
||||
switch (Hat)
|
||||
{
|
||||
case HatType.Harry:
|
||||
return "harry";
|
||||
|
||||
case HatType.Mth:
|
||||
default:
|
||||
return "mth";
|
||||
}
|
||||
}
|
||||
|
||||
// New constructor for v2.0
|
||||
public SerialPortData(
|
||||
string portName,
|
||||
string cmdClientName,
|
||||
MeterProduct meter = MeterProduct.Poseidon,
|
||||
HatType hat = HatType.Mth,
|
||||
int timeoutSeconds = 10,
|
||||
string macro = "readall")
|
||||
{
|
||||
PortName = portName;
|
||||
CmdClientName = cmdClientName;
|
||||
Meter = meter;
|
||||
Hat = hat;
|
||||
TimeoutSeconds = timeoutSeconds;
|
||||
Macro = macro;
|
||||
}
|
||||
|
||||
// Old constructor kept for backward compatibility
|
||||
public SerialPortData(
|
||||
string portName,
|
||||
string cmdClientName,
|
||||
@@ -264,9 +53,7 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
{
|
||||
PortName = portName;
|
||||
CmdClientName = cmdClientName;
|
||||
OldMeterType = meterType;
|
||||
MeterType = meterType;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.IO;
|
||||
using System.IO.Ports;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms.VisualStyles;
|
||||
using System.Xml.Linq;
|
||||
using Common;
|
||||
using Common.Iperl;
|
||||
@@ -11,6 +12,8 @@ using NHibernate;
|
||||
using Sensus.iPerl.NfcHandler;
|
||||
using TBF.Rig.Generic;
|
||||
using TBF.Rig.GenericDevices;
|
||||
using TBF.Rig.RegisterReaders.PoseidonReader.communication.C7;
|
||||
using TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Protocols;
|
||||
using TBF.Rig.TestMethods.iPerlCommunication.iPerlHead;
|
||||
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.common;
|
||||
using CalibrationStruct = TBF.Rig.RegisterReaders.CommonRR.IPerl.communication.CalibrationStruct;
|
||||
@@ -45,6 +48,7 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
|
||||
readonly PoseidonCfg _poseidonCfg;
|
||||
|
||||
|
||||
public PoseidonCfg RegPoseidonCfg { get { return _poseidonCfg; } }
|
||||
public int RfidComPortNr { get { return _poseidonCfg.RfidComPortNr; } }
|
||||
public int OptoComPortNr { get { return _poseidonCfg.OptoComPortNr; } }
|
||||
public MeterType MeterType { get { return _poseidonCfg.MeterType; } }
|
||||
@@ -86,6 +90,21 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
|
||||
|
||||
float[] x;
|
||||
public float[] X { get { return x; } }
|
||||
|
||||
|
||||
|
||||
// Volume of water from the opto telegram
|
||||
private DateTime _firstSampleTime;
|
||||
private DateTime _lastSampleTime;
|
||||
|
||||
private double _averageFlow;
|
||||
private long _averageFlowCount;
|
||||
private readonly object _avgLock = new object();
|
||||
private bool _optoheadStarted = false;
|
||||
|
||||
private OptoHeadService _optoHeadService;
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Passed to OptoTelegramRaw.UpdateFromString(...)
|
||||
@@ -164,9 +183,7 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
|
||||
///
|
||||
/// Timestamp from the opto telegram
|
||||
///
|
||||
private Int64 lastTimestamp;
|
||||
private double timestampSec;
|
||||
private double timestampSec0;
|
||||
|
||||
|
||||
int timeFromStart; /// [s] Time from test start to determine when the test start sample should be taken
|
||||
|
||||
@@ -174,12 +191,22 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
|
||||
/// Test start volume for metrology in seconds
|
||||
public double TimestampSecStart
|
||||
{
|
||||
get { return TimeFromSamples(optoData, optoDataCount, TestStartTelegramIx, StartEndFilterSamplesCount2); }
|
||||
get
|
||||
{
|
||||
return _lastSampleTime != DateTime.MinValue ? 1 : 0; // return one second if is initialized, 0 - is false
|
||||
//return TimeFromSamples(optoData, optoDataCount, TestStartTelegramIx, StartEndFilterSamplesCount2);
|
||||
}
|
||||
}
|
||||
/// Test end time for metrology in seconds
|
||||
public double TimestampSecEnd
|
||||
{
|
||||
get { return TimeFromSamples(optoData, optoDataCount, TestEndTelegramIx, StartEndFilterSamplesCount2); }
|
||||
get
|
||||
{
|
||||
if (_lastSampleTime == DateTime.MinValue) return 0;
|
||||
TimeSpan delta = _lastSampleTime - _firstSampleTime;
|
||||
return (delta.TotalSeconds + 1);
|
||||
//return TimeFromSamples(optoData, optoDataCount, TestEndTelegramIx, StartEndFilterSamplesCount2);
|
||||
}
|
||||
}
|
||||
///
|
||||
public bool NoSamples
|
||||
@@ -197,12 +224,20 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
|
||||
/// Test start volume for metrology in liters
|
||||
public double VolumeLtrStart
|
||||
{
|
||||
get { return NoSamples ? 0 : VolumeFromSamples(optoData, optoDataCount, TestStartTelegramIx, ScalingFactor(), StartEndFilterSamplesCount2); }
|
||||
get
|
||||
{
|
||||
return 0;
|
||||
//return NoSamples ? 0 : VolumeFromSamples(optoData, optoDataCount, TestStartTelegramIx, ScalingFactor(), StartEndFilterSamplesCount2);
|
||||
}
|
||||
}
|
||||
/// Test end volume for metrology in liters
|
||||
public double VolumeLtrEnd
|
||||
{
|
||||
get { return NoSamples ? 0 : VolumeFromSamples(optoData, optoDataCount, TestEndTelegramIx, ScalingFactor(), StartEndFilterSamplesCount2); }
|
||||
get
|
||||
{
|
||||
return wmVolume; // complet calculated volume (time * flowrate)
|
||||
//return NoSamples ? 0 : VolumeFromSamples(optoData, optoDataCount, TestEndTelegramIx, ScalingFactor(), StartEndFilterSamplesCount2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -274,9 +309,10 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
|
||||
{
|
||||
if (_poseidonCfg != null)
|
||||
{
|
||||
OpenOptoSerialPort($"COM{_poseidonCfg.OptoComPortNr}", 9600, Parity.None, 8, StopBits.One,
|
||||
Handshake.None);
|
||||
CloseOptoSerialPort();
|
||||
|
||||
// OpenOptoSerialPort($"COM{_poseidonCfg.OptoComPortNr}", 9600, Parity.None, 8, StopBits.One,
|
||||
// Handshake.None);
|
||||
// CloseOptoSerialPort();
|
||||
log.FatalFormat($"{Name} initialized: {this}");
|
||||
}
|
||||
else
|
||||
@@ -401,6 +437,16 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
|
||||
Q2CorrRL = 0;
|
||||
Q2CorrLR = 0;
|
||||
|
||||
|
||||
lock (_avgLock)
|
||||
{
|
||||
_firstSampleTime = DateTime.MinValue;
|
||||
_lastSampleTime = DateTime.MinValue;
|
||||
_averageFlow = 0;
|
||||
_averageFlowCount = 0;
|
||||
log.Debug("Initializing datastream state");
|
||||
}
|
||||
|
||||
simulatedPcbNr = null;
|
||||
|
||||
dataStreamState = DataStreamState.Flush;
|
||||
@@ -442,6 +488,12 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
|
||||
{
|
||||
timeFromStart += StateMachine.Period;
|
||||
ReadPulses();
|
||||
|
||||
//TODO read flow
|
||||
if (_optoHeadService!= null && !_optoHeadService.IsRunning)
|
||||
StartOptohead();
|
||||
|
||||
|
||||
|
||||
if (!startSampleAcquired && (timeFromStart >= 8) && (currentTelegramIx >= 0))
|
||||
{
|
||||
@@ -462,7 +514,94 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
|
||||
return Event.ReadRegisterDone;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
private void StartOptohead()
|
||||
{
|
||||
lock (_avgLock)
|
||||
{
|
||||
_firstSampleTime = DateTime.MinValue;
|
||||
_lastSampleTime = DateTime.MinValue;
|
||||
_averageFlow = 0;
|
||||
_averageFlowCount = 0;
|
||||
}
|
||||
|
||||
StartOptoTestInputLoop(new EventHandler<CommonRR.IPerl.communication.OptoReceivedEventArgs>(OnOptoHandler));
|
||||
}
|
||||
|
||||
private bool OpenOptoConnection(PoseidonCfg iHeadCfg)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (iHeadCfg != null)
|
||||
{
|
||||
if (_optoHeadService != null) return false;
|
||||
|
||||
OptoHeadService.Con connection = new OptoHeadService.Con($"COM{iHeadCfg.OptoComPortNr}", iHeadCfg.DebugLevel);
|
||||
_optoHeadService = new OptoHeadService(connection);
|
||||
return _optoHeadService.CreateSerialConnection();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool StartOptoTestInputLoop(EventHandler<CommonRR.IPerl.communication.OptoReceivedEventArgs> onOptoReceivedHandler)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_optoHeadService != null)
|
||||
{
|
||||
if (_optoHeadService.IsRunning) return false;
|
||||
|
||||
_optoHeadService.RunLoop(onOptoReceivedHandler);
|
||||
//run loop runstate = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.Error(ex.Message);
|
||||
throw ex;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void OnOptoHandler(object sender, CommonRR.IPerl.communication.OptoReceivedEventArgs e)
|
||||
{
|
||||
//received data from optohead
|
||||
WaterMetrologyData eWaterMetrologyData = e?.WaterMetrologyData;
|
||||
if (eWaterMetrologyData != null && eWaterMetrologyData.C7Data != null)
|
||||
{
|
||||
double flowRateLPerS = eWaterMetrologyData.C7Data?.FlowRateLPerS ?? 0;
|
||||
|
||||
lock (_avgLock)
|
||||
{
|
||||
if (_averageFlowCount == 0)
|
||||
{
|
||||
_firstSampleTime = eWaterMetrologyData.C7Data?.Dt ?? DateTime.Now;
|
||||
}
|
||||
|
||||
_lastSampleTime = eWaterMetrologyData.C7Data?.Dt ?? DateTime.Now;
|
||||
|
||||
_averageFlowCount++;
|
||||
|
||||
// Running average (no overflow)
|
||||
_averageFlow += (flowRateLPerS - _averageFlow) / _averageFlowCount;
|
||||
TimeSpan delta = _lastSampleTime - _firstSampleTime;
|
||||
if (delta.TotalMilliseconds == 0)
|
||||
wmVolume = 0;
|
||||
else
|
||||
wmVolume = _averageFlow * (delta.TotalMilliseconds / 1000); //volume in liters
|
||||
//wmVolume = Units.ConvertFrom(Unit.l, _averageFlow * (delta.TotalMilliseconds / 1000));
|
||||
log.Info("Calculated Value:" + wmVolume);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Stop this operation
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
@@ -570,78 +709,7 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Q2 correction factor calculated from the last test (Q2).
|
||||
/// This factor should be used only for R800 meters.
|
||||
/// </summary>
|
||||
/// <param name="q2TestResult">A test result from which to calculate the factor</param>
|
||||
/// <param name="nominalFlow">Nominal flow in m3/h</param>
|
||||
/// <param name="currentFactor">0 or the current Q2 correction factor when updating the factor</param>
|
||||
/// <returns>Calculated Q2 correction factor</returns>
|
||||
public double CalculateQ2CorrectionFactor(Results.Entities.MeterTestRslt currentQ2Result, int currentFactor, double nominalFlow, double errorTarget = 0)
|
||||
{
|
||||
double nominalTestFlowLph = Units.ConvertTo(Unit.lph, nominalFlow);
|
||||
double volumeRefShiftedToTarget = currentQ2Result.VolumeRef * (1.0 + errorTarget / 100.0);
|
||||
double q2adjErrorShiftedToTarget = Config.Formulas.ErrorFromVolumes(currentQ2Result.VolumeMeter, volumeRefShiftedToTarget);
|
||||
|
||||
double A = 16.0 / ScalingFactor(); /// Raw units per ml: DN15=16, DN20=8, DN25=4, DN32=2, DN40=1
|
||||
const double B = 8.0; /// Raw units per minute, 8
|
||||
const double C = B * 60.0; /// Raw units per hour, 480
|
||||
double D = C / A; /// ml correction per hour
|
||||
double F = D / (nominalTestFlowLph * 10.0); /// Error corrected with 8 Raw Units per minute [%]
|
||||
double G = F / B; /// Error corrected with 1 Raw Unit per minute [%]
|
||||
|
||||
/// Do not change the factor for an invalid measurement (q2adjResult.VolumeMeter == 0)
|
||||
double q2CorrectionFactor = (Math.Abs(currentQ2Result.VolumeMeter) <= float.Epsilon) ? Convert.ToDouble(currentFactor) :
|
||||
Convert.ToDouble(currentFactor) - (q2adjErrorShiftedToTarget / G) * (volumeRefShiftedToTarget / currentQ2Result.VolumeMeter);
|
||||
|
||||
log.WarnFormat("CalculateQ2CorrectionFactor() : Pos={0}, PCB#={1}, Error={2}%, Target={3}%, Current factor={4} New factor={5}",
|
||||
Name,
|
||||
SerialNr,
|
||||
currentQ2Result.Error.ToString("F2"),
|
||||
errorTarget.ToString("F3"),
|
||||
currentFactor.ToString("F1"),
|
||||
q2CorrectionFactor.ToString("F1"));
|
||||
|
||||
return q2CorrectionFactor;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 2 Hz correction factor calculated from two Q3 tests - done at 2Hz and at 8Hz.
|
||||
/// This factors should be used only for DN32 and DN40 meters.
|
||||
/// </summary>
|
||||
/// <param name="resultAt2Hz">Test result @2Hz from which to calculate the factor</param>
|
||||
/// <param name="resultAt8Hz">Test result @8Hz from which to calculate the factor</param>
|
||||
/// <param name="hz2CorrectionFactor">The calculated Q2 correction factor</param>
|
||||
/// <returns>true = OK, false = failed</returns>
|
||||
public bool Calculate2HzCorrectionFactor(Results.Entities.MeterTestRslt resultAt2Hz,
|
||||
Results.Entities.MeterTestRslt resultAt8Hz,
|
||||
out double diff2Hz8Hz, out int hz2CorrectionFactor)
|
||||
{
|
||||
hz2CorrectionFactor = 0;
|
||||
diff2Hz8Hz = 0;
|
||||
|
||||
if ((resultAt2Hz == null) || (resultAt8Hz == null))
|
||||
{
|
||||
return false; /// Test result @2Hz and/or @8Hz is missing ==> water meter failed
|
||||
}
|
||||
|
||||
diff2Hz8Hz = resultAt2Hz.Error - resultAt8Hz.Error;
|
||||
|
||||
if (Math.Abs(diff2Hz8Hz) > 2.5) return false; /// Difference of errors > 2.5 % ==> water meter failed
|
||||
|
||||
hz2CorrectionFactor = -1 * (int)Math.Round(10 * diff2Hz8Hz);
|
||||
|
||||
log.WarnFormat("2Hz correction: Pos={0}, PCB#={1}, corrFactor={2}, erro@2Hz={3}%, erro@8Hz={4}%",
|
||||
Name,
|
||||
SerialNr,
|
||||
hz2CorrectionFactor,
|
||||
resultAt2Hz.Error.ToString("F2"),
|
||||
resultAt8Hz.Error.ToString("F2"));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
@@ -703,147 +771,24 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
|
||||
/// <param name="optoState">OptoState.Read or OptoState.Flush</param>
|
||||
void ReadOptoData(DataStreamState optoState)
|
||||
{
|
||||
if (optoSerialPort is null) return;
|
||||
lock (this)
|
||||
{
|
||||
int nrBytes = optoSerialPort.BytesToRead;
|
||||
if (nrBytes > 0)
|
||||
{
|
||||
char[] buffer = new char[nrBytes];
|
||||
optoSerialPort.Read(buffer, 0, nrBytes);
|
||||
string received = new string(buffer);
|
||||
|
||||
string allRcvd = partOfTelegram + received;
|
||||
|
||||
while (true)
|
||||
{
|
||||
int pos = allRcvd.IndexOf("\r\n");
|
||||
|
||||
if (pos < 0)
|
||||
{
|
||||
/// No CR+LF found, wait for more characters in the next invocation
|
||||
partOfTelegram = allRcvd;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
/// CR+LF found
|
||||
if (optoState == DataStreamState.ProcessAndSave)
|
||||
{
|
||||
int bufferIx = BufferIdx(optoDataCount);
|
||||
|
||||
if (pos < OptoTelegramRaw.Length - 2)
|
||||
{
|
||||
/// CR+LF found too early, truncate the beginning incl CR+LF and keep scanning in this loop
|
||||
allRcvd = allRcvd.Substring(pos + 2);
|
||||
if (synchronized)
|
||||
{
|
||||
optoData[bufferIx].Counter = optoDataCount;
|
||||
optoData[bufferIx].SetFlags(OptoTelegramFlags.SyncError);
|
||||
}
|
||||
synchronized = true;
|
||||
}
|
||||
else if (optoData[bufferIx].UpdateFromString(allRcvd.Substring(pos - OptoTelegramRaw.Length + 2),
|
||||
optoDataCount,
|
||||
Convert.ToSingle(Sequences.ProcessData.RefFlow.Val),
|
||||
ref volumeRawExtLast, ref timestampExtLast))
|
||||
{
|
||||
/// CR+LF was found && (pos >= OptoTelegramRaw.Length - 2) && the telegram is OK
|
||||
flowDirectionDetection.WriteToFifo(volumeRawExtLast, timestampExtLast);
|
||||
OptoTelegramReceived(optoDataCount, synchronized2, volumeRawExtLast, timestampExtLast);
|
||||
synchronized2 = synchronized;
|
||||
allRcvd = allRcvd.Substring(pos + 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
/// CR+LF was found && (pos >= OptoTelegramRaw.Length - 2) but the telgram was not OK
|
||||
optoData[bufferIx].Counter = optoDataCount;
|
||||
optoDataCount++;
|
||||
allRcvd = allRcvd.Substring(pos + 2);
|
||||
}
|
||||
|
||||
optoDataCount++;
|
||||
}
|
||||
else /// optoState == OptoState.Flush
|
||||
{
|
||||
if (pos < OptoTelegramRaw.Length - 2)
|
||||
{
|
||||
/// CR+LF found too early, truncate the beginning incl CR+LF and keep scanning in this loop
|
||||
allRcvd = allRcvd.Substring(pos + 2);
|
||||
synchronized = true;
|
||||
}
|
||||
// CR+LF found and (pos >= OptoTelegram.Length - 2)
|
||||
else if (toBeFlushed.UpdateFromString(allRcvd.Substring(pos - OptoTelegramRaw.Length + 2),
|
||||
0,
|
||||
Convert.ToSingle(Sequences.ProcessData.RefFlow.Val),
|
||||
ref volumeRawExtLast, ref timestampExtLast))
|
||||
{
|
||||
flowDirectionDetection.WriteToFifo(volumeRawExtLast, timestampExtLast);
|
||||
synchronized2 = synchronized;
|
||||
allRcvd = allRcvd.Substring(pos + 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
allRcvd = allRcvd.Substring(pos + 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//OnOptoReceived(this, new OptoReceivedEventArgs(s));
|
||||
}
|
||||
else
|
||||
{
|
||||
//OnOptoReceived(this, new OptoReceivedEventArgs("."));
|
||||
}
|
||||
}
|
||||
|
||||
// lock (this)
|
||||
// {
|
||||
//
|
||||
// }
|
||||
}
|
||||
|
||||
public string ReadOptoData()
|
||||
{
|
||||
if (optoSerialPort is null) return "";
|
||||
string received = ".";
|
||||
lock (this)
|
||||
{
|
||||
int nrBytes = optoSerialPort.BytesToRead;
|
||||
if (nrBytes > 0)
|
||||
{
|
||||
char[] buffer = new char[nrBytes];
|
||||
optoSerialPort.Read(buffer, 0, nrBytes);
|
||||
received = new string(buffer);
|
||||
}
|
||||
}
|
||||
// lock (this)
|
||||
// {
|
||||
//
|
||||
// }
|
||||
return received;
|
||||
}
|
||||
|
||||
|
||||
void OptoTelegramReceived(int currentIx, bool async, Int64 volumeRawExt, Int64 timestampRawExt)
|
||||
{
|
||||
currentTelegramIx = currentIx;
|
||||
|
||||
lastVolumeRaw = volumeRawExt;
|
||||
lastTimestamp = timestampRawExt;
|
||||
|
||||
if (volumeLtr == 0 && volumeLtr0 == 0)
|
||||
{
|
||||
volumeLtr = (double)lastVolumeRaw * ScalingFactor() / 16000.0;
|
||||
volumeLtr0 = volumeLtr;
|
||||
}
|
||||
else
|
||||
{
|
||||
volumeLtr = (double)lastVolumeRaw * ScalingFactor() / 16000.0;
|
||||
}
|
||||
|
||||
if (timestampSec == 0 && timestampSec0 == 0)
|
||||
{
|
||||
timestampSec = (double)lastTimestamp / 8192.0;
|
||||
timestampSec0 = timestampSec;
|
||||
}
|
||||
else
|
||||
{
|
||||
timestampSec = (double)lastTimestamp / 8192.0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
@@ -1002,12 +947,15 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
|
||||
|
||||
void ReadPulses()
|
||||
{
|
||||
beginWMState = volumeLtr0;
|
||||
endWMState = volumeLtr;
|
||||
TimeSpan delta = _lastSampleTime - _firstSampleTime;
|
||||
double volume = _averageFlow * (delta.TotalMilliseconds / 1000);
|
||||
//log.Debug("ReadPulses - Calculated Value:" + volume);
|
||||
beginWMState = 1;
|
||||
endWMState = beginWMState + volume ;
|
||||
wmVolume = Math.Abs(endWMState - beginWMState);
|
||||
wmPulses = (int)(wmVolume * (double)PulsesPerLtr + 0.5);
|
||||
wmRefPulses = StateMachine.ControlBoardMain.RefPulses;
|
||||
wmTestTime = timestampSec - timestampSec0;
|
||||
wmTestTime = delta.TotalSeconds;
|
||||
}
|
||||
|
||||
private void OpenOptoSerialPort(string comPort, int baudRate, Parity parity, int dataBits, StopBits stopBit, Handshake handshake)
|
||||
@@ -1018,6 +966,7 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
|
||||
/// Open serial port: 9600 Bd, 8 data bits, 1 stop bit, no parity
|
||||
try
|
||||
{
|
||||
|
||||
CloseOptoSerialPort();
|
||||
optoSerialPort = new SerialPort(comPort, baudRate, parity, dataBits, stopBit);
|
||||
optoSerialPort.Handshake = handshake;
|
||||
@@ -1039,12 +988,15 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
|
||||
|
||||
private void CloseOptoSerialPort()
|
||||
{
|
||||
if (optoSerialPort != null)
|
||||
if (_optoHeadService != null)
|
||||
{
|
||||
optoSerialPort.Close();
|
||||
optoSerialPort = null;
|
||||
_optoHeadService.CloseSerialConnection();
|
||||
_optoHeadService = null;
|
||||
log.FatalFormat($"{Name} OptoPort closed: {this}");
|
||||
}
|
||||
|
||||
|
||||
communication.OpticalHeadTest.SetActiveMode(_poseidonCfg);
|
||||
}
|
||||
|
||||
|
||||
@@ -1056,10 +1008,14 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
|
||||
{
|
||||
try
|
||||
{
|
||||
OpenOptoSerialPort($"COM{_poseidonCfg.OptoComPortNr}", 9600, Parity.None, 8, StopBits.One, Handshake.None);
|
||||
//set test mode via the cli
|
||||
communication.OpticalHeadTest.SetTestMode(_poseidonCfg);
|
||||
//open opto serial port
|
||||
OpenOptoConnection(_poseidonCfg);
|
||||
}
|
||||
catch (Exception)
|
||||
catch (Exception e)
|
||||
{
|
||||
log.Error($"{Name} OptoPort - error opening port: {_poseidonCfg.OptoComPortNr}, Details: {e.Message}");
|
||||
}
|
||||
/// Reset opto-data, etc.
|
||||
optoDataCount = 0;
|
||||
@@ -1482,8 +1438,7 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
|
||||
|
||||
volumeLtr = 0;
|
||||
volumeLtr0 = 0;
|
||||
timestampSec = 0;
|
||||
timestampSec0 = 0;
|
||||
|
||||
|
||||
extraDataPath = null;
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using log4net;
|
||||
using TBF.Rig.RegisterReaders.CommonRR.IPerl.communication;
|
||||
using TBF.Rig.RegisterReaders.iPerlReaderUNI.common;
|
||||
using TBF.Rig.RegisterReaders.PoseidonReader.implementations;
|
||||
@@ -12,7 +11,6 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
|
||||
{
|
||||
public partial class UniHeadTestCtrl : UserControl
|
||||
{
|
||||
private static readonly ILog log = LogManager.GetLogger(typeof(UniHeadTestCtrl));
|
||||
private IUniHeadTestCtrl _ctrl;
|
||||
private IUniHeadTestCtrl Ctrl { get => _ctrl; }
|
||||
|
||||
@@ -79,12 +77,6 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
|
||||
RfidOutputListBox = rfidOutputListBox
|
||||
});
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
// A device/CLI communication failure must not terminate Application.Run.
|
||||
log.Error("Poseidon head test command failed.", exception);
|
||||
rfidOutputListBox.Items.Add("Error: " + exception.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
commandTestButton.Enabled = true;
|
||||
|
||||
@@ -2,6 +2,8 @@ using System;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using log4net;
|
||||
using TBF.Rig.Output.Printers.Label;
|
||||
using TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Utils;
|
||||
using CliRunner = TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Utils.CliRunnerOld;
|
||||
using OptoHeadStatus = TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Protocols.OptoHeadStatus;
|
||||
@@ -13,6 +15,7 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7
|
||||
public class NfcHeadServiceOld
|
||||
{
|
||||
|
||||
private static readonly ILog log = LogManager.GetLogger(typeof(NfcHeadServiceOld));
|
||||
private bool activeHandlerSessioEnabled = false;
|
||||
private CliRunner _cliRunner;
|
||||
|
||||
@@ -208,7 +211,8 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception($"Failed to parse OptoHeadStatus from output. Result: {result}");
|
||||
log.Error($"Failed to parse OptoHeadStatus from output. Result: {result}");
|
||||
//throw new Exception($"Failed to parse OptoHeadStatus from output. Result: {result}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
using System;
|
||||
using System.IO.Ports;
|
||||
using System.Threading.Tasks;
|
||||
using Common;
|
||||
using log4net;
|
||||
using TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Protocols;
|
||||
using TBF.Rig.Sequences;
|
||||
using SERIAL_Driver = TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Utils.SERIAL_Driver;
|
||||
using WaterMetrologyData = TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Protocols.WaterMetrologyData;
|
||||
|
||||
@@ -8,9 +12,11 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7
|
||||
{
|
||||
public class OptoHeadService
|
||||
{
|
||||
|
||||
static readonly ILog log = LogManager.GetLogger("PoseidonConnection");
|
||||
|
||||
public class Con
|
||||
{
|
||||
|
||||
public string com = "COM5";
|
||||
public int baudrate = 38400;
|
||||
public int dataBits = 8;
|
||||
@@ -18,6 +24,8 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7
|
||||
public StopBits stopbits = StopBits.Two;
|
||||
public int readTimeout = 5000;
|
||||
public int writeTimeout = 1000;
|
||||
private DebugMode _debugLevel;
|
||||
public DebugMode DebugModeSetting { get => _debugLevel; }
|
||||
|
||||
public Con(string com, int baudrate, int dataBits, Parity parity, StopBits stopbits, int readTimeout,
|
||||
int writeTimeout) : this(com)
|
||||
@@ -29,10 +37,23 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7
|
||||
this.readTimeout = readTimeout;
|
||||
this.writeTimeout = writeTimeout;
|
||||
}
|
||||
|
||||
public Con(DebugMode debugLevel,string com, int baudrate, int dataBits, Parity parity, StopBits stopbits, int readTimeout,
|
||||
int writeTimeout) : this(com)
|
||||
{
|
||||
this._debugLevel = debugLevel;
|
||||
this.baudrate = baudrate;
|
||||
this.dataBits = dataBits;
|
||||
this.parity = parity;
|
||||
this.stopbits = stopbits;
|
||||
this.readTimeout = readTimeout;
|
||||
this.writeTimeout = writeTimeout;
|
||||
}
|
||||
|
||||
public Con(string com)
|
||||
public Con(string com, DebugMode debugLevel = DebugMode.Normal)
|
||||
{
|
||||
this.com = com;
|
||||
this._debugLevel = debugLevel;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,11 +76,19 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7
|
||||
OnOptoReceivedHandler = null;
|
||||
bool isopen = false;
|
||||
Con con = Connection;
|
||||
if (con == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
byte[] message = {0x00};
|
||||
byte[] bytesReceived;
|
||||
|
||||
if (!driver.isOpen())
|
||||
if (con?.DebugModeSetting == DebugMode.Simulate)
|
||||
{
|
||||
isopen = true;
|
||||
}
|
||||
else if (!driver.isOpen())
|
||||
{
|
||||
|
||||
isopen = driver.OpenConnection(
|
||||
@@ -72,6 +101,8 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7
|
||||
con.writeTimeout);
|
||||
}
|
||||
|
||||
_bRunStarted = false;
|
||||
|
||||
return isopen;
|
||||
}
|
||||
|
||||
@@ -79,24 +110,39 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7
|
||||
{
|
||||
dissableRunLoop = true;
|
||||
OnOptoReceivedHandler = null;
|
||||
driver.Close();
|
||||
OnOptoReceivedHandler = null;
|
||||
if (Connection?.DebugModeSetting != DebugMode.Simulate)
|
||||
{
|
||||
driver.Close();
|
||||
}
|
||||
_bRunStarted = false;
|
||||
}
|
||||
|
||||
private EventHandler<CommonRR.IPerl.communication.OptoReceivedEventArgs> OnOptoReceivedHandler;
|
||||
|
||||
|
||||
|
||||
public bool IsRunning
|
||||
{
|
||||
get { return !dissableRunLoop
|
||||
&& ((Connection?.DebugModeSetting != DebugMode.Simulate) ? driver.isOpen() : true)
|
||||
&& _bRunStarted;}
|
||||
}
|
||||
|
||||
public void RunLoop(EventHandler<CommonRR.IPerl.communication.OptoReceivedEventArgs> onOptoReceivedHandler)
|
||||
{
|
||||
log.Debug("RunLoop started on event!");
|
||||
OnOptoReceivedHandler = onOptoReceivedHandler;
|
||||
Task.Run(() => Run());
|
||||
}
|
||||
|
||||
public void RunLoop()
|
||||
{
|
||||
log.Debug("RunLoop started!");
|
||||
Task.Run(() => Run());
|
||||
}
|
||||
|
||||
private bool dissableRunLoop = false;
|
||||
private bool _bRunStarted = false;
|
||||
/// <summary>
|
||||
/// Run the service. Catch one communication to WaterMetrologyData field.
|
||||
/// </summary>
|
||||
@@ -104,10 +150,12 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7
|
||||
{
|
||||
while (!dissableRunLoop)
|
||||
{
|
||||
_bRunStarted = true;
|
||||
WaterMetrologyData = ParseData(RunReading());
|
||||
if (OnOptoReceivedHandler != null && WaterMetrologyData != null)
|
||||
{
|
||||
OnOptoReceivedHandler.Invoke(this, new CommonRR.IPerl.communication.OptoReceivedEventArgs(WaterMetrologyData.ToString()));
|
||||
log.Debug($"Received OptoData: {WaterMetrologyData}");
|
||||
OnOptoReceivedHandler?.Invoke(this, new CommonRR.IPerl.communication.OptoReceivedEventArgs(WaterMetrologyData?.ToString(), WaterMetrologyData));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,13 +163,20 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7
|
||||
|
||||
byte[] RunReading()
|
||||
{
|
||||
if (Connection?.DebugModeSetting != DebugMode.Simulate)
|
||||
{
|
||||
return new byte[] {0x00};
|
||||
}
|
||||
if (driver.isOpen())
|
||||
{
|
||||
driver.SendMessage(new byte[] {0x00}, 1);
|
||||
return driver.GetRawData();
|
||||
byte[] rawData = driver.GetRawData();
|
||||
log.Debug($"Received data size: {rawData?.Length ?? 0} bytes, raw data: {(rawData==null? "" :BitConverter.ToString(rawData))}");
|
||||
return rawData;
|
||||
}
|
||||
else
|
||||
{
|
||||
log.Debug("Serial port is not open.");
|
||||
dissableRunLoop = true;
|
||||
}
|
||||
|
||||
@@ -130,6 +185,10 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7
|
||||
|
||||
public WaterMetrologyData ParseData(byte[] data)
|
||||
{
|
||||
if (Connection?.DebugModeSetting != DebugMode.Simulate)
|
||||
{
|
||||
return WaterMetrologyData.SimulateC7();
|
||||
}
|
||||
try
|
||||
{
|
||||
if (data == null || data.Length == 0)
|
||||
|
||||
+15
@@ -37,6 +37,21 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Protocols
|
||||
return waterMetrologyData;
|
||||
}
|
||||
|
||||
public static WaterMetrologyData SimulateC7()
|
||||
{
|
||||
WaterMetrologyData waterMetrologyData = new WaterMetrologyData();
|
||||
waterMetrologyData.c7Data = WaterMetrologyDataC7.Simulate();
|
||||
return waterMetrologyData;
|
||||
}
|
||||
|
||||
public static WaterMetrologyData SimulateC2()
|
||||
{
|
||||
WaterMetrologyData waterMetrologyData = new WaterMetrologyData();
|
||||
waterMetrologyData.c2Data = WaterMetrologyDataC2.Simulate();
|
||||
return waterMetrologyData;
|
||||
}
|
||||
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Status: {_optoHeadStatus}, C7Data: {c7Data}, C2Data: {c2Data}";
|
||||
|
||||
+37
-1
@@ -21,7 +21,17 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Protocols
|
||||
public bool FastHPFC { get; set; }
|
||||
public bool FieldPolarity { get; set; }
|
||||
public bool ImpedancePolarity { get; set; }
|
||||
|
||||
|
||||
|
||||
public double FlowRateLPerS // Flow Rate in L/s metric units
|
||||
{
|
||||
get
|
||||
{
|
||||
double flowRateGPM = FlowRate / 10000; //investigation flow meter GPM
|
||||
double flowRateLPerS = flowRateGPM * 0.063090196432096 ; // conversion factor from GPM to L/s with minimal digit lost
|
||||
return flowRateLPerS;
|
||||
}
|
||||
}
|
||||
public double CalcFlowmLps
|
||||
{
|
||||
get { return FlowRate / 4.0; } // FlowRate is in 1/4 mL/s
|
||||
@@ -41,6 +51,32 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Protocols
|
||||
return Parse(data, dt, dutinfo);
|
||||
}
|
||||
|
||||
public static WaterMetrologyDataC2 Simulate()
|
||||
{
|
||||
var result = new WaterMetrologyDataC2();
|
||||
|
||||
result.DutInfo = "dutinfo";
|
||||
result.Dt = DateTime.Now;
|
||||
result.AdcSample = 1;
|
||||
result.LastField = 2;
|
||||
result.FlowRate = 12456;
|
||||
result.Accumulator = 789465;
|
||||
result.FlipPeriod = 1;
|
||||
result.VinfStart = 0;
|
||||
result.VinfEnd = 0;
|
||||
result.ElectrodeDelta = 1;
|
||||
result.Impedance = 1;
|
||||
result.FieldDriveTime = 0x00 ;
|
||||
|
||||
result.IsInLowFlow = false;
|
||||
result.IsInEmptyPipe = false;
|
||||
result.FastHPFC = false; // Fast High Pass Filter Constant in bit 2
|
||||
result.FieldPolarity = false; // Field Polarity in bit 3
|
||||
result.ImpedancePolarity = false; // Impedance Polarity in bit 4
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static WaterMetrologyDataC2 Parse(byte[] data, DateTime dt, string dutinfo)
|
||||
{
|
||||
if (data.Length < 24)
|
||||
|
||||
+41
@@ -23,6 +23,47 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Protocols
|
||||
public bool IsLearningActive { get; set; }
|
||||
public bool AdcShiftsUpdated { get; set; }
|
||||
|
||||
public static WaterMetrologyDataC7 Simulate()
|
||||
{
|
||||
var result = new WaterMetrologyDataC7();
|
||||
|
||||
result.DutInfo = "dutinfo";
|
||||
result.Dt = DateTime.Now;
|
||||
result.AdcSample = 1;
|
||||
result.LastField = 2;
|
||||
result.FlowRate = 12456;
|
||||
result.Accumulator = 789465;
|
||||
result.FlipPeriod = 1;
|
||||
result.VinfStart = 0;
|
||||
result.VinfEnd = 0;
|
||||
result.ElectrodeDelta = 1;
|
||||
result.Impedance = 1;
|
||||
result.FieldDriveTime = 0x00 ;
|
||||
|
||||
result.IsInLowFlow = false;
|
||||
result.IsInEmptyPipe = false;
|
||||
result.FastHPFC = false; // Fast High Pass Filter Constant in bit 2
|
||||
result.FieldPolarity = false; // Field Polarity in bit 3
|
||||
result.ImpedancePolarity = false; // Impedance Polarity in bit 4
|
||||
|
||||
result.MagTamperState = true; // bits 5 and 6 represent MagTamperState
|
||||
result.IsLearningActive = true; // bit 7 represents IsLearningActive
|
||||
|
||||
|
||||
|
||||
result.AdcShiftsUpdated = false; // bit 0 represents AdcShiftsUpdated
|
||||
|
||||
result.LastFieldmilliGauss = 0;
|
||||
result.ImpedanceI = 0; // in phase
|
||||
result.ImpedanceQ = 0; // out of phase
|
||||
result.NoiseMetric = 0; //
|
||||
result.LearningLockout = 0;
|
||||
result.ReverseBuffer = 0;
|
||||
result.ConditionedAdc = 0;
|
||||
result.Totalalizer = 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static WaterMetrologyDataC7 Parse(string base64Data, DateTime dt, string dutinfo)
|
||||
{
|
||||
|
||||
@@ -6,6 +6,6 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication
|
||||
{
|
||||
[Description("..")] None,
|
||||
[Description("Nfc")] Nfc,
|
||||
[Description("Touch Capl")]Touched,
|
||||
[Description("cTouchRead")]Touched,
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,9 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication
|
||||
internal class OpticalHeadTest
|
||||
{
|
||||
protected static readonly ILog rfidDataLogger = LogManager.GetLogger("RfidData");
|
||||
|
||||
DebugMode _debugMode;
|
||||
public DebugMode DebugMode { get => _debugMode; set => _debugMode = value; }
|
||||
|
||||
internal static string OpenSealing(ISmartReader iHead)
|
||||
{
|
||||
@@ -26,6 +29,11 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication
|
||||
|
||||
internal static string ReadRequest_SerialNo(PoseidonCfg iHeadCfg)
|
||||
{
|
||||
if (iHeadCfg != null && iHeadCfg.DebugLevel == DebugMode.Simulate)
|
||||
{
|
||||
return "1111";
|
||||
}
|
||||
|
||||
string serialNo = null;
|
||||
try
|
||||
{
|
||||
@@ -77,26 +85,26 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication
|
||||
|
||||
internal static string SetActiveMode(PoseidonCfg iHeadCfg)
|
||||
{
|
||||
try
|
||||
if (iHeadCfg != null && iHeadCfg.DebugLevel == DebugMode.Simulate)
|
||||
{
|
||||
SerialPortData serialPortData = new SerialPortData(
|
||||
$"COM{iHeadCfg.RfidComPortNr}",
|
||||
iHeadCfg.CliProgramName,
|
||||
iHeadCfg.CliMeterType);
|
||||
NfcHeadServiceOld headService = new NfcHeadServiceOld(serialPortData);
|
||||
OptoHeadStatus optoHeadStatus = headService.SetTestingMode(OptoHeadStatus.OptoHeadDisabled);
|
||||
if (optoHeadStatus == OptoHeadStatus.OptoHeadDisabled)
|
||||
{
|
||||
_lastOptoHeadStatus = optoHeadStatus;
|
||||
return "OK";
|
||||
}
|
||||
|
||||
return "Error Set Active Mode";
|
||||
return "OK";
|
||||
}
|
||||
catch (Exception exception)
|
||||
|
||||
SerialPortData serialPortData = new SerialPortData(
|
||||
$"COM{iHeadCfg.RfidComPortNr}",
|
||||
iHeadCfg.CliProgramName,
|
||||
iHeadCfg.CliMeterType);
|
||||
NfcHeadServiceOld headService = new NfcHeadServiceOld(serialPortData);
|
||||
// Wait synchronously
|
||||
OptoHeadStatus optoHeadStatus = headService.SetTestingMode(OptoHeadStatus.OptoHeadDisabled);
|
||||
if (optoHeadStatus == OptoHeadStatus.OptoHeadDisabled)
|
||||
{
|
||||
rfidDataLogger.Error("Poseidon Set Active Mode failed.", exception);
|
||||
return "Error Set Active Mode: " + exception.Message;
|
||||
_lastOptoHeadStatus = optoHeadStatus;
|
||||
return "OK";
|
||||
}
|
||||
else
|
||||
{
|
||||
return "Error Set Test Mode";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,27 +113,27 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication
|
||||
|
||||
internal static string SetTestMode(PoseidonCfg iHeadCfg)
|
||||
{
|
||||
try
|
||||
if (iHeadCfg != null && iHeadCfg.DebugLevel == DebugMode.Simulate)
|
||||
{
|
||||
SerialPortData serialPortData = new SerialPortData(
|
||||
$"COM{iHeadCfg.RfidComPortNr}",
|
||||
iHeadCfg.CliProgramName,
|
||||
iHeadCfg.CliMeterType);
|
||||
NfcHeadServiceOld headService = new NfcHeadServiceOld(serialPortData);
|
||||
OptoHeadStatus optoHeadStatus = headService.SetTestingMode(OptoHeadStatus.OptoHeadC7);
|
||||
if (optoHeadStatus == OptoHeadStatus.OptoHeadC7)
|
||||
{
|
||||
_lastOptoHeadStatus = optoHeadStatus;
|
||||
_lastIHeadCfg = iHeadCfg;
|
||||
return "OK";
|
||||
}
|
||||
|
||||
return "Error Set Test Mode";
|
||||
return "OK";
|
||||
}
|
||||
catch (Exception exception)
|
||||
|
||||
SerialPortData serialPortData = new SerialPortData(
|
||||
$"COM{iHeadCfg.RfidComPortNr}",
|
||||
iHeadCfg.CliProgramName,
|
||||
iHeadCfg.CliMeterType);
|
||||
NfcHeadServiceOld headService = new NfcHeadServiceOld(serialPortData);
|
||||
// Wait synchronously
|
||||
OptoHeadStatus optoHeadStatus = headService.SetTestingMode(OptoHeadStatus.OptoHeadC7);
|
||||
if (optoHeadStatus == OptoHeadStatus.OptoHeadC7)
|
||||
{
|
||||
rfidDataLogger.Error("Poseidon Set Test Mode failed.", exception);
|
||||
return "Error Set Test Mode: " + exception.Message;
|
||||
_lastOptoHeadStatus = optoHeadStatus;
|
||||
_lastIHeadCfg = iHeadCfg;
|
||||
return "OK";
|
||||
}
|
||||
else
|
||||
{
|
||||
return "Error Set Test Mode";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,6 +141,10 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication
|
||||
|
||||
public static void Deactivate()
|
||||
{
|
||||
if (_lastIHeadCfg != null && _lastIHeadCfg.DebugLevel == DebugMode.Simulate)
|
||||
{
|
||||
return;
|
||||
}
|
||||
StopOptoTestInputLoop();
|
||||
if (_lastOptoHeadStatus != OptoHeadStatus.Unknown &&
|
||||
_lastOptoHeadStatus != OptoHeadStatus.OptoHeadDisabled &&
|
||||
@@ -152,7 +164,7 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication
|
||||
{
|
||||
if (optoHeadService != null) return false;
|
||||
|
||||
OptoHeadService.Con connection = new OptoHeadService.Con($"COM{iHeadCfg.OptoComPortNr}");
|
||||
OptoHeadService.Con connection = new OptoHeadService.Con($"COM{iHeadCfg.OptoComPortNr}", iHeadCfg.DebugLevel);
|
||||
optoHeadService = new OptoHeadService(connection);
|
||||
optoHeadService.CreateSerialConnection();
|
||||
optoHeadService.RunLoop(onOptoReceivedHandler);
|
||||
|
||||
+11
-13
@@ -85,20 +85,18 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.implementations
|
||||
rfidListItem.Text = $"ReadSerialNo: {OpticalHeadTest.ReadRequest_SerialNo(poseidonCfg)}";
|
||||
break;
|
||||
case Operations.SetTestModeOn:
|
||||
string setTestModeResult = OpticalHeadTest.SetTestMode(poseidonCfg);
|
||||
rfidListItem.Text = $"SetTestMode: {setTestModeResult}";
|
||||
// Start the opto worker only after a successful mode change.
|
||||
if (setTestModeResult == "OK")
|
||||
rfidListItem.Text = $"SetTestMode: {OpticalHeadTest.SetTestMode(poseidonCfg)}";
|
||||
//Do start thread
|
||||
|
||||
a.OptoListBox.Items.Clear();
|
||||
stopWorkerThread = false;
|
||||
optoThread = new Thread(OptoWorker);
|
||||
if (!optoThread.IsAlive)
|
||||
{
|
||||
a.OptoListBox.Items.Clear();
|
||||
stopWorkerThread = false;
|
||||
optoThread = new Thread(OptoWorker);
|
||||
if (!optoThread.IsAlive)
|
||||
{
|
||||
OpticalHeadTest.StartOptotestInputLoop(poseidonCfg, OptoReceivedHandler);
|
||||
optoThread.Start();
|
||||
}
|
||||
OpticalHeadTest.StartOptotestInputLoop(poseidonCfg,OptoReceivedHandler); // open opto port
|
||||
optoThread.Start();
|
||||
}
|
||||
|
||||
break;
|
||||
case Operations.SetTestModeOff:
|
||||
//Do stop thread
|
||||
@@ -135,4 +133,4 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.implementations
|
||||
this.stopWorkerThread = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
using System.Web.UI;
|
||||
using System.Windows.Forms;
|
||||
using TBF.Rig.RegisterReaders.iPerlReaderUNI.iCommon;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.iPerlReaderUNI.IPerlS4
|
||||
{
|
||||
public class IperlHeadTestCtrl : UNIHeadTestCtrl
|
||||
{
|
||||
System.Windows.Forms.ListBox rfidOutputListBox;
|
||||
|
||||
public IperlHeadTestCtrl(ListBox rfidOutputListBox)
|
||||
{
|
||||
this.rfidOutputListBox = rfidOutputListBox;
|
||||
|
||||
var foo = new[]
|
||||
{
|
||||
new {Name = "Read PCB", Value = "ReadPCB" },
|
||||
new {Name = "Set Test Mode", Value = "SetTestMode" },
|
||||
new {Name = "Set Active Mode", Value = "SetActiveMode" },
|
||||
#if DEBUG
|
||||
new {Name = "Start Read Opto Data", Value = "ReadOptoData" },
|
||||
new {Name = "Stop Read Opto Data", Value = "StopReadOptoData" },
|
||||
#endif
|
||||
new {Name = " ", Value = "" },
|
||||
new {Name = "Reset NFC Head", Value = "ResetNfcHead" },
|
||||
new {Name = "Set NFC Head Interface", Value = "SetNfcHead" },
|
||||
new {Name = "Set RFID Head interface", Value = "SetRfidHead" }
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void CommandTestButtonClick(object sender, MouseEventArgs e)
|
||||
{
|
||||
rfidOutputListBox.Items.Clear();
|
||||
|
||||
using (Tools.LogChecker logChecker = new Tools.LogChecker("RfidData", log4net.Core.Level.Debug))
|
||||
{
|
||||
ListItem rfidListItem = new ListItem();
|
||||
rfidListItem.Attributes.Add("style", "font-weight:bold");
|
||||
switch (rfidCommandComboBox.SelectedValue)
|
||||
{
|
||||
case "ReadPCB":
|
||||
rfidListItem.Text = $"PCB: {OpticalHeadTest.ReadRequest_PCB(_iPerlReader)}";
|
||||
break;
|
||||
case "SetTestMode":
|
||||
rfidListItem.Text = OpticalHeadTest.SetTestMode(_iPerlReader);
|
||||
optoListBox.Items.Clear();
|
||||
stopWorkerThread = false;
|
||||
optoThread = new Thread(OptoWorker);
|
||||
if (!optoThread.IsAlive)
|
||||
{
|
||||
_iPerlReader.StartDataStreamProcessing(); // open opto port
|
||||
optoThread.Start();
|
||||
}
|
||||
break;
|
||||
case "SetActiveMode":
|
||||
rfidListItem.Text = OpticalHeadTest.SetActiveMode(_iPerlReader);
|
||||
stopWorkerThread = true;
|
||||
_iPerlReader.StopDataStreamProcessing(); // close opto port
|
||||
break;
|
||||
case "ResetNfcHead":
|
||||
_iPerlReader.ResetNfcInterface();
|
||||
break;
|
||||
case "SetNfcHead":
|
||||
_iPerlReader.SetNfcInterface();
|
||||
break;
|
||||
case "SetRfidHead":
|
||||
_iPerlReader.SetRfidInterface();
|
||||
break;
|
||||
case "ReadOptoData":
|
||||
optoListBox.Items.Clear();
|
||||
stopWorkerThread = false;
|
||||
optoThread = new Thread(OptoWorker);
|
||||
if (optoThread.IsAlive)
|
||||
{
|
||||
stopWorkerThread = true;
|
||||
_iPerlReader.StopDataStreamProcessing(); // close opto port
|
||||
}
|
||||
if (!optoThread.IsAlive)
|
||||
{
|
||||
_iPerlReader.StartDataStreamProcessing(); // open opto port
|
||||
optoThread.Start();
|
||||
}
|
||||
break;
|
||||
case "StopReadOptoData":
|
||||
stopWorkerThread = true;
|
||||
_iPerlReader.StopDataStreamProcessing(); // close opto port
|
||||
break;
|
||||
}
|
||||
rfidOutputListBox.Items.Add(rfidListItem);
|
||||
rfidOutputListBox.Items.AddRange(logChecker.Messages.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.iPerlReaderUNI.iCommon
|
||||
{
|
||||
public interface UNIHeadTestCtrl
|
||||
{
|
||||
void CommandTestButtonClick(object sender, MouseEventArgs e);
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ using TBF.Rig.Network.RestAPI;
|
||||
using TBF.Rig.Network.RestAPI.facade;
|
||||
using TBF.Rig.Output.Printers.GroupPrinting.Single;
|
||||
using TBF.UiBridge;
|
||||
using SharedComponents;
|
||||
using System.Text;
|
||||
using TBF.Rig.RegisterReaders.CommonRR.IPerl;
|
||||
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication;
|
||||
@@ -56,7 +57,11 @@ namespace TBF.Rig.Sequences
|
||||
try
|
||||
{
|
||||
/// 1nd argument
|
||||
ITestMethodCfg iPerlCfgIPerl = cfg as ITestMethodCfg;
|
||||
ITestMethodCfg testMethodCfg = cfg as ITestMethodCfg;
|
||||
if (testMethodCfg == null)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// 2rd argument: as is
|
||||
|
||||
@@ -67,8 +72,7 @@ namespace TBF.Rig.Sequences
|
||||
/*myRef.modelessDlg = new TestMethods.iPerlCommunication.iPerlCommunicationForm(iPerlCfg, tests, iPerlCommParams);
|
||||
myRef.modelessDlg.Show();*/
|
||||
|
||||
myRef.modelessDlg = new SmartCommunicationForm(
|
||||
testMethod , tests, iPerlCommParams);
|
||||
myRef.modelessDlg = new SmartCommunicationForm( testMethod , tests, iPerlCommParams);
|
||||
myRef.modelessDlg.Show();
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -1547,7 +1551,7 @@ namespace TBF.Rig.Sequences
|
||||
}
|
||||
|
||||
// ✍️ Uloženie do vlastného logu
|
||||
//LiveLogCache.Instance.AddLog(logBuilder.ToString());
|
||||
LiveLogCache.Instance.AddLog(logBuilder.ToString());
|
||||
|
||||
Bridge.OnError(this, "Chyba pri aktualizácii výsledkov v MySQL.");
|
||||
goto error;
|
||||
|
||||
@@ -91,6 +91,7 @@ namespace TBF.Rig
|
||||
new Network.Camera.RoiForFixedStartKeyence.Factory(),
|
||||
new Network.Comet.Ambient.Factory(),
|
||||
new Network.RestAPI.Factory(),
|
||||
new Output.DB.DatabaseWriter.Factory(), // 'DatabaseWriter' module implements more store specific modules
|
||||
new Output.DB.ProductionTracing.Factory(),
|
||||
new Output.DB.SaveDiverterCorrections.Factory(),
|
||||
new Output.DB.SaveFlowmeterCorrections.Factory(),
|
||||
@@ -138,6 +139,7 @@ namespace TBF.Rig
|
||||
new RegisterReaders.PulsesFromUniCB.Factory(), /// 'RegisterReader'
|
||||
new RegisterReaders.StandingStartStop.Factory(), /// 'RegisterReader for standing start/stop'
|
||||
new TestMethods.iPerlCommunication.iPerlHead.Factory(), /// 'RegisterReader for iPerl'
|
||||
new TestMethods.GenesisCommunication.GenesisHead.Factory(), /// 'RegisterReader for Cordonel'
|
||||
new RegisterReaders.S640Stream.Factory(), /// 'RegisterReader for S640'
|
||||
new RegisterReaders.SerialStream.Factory(), /// 'RegisterReader for generic serial stream'
|
||||
new RegisterReaders.PoseidonCmdStartStop.Factory(), /// 'RegisterReader for poseidon start/stop'
|
||||
|
||||
@@ -6,10 +6,13 @@ using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using log4net;
|
||||
using Common;
|
||||
using Config.Entities;
|
||||
using Results.Entities;
|
||||
using TBF.Rig;
|
||||
using TBF.Rig.GenericDevices;
|
||||
using TBF.Boxes;
|
||||
using TBF.Resources;
|
||||
using TBF.Rig.TestMethods.GenesisCommunication.GenesisHead;
|
||||
using TBF.UiBridge;
|
||||
|
||||
namespace TBF.Rig.TestMethods.FlyingStart
|
||||
@@ -135,6 +138,8 @@ namespace TBF.Rig.TestMethods.FlyingStart
|
||||
Bridge.OnTestSelected(this, new TestSelectedEventArgs(test, repetitionNr, inPath, benchPath, outPath, sensPath, heatMetersPath));
|
||||
string testName = Results.Utils.GetTestName(test.Name, test.Repeats, repetitionNr);
|
||||
TestStartTime = DateTime.Now;
|
||||
// Genesis switch
|
||||
bool atleastOneGenesis = GenesisHeadBatch.Start(sensPath.RegisterReaders, Program.LocalSettings.LastSNTexts);
|
||||
|
||||
///
|
||||
/// Optionally display prompt to emerge temperature meters to appropriate baths for heat meters test
|
||||
@@ -323,6 +328,20 @@ namespace TBF.Rig.TestMethods.FlyingStart
|
||||
|
||||
temperature_set:
|
||||
|
||||
//TODO genesis - check with genesis switch
|
||||
if (atleastOneGenesis)
|
||||
{
|
||||
if (test.Name.ToLower().Contains("calib"))
|
||||
{
|
||||
GenesisHeadBatch.BatchHolder.Value.MetersLogin();
|
||||
GenesisHeadBatch.BatchHolder.Value.MetersInitCalibration();
|
||||
|
||||
} else if (test.Name.ToLower().Contains("Init"))
|
||||
{
|
||||
GenesisHeadBatch.BatchHolder.Value.MetersLogin();
|
||||
GenesisHeadBatch.BatchHolder.Value.MetersInitMeasurement();
|
||||
}
|
||||
}
|
||||
///
|
||||
/// Prepare cameras, ROI-s and measurementOperations
|
||||
///
|
||||
@@ -358,7 +377,12 @@ namespace TBF.Rig.TestMethods.FlyingStart
|
||||
|
||||
foreach (var rr in sensPath.RegisterReaders)
|
||||
{
|
||||
if (rr is IRegReaderDatastream) (rr as IRegReaderDatastream).TestIsGoingToStartSoon(test, repetitionNr);
|
||||
if (rr is IRegReaderDatastream)
|
||||
(rr as IRegReaderDatastream).TestIsGoingToStartSoon(test, repetitionNr);
|
||||
|
||||
if (rr is GenesisHead) // Genesis - CORDONEL head
|
||||
(rr as GenesisHead).StartRead(test.Name, BatchRslts.Batch.BatchNr, repetitionNr);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -426,8 +450,21 @@ namespace TBF.Rig.TestMethods.FlyingStart
|
||||
|
||||
/// Measurement loop end
|
||||
StopRecordingStatistics();
|
||||
|
||||
//TODO genesis - check with genesis switch
|
||||
if (atleastOneGenesis)
|
||||
{
|
||||
if (test.Name.ToLower().Contains("calib"))
|
||||
{
|
||||
GenesisHeadBatch.BatchHolder.Value.MetersStopCalibration();
|
||||
}
|
||||
else if (test.Name.ToLower().Contains("Init"))
|
||||
{
|
||||
GenesisHeadBatch.BatchHolder.Value.MetersStopMeasurement();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------
|
||||
//------------------------------------------------
|
||||
Bridge.OnActivity(this, Strings.Test_completed);
|
||||
//------------------------------------------------
|
||||
|
||||
@@ -589,6 +626,7 @@ namespace TBF.Rig.TestMethods.FlyingStart
|
||||
GenericDevices.IRegReaderDatastream dstrReader = regReader as GenericDevices.IRegReaderDatastream;
|
||||
TestMethods.iPerlCommunication.iPerlHead.IperlHead iPerl = regReader as TestMethods.iPerlCommunication.iPerlHead.IperlHead;
|
||||
GenericDevices.IRegReaderLiveCamera cameraRoi = regReader as GenericDevices.IRegReaderLiveCamera;
|
||||
GenesisHead Genesis = regReader as GenesisHead;
|
||||
|
||||
if (meterRslt != null && regReader != null)
|
||||
{
|
||||
@@ -596,83 +634,147 @@ namespace TBF.Rig.TestMethods.FlyingStart
|
||||
meterRslt.PulsesPerLiter = regReader.PulsesPerLtr;
|
||||
meterRslt.PulsesMeter = Convert.ToDouble(regReader.WMPulses);
|
||||
|
||||
if (dstrReader != null)
|
||||
{
|
||||
meterRslt.TimestampStart = dstrReader.TimestampSecStart;
|
||||
meterRslt.TimestampEnd = dstrReader.NoSamples ? (dstrReader.TimestampSecStart + tstRslt.TestTime) : dstrReader.TimestampSecEnd;
|
||||
meterRslt.TestTime = meterRslt.TimestampEnd - meterRslt.TimestampStart;
|
||||
meterRslt.VolumeStart = dstrReader.VolumeLtrStart; /// liter
|
||||
meterRslt.VolumeEnd = dstrReader.VolumeLtrEnd; /// liter
|
||||
meterRslt.VolumeMeter = Math.Abs(dstrReader.VolumeLtrEnd - dstrReader.VolumeLtrStart);
|
||||
meterRslt.VolumeRef = tstRslt.VolumeCTV * meterRslt.TestTime / tstRslt.TestTime;
|
||||
meterRslt.PulsesMaster = tstRslt.PulsesMaster * meterRslt.TestTime / tstRslt.TestTime;
|
||||
|
||||
if (Genesis != null)
|
||||
{
|
||||
Genesis.Stop(tstRslt.TestTime, tstRslt.VolumeCTV);
|
||||
|
||||
if (iPerl != null)
|
||||
meterRslt.TimestampStart = Genesis.TimestampSecStart;
|
||||
meterRslt.TimestampEnd = Genesis.TimestampSecEnd;
|
||||
meterRslt.TestTime = Genesis.WMTestTime;
|
||||
meterRslt.VolumeStart = Genesis.BeginWMState;
|
||||
meterRslt.VolumeEnd = Genesis.EndWMState; /// liter
|
||||
meterRslt.VolumeMeter = Math.Abs(Genesis.WMVolume);
|
||||
meterRslt.VolumeRef = tstRslt.VolumeCTV;
|
||||
if (GenesisHeadBatch.MeterIdDetailResults == null)
|
||||
{
|
||||
if (iPerl.ResultCode != 0 && (meterRslt.WaterMeter.ResultCode & (int)Results.Entities.ResultCode.OptoErrorCodeMask) == 0)
|
||||
Genesis.Log("MeterIdDetailResults na!");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Genesis.DetailedResults != null)
|
||||
{
|
||||
meterRslt.WaterMeter.ResultCode |= iPerl.ResultCode;
|
||||
try
|
||||
{
|
||||
GenesisHeadBatch.MeterIdDetailResults.Add(meterRslt.SerialNr(), Genesis.DetailedResults);
|
||||
}
|
||||
catch (Exception ex) { Genesis.Log(ex.Message.ToString()); }
|
||||
}
|
||||
#if IPERL
|
||||
meterRslt.WaterMeter.CalibFactor = iPerl.CalibFactor;
|
||||
meterRslt.ExtraDataPath = iPerl.ExtraDataPath;
|
||||
if (TestMethods.iPerlCommunication.iPerlHead.IperlHead.FeatureVectorSize >= 1) meterRslt.X1 = iPerl.X[0];
|
||||
if (TestMethods.iPerlCommunication.iPerlHead.IperlHead.FeatureVectorSize >= 2) meterRslt.X2 = iPerl.X[1];
|
||||
if (TestMethods.iPerlCommunication.iPerlHead.IperlHead.FeatureVectorSize >= 3) meterRslt.X3 = iPerl.X[2];
|
||||
if (TestMethods.iPerlCommunication.iPerlHead.IperlHead.FeatureVectorSize >= 4) meterRslt.X4 = iPerl.X[3];
|
||||
if (TestMethods.iPerlCommunication.iPerlHead.IperlHead.FeatureVectorSize >= 5) meterRslt.X5 = iPerl.X[4];
|
||||
if (TestMethods.iPerlCommunication.iPerlHead.IperlHead.FeatureVectorSize >= 6) meterRslt.X6 = iPerl.X[5];
|
||||
if (TestMethods.iPerlCommunication.iPerlHead.IperlHead.FeatureVectorSize >= 7) meterRslt.X7 = iPerl.X[6];
|
||||
if (TestMethods.iPerlCommunication.iPerlHead.IperlHead.FeatureVectorSize >= 8) meterRslt.X8 = iPerl.X[7];
|
||||
if (TestMethods.iPerlCommunication.iPerlHead.IperlHead.FeatureVectorSize >= 9) meterRslt.X9 = iPerl.X[8];
|
||||
#endif
|
||||
iPerl.LastTestResult2 = iPerl.LastTestResult; /// Save shift previous test result
|
||||
iPerl.LastTestResult = meterRslt; /// Save this test result
|
||||
}
|
||||
}
|
||||
else if (cameraRoi != null)
|
||||
{
|
||||
meterRslt.TimestampStart = cameraRoi.TimestampStart; /// second
|
||||
meterRslt.TimestampEnd = cameraRoi.TimestampEnd; /// second
|
||||
|
||||
meterRslt.VolumeStart = cameraRoi.VolumeStart; /// liter
|
||||
meterRslt.VolumeEnd = cameraRoi.VolumeEnd; /// liter
|
||||
meterRslt.VolumeMeter = cameraRoi.VolumeEnd - cameraRoi.VolumeStart; /// liter
|
||||
|
||||
if (meterRslt.VolumeMeter != 0)
|
||||
{
|
||||
/// Normal measurement with camera
|
||||
meterRslt.TestTime = cameraRoi.TimestampEnd - cameraRoi.TimestampStart; /// second
|
||||
meterRslt.VolumeRef = tstRslt.VolumeCTV * meterRslt.TestTime / tstRslt.TestTime;
|
||||
meterRslt.PulsesMaster = tstRslt.PulsesMaster * meterRslt.TestTime / tstRslt.TestTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
/// None or one pulse from the water meter using camera
|
||||
meterRslt.TestTime = tstRslt.TestTime;
|
||||
meterRslt.VolumeRef = tstRslt.VolumeCTV;
|
||||
meterRslt.PulsesMaster = tstRslt.PulsesMaster;
|
||||
else
|
||||
{
|
||||
Genesis.Log("DetailedResults na!");
|
||||
}
|
||||
}
|
||||
|
||||
Genesis.Log("VolumeRef=" + meterRslt.VolumeRef);
|
||||
Genesis.Log("TestTime Meter =" + meterRslt.TestTime + "S, test time ref =" + tstRslt.TestTime + "s");
|
||||
Genesis.Log(" results for " + test.Name);
|
||||
Genesis.Log(" Ref Vol = " + meterRslt.VolumeRef + " m³");
|
||||
Genesis.Log(" Ref Time = " + tstRslt.TestTime + " s");
|
||||
Genesis.Log(" Meter Time = " + meterRslt.TestTime + " s");
|
||||
Genesis.Log(" Meter Vol = " + meterRslt.VolumeMeter + " m³");
|
||||
|
||||
var calError = Formulas.ErrorFromVolumes(meterRslt.VolumeMeter, meterRslt.VolumeRef);
|
||||
Genesis.Log(" MeterError = " + calError.ToString() + " %");
|
||||
}
|
||||
else
|
||||
{
|
||||
meterRslt.PulsesMaster = Convert.ToDouble(regReader.WMRefPulses);
|
||||
meterRslt.VolumeStart = 0;
|
||||
meterRslt.VolumeEnd = 0;
|
||||
meterRslt.VolumeMeter = meterRslt.PulsesMeter * regReader.LtrsPerPulse; /// liter
|
||||
///
|
||||
if (regReader.WMPulses >= 1)
|
||||
{
|
||||
/// Normal measurement
|
||||
meterRslt.TestTime = cBrd.TestTimeWM(regReader.Position);
|
||||
meterRslt.VolumeRef = meterRslt.PulsesMaster * tstRslt.ConstMaster; /// liter
|
||||
}
|
||||
else
|
||||
{
|
||||
/// None or one pulse from the water meter
|
||||
meterRslt.TestTime = tstRslt.TestTime;
|
||||
meterRslt.VolumeRef = tstRslt.VolumeCTV; /// liter
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dstrReader != null)
|
||||
{
|
||||
meterRslt.TimestampStart = dstrReader.TimestampSecStart;
|
||||
meterRslt.TimestampEnd = dstrReader.NoSamples
|
||||
? (dstrReader.TimestampSecStart + tstRslt.TestTime)
|
||||
: dstrReader.TimestampSecEnd;
|
||||
meterRslt.TestTime = meterRslt.TimestampEnd - meterRslt.TimestampStart;
|
||||
meterRslt.VolumeStart = dstrReader.VolumeLtrStart; /// liter
|
||||
meterRslt.VolumeEnd = dstrReader.VolumeLtrEnd; /// liter
|
||||
meterRslt.VolumeMeter =
|
||||
Math.Abs(dstrReader.VolumeLtrEnd - dstrReader.VolumeLtrStart);
|
||||
meterRslt.VolumeRef = tstRslt.VolumeCTV * meterRslt.TestTime / tstRslt.TestTime;
|
||||
meterRslt.PulsesMaster =
|
||||
tstRslt.PulsesMaster * meterRslt.TestTime / tstRslt.TestTime;
|
||||
|
||||
if (iPerl != null)
|
||||
{
|
||||
if (iPerl.ResultCode != 0 && (meterRslt.WaterMeter.ResultCode &
|
||||
(int)Results.Entities.ResultCode
|
||||
.OptoErrorCodeMask) == 0)
|
||||
{
|
||||
meterRslt.WaterMeter.ResultCode |= iPerl.ResultCode;
|
||||
}
|
||||
#if IPERL
|
||||
meterRslt.WaterMeter.CalibFactor = iPerl.CalibFactor;
|
||||
meterRslt.ExtraDataPath = iPerl.ExtraDataPath;
|
||||
if (TestMethods.iPerlCommunication.iPerlHead.IperlHead.FeatureVectorSize >= 1)
|
||||
meterRslt.X1 = iPerl.X[0];
|
||||
if (TestMethods.iPerlCommunication.iPerlHead.IperlHead.FeatureVectorSize >= 2)
|
||||
meterRslt.X2 = iPerl.X[1];
|
||||
if (TestMethods.iPerlCommunication.iPerlHead.IperlHead.FeatureVectorSize >= 3)
|
||||
meterRslt.X3 = iPerl.X[2];
|
||||
if (TestMethods.iPerlCommunication.iPerlHead.IperlHead.FeatureVectorSize >= 4)
|
||||
meterRslt.X4 = iPerl.X[3];
|
||||
if (TestMethods.iPerlCommunication.iPerlHead.IperlHead.FeatureVectorSize >= 5)
|
||||
meterRslt.X5 = iPerl.X[4];
|
||||
if (TestMethods.iPerlCommunication.iPerlHead.IperlHead.FeatureVectorSize >= 6)
|
||||
meterRslt.X6 = iPerl.X[5];
|
||||
if (TestMethods.iPerlCommunication.iPerlHead.IperlHead.FeatureVectorSize >= 7)
|
||||
meterRslt.X7 = iPerl.X[6];
|
||||
if (TestMethods.iPerlCommunication.iPerlHead.IperlHead.FeatureVectorSize >= 8)
|
||||
meterRslt.X8 = iPerl.X[7];
|
||||
if (TestMethods.iPerlCommunication.iPerlHead.IperlHead.FeatureVectorSize >= 9)
|
||||
meterRslt.X9 = iPerl.X[8];
|
||||
#endif
|
||||
iPerl.LastTestResult2 =
|
||||
iPerl.LastTestResult; /// Save shift previous test result
|
||||
iPerl.LastTestResult = meterRslt; /// Save this test result
|
||||
}
|
||||
}
|
||||
else if (cameraRoi != null)
|
||||
{
|
||||
meterRslt.TimestampStart = cameraRoi.TimestampStart; /// second
|
||||
meterRslt.TimestampEnd = cameraRoi.TimestampEnd; /// second
|
||||
|
||||
meterRslt.VolumeStart = cameraRoi.VolumeStart; /// liter
|
||||
meterRslt.VolumeEnd = cameraRoi.VolumeEnd; /// liter
|
||||
meterRslt.VolumeMeter = cameraRoi.VolumeEnd - cameraRoi.VolumeStart; /// liter
|
||||
|
||||
if (meterRslt.VolumeMeter != 0)
|
||||
{
|
||||
/// Normal measurement with camera
|
||||
meterRslt.TestTime =
|
||||
cameraRoi.TimestampEnd - cameraRoi.TimestampStart; /// second
|
||||
meterRslt.VolumeRef = tstRslt.VolumeCTV * meterRslt.TestTime / tstRslt.TestTime;
|
||||
meterRslt.PulsesMaster =
|
||||
tstRslt.PulsesMaster * meterRslt.TestTime / tstRslt.TestTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
/// None or one pulse from the water meter using camera
|
||||
meterRslt.TestTime = tstRslt.TestTime;
|
||||
meterRslt.VolumeRef = tstRslt.VolumeCTV;
|
||||
meterRslt.PulsesMaster = tstRslt.PulsesMaster;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
meterRslt.PulsesMaster = Convert.ToDouble(regReader.WMRefPulses);
|
||||
meterRslt.VolumeStart = 0;
|
||||
meterRslt.VolumeEnd = 0;
|
||||
meterRslt.VolumeMeter = meterRslt.PulsesMeter * regReader.LtrsPerPulse; /// liter
|
||||
///
|
||||
if (regReader.WMPulses >= 1)
|
||||
{
|
||||
/// Normal measurement
|
||||
meterRslt.TestTime = cBrd.TestTimeWM(regReader.Position);
|
||||
meterRslt.VolumeRef = meterRslt.PulsesMaster * tstRslt.ConstMaster; /// liter
|
||||
}
|
||||
else
|
||||
{
|
||||
/// None or one pulse from the water meter
|
||||
meterRslt.TestTime = tstRslt.TestTime;
|
||||
meterRslt.VolumeRef = tstRslt.VolumeCTV; /// liter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
meterRslt.Error = Formulas.ErrorFromVolumes(meterRslt.VolumeMeter, meterRslt.VolumeRef);
|
||||
@@ -724,10 +826,14 @@ namespace TBF.Rig.TestMethods.FlyingStart
|
||||
/// Append the results to the CSV-file
|
||||
allResults.Info(TestResult2CsvLine(testName, test.Part));
|
||||
|
||||
//TODO genesis - process result writing
|
||||
//ProcessDatabaseResultsWriting(test, tstRslt);
|
||||
|
||||
if (stopCycle) retVal = Event.ErrorFlagsStop;
|
||||
|
||||
stopTest:
|
||||
|
||||
GenesisHeadBatch.BatchHolder.Value.RemoveAllMeters();
|
||||
StopRecordingStatistics();
|
||||
|
||||
cBrd.StopAll(false);
|
||||
@@ -748,8 +854,36 @@ namespace TBF.Rig.TestMethods.FlyingStart
|
||||
return new List<Event> { retVal };
|
||||
}
|
||||
|
||||
//backup how work genesis - not a clean code!
|
||||
// private void ProcessDatabaseResultsWriting(Test test, TestRslt tstRslt)
|
||||
// {
|
||||
// IList<Event> e;
|
||||
// if (!String.IsNullOrEmpty(test.Procedure.ResultsWriter))
|
||||
// {
|
||||
// string[] writers = StateMachine.Procedure.ResultsWriter.Split(new char[] { '~' });
|
||||
// foreach (var writerName in writers)
|
||||
// {
|
||||
// IResultsWriter writer = TbfComponents.FindComponent(writerName) as IResultsWriter;
|
||||
// if (writer != null && writer is )
|
||||
// {
|
||||
// var SensusLaWriter = ((DB.SensusLa.Database)writer);
|
||||
//
|
||||
// State.Create(string.Format("{0}({1}) : Store results into db.", test.Method, test.Name))
|
||||
// .AddOperation(checkUiOp)
|
||||
// .AddOperation(SensusLaWriter.WriteResultsOp(tstRslt, BatchRslts, GenesisHeadBatch.MeterIdDetailResults))
|
||||
// .EnterState();
|
||||
// do
|
||||
// {
|
||||
// e = StateMachine.WaitRunDevsRunOps();
|
||||
// }
|
||||
// while (!e.Contains(Event.Error) && !e.Contains(Event.ResultsWritten) && !e.Contains(Event.ResultsNotWritten));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
IList<Event> Simulate(Config.Entities.Test test, int repetitionNr, bool isLastRepetition,
|
||||
|
||||
IList<Event> Simulate(Config.Entities.Test test, int repetitionNr, bool isLastRepetition,
|
||||
Compound.TestParams compoundTestParams,
|
||||
HeatMeters.TestParams heatMetersTestParams,
|
||||
Common.DebugMode debugLevel)
|
||||
|
||||
@@ -12,6 +12,9 @@ using TBF.Boxes;
|
||||
using TBF.Resources;
|
||||
using TBF.UiBridge;
|
||||
using TBF.Rig.GenericDevices;
|
||||
using TBF.Rig.RegisterReaders.PoseidonReader;
|
||||
using TBF.Rig.RegisterReaders.PoseidonReader.implementations;
|
||||
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.common;
|
||||
|
||||
namespace TBF.Rig.TestMethods.FlyingStartMassCollection
|
||||
{
|
||||
@@ -751,25 +754,56 @@ namespace TBF.Rig.TestMethods.FlyingStartMassCollection
|
||||
if (oneMTR != null && regReader != null)
|
||||
{
|
||||
oneMTR.RegReaderType = (int)regReader.RegisterReaderType;
|
||||
oneMTR.PulsesPerLiter = regReader.PulsesPerLtr;
|
||||
|
||||
/// Optionally supress pulses from the large water meter
|
||||
oneMTR.PulsesMeter = (isAux == 0 && compoundTestParams.SupressTrills) ? 0 : Convert.ToDouble(regReader.WMPulses);
|
||||
oneMTR.PulsesMaster = Convert.ToDouble(regReader.WMRefPulses);
|
||||
oneMTR.TestTime = cBrd.TestTime;
|
||||
oneMTR.VolumeStart = 0;
|
||||
oneMTR.VolumeEnd = 0;
|
||||
oneMTR.VolumeRef = tstRslt.VolumeCTV;
|
||||
|
||||
if (oneMTR.PulsesMaster != 0)
|
||||
if (regReader is PoseidonReader poseidon) //is Poseidon reader family
|
||||
{
|
||||
oneMTR.PulsesMeter *= (tstRslt.PulsesMaster / oneMTR.PulsesMaster);
|
||||
oneMTR.PulsesMaster = tstRslt.PulsesMaster;
|
||||
oneMTR.PulsesPerLiter = 0;
|
||||
|
||||
/// Optionally supress pulses from the large water meter
|
||||
oneMTR.PulsesMeter = 0;
|
||||
oneMTR.PulsesMaster = 0;
|
||||
oneMTR.TestTime = cBrd.TestTime;
|
||||
oneMTR.VolumeStart = 0;
|
||||
oneMTR.VolumeEnd = 0;
|
||||
oneMTR.VolumeRef = tstRslt.VolumeCTV;
|
||||
|
||||
if (oneMTR.PulsesMaster != 0)
|
||||
{
|
||||
oneMTR.PulsesMeter *= (tstRslt.PulsesMaster / oneMTR.PulsesMaster);
|
||||
oneMTR.PulsesMaster = tstRslt.PulsesMaster;
|
||||
}
|
||||
|
||||
oneMTR.VolumeMeter = poseidon.WMVolume;
|
||||
|
||||
oneMTR.Error =
|
||||
Formulas.ErrorFromVolumes(oneMTR.VolumeMeter,
|
||||
tstRslt.VolumeCTV); /// Main/Aux meter error is not usedfor evaluation
|
||||
}
|
||||
else
|
||||
{
|
||||
oneMTR.PulsesPerLiter = regReader.PulsesPerLtr;
|
||||
|
||||
oneMTR.VolumeMeter = oneMTR.PulsesMeter * regReader.LtrsPerPulse; /// liter
|
||||
/// Optionally supress pulses from the large water meter
|
||||
oneMTR.PulsesMeter = (isAux == 0 && compoundTestParams.SupressTrills)
|
||||
? 0
|
||||
: Convert.ToDouble(regReader.WMPulses);
|
||||
oneMTR.PulsesMaster = Convert.ToDouble(regReader.WMRefPulses);
|
||||
oneMTR.TestTime = cBrd.TestTime;
|
||||
oneMTR.VolumeStart = 0;
|
||||
oneMTR.VolumeEnd = 0;
|
||||
oneMTR.VolumeRef = tstRslt.VolumeCTV;
|
||||
|
||||
oneMTR.Error = Formulas.ErrorFromVolumes(oneMTR.VolumeMeter, tstRslt.VolumeCTV); /// Main/Aux meter error is not usedfor evaluation
|
||||
if (oneMTR.PulsesMaster != 0)
|
||||
{
|
||||
oneMTR.PulsesMeter *= (tstRslt.PulsesMaster / oneMTR.PulsesMaster);
|
||||
oneMTR.PulsesMaster = tstRslt.PulsesMaster;
|
||||
}
|
||||
|
||||
oneMTR.VolumeMeter = oneMTR.PulsesMeter * regReader.LtrsPerPulse; /// liter
|
||||
|
||||
oneMTR.Error =
|
||||
Formulas.ErrorFromVolumes(oneMTR.VolumeMeter,
|
||||
tstRslt.VolumeCTV); /// Main/Aux meter error is not usedfor evaluation
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -887,16 +921,58 @@ namespace TBF.Rig.TestMethods.FlyingStartMassCollection
|
||||
if (dstrReader != null)
|
||||
{
|
||||
|
||||
meterRslt.TimestampStart = dstrReader.TimestampSecStart;
|
||||
meterRslt.TimestampEnd = !dstrReader.NoSamples ? dstrReader.TimestampSecEnd : (dstrReader.TimestampSecStart + tstRslt.TestTime);
|
||||
meterRslt.TestTime = meterRslt.TimestampEnd - meterRslt.TimestampStart;
|
||||
meterRslt.VolumeStart = dstrReader.VolumeLtrStart; /// liter
|
||||
meterRslt.VolumeEnd = dstrReader.VolumeLtrEnd; /// liter
|
||||
meterRslt.VolumeMeter = Math.Abs(dstrReader.VolumeLtrEnd - dstrReader.VolumeLtrStart);
|
||||
meterRslt.VolumeRef = tstRslt.VolumeCTV * meterRslt.TestTime / tstRslt.TestTime;
|
||||
meterRslt.PulsesMaster = tstRslt.PulsesMaster * meterRslt.TestTime / tstRslt.TestTime;
|
||||
if (dstrReader is SmartReader poseidon) //is Poseidon reader family
|
||||
{
|
||||
log.Info("Poseidon reader detected - Results");
|
||||
meterRslt.TimestampStart = poseidon.TimestampSecStart;
|
||||
meterRslt.TimestampEnd = !poseidon.NoSamples
|
||||
? poseidon.TimestampSecEnd
|
||||
: (poseidon.TimestampSecStart + tstRslt.TestTime);
|
||||
meterRslt.TestTime = meterRslt.TimestampEnd - meterRslt.TimestampStart;
|
||||
meterRslt.VolumeStart = poseidon.VolumeLtrStart; /// liter
|
||||
meterRslt.VolumeEnd = poseidon.VolumeLtrStart + poseidon.WMVolume; //dstrReader.VolumeLtrEnd; /// liter
|
||||
meterRslt.VolumeMeter = poseidon.WMVolume;
|
||||
|
||||
if (iPerl != null)
|
||||
if (!(meterRslt.TestTime == 0 || tstRslt.TestTime == 0))
|
||||
{
|
||||
meterRslt.VolumeRef = tstRslt.VolumeCTV * meterRslt.TestTime / tstRslt.TestTime;
|
||||
meterRslt.PulsesMaster =
|
||||
tstRslt.PulsesMaster * meterRslt.TestTime / tstRslt.TestTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
meterRslt.VolumeRef = tstRslt.VolumeCTV;
|
||||
meterRslt.PulsesMaster = tstRslt.PulsesMaster;
|
||||
}
|
||||
|
||||
log.Info($"meterRslt.TimestampStart = {meterRslt.TimestampStart} \n" +
|
||||
$"meterRslt.TimestampEnd = {meterRslt.TimestampEnd }\n" +
|
||||
$"meterRslt.TestTime = {meterRslt.TestTime}\n" +
|
||||
$"meterRslt.VolumeStart = {meterRslt.VolumeStart}\n" +
|
||||
$"meterRslt.VolumeEnd = {meterRslt.VolumeEnd}\n" +
|
||||
$"meterRslt.VolumeMeter = {meterRslt.VolumeMeter}\n" +
|
||||
$"meterRslt.VolumeRef = {meterRslt.VolumeRef}\n" +
|
||||
$"meterRslt.PulsesMaster = {meterRslt.PulsesMaster}\n");
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
meterRslt.TimestampStart = dstrReader.TimestampSecStart;
|
||||
meterRslt.TimestampEnd = !dstrReader.NoSamples
|
||||
? dstrReader.TimestampSecEnd
|
||||
: (dstrReader.TimestampSecStart + tstRslt.TestTime);
|
||||
meterRslt.TestTime = meterRslt.TimestampEnd - meterRslt.TimestampStart;
|
||||
meterRslt.VolumeStart = dstrReader.VolumeLtrStart; /// liter
|
||||
meterRslt.VolumeEnd = dstrReader.VolumeLtrEnd; /// liter
|
||||
meterRslt.VolumeMeter =
|
||||
Math.Abs(dstrReader.VolumeLtrEnd - dstrReader.VolumeLtrStart);
|
||||
meterRslt.VolumeRef = tstRslt.VolumeCTV * meterRslt.TestTime / tstRslt.TestTime;
|
||||
meterRslt.PulsesMaster =
|
||||
tstRslt.PulsesMaster * meterRslt.TestTime / tstRslt.TestTime;
|
||||
}
|
||||
|
||||
if (iPerl != null)
|
||||
{
|
||||
if (iPerl.ResultCode != 0 && (meterRslt.WaterMeter.ResultCode & (int)Results.Entities.ResultCode.OptoErrorCodeMask) == 0)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,197 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2017 Sensus Metering Systems
|
||||
///
|
||||
using System;
|
||||
|
||||
namespace TBF.Rig.TestMethods.GenesisCommunication.GenesisHead
|
||||
{
|
||||
public class CalibrationStruct
|
||||
{
|
||||
public static readonly int Length = 35;
|
||||
|
||||
public Byte Version;
|
||||
public MeterType MeterType;
|
||||
public UInt16 Calibration;
|
||||
public VolumeUnits VolumeUnits;
|
||||
public FlowArrow FlowArrow;
|
||||
public UInt16 FWVersion;
|
||||
public UInt16[] TargetField;
|
||||
public UInt16 RecipMeanCurrent;
|
||||
public UInt16 ThresholdVolume;
|
||||
public UInt16 ThresholdTime;
|
||||
public UInt16 FlowActivationThr;
|
||||
public UInt16 VolumeArrowThr;
|
||||
public UInt32 CalibrationTime;
|
||||
public ulong SerialNumber;
|
||||
public MeterSealed MeterSealed;
|
||||
public byte CheckSum;
|
||||
|
||||
|
||||
public CalibrationStruct()
|
||||
{
|
||||
TargetField = new UInt16[3];
|
||||
}
|
||||
|
||||
public byte[] ToByteArray()
|
||||
{
|
||||
byte[] result = new byte[Length];
|
||||
|
||||
result[0] = Version;
|
||||
result[1] = (byte)MeterType;
|
||||
|
||||
result[2] = (byte)(Calibration & 0x00FF);
|
||||
result[3] = (byte)((Calibration >> 8) & 0x00FF);
|
||||
|
||||
result[4] = (byte)VolumeUnits;
|
||||
|
||||
result[5] = (byte)FlowArrow;
|
||||
|
||||
result[6] = (byte)(FWVersion & 0x00FF);
|
||||
result[7] = (byte)((FWVersion >> 8) & 0x00FF);
|
||||
|
||||
result[8] = (byte)( TargetField[0] & 0x00FF);
|
||||
result[9] = (byte)((TargetField[0] >> 8) & 0x00FF);
|
||||
result[10] = (byte)( TargetField[1] & 0x00FF);
|
||||
result[11] = (byte)((TargetField[1] >> 8) & 0x00FF);
|
||||
result[12] = (byte)( TargetField[2] & 0x00FF);
|
||||
result[13] = (byte)((TargetField[2] >> 8) & 0x00FF);
|
||||
|
||||
result[14] = (byte)(RecipMeanCurrent & 0x00FF);
|
||||
result[15] = (byte)((RecipMeanCurrent >> 8) & 0x00FF);
|
||||
|
||||
result[16] = (byte)(ThresholdVolume & 0x00FF);
|
||||
result[17] = (byte)((ThresholdVolume >> 8) & 0x00FF);
|
||||
|
||||
result[18] = (byte)(ThresholdTime & 0x00FF);
|
||||
result[19] = (byte)((ThresholdTime >> 8) & 0x00FF);
|
||||
|
||||
result[20] = (byte)(FlowActivationThr & 0x00FF);
|
||||
result[21] = (byte)((FlowActivationThr >> 8) & 0x00FF);
|
||||
|
||||
result[22] = (byte)(VolumeArrowThr & 0x00FF);
|
||||
result[23] = (byte)((VolumeArrowThr >> 8) & 0x00FF);
|
||||
|
||||
result[24] = (byte)(CalibrationTime & 0x000000FF);
|
||||
result[25] = (byte)((CalibrationTime >> 8) & 0x000000FF);
|
||||
result[26] = (byte)((CalibrationTime >> 16) & 0x000000FF);
|
||||
result[27] = (byte)((CalibrationTime >> 24) & 0x000000FF);
|
||||
|
||||
result[28] = (byte)(SerialNumber & 0x00000000000000FF);
|
||||
result[29] = (byte)((SerialNumber >> 8) & 0x00000000000000FF);
|
||||
result[30] = (byte)((SerialNumber >> 16) & 0x00000000000000FF);
|
||||
result[31] = (byte)((SerialNumber >> 24) & 0x00000000000000FF);
|
||||
result[32] = (byte)((SerialNumber >> 32) & 0x00000000000000FF);
|
||||
|
||||
result[33] = (byte)MeterSealed;
|
||||
result[34] = CheckSum;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a calibration structure from a complete byte array
|
||||
/// </summary>
|
||||
/// <param name="data">A complete byte array data</param>
|
||||
/// <returns>CalibrationStruct or null when byte array was not complete</returns>
|
||||
public static CalibrationStruct FromByteArray(byte[] data)
|
||||
{
|
||||
if (data.Length != Length) return null;
|
||||
|
||||
CalibrationStruct result = new CalibrationStruct();
|
||||
|
||||
result.Version = data[0];
|
||||
result.MeterType = (MeterType)data[1];
|
||||
result.Calibration = (UInt16)(data[2] + 256 * data[3]);
|
||||
result.VolumeUnits = (VolumeUnits)data[4];
|
||||
result.FlowArrow = (FlowArrow)data[5];
|
||||
result.FWVersion = (UInt16)(data[6] + 256 * data[7]);
|
||||
result.TargetField[0] = (UInt16)(data[8] + 256 * data[9]);
|
||||
result.TargetField[1] = (UInt16)(data[10] + 256 * data[11]);
|
||||
result.TargetField[2] = (UInt16)(data[12] + 256 * data[13]);
|
||||
result.RecipMeanCurrent = (UInt16)(data[14] + 256 * data[15]);
|
||||
result.ThresholdVolume = (UInt16)(data[16] + 256 * data[17]);
|
||||
result.ThresholdTime = (UInt16)(data[18] + 256 * data[19]);
|
||||
result.FlowActivationThr = (UInt16)(data[20] + 256 * data[21]);
|
||||
result.VolumeArrowThr = (UInt16)(data[22] + 256 * data[23]);
|
||||
result.CalibrationTime = (((UInt32)data[27] * 256 + data[26]) * 256 + data[25]) * 256 + data[24];
|
||||
result.SerialNumber = ((((UInt64)data[32] * 256 + data[31]) * 256 + data[30]) * 256 + data[29]) * 256 + data[28];
|
||||
result.MeterSealed = (MeterSealed)data[33];
|
||||
result.CheckSum = data[34];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the calibration structure from an incomplete byte array
|
||||
/// </summary>
|
||||
/// <param name="data">Byte array data</param>
|
||||
/// <param name="offset">Offset of byte array data in CalibrationStruct</param>
|
||||
/// <returns>true when successful, false when data are not appropriate</returns>
|
||||
public bool Update(byte[] data, int offset)
|
||||
{
|
||||
if (offset == 2 && data.Length == 2)
|
||||
{
|
||||
/// Data containing iPerl calibration factor
|
||||
Calibration = (UInt16)(data[2 - offset] + 256 * data[3 - offset]);
|
||||
return true;
|
||||
}
|
||||
else if (offset == 0 && data.Length == Length)
|
||||
{
|
||||
/// Data containing a complete CalibrationStruct
|
||||
Version = data[0];
|
||||
MeterType = (MeterType)data[1];
|
||||
Calibration = (UInt16)(data[2] + 256 * data[3]);
|
||||
VolumeUnits = (VolumeUnits)data[4];
|
||||
FlowArrow = (FlowArrow)data[5];
|
||||
FWVersion = (UInt16)(data[6] + 256 * data[7]);
|
||||
TargetField[0] = (UInt16)(data[8] + 256 * data[9]);
|
||||
TargetField[1] = (UInt16)(data[10] + 256 * data[11]);
|
||||
TargetField[2] = (UInt16)(data[12] + 256 * data[13]);
|
||||
RecipMeanCurrent = (UInt16)(data[14] + 256 * data[15]);
|
||||
ThresholdVolume = (UInt16)(data[16] + 256 * data[17]);
|
||||
ThresholdTime = (UInt16)(data[18] + 256 * data[19]);
|
||||
FlowActivationThr = (UInt16)(data[20] + 256 * data[21]);
|
||||
VolumeArrowThr = (UInt16)(data[22] + 256 * data[23]);
|
||||
CalibrationTime = (((UInt32)data[27] * 256 + data[26]) * 256 + data[25]) * 256 + data[24];
|
||||
SerialNumber = ((((UInt64)data[32] * 256 + data[31]) * 256 + data[30]) * 256 + data[29]) * 256 + data[28];
|
||||
MeterSealed = (MeterSealed)data[33];
|
||||
CheckSum = data[34];
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public string FWVersionStr()
|
||||
{
|
||||
int d1 = (FWVersion >> 8) & 0x000F;
|
||||
int d2 = (FWVersion >> 12) & 0x000F;
|
||||
int d3 = (FWVersion >> 4) & 0x000F;
|
||||
int d4 = FWVersion & 0x000F;
|
||||
return string.Format("{0}.{1}{2}{3}", d1, d2, d3, d4);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("Calibration: V{0} Type={1} Cal={2} Units={3} FlowArrow.{4} FW={5} Hi={6} Norm={7} Low={8} RMC={9} ThrVol={10} ThrTime={11} FlActThr={12} VolArrThr={13} CalTm={14} SN={15} MeterSealed={16} Chksum={17}",
|
||||
Version,
|
||||
MeterType,
|
||||
Calibration,
|
||||
VolumeUnits,
|
||||
FlowArrow,
|
||||
FWVersion,
|
||||
TargetField[0],
|
||||
TargetField[1],
|
||||
TargetField[2],
|
||||
RecipMeanCurrent,
|
||||
ThresholdVolume,
|
||||
ThresholdTime,
|
||||
FlowActivationThr,
|
||||
VolumeArrowThr,
|
||||
CalibrationTime,
|
||||
SerialNumber,
|
||||
MeterSealed,
|
||||
CheckSum.ToString("X2"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2017 Sensus Metering Systems
|
||||
///
|
||||
using System;
|
||||
|
||||
namespace TBF.Rig.TestMethods.GenesisCommunication.GenesisHead
|
||||
{
|
||||
public class ConfigStruct
|
||||
{
|
||||
public const int Length = 32;
|
||||
|
||||
public Byte Version; /// 0: 1 byte
|
||||
public MeterState MeterState; /// 1: 1 byte
|
||||
public UInt32 TargetTimeVeryLowBatt; /// 2: 4 bytes in seconds
|
||||
public UInt32 TargetTimeLowBatt; /// 6: 4 bytes, in seconds
|
||||
public UInt32 TestModeTime; /// 10: 4 bytes, Max. test mode time in seconds
|
||||
public UInt16 EmptyPipeThreshold; /// 14: 2 bytes
|
||||
public byte[] PCBNumber; /// 16: 5 bytes
|
||||
public byte TestModeConfig; /// 21: 1 byte
|
||||
public UInt32 RadioAddress; /// 22: 4 bytes
|
||||
public UInt16 TempCalibration; /// 26: 2 bytes
|
||||
public UInt16 AlarmMask; /// 28: 2 bytes, Default 0xA3F7
|
||||
public UInt16 ConfigCheckSum; /// 30: 2 bytes
|
||||
|
||||
public ConfigStruct()
|
||||
{
|
||||
PCBNumber = new byte[5];
|
||||
}
|
||||
|
||||
public byte[] ToByteArray()
|
||||
{
|
||||
byte[] result = new byte[Length];
|
||||
|
||||
result[0] = Version;
|
||||
result[1] = (byte)MeterState;
|
||||
|
||||
result[2] = (byte)(TargetTimeVeryLowBatt & 0x000000FF);
|
||||
result[3] = (byte)((TargetTimeVeryLowBatt >> 8) & 0x000000FF);
|
||||
result[4] = (byte)((TargetTimeVeryLowBatt >> 16) & 0x000000FF);
|
||||
result[5] = (byte)((TargetTimeVeryLowBatt >> 24) & 0x000000FF);
|
||||
|
||||
result[6] = (byte)(TargetTimeLowBatt & 0x000000FF);
|
||||
result[7] = (byte)((TargetTimeLowBatt >> 8) & 0x000000FF);
|
||||
result[8] = (byte)((TargetTimeLowBatt >> 16) & 0x000000FF);
|
||||
result[9] = (byte)((TargetTimeLowBatt >> 24) & 0x000000FF);
|
||||
|
||||
result[10] = (byte)(TestModeTime & 0x000000FF);
|
||||
result[11] = (byte)((TestModeTime >> 8) & 0x000000FF);
|
||||
result[12] = (byte)((TestModeTime >> 16) & 0x000000FF);
|
||||
result[13] = (byte)((TestModeTime >> 24) & 0x000000FF);
|
||||
|
||||
result[14] = (byte)(EmptyPipeThreshold & 0x00FF);
|
||||
result[15] = (byte)((EmptyPipeThreshold >> 8) & 0x00FF);
|
||||
|
||||
result[16] = PCBNumber[0];
|
||||
result[17] = PCBNumber[1];
|
||||
result[18] = PCBNumber[2];
|
||||
result[19] = PCBNumber[3];
|
||||
result[20] = PCBNumber[4];
|
||||
|
||||
result[21] = TestModeConfig;
|
||||
|
||||
result[22] = (byte)(RadioAddress & 0x000000FF);
|
||||
result[23] = (byte)((RadioAddress >> 8) & 0x000000FF);
|
||||
result[24] = (byte)((RadioAddress >> 16) & 0x000000FF);
|
||||
result[25] = (byte)((RadioAddress >> 24) & 0x000000FF);
|
||||
|
||||
result[26] = (byte)(TempCalibration & 0x00FF);
|
||||
result[27] = (byte)((TempCalibration >> 8) & 0x00FF);
|
||||
|
||||
result[28] = (byte)(AlarmMask & 0x00FF);
|
||||
result[29] = (byte)((AlarmMask >> 8) & 0x00FF);
|
||||
|
||||
result[30] = (byte)(ConfigCheckSum & 0x00FF);
|
||||
result[31] = (byte)((ConfigCheckSum >> 8) & 0x00FF);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a configuration structure from a complete byte array
|
||||
/// </summary>
|
||||
/// <param name="data">A complete byte array data</param>
|
||||
/// <returns>ConfigStruct or null when byte array was not complete</returns>
|
||||
public static ConfigStruct FromByteArray(byte[] data)
|
||||
{
|
||||
if (data.Length != Length) return null;
|
||||
|
||||
ConfigStruct result = new ConfigStruct();
|
||||
|
||||
result.Version = data[0];
|
||||
result.MeterState = (MeterState)data[1];
|
||||
result.TargetTimeVeryLowBatt = (((UInt32)data[5] * 256 + data[4]) * 256 + data[3]) * 256 + data[2];
|
||||
result.TargetTimeLowBatt = (((UInt32)data[9] * 256 + data[8]) * 256 + data[7]) * 256 + data[6];
|
||||
result.TestModeTime = (((UInt32)data[13] * 256 + data[12]) * 256 + data[11]) * 256 + data[10];
|
||||
result.EmptyPipeThreshold = (UInt16)(data[15] * 256 + data[14]);
|
||||
result.PCBNumber[0] = data[16];
|
||||
result.PCBNumber[1] = data[17];
|
||||
result.PCBNumber[2] = data[18];
|
||||
result.PCBNumber[3] = data[19];
|
||||
result.PCBNumber[4] = data[20];
|
||||
result.TestModeConfig = data[21];
|
||||
result.RadioAddress = (((UInt32)data[25] * 256 + data[24]) * 256 + data[23]) * 256 + data[22];
|
||||
result.TempCalibration = (UInt16)(data[27] * 256 + data[26]);
|
||||
result.AlarmMask = (UInt16)(data[29] * 256 + data[28]);
|
||||
result.ConfigCheckSum = (UInt16)(data[31] * 256 + data[30]);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the configuration structure from an incomplete byte array
|
||||
/// </summary>
|
||||
/// <param name="offset">Offset of byte array data in ConfigStruct</param>
|
||||
/// <param name="data">Byte array data</param>
|
||||
/// <returns>true when successful, false when data are not appropriate</returns>
|
||||
public bool Update(int offset, byte[] data)
|
||||
{
|
||||
if (offset == 0 && data.Length == 2)
|
||||
{
|
||||
/// iPerl mode of function
|
||||
Version = data[0];
|
||||
MeterState = (MeterState)data[1];
|
||||
return true;
|
||||
}
|
||||
else if (offset == 0 && data.Length == 4)
|
||||
{
|
||||
/// iPerl mode of function and extra 2 bytes
|
||||
Version = data[0];
|
||||
MeterState = (MeterState)data[1];
|
||||
return true;
|
||||
}
|
||||
else if (offset == 21 && data.Length == 1)
|
||||
{
|
||||
/// TestModeConfig value
|
||||
TestModeConfig = data[21 - offset];
|
||||
return true;
|
||||
}
|
||||
else if (offset == 0 && data.Length == Length)
|
||||
{
|
||||
/// Complete ConfigStruct
|
||||
Version = data[0];
|
||||
MeterState = (MeterState)data[1];
|
||||
TargetTimeVeryLowBatt = (((UInt32)data[5] * 256 + data[4]) * 256 + data[3]) * 256 + data[2];
|
||||
TargetTimeLowBatt = (((UInt32)data[9] * 256 + data[8]) * 256 + data[7]) * 256 + data[6];
|
||||
TestModeTime = (((UInt32)data[13] * 256 + data[12]) * 256 + data[11]) * 256 + data[10];
|
||||
EmptyPipeThreshold = (UInt16)(data[15] * 256 + data[14]);
|
||||
PCBNumber[0] = data[16];
|
||||
PCBNumber[1] = data[17];
|
||||
PCBNumber[2] = data[18];
|
||||
PCBNumber[3] = data[19];
|
||||
PCBNumber[4] = data[20];
|
||||
TestModeConfig = data[21];
|
||||
RadioAddress = (((UInt32)data[25] * 256 + data[24]) * 256 + data[23]) * 256 + data[22];
|
||||
TempCalibration = (UInt16)(data[27] * 256 + data[26]);
|
||||
AlarmMask = (UInt16)(data[29] * 256 + data[28]);
|
||||
ConfigCheckSum = (UInt16)(data[31] * 256 + data[30]);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns PCB number string (12 characters, 12 decimal digits)
|
||||
/// </summary>
|
||||
/// <returns>PCB number STRING</returns>
|
||||
public string GetPcbNrString()
|
||||
{
|
||||
return PCBNumber2String(this.PCBNumber);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts PCBNumber to string (12 characters, 12 decimal digits)
|
||||
/// </summary>
|
||||
/// <param name="pcbNumber"></param>
|
||||
/// <returns>PCB number string</returns>
|
||||
public static string PCBNumber2String(byte[] pcbNumber)
|
||||
{
|
||||
if (pcbNumber.Length != 5) return string.Empty;
|
||||
|
||||
Int64 number = 0;
|
||||
for (int i = 4; i >= 0; i--)
|
||||
{
|
||||
number = 256 * number + (Int64)pcbNumber[i];
|
||||
}
|
||||
|
||||
return number.ToString();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("Config: V{0} State={1} VLoBattT={2}s LoBattT={3}s TestModeT={4}s EPThld={5} PCB#={6} TMCfg={7} RadioAddr={8} TempCalib={9} AlarmMask={10} CfgCheckSum={11}",
|
||||
Version,
|
||||
MeterState,
|
||||
TargetTimeVeryLowBatt,
|
||||
TargetTimeLowBatt,
|
||||
TestModeTime,
|
||||
EmptyPipeThreshold,
|
||||
GetPcbNrString(),
|
||||
TestModeConfig.ToString("X2"),
|
||||
RadioAddress,
|
||||
TempCalibration,
|
||||
AlarmMask.ToString("X4"),
|
||||
ConfigCheckSum.ToString("X4"));
|
||||
}
|
||||
|
||||
public string ToString(int sel)
|
||||
{
|
||||
return string.Format("{1} PCB#={6} TMCfg={7}",
|
||||
Version,
|
||||
MeterState,
|
||||
TargetTimeVeryLowBatt,
|
||||
TargetTimeLowBatt,
|
||||
TestModeTime,
|
||||
EmptyPipeThreshold,
|
||||
GetPcbNrString(),
|
||||
TestModeConfig.ToString("X2"),
|
||||
RadioAddress,
|
||||
TempCalibration,
|
||||
AlarmMask.ToString("X4"),
|
||||
ConfigCheckSum.ToString("X4"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2017 Sensus Metering Systems
|
||||
///
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace TBF.Rig.TestMethods.GenesisCommunication.GenesisHead
|
||||
{
|
||||
public enum MessageID
|
||||
{
|
||||
Calibration = 0x00, /// Access to stCalibration
|
||||
Configuration = 0x01, /// Access to stConfig
|
||||
Status = 0x02, /// Access to stStaus, read only
|
||||
Power = 0x03, /// Access to stPower, containing power info from both processors
|
||||
LCD = 0x04, /// Access to stLCD
|
||||
EventData = 0x05, /// NOT USED
|
||||
IntervalData = 0x06, /// NOT USED
|
||||
Diagnostics = 0x07, /// Access tostMetroDiagArray, read onl
|
||||
MetrologyMemory = 0x08, /// Memory block access, read only
|
||||
Error_LongAck = 0x09, /// Error message
|
||||
Command = 0x0A, /// Command to execute, with no arguments
|
||||
Parameterizing = 0x0B, /// Parameterizing message is used in MCI-SPI interface only
|
||||
Error_ShortAck = 0x0C, /// Short acknowledge message is used in MCI-SPI interface only
|
||||
ChanelAlive = 0x0D, /// Channel alive message is used in MCI-SPI interface only
|
||||
RadioPassthrough = 0x0E, /// RFID <-> Metrology <-> Radio passthrough message
|
||||
ASICRegisterReadTest = 0x0F, /// ASIC Register read test
|
||||
IMIDebugMessagesAccess = 0x10, /// IMI debug messages read test
|
||||
ProductionChecksumsRead = 0x11, /// Production checksum read: Calibration (1 byte), Configuration (2 bytes), spare (4 bytes)
|
||||
HardwareParametersTest = 0x12, /// Hardware Parameters Testing: User configurable fixed field drive time (1 byte)
|
||||
/// <summary>
|
||||
/// Notes:
|
||||
/// 1. Short Ack message contains 1-byte error code and all the fields (Offset, Payload length, payload and password) will not be present.
|
||||
/// 2. Channel Alive message does not contain the fields (Offset, Payload length, payload and password).
|
||||
/// 3. Except the above two special messages, rest all the messages in the above table will follow the message format mentioned in sections 3.1 and 3.2.
|
||||
/// </summary>
|
||||
Count /// Number of MessageID-s
|
||||
}
|
||||
|
||||
public enum MeterType : byte
|
||||
{
|
||||
DN15 = 0,
|
||||
CoaxManifold = 1,
|
||||
DN20 = 2,
|
||||
DN25 = 3,
|
||||
DN26 = 4, /// DN25*
|
||||
DN32 = 5,
|
||||
DN40 = 6,
|
||||
AutoDetect,
|
||||
Count /// Number of meter types
|
||||
}
|
||||
|
||||
public enum VolumeUnits : byte
|
||||
{
|
||||
m3 = 0,
|
||||
UK_gallon = 1,
|
||||
US_gallon = 2,
|
||||
Count /// Number of volume units
|
||||
}
|
||||
|
||||
public enum FlowArrow : byte
|
||||
{
|
||||
No = 0,
|
||||
Right = 1,
|
||||
Left = 2,
|
||||
Count /// Number of flow arrows
|
||||
}
|
||||
|
||||
public enum MeterSealed : byte
|
||||
{
|
||||
InProduction = 0x00,
|
||||
OutOfProduction = 0xA5,
|
||||
Sealed = 0x5A,
|
||||
}
|
||||
|
||||
public enum MeterState : byte
|
||||
{
|
||||
None = 0,
|
||||
Idle = 1,
|
||||
Active = 2,
|
||||
Test = 3,
|
||||
EndOfLife = 4,
|
||||
Count /// Number of meter states
|
||||
}
|
||||
|
||||
public enum FlowState : byte
|
||||
{
|
||||
No = 0,
|
||||
Reverse = 1,
|
||||
Forward = 2,
|
||||
EmptyPipe = 3,
|
||||
Count /// Number of flow states
|
||||
}
|
||||
|
||||
public enum OptoTelegramFlags : byte
|
||||
{
|
||||
OK = 0,
|
||||
OK_TestStart,
|
||||
OK_TestEnd,
|
||||
InvalidTelegram, /// Wrong telegram format of checksum error
|
||||
SyncError,
|
||||
}
|
||||
|
||||
public enum OptoState
|
||||
{
|
||||
Read,
|
||||
Flush,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2017 Sensus Metering Systems
|
||||
///
|
||||
using System.Collections.Generic;
|
||||
using TBF.Rig.Generic;
|
||||
|
||||
namespace TBF.Rig.TestMethods.GenesisCommunication.GenesisHead
|
||||
{
|
||||
public class Factory : IComponentFactory
|
||||
{
|
||||
public string ClassName { get { return "RegisterReader for Genesis"; } }
|
||||
|
||||
public void ResetStaticProperties() { GenesisHead.ResetStaticProperties(); }
|
||||
|
||||
public IComponent DummyComponent() { return new GenesisHead(); }
|
||||
|
||||
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components) { return new GenesisHead(cfg); }
|
||||
|
||||
public IComponentCfg DefaultConfig() { return new GenesisHeadCfg(this); }
|
||||
|
||||
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
|
||||
{
|
||||
return ComponentCfgBase.CreateFromDbEntity(GenesisHeadCfg.Serializer, component, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,636 @@
|
||||
using Config.Entities;
|
||||
using log4net;
|
||||
///
|
||||
/// Copyright (c) 2015-2018 Sensus Slovensko a.s.
|
||||
///
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using TBF.Rig.Generic;
|
||||
using TBF.Rig.GenericDevices;
|
||||
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore;
|
||||
using Xylem.Common.Hardware.WaterMeter.WaterMeterCore;
|
||||
using Xylem.Common.Metrology.Measurements;
|
||||
using Xylem.Common.Metrology.Measurements.Consts;
|
||||
using Common;
|
||||
using System.IO.Ports;
|
||||
|
||||
namespace TBF.Rig.TestMethods.GenesisCommunication.GenesisHead
|
||||
{
|
||||
public static class GenesisHeadBatch
|
||||
{
|
||||
public static Dictionary<string, List<MeasurementResults>> MeterIdDetailResults = new Dictionary<string, List<MeasurementResults>>();
|
||||
private static readonly ILog log = LogManager.GetLogger(typeof(GenesisHeadBatch));
|
||||
public static readonly Lazy<MeterBatch> BatchHolder = new Lazy<MeterBatch>(() =>
|
||||
{
|
||||
return new MeterBatch();
|
||||
});
|
||||
|
||||
internal static bool Start(IRegReader[] registerReaders, string[] lastSNTexts)
|
||||
{
|
||||
try
|
||||
{
|
||||
MeterIdDetailResults = new Dictionary<string, List<MeasurementResults>>();
|
||||
int index = 0;
|
||||
var ret = false;
|
||||
foreach (var rr in registerReaders)
|
||||
{
|
||||
if (rr is TestMethods.GenesisCommunication.GenesisHead.GenesisHead)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(lastSNTexts[index]))
|
||||
{
|
||||
var myGenesis = ((TestMethods.GenesisCommunication.GenesisHead.GenesisHead)rr).SetUp();
|
||||
myGenesis.SerialNumber = lastSNTexts[index];
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
index = index + 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.Fatal(ex.Message, ex);
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// This component = instance of this class is a placeholder for a combined main watermeter
|
||||
/// </summary>
|
||||
public class GenesisHead : ComponentBase, IDevice, GenericDevices./*IRegisterReader*/IRegReader, IOperation
|
||||
{
|
||||
public List<MeasurementResults> DetailedResults { get; set; }
|
||||
private static readonly ILog log = LogManager.GetLogger(typeof(GenesisHead));
|
||||
public override string ToString() { return string.Format("Genesis({0})", Cfg.ToString(1)); }
|
||||
|
||||
public RegisterReaderType RegisterReaderType { get { return RegisterReaderType.DataStream; } }
|
||||
|
||||
private readonly GenesisHeadCfg genesisHeadCfg;
|
||||
public int SlotNr { get { return genesisHeadCfg.SlotNr; } }
|
||||
public double PulsesPerLtr { get { return 1000.0; } }
|
||||
public double LtrsPerPulse { get { return 1 / PulsesPerLtr; } }
|
||||
public int Position { get; }//...MF
|
||||
|
||||
// Adding the missing static method to resolve the error. ...MF
|
||||
public static void ResetStaticProperties()
|
||||
{
|
||||
// Add logic to reset static properties here, if applicable.
|
||||
// If no static properties exist, this method can remain empty.
|
||||
}
|
||||
|
||||
#if ORACLE_DB
|
||||
public int WMType_ID { get { return iperlHeadCfg.ProcParams.WMType_ID; } } /// Required by Oracle DB
|
||||
public int WMType_Rev { get { return iperlHeadCfg.ProcParams.WMType_Rev; } } /// Required by Oracle DB
|
||||
#endif
|
||||
public float CalibTarget { get { return (ushort)genesisHeadCfg.ProcParams.CalibTarget; } }
|
||||
public ushort FactorLimitLo { get { return (ushort)genesisHeadCfg.ProcParams.FactorLimitLo; } }
|
||||
public ushort FactorLimitHi { get { return (ushort)genesisHeadCfg.ProcParams.FactorLimitHi; } }
|
||||
|
||||
/// Properties set by the Begin and the End form
|
||||
//todo rd implement
|
||||
public string SerialNr;
|
||||
|
||||
|
||||
public string EndState
|
||||
{
|
||||
get { return endState; }
|
||||
set { endState = value; }
|
||||
}
|
||||
|
||||
private string endState;
|
||||
|
||||
public string BeginState
|
||||
{
|
||||
get { return beginState; }
|
||||
set { beginState = value; }
|
||||
}
|
||||
|
||||
private string beginState;
|
||||
|
||||
public bool Disabled
|
||||
{
|
||||
get { return disabled; }
|
||||
set { disabled = value; }
|
||||
}
|
||||
|
||||
private bool disabled;
|
||||
|
||||
public bool CommFailed
|
||||
{
|
||||
get { return commFailed; }
|
||||
set { commFailed = value; }
|
||||
}
|
||||
|
||||
private bool commFailed;
|
||||
|
||||
public int ResultCode
|
||||
{
|
||||
get { return resultCode; }
|
||||
}
|
||||
|
||||
private int resultCode;
|
||||
|
||||
|
||||
/// <summary> ConfigStruct of the water meter obtained or updated by iPerlCommunication </summary>
|
||||
public ConfigStruct ConfigStruct
|
||||
{
|
||||
get { return configStruct; }
|
||||
set { configStruct = value; }
|
||||
}
|
||||
|
||||
private ConfigStruct configStruct;
|
||||
|
||||
/// <summary> CalibrationStruct of the water meter obtained or updated by iPerlCommunication </summary>
|
||||
public CalibrationStruct CalibrationStruct
|
||||
{
|
||||
get { return calibrationStruct; }
|
||||
set { calibrationStruct = value; }
|
||||
}
|
||||
|
||||
private CalibrationStruct calibrationStruct;
|
||||
|
||||
public ushort OrigCalibFactor;
|
||||
public ushort CalibFactor { get { return (CalibrationStruct != null) ? CalibrationStruct.Calibration : (ushort)0; } }
|
||||
|
||||
public double Q2ErrWOCorrection;
|
||||
public bool Q2CorrectionDone;
|
||||
public double Q2Correction;
|
||||
public int Q2CorrRFlow;
|
||||
public int Q2CorrLFlow;
|
||||
|
||||
public double Diff2Hz8Hz;
|
||||
public bool Hz2CorrectionDone;
|
||||
public int Hz2Correction;
|
||||
|
||||
public string FWVersion { get { return (CalibrationStruct != null) ? CalibrationStruct.FWVersionStr() : string.Empty; } }
|
||||
|
||||
|
||||
/// <summary> Result of the last test used to calculate Q2 correction factors, etc </summary>
|
||||
public Results.Entities.MeterTestRslt LastTestResult2;
|
||||
public Results.Entities.MeterTestRslt LastTestResult;
|
||||
public double NominalTestFlowLph; /// in liter per hour
|
||||
|
||||
|
||||
///
|
||||
/// Required for IRegisterReader interface
|
||||
///
|
||||
public int WMPulses { get { return wmPulses; } }
|
||||
public int WMRefPulses { get { return wmRefPulses; } }
|
||||
public double WMVolume { get { return wmVolume; } }
|
||||
public double BeginWMState { get { return beginWMState; } }
|
||||
public double EndWMState { get { return endWMState; } }
|
||||
public double WMTestTime { get { return wmTestTime; } }
|
||||
|
||||
private double beginWMState;
|
||||
private double endWMState;
|
||||
private double wmVolume;
|
||||
private int wmPulses;
|
||||
private int wmRefPulses;
|
||||
private double wmTestTime;
|
||||
|
||||
|
||||
/// <summary> Name set by the test, to be used as a part of the opto-data log file name </summary>
|
||||
public string TestName;
|
||||
|
||||
/// <summary> Name set by the test, to be used as a part of the opto-data log file name </summary>
|
||||
public string BenchName;
|
||||
|
||||
///
|
||||
/// Volume of water from the opto telegram
|
||||
///
|
||||
private Int64 lastVolumeRaw; /// Last read raw volume
|
||||
private double volumeLtr; ///
|
||||
private double volumeLtr0;
|
||||
|
||||
|
||||
///
|
||||
/// Timestamp from the opto telegram
|
||||
///
|
||||
private double timestampSec;
|
||||
private double timestampSec0;
|
||||
|
||||
public bool NoSamples { get { return (timestampSecEnd - timestampSecStart) < float.Epsilon; } }
|
||||
public double TimestampSecStart { get { return timestampSecStart; } }
|
||||
public double TimestampSecEnd { get { return timestampSecEnd; } }
|
||||
|
||||
private double timestampSecStart;
|
||||
private double timestampSecEnd;
|
||||
|
||||
public GenesisHead()
|
||||
{
|
||||
}
|
||||
|
||||
public GenesisHead(Generic.IComponentCfg cfg)
|
||||
: base(cfg)
|
||||
{
|
||||
ClearData();
|
||||
|
||||
genesisHeadCfg = cfg as GenesisHeadCfg;
|
||||
|
||||
log.Debug(this.ToString());
|
||||
}
|
||||
|
||||
private GenesisMeter myGenesis = null;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public GenesisMeter SetUp()
|
||||
{
|
||||
try
|
||||
{
|
||||
Log("Call SetUp()");
|
||||
if (myGenesis != null)
|
||||
{
|
||||
myGenesis.DisposeMeter();
|
||||
}
|
||||
//add for gen
|
||||
|
||||
myGenesis = new GenesisMeter();
|
||||
myGenesis.SetupFromConfigFile(SlotNr);
|
||||
Log("Add Meter to batch");
|
||||
GenesisHeadBatch.BatchHolder.Value.AddMeter(myGenesis);
|
||||
Log("Log Raw Data");
|
||||
myGenesis.LogRawData(true);
|
||||
return myGenesis;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (myGenesis != null)
|
||||
{
|
||||
Log(e.Message);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear data related to a specific water meter
|
||||
/// </summary>
|
||||
public void ClearData()
|
||||
{
|
||||
DetailedResults = new List<MeasurementResults>();
|
||||
resultCode = 0;
|
||||
|
||||
disabled = false;
|
||||
commFailed = false;
|
||||
endState = string.Empty;
|
||||
beginState = string.Empty;
|
||||
|
||||
configStruct = null;
|
||||
calibrationStruct = null;
|
||||
|
||||
LastTestResult = null;
|
||||
NominalTestFlowLph = 0;
|
||||
|
||||
OrigCalibFactor = 0;
|
||||
Q2ErrWOCorrection = 0;
|
||||
Q2CorrectionDone = false;
|
||||
Q2CorrRFlow = 0;
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
ClearData();
|
||||
|
||||
if (DebugLevel == DebugMode.Normal)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void RunDeviceBefore()
|
||||
{
|
||||
|
||||
|
||||
////todo: RD- Login??
|
||||
//if (DebugLevel == DebugMode.Normal)
|
||||
//{
|
||||
|
||||
|
||||
// if (myGenesis != null)
|
||||
// {
|
||||
// Log("TBF RunDeviceBefore");
|
||||
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// //throw new Exception("No meter was bound!");
|
||||
// }
|
||||
//}
|
||||
//else if (DebugLevel == DebugMode.FailureDuringOperation)
|
||||
//{
|
||||
//}
|
||||
}
|
||||
|
||||
public void RunDeviceAfter() { }
|
||||
|
||||
public void StopDevice()
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
if (DebugLevel == DebugMode.Normal && myGenesis != null)
|
||||
{
|
||||
myGenesis.DisposeMeter();
|
||||
|
||||
GenesisHeadBatch.BatchHolder.Value.RemoveMeter(myGenesis);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public void StopDevice2() { }
|
||||
|
||||
/// <summary>
|
||||
/// Events: Event.ReadRegisterDone, Event.Error
|
||||
/// </summary>
|
||||
/// <returns>ReadWaterMeter instance reference casted to IOperaton</returns>
|
||||
public IOperation ReadRegisterOp()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear data/counters related to a specific tests
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
resultCode = 0;
|
||||
|
||||
sampleNr = 0;
|
||||
|
||||
volumeLtr = 0;
|
||||
volumeLtr0 = 0;
|
||||
timestampSec = 0;
|
||||
timestampSec0 = 0;
|
||||
|
||||
ReadPulses();
|
||||
}
|
||||
|
||||
public void TestCompleted()
|
||||
{
|
||||
/// TODO: Implement
|
||||
}
|
||||
|
||||
private int sampleNr; /// This is to determine when the test start sample should be taken
|
||||
|
||||
|
||||
private bool StoreStartPackage = false;
|
||||
private bool StoreEndPackage = false;
|
||||
private bool Enable = false;
|
||||
public bool IsCalibration = false;
|
||||
/// <summary>Start this operation</summary>
|
||||
public void Start()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
public void StartRead(string TestName, int batchNr, int repetitionNr)
|
||||
{
|
||||
StoreStartPackage = false;
|
||||
StoreEndPackage = false;
|
||||
//Start mesurement
|
||||
if (DebugLevel == DebugMode.Normal)
|
||||
{
|
||||
if (myGenesis != null)
|
||||
{
|
||||
IsCalibration = false;
|
||||
Log($"TBF Start Measurement {TestName}");
|
||||
myGenesis.CurrentActionText = $"Batch{batchNr}_Rep{repetitionNr}";
|
||||
|
||||
|
||||
if (TestName.ToLower().Contains("calib"))
|
||||
{
|
||||
IsCalibration = true;
|
||||
//myGenesis.Login();
|
||||
myGenesis.StartCalibration();
|
||||
}
|
||||
else if (TestName.ToLower().Contains("login"))
|
||||
{
|
||||
//myGenesis.Login();
|
||||
|
||||
myGenesis.InitMeasurement();
|
||||
}
|
||||
else
|
||||
{
|
||||
DetailedResults = new List<MeasurementResults>();
|
||||
|
||||
myGenesis.StartMeasurement();
|
||||
}
|
||||
|
||||
StoreStartPackage = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Log(string text)
|
||||
{
|
||||
if (DebugLevel == DebugMode.Normal)
|
||||
{
|
||||
if (myGenesis != null)
|
||||
{
|
||||
myGenesis.WriteLog(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>Run this operation</summary>
|
||||
/// <returns>eventDone</returns>
|
||||
public Event Run()
|
||||
{
|
||||
if (DebugLevel == DebugMode.Normal)
|
||||
{
|
||||
if (myGenesis != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
//var results = myGenesis.GetIntermediateMeasurementResult();
|
||||
//readOutResults(results);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return Event.ReadRegisterDone;
|
||||
}
|
||||
public double RefVolume = 0.0;
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
//Stop(null);
|
||||
if (DebugLevel == DebugMode.Normal && myGenesis != null)
|
||||
{
|
||||
if (IsCalibration)
|
||||
{
|
||||
myGenesis.StopCalibration();
|
||||
}
|
||||
else
|
||||
{
|
||||
myGenesis.StopMeasurement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Stop this operation</summary>
|
||||
public void Stop(Double? testTimeS = null, double? refVol = null)
|
||||
{
|
||||
|
||||
if (DebugLevel == DebugMode.Normal && myGenesis != null)
|
||||
{
|
||||
Log($"TBF Stop Measurement {IsCalibration} {testTimeS} {refVol }");
|
||||
if (IsCalibration)
|
||||
{
|
||||
//myGenesis.StopCalibration();
|
||||
int retryCounter = 400;
|
||||
while (myGenesis.GetCalibrationState() != MeasurementStates.IsCompleted)
|
||||
{
|
||||
if (retryCounter < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
Thread.Sleep(10);
|
||||
retryCounter = retryCounter - 1;
|
||||
}
|
||||
try
|
||||
{
|
||||
var results = myGenesis.GetMainMeasurementResult(refVol, testTimeS, false);
|
||||
|
||||
readOutResults(results, testTimeS);
|
||||
if (refVol.HasValue && refVol.Value != 0.0)
|
||||
{
|
||||
|
||||
|
||||
myGenesis.BuildAndCheckCalibFactorsAllChannels(refVol.Value / 1000, testTimeS, Q2ErrWOCorrection);
|
||||
myGenesis.SetCalibFactorsAllChannels(false);
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MarkAsError();
|
||||
Log("Error while Stop Calib " + ex.Message);
|
||||
if (ex.InnerException != null)
|
||||
{
|
||||
Log("Inner Error:" + ex.InnerException.Message);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int retryCounter = 4000;
|
||||
//myGenesis.StopMeasurement();
|
||||
try
|
||||
{
|
||||
while (myGenesis.GetMeasurementState() != MeasurementStates.IsCompleted)
|
||||
{
|
||||
if (retryCounter < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
Thread.Sleep(10);
|
||||
retryCounter = retryCounter - 1;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (refVol.HasValue && testTimeS.HasValue)
|
||||
{
|
||||
Log("GetMainMeasurementResult V" + refVol.ToString() + " and S" + testTimeS.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log("GetMainMeasurementResult empty");
|
||||
}
|
||||
|
||||
DetailedResults = myGenesis.GetAllMeasurementResults(refVol, testTimeS);
|
||||
foreach (var item in DetailedResults)
|
||||
{
|
||||
Log("Detail Measurement Channel =" + item.Channel + "; CorrectedDutVolumeCm= " + item.CorrectedDutVolumeCm + "; DeviationDutToRefPer= " + item.DeviationDutToRefPer);
|
||||
}
|
||||
|
||||
|
||||
readOutResults(DetailedResults.First(), testTimeS);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MarkAsError();
|
||||
Log("Error while Stop Measurement " + ex.Message);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MarkAsError();
|
||||
Log("Error while GetMeasurementState " + ex.Message);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
StoreEndPackage = true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void readOutResults(MeasurementResults results, double? testTimeS)
|
||||
{
|
||||
volumeLtr = results.CorrectedDutVolumeCm * 1000;
|
||||
timestampSec = results.DutStopRecord.GetTimeS();
|
||||
if (testTimeS.HasValue)
|
||||
{
|
||||
wmTestTime = testTimeS.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
wmTestTime = results.DutTimeS;
|
||||
}
|
||||
|
||||
wmVolume = results.CorrectedDutVolumeCm * 1000;
|
||||
Log("DutFlowRateCmPh" + results.DutFlowRateCmPh.ToString());
|
||||
Log("CorrectedDutVolumeCm=" + results.CorrectedDutVolumeCm.ToString());
|
||||
Log("DutVolumeCm=" + results.DutVolumeCm.ToString());
|
||||
ReadPulses();
|
||||
}
|
||||
|
||||
private void MarkAsError()
|
||||
{
|
||||
volumeLtr = 0;
|
||||
timestampSec = 0;
|
||||
wmTestTime = 0;
|
||||
wmVolume = 0;
|
||||
ReadPulses();
|
||||
}
|
||||
|
||||
private void ReadPulses()
|
||||
{
|
||||
beginWMState = volumeLtr0;
|
||||
endWMState = volumeLtr;
|
||||
wmPulses = (int)(wmVolume * (double)PulsesPerLtr + 0.5);
|
||||
wmRefPulses = StateMachine.ControlBoardMain.RefPulses;//EtPulses(0);//...MF
|
||||
}
|
||||
|
||||
private bool optoSerialPortParsingEnabled;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2017 Sensus Metering Systems
|
||||
///
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Xml.Serialization;
|
||||
using Config.Entities;
|
||||
using TBF.Rig.Generic;
|
||||
using TBF.Resources;
|
||||
using Common;
|
||||
|
||||
namespace TBF.Rig.TestMethods.GenesisCommunication.GenesisHead
|
||||
{
|
||||
public class GenesisHeadCfg : ComponentCfgBase, Generic.IComponentCfg
|
||||
{
|
||||
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(GenesisHeadCfg) })[0];
|
||||
public override XmlSerializer GetSerializer() { return Serializer; }
|
||||
|
||||
|
||||
public IComponentCfgCtrl GetControl(IList<Config.Entities.Component> cmpntEntities) { return new GenesisHeadCfgCtrl(); }//...MF
|
||||
|
||||
///
|
||||
/// Serialized parameters
|
||||
///
|
||||
public int SlotNr; /// Number written to QuidoRS to connct the watermeter to RfidComPort, 1 .. 10
|
||||
|
||||
/// <summary> Procedure parameters </summary>
|
||||
[XmlIgnore]
|
||||
public ProcParams ProcParams;
|
||||
public override IParamsProvider GetRuntimeProcParamsProvider() { return ProcParams; }
|
||||
public override IParamsProvider CreateProcParamsProvider() { return new ProcParams(true); }
|
||||
|
||||
[XmlIgnore]
|
||||
public MeterType MeterType { get { return (ProcParams != null) ? ProcParams.MeterType : MeterType.AutoDetect; } }
|
||||
|
||||
|
||||
/// Private parameterless constructor invoked by all other (public) constructors
|
||||
GenesisHeadCfg()
|
||||
{
|
||||
Name = "Genesis";
|
||||
ParentName = string.Empty;
|
||||
SlotNr = 0;
|
||||
ProcParams = new ProcParams(true);
|
||||
}
|
||||
|
||||
public GenesisHeadCfg(IComponentFactory factory)
|
||||
: this()
|
||||
{
|
||||
this.Factory = factory;
|
||||
}
|
||||
|
||||
public string ToString(int i)
|
||||
{
|
||||
return string.Format("{0} SlotNr={1}",
|
||||
Name,
|
||||
SlotNr
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2017 Sensus Metering Systems
|
||||
///
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Windows.Forms;
|
||||
using log4net;
|
||||
using TBF.Rig.Generic;
|
||||
using TBF.Resources;
|
||||
using Config.Entities;
|
||||
using Common;
|
||||
|
||||
namespace TBF.Rig.TestMethods.GenesisCommunication.GenesisHead
|
||||
{
|
||||
public partial class GenesisHeadCfgCtrl : UserControl, IComponentCfgCtrl
|
||||
{
|
||||
static readonly ILog log = LogManager.GetLogger(typeof(GenesisHeadCfgCtrl));
|
||||
|
||||
public bool ShowMore { get { return false; } }
|
||||
|
||||
GenesisHeadCfg config;
|
||||
public IComponentCfg Config
|
||||
{
|
||||
get { return config as IComponentCfg; }
|
||||
set
|
||||
{
|
||||
config = value as GenesisHeadCfg;
|
||||
Redraw();
|
||||
}
|
||||
}
|
||||
|
||||
public GenesisHeadCfgCtrl()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void WaterMeterCfgCtrl_Load(object sender, EventArgs e)
|
||||
{
|
||||
nameLabel.Text = Strings.Name;
|
||||
classNameLabel.Text = config.Factory.ClassName;
|
||||
slotNrTextBox.Text = config.SlotNr.ToString();
|
||||
Redraw();
|
||||
}
|
||||
|
||||
public void Closing()
|
||||
{
|
||||
}
|
||||
|
||||
void Redraw()
|
||||
{
|
||||
if (config == null) return; /// Control was not loaded, settings were not changed
|
||||
nameTextBox.Text = config.Name;
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void Unlock()
|
||||
{
|
||||
nameTextBox.Enabled = true;
|
||||
slotNrTextBox.Enabled = true;
|
||||
}
|
||||
|
||||
public CfgUpdateFlags VerifyCfg(ref string message)
|
||||
{
|
||||
CfgUpdateFlags flags = CfgUpdateFlags.None;
|
||||
|
||||
int dummy;
|
||||
|
||||
if (!int.TryParse(slotNrTextBox.Text, out dummy) || dummy < 1 || dummy > 7)
|
||||
{
|
||||
flags |= CfgUpdateFlags.Error;
|
||||
message += Environment.NewLine + string.Format(Strings.Invalid_0, muxBoardNrLabel.Text);
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
public CfgUpdateFlags UpdateCfg()
|
||||
{
|
||||
CfgUpdateFlags flags = CfgUpdateFlags.RestartRqrd;
|
||||
|
||||
if (config == null) return CfgUpdateFlags.Error; /// Control was not loaded, settings were not changed
|
||||
|
||||
config.Name = nameTextBox.Text;
|
||||
|
||||
config.SlotNr = int.Parse(slotNrTextBox.Text);
|
||||
|
||||
return flags;
|
||||
}
|
||||
}
|
||||
}
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2017 Sensus Metering Systems
|
||||
///
|
||||
namespace TBF.Rig.TestMethods.GenesisCommunication.GenesisHead
|
||||
{
|
||||
partial class GenesisHeadCfgCtrl : System.Windows.Forms.UserControl
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.nameTextBox = new System.Windows.Forms.TextBox();
|
||||
this.nameLabel = new System.Windows.Forms.Label();
|
||||
this.classNameLabel = new System.Windows.Forms.Label();
|
||||
this.slotNrTextBox = new System.Windows.Forms.TextBox();
|
||||
this.muxBoardNrLabel = new System.Windows.Forms.Label();
|
||||
this.label3 = new System.Windows.Forms.Label();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// nameTextBox
|
||||
//
|
||||
this.nameTextBox.Enabled = false;
|
||||
this.nameTextBox.Location = new System.Drawing.Point(135, 40);
|
||||
this.nameTextBox.Name = "nameTextBox";
|
||||
this.nameTextBox.Size = new System.Drawing.Size(121, 20);
|
||||
this.nameTextBox.TabIndex = 2;
|
||||
//
|
||||
// nameLabel
|
||||
//
|
||||
this.nameLabel.AutoSize = true;
|
||||
this.nameLabel.Location = new System.Drawing.Point(25, 43);
|
||||
this.nameLabel.Name = "nameLabel";
|
||||
this.nameLabel.Size = new System.Drawing.Size(35, 13);
|
||||
this.nameLabel.TabIndex = 1;
|
||||
this.nameLabel.Text = "Name";
|
||||
//
|
||||
// classNameLabel
|
||||
//
|
||||
this.classNameLabel.AutoSize = true;
|
||||
this.classNameLabel.Location = new System.Drawing.Point(132, 16);
|
||||
this.classNameLabel.Name = "classNameLabel";
|
||||
this.classNameLabel.Size = new System.Drawing.Size(60, 13);
|
||||
this.classNameLabel.TabIndex = 0;
|
||||
this.classNameLabel.Text = "ClassName";
|
||||
//
|
||||
// slotNrTextBox
|
||||
//
|
||||
this.slotNrTextBox.Enabled = false;
|
||||
this.slotNrTextBox.Location = new System.Drawing.Point(135, 63);
|
||||
this.slotNrTextBox.Name = "slotNrTextBox";
|
||||
this.slotNrTextBox.Size = new System.Drawing.Size(34, 20);
|
||||
this.slotNrTextBox.TabIndex = 9;
|
||||
//
|
||||
// muxBoardNrLabel
|
||||
//
|
||||
this.muxBoardNrLabel.AutoSize = true;
|
||||
this.muxBoardNrLabel.Location = new System.Drawing.Point(25, 66);
|
||||
this.muxBoardNrLabel.Name = "muxBoardNrLabel";
|
||||
this.muxBoardNrLabel.Size = new System.Drawing.Size(37, 13);
|
||||
this.muxBoardNrLabel.TabIndex = 8;
|
||||
this.muxBoardNrLabel.Text = "Slot nr";
|
||||
//
|
||||
// label3
|
||||
//
|
||||
this.label3.AutoSize = true;
|
||||
this.label3.Location = new System.Drawing.Point(176, 66);
|
||||
this.label3.Name = "label3";
|
||||
this.label3.Size = new System.Drawing.Size(31, 13);
|
||||
this.label3.TabIndex = 13;
|
||||
this.label3.Text = "1 .. 6";
|
||||
//
|
||||
// GenesisHeadCfgCtrl
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.Controls.Add(this.label3);
|
||||
this.Controls.Add(this.slotNrTextBox);
|
||||
this.Controls.Add(this.muxBoardNrLabel);
|
||||
this.Controls.Add(this.nameTextBox);
|
||||
this.Controls.Add(this.nameLabel);
|
||||
this.Controls.Add(this.classNameLabel);
|
||||
this.Name = "GenesisHeadCfgCtrl";
|
||||
this.Size = new System.Drawing.Size(396, 123);
|
||||
this.Load += new System.EventHandler(this.WaterMeterCfgCtrl_Load);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.TextBox nameTextBox;
|
||||
private System.Windows.Forms.Label nameLabel;
|
||||
private System.Windows.Forms.Label classNameLabel;
|
||||
private System.Windows.Forms.TextBox slotNrTextBox;
|
||||
private System.Windows.Forms.Label muxBoardNrLabel;
|
||||
private System.Windows.Forms.Label label3;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
@@ -0,0 +1,20 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2017 Sensus Metering Systems
|
||||
///
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace TBF.Rig.TestMethods.GenesisCommunication.GenesisHead
|
||||
{
|
||||
public class OptoReceivedEventArgs : EventArgs
|
||||
{
|
||||
public string Data;
|
||||
|
||||
public OptoReceivedEventArgs(string data)
|
||||
{
|
||||
this.Data = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,295 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2017 Sensus Metering Systems
|
||||
///
|
||||
using System;
|
||||
using System.Globalization;
|
||||
namespace TBF.Rig.TestMethods.GenesisCommunication.GenesisHead
|
||||
{
|
||||
public class OptoTelegramRaw
|
||||
{
|
||||
public static readonly int Length = 42;
|
||||
private static CultureInfo culture;
|
||||
|
||||
|
||||
///
|
||||
/// Strobed value
|
||||
///
|
||||
public static decimal TestStartTimestampDec;
|
||||
|
||||
///
|
||||
/// Stored values
|
||||
///
|
||||
public OptoTelegramFlags Flags;
|
||||
|
||||
public DateTime DateTime; /// From PC
|
||||
public float RefFlow; /// [m3/h]
|
||||
public int Counter;
|
||||
|
||||
public UInt32 EmfRaw; /// From iPerl opto data
|
||||
public Int16 MagneticFieldRaw;
|
||||
public Int16 FlowRaw;
|
||||
public UInt32 VolumeRaw;
|
||||
public Int64 VolumeRawExt;
|
||||
public Int16 Impedance;
|
||||
public UInt32 Timestamp;
|
||||
public Int64 TimestampExt;
|
||||
public byte CheckSum;
|
||||
|
||||
///
|
||||
/// Calculated values
|
||||
///
|
||||
public double EMF()
|
||||
{
|
||||
Int32 signedEmf = (EmfRaw > 0x7FFFFF) ? ((int)EmfRaw - 0x1000000) : (int)EmfRaw;
|
||||
return 0.000000333 * (double)signedEmf;
|
||||
}
|
||||
public double MagneticField() { return (double)MagneticFieldRaw; }
|
||||
public double Flow(double scalingFactor) { return 0.225 * scalingFactor * (double)FlowRaw; }
|
||||
public double Volume(double scalingFactor) { return 0.0000625 * scalingFactor * (double)VolumeRawExt; }
|
||||
public Int32 FlipTime() { return Impedance; }
|
||||
public decimal TimestampDec() { return (decimal)TimestampExt / (decimal)8192; }
|
||||
public double VolumeDelta(double scalingFactor, OptoTelegramRaw previous) { return (previous == null) ? 0 : Volume(scalingFactor) - previous.Volume(scalingFactor); }
|
||||
public decimal TimeDelta() { return TimestampDec() - TestStartTimestampDec; }
|
||||
public string Label()
|
||||
{
|
||||
if (Flags == OptoTelegramFlags.OK_TestStart) return "#### start test ####";
|
||||
else if (Flags == OptoTelegramFlags.OK_TestEnd) return "#### end of test ####";
|
||||
else return string.Empty;
|
||||
}
|
||||
|
||||
|
||||
static OptoTelegramRaw()
|
||||
{
|
||||
culture = CultureInfo.CreateSpecificCulture("DE"); /// This is to use comma as decimal number separator
|
||||
}
|
||||
|
||||
public OptoTelegramRaw()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses optical telegram and returns OptoTelegramRaw object
|
||||
/// </summary>
|
||||
/// <description>
|
||||
/// Create a configuration structure from a complete byte array
|
||||
///
|
||||
/// Telegram description:
|
||||
///
|
||||
/// AAAAAA[tab]BBBB[tab]CCCC[tab]DDDDDD[tab]EEEE[tab]FFFFFFFF[tab]GG[cr][lf] (42 bytes)
|
||||
///
|
||||
/// Data Comment Type Calculate to decimal
|
||||
/// ----------------------------------------------------------------
|
||||
/// AAAAAA EMF Int24 Value * 0.000000333
|
||||
/// BBBB Magnetic field Int16 Value
|
||||
/// CCCC Flow Int16 Value * 0.225 * Scalig factor
|
||||
/// DDDDDD Volume Int24 Value / 16000 * Scaling factor
|
||||
/// EEEE Impedance Int16 Value
|
||||
/// FFFFFFFF Timestamp Uint32 Value / 8192
|
||||
/// GG Checksum Byte
|
||||
/// ----------------------------------------------------------------
|
||||
///
|
||||
/// Example:
|
||||
/// FFFFFE 51EA 0000 65324E 0087 F6319DFF 86
|
||||
/// FFDD3A 51F9 0000 65324E 0088 F631A60B 45
|
||||
/// ...
|
||||
/// </description>
|
||||
/// <param name="data">A complete byte array data</param>
|
||||
/// <returns>true = telegram OK, false = telegram NOK</returns>
|
||||
public bool UpdateFromString(string telegram, int counter, ref Int64 volumeRawExtLast, ref Int64 timestampExtLast)
|
||||
{
|
||||
DateTime = DateTime.Now;
|
||||
Counter = counter;
|
||||
RefFlow = (float)Sequences.ProcessData.RefFlow.Val;
|
||||
|
||||
if ((telegram == null) || (telegram.Length < Length) ||
|
||||
(telegram[6] != '\t') || (telegram[11] != '\t') || (telegram[16] != '\t') ||
|
||||
(telegram[23] != '\t') || (telegram[28] != '\t') || (telegram[37] != '\t') ||
|
||||
(telegram[40] != '\r') || (telegram[41] != '\n'))
|
||||
{
|
||||
Flags = OptoTelegramFlags.InvalidTelegram;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool f1 = UInt32.TryParse(telegram.Substring(0, 6), NumberStyles.HexNumber, CultureInfo.CurrentCulture, out EmfRaw);
|
||||
bool f2 = Int16.TryParse(telegram.Substring(7, 4), NumberStyles.HexNumber, CultureInfo.CurrentCulture, out MagneticFieldRaw);
|
||||
bool f3 = Int16.TryParse(telegram.Substring(12, 4), NumberStyles.HexNumber, CultureInfo.CurrentCulture, out FlowRaw);
|
||||
bool f4 = UInt32.TryParse(telegram.Substring(17, 6), NumberStyles.HexNumber, CultureInfo.CurrentCulture, out VolumeRaw);
|
||||
bool f5 = Int16.TryParse(telegram.Substring(24, 4), NumberStyles.HexNumber, CultureInfo.CurrentCulture, out Impedance);
|
||||
bool f6 = UInt32.TryParse(telegram.Substring(29, 8), NumberStyles.HexNumber, CultureInfo.CurrentCulture, out Timestamp);
|
||||
bool f7 = byte.TryParse(telegram.Substring(38, 2), NumberStyles.HexNumber, CultureInfo.CurrentCulture, out CheckSum);
|
||||
|
||||
bool allOk = f1 && f2 && f3 && f4 && f5 && f6 && f7;
|
||||
Flags = allOk ? OptoTelegramFlags.OK : OptoTelegramFlags.InvalidTelegram;
|
||||
|
||||
///
|
||||
/// Cope with 'VolumeRaw' overflow
|
||||
///
|
||||
Int64 uncorrected = (Int64)(((UInt64)volumeRawExtLast & 0xFFFFFFFFFF000000UL) | VolumeRaw);
|
||||
if (Math.Abs(uncorrected - volumeRawExtLast) <= 0x800000L)
|
||||
{
|
||||
VolumeRawExt = volumeRawExtLast = uncorrected;
|
||||
}
|
||||
else if (Math.Abs(uncorrected + 0x1000000L - volumeRawExtLast) <= 0x800000L)
|
||||
{
|
||||
VolumeRawExt = volumeRawExtLast = uncorrected + 0x1000000L;
|
||||
}
|
||||
else if (Math.Abs(uncorrected - 0x1000000L - volumeRawExtLast) <= 0x800000L)
|
||||
{
|
||||
VolumeRawExt = volumeRawExtLast = uncorrected - 0x1000000L;
|
||||
}
|
||||
else
|
||||
{
|
||||
VolumeRawExt = volumeRawExtLast = uncorrected;
|
||||
}
|
||||
|
||||
///
|
||||
/// Cope with 'Timestamp' overflow
|
||||
///
|
||||
uncorrected = (Int64)(((UInt64)timestampExtLast & 0xFFFFFFFF00000000UL) | Timestamp);
|
||||
if (Math.Abs(uncorrected - timestampExtLast) <= 0x80000000L)
|
||||
{
|
||||
TimestampExt = timestampExtLast = uncorrected;
|
||||
}
|
||||
else if (Math.Abs(uncorrected + 0x100000000L - timestampExtLast) <= 0x80000000L)
|
||||
{
|
||||
TimestampExt = timestampExtLast = uncorrected + 0x100000000L;
|
||||
}
|
||||
else if (Math.Abs(uncorrected - 0x100000000L - timestampExtLast) <= 0x80000000L)
|
||||
{
|
||||
TimestampExt = timestampExtLast = uncorrected - 0x100000000L;
|
||||
}
|
||||
else
|
||||
{
|
||||
TimestampExt = timestampExtLast = uncorrected;
|
||||
}
|
||||
|
||||
return allOk;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Alternative to UpdateFromString(...) when data are flushed
|
||||
/// </summary>
|
||||
public bool UpdateFromStringDummy(string telegram)
|
||||
{
|
||||
DateTime = DateTime.Now;
|
||||
RefFlow = (float)Sequences.ProcessData.RefFlow.Val;
|
||||
|
||||
if ((telegram == null) || (telegram.Length < Length) ||
|
||||
(telegram[6] != '\t') || (telegram[11] != '\t') || (telegram[16] != '\t') ||
|
||||
(telegram[23] != '\t') || (telegram[28] != '\t') || (telegram[37] != '\t') ||
|
||||
(telegram[40] != '\r') || (telegram[41] != '\n'))
|
||||
{
|
||||
Flags = OptoTelegramFlags.InvalidTelegram;
|
||||
return false;
|
||||
}
|
||||
|
||||
//bool f1 = UInt32.TryParse(telegram.Substring(0, 6), NumberStyles.HexNumber, CultureInfo.CurrentCulture, out EmfRaw);
|
||||
//bool f2 = Int16.TryParse(telegram.Substring(7, 4), NumberStyles.HexNumber, CultureInfo.CurrentCulture, out MagneticFieldRaw);
|
||||
//bool f3 = Int16.TryParse(telegram.Substring(12, 4), NumberStyles.HexNumber, CultureInfo.CurrentCulture, out FlowRaw);
|
||||
//bool f4 = UInt32.TryParse(telegram.Substring(17, 6), NumberStyles.HexNumber, CultureInfo.CurrentCulture, out VolumeRaw);
|
||||
//bool f5 = Int16.TryParse(telegram.Substring(24, 4), NumberStyles.HexNumber, CultureInfo.CurrentCulture, out Impedance);
|
||||
//bool f6 = UInt32.TryParse(telegram.Substring(29, 8), NumberStyles.HexNumber, CultureInfo.CurrentCulture, out Timestamp);
|
||||
//bool f7 = byte.TryParse(telegram.Substring(38, 2), NumberStyles.HexNumber, CultureInfo.CurrentCulture, out CheckSum);
|
||||
//return f1 && f2 && f3 && f4 && f5 && f6 && f7;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public void SetFlags(OptoTelegramFlags flags)
|
||||
{
|
||||
this.Flags = flags;
|
||||
}
|
||||
|
||||
|
||||
public string ToString(double scalingFactor, OptoTelegramRaw previous)
|
||||
{
|
||||
if (Flags == OptoTelegramFlags.SyncError)
|
||||
{
|
||||
return "Sychronization error";
|
||||
}
|
||||
else if (Flags == OptoTelegramFlags.InvalidTelegram)
|
||||
{
|
||||
return "Invalid telegram";
|
||||
}
|
||||
else /// if (flags == OptoTelegramFlags.OK / OptoTelegramFlags.OK_TestStart / OptoTelegramFlags.OK_TestEnd)
|
||||
{
|
||||
return string.Format("{0}:{1}:{2}.{3}\t{4} :\t{5}\t{6}\t{7}\t{8}\t{9}\t{10}\t{11}\t{12}\t{13}\t{14}\t{15}\t{16}\t{17}\t{18}\t{19}\t{20}\t{21}\t{22}",
|
||||
DateTime.Hour.ToString("D2"),
|
||||
DateTime.Minute.ToString("D2"),
|
||||
DateTime.Second.ToString("D2"),
|
||||
DateTime.Millisecond.ToString("D4"),
|
||||
Counter,
|
||||
EmfRaw.ToString("X6"),
|
||||
MagneticFieldRaw.ToString("X4"),
|
||||
FlowRaw.ToString("X4"),
|
||||
VolumeRaw.ToString("X6"),
|
||||
Impedance.ToString("X4"),
|
||||
Timestamp.ToString("X8"),
|
||||
CheckSum.ToString("X2"),
|
||||
EMF().ToString("F4", culture),
|
||||
MagneticField().ToString("F0", culture),
|
||||
Flow(scalingFactor).ToString("F2", culture),
|
||||
Volume(scalingFactor).ToString("F4", culture),
|
||||
FlipTime().ToString("F0", culture),
|
||||
TimestampDec().ToString("F4", culture),
|
||||
(RefFlow * 1000).ToString("F2", culture),
|
||||
VolumeDelta(scalingFactor, previous).ToString("F4", culture),
|
||||
TimeDelta().ToString("F3", culture),
|
||||
scalingFactor.ToString("F1", culture),
|
||||
Label());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Filter RefFlow data in an array of OptoTelegramRaw objects by a FIR filter:
|
||||
///
|
||||
/// kSize = 5, kSize2 = 2
|
||||
///
|
||||
/// i k
|
||||
/// ---------------------------------------------------------------------------
|
||||
/// 0 -5 filtered[0] = data[0]
|
||||
/// 1 -4 filtered[1] = data[1]
|
||||
/// 2 -3 filtered[2] = data[0]*k[0] + ... + data[4]*k[4]
|
||||
/// 3 -2 filtered[3] = data[1]*k[0] + ... + data[5]*k[4]
|
||||
/// 4 -1 filtered[4] = data[2]*k[0] + ... + data[6]*k[4]
|
||||
/// 5 0 data[0] = filtered[0], filtered[0] = data[3]*k[0] + ... + data[7]*k[4]
|
||||
/// 6 1 data[1] = filtered[1], filtered[1] = data[4]*k[0] + ... + data[8]*k[4]
|
||||
/// 7 ...
|
||||
/// </summary>
|
||||
/// <param name="optoData">array of OptoTelegramRaw objects</param>
|
||||
/// <param name="optoDataCount">number of objects to process</param>
|
||||
public static void FIRFilterFlow(OptoTelegramRaw[] optoData, int optoDataCount)
|
||||
{
|
||||
float[] kernel = new float[] { 0.1f, 0.2f, 0.4f, 0.2f, 0.1f };
|
||||
int kSize = kernel.Length;
|
||||
int kSize2 = kernel.Length / 2;
|
||||
|
||||
float[] filtered = new float[kSize];
|
||||
|
||||
for (int i = 0; i < optoDataCount; i++)
|
||||
{
|
||||
int k = i - kSize;
|
||||
if (k >= 0) optoData[k].RefFlow = filtered[i % kSize];
|
||||
|
||||
if (i < kSize2 || i >= optoDataCount - kSize2)
|
||||
{
|
||||
filtered[i % kSize] = optoData[i].RefFlow;
|
||||
}
|
||||
else
|
||||
{
|
||||
float weoightedSum = 0;
|
||||
for (int j = -kSize2; j <= kSize2; j++)
|
||||
weoightedSum += optoData[i + j].RefFlow * kernel[j + kSize2];
|
||||
|
||||
filtered[i % kSize] = weoightedSum;
|
||||
}
|
||||
}
|
||||
|
||||
for (int k = optoDataCount - kSize; k < optoDataCount; k++)
|
||||
{
|
||||
if (k >= 0) optoData[k].RefFlow = filtered[k % kSize];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2017 Sensus Metering Systems
|
||||
///
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Xml.Serialization;
|
||||
using Config.Entities;
|
||||
using TBF.Rig.Generic;
|
||||
using TBF.Resources;
|
||||
using Common;
|
||||
|
||||
namespace TBF.Rig.TestMethods.GenesisCommunication.GenesisHead
|
||||
{
|
||||
public class ProcParams : ProcedureParamsBase, IParamsProvider, IProcedureParams
|
||||
{
|
||||
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(ProcParams) })[0];
|
||||
public override XmlSerializer GetSerializer() { return Serializer; }
|
||||
|
||||
public MeterType MeterType;
|
||||
public float CalibTarget; /// Target error after calibration in [%]
|
||||
public int FactorLimitLo; /// Lower limit for the calibration factor
|
||||
public int FactorLimitHi; /// Upper limit for the calibration factor
|
||||
#if ORACLE_DB
|
||||
public int WMType_ID; /// Required for Oracle DB: ID_WZTyp in table VT_PRUEFPUNKT_SOLL_SD
|
||||
public int WMType_Rev; /// Required for Oracle DB: Rev_WZTyp in table VT_PRUEFPUNKT_SOLL_SD
|
||||
#endif
|
||||
|
||||
|
||||
public override void InitializeAll()
|
||||
{
|
||||
MeterType = MeterType.AutoDetect;
|
||||
CalibTarget = 0;
|
||||
FactorLimitLo = 1000;
|
||||
FactorLimitHi = 8000;
|
||||
#if ORACLE_DB
|
||||
WMType_ID = 2; /// Value for iPerl DN15
|
||||
WMType_Rev = 1; /// Value for iPerl DN15
|
||||
#endif
|
||||
}
|
||||
|
||||
string[] paramNames = new string[]
|
||||
{
|
||||
"iPerl type",
|
||||
"Calib. target [%]",
|
||||
"Calib. factor Lo",
|
||||
"Calib. factor Hi",
|
||||
#if ORACLE_DB
|
||||
"WMType ID",
|
||||
"WMType Rev.",
|
||||
#endif
|
||||
};
|
||||
public override string ParamName(int i) { return paramNames[i]; }
|
||||
public override int ParamsCount() { return paramNames.Length; }
|
||||
|
||||
public override string ToString(int i)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0: return MeterType.ToString();
|
||||
case 1: return CalibTarget.ToString();
|
||||
case 2: return FactorLimitLo.ToString();
|
||||
case 3: return FactorLimitHi.ToString();
|
||||
#if ORACLE_DB
|
||||
case 4: return WMType_ID.ToString();
|
||||
case 5: return WMType_Rev.ToString();
|
||||
#endif
|
||||
default: return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
public CfgUpdateFlags UpdateParam(int i, string strValue)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
for (MeterType mt = 0; mt < MeterType.Count; mt++)
|
||||
{
|
||||
if (mt.ToString().Equals(strValue)) { MeterType = mt; return CfgUpdateFlags.None; }
|
||||
}
|
||||
break;
|
||||
case 1: CalibTarget = Utils.ParseSFloat(strValue); return CfgUpdateFlags.None;
|
||||
case 2: FactorLimitLo = int.Parse(strValue); return CfgUpdateFlags.None;
|
||||
case 3: FactorLimitHi = int.Parse(strValue); return CfgUpdateFlags.None;
|
||||
#if ORACLE_DB
|
||||
case 4: WMType_ID = int.Parse(strValue); return CfgUpdateFlags.None;
|
||||
case 5: WMType_Rev = int.Parse(strValue); return CfgUpdateFlags.None;
|
||||
#endif
|
||||
default: return CfgUpdateFlags.None;
|
||||
}
|
||||
|
||||
return CfgUpdateFlags.None;
|
||||
}
|
||||
|
||||
public bool ValidateParam(int i, string strValue, out string message)
|
||||
{
|
||||
message = string.Empty;
|
||||
|
||||
int iDummy;
|
||||
float fDummy;
|
||||
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
for (MeterType mt = 0; mt < MeterType.Count; mt++) if (mt.ToString().Equals(strValue)) return true;
|
||||
break;
|
||||
case 1:
|
||||
if (Utils.TryParseSFloat(strValue, out fDummy) && fDummy >= -10.0f && fDummy <= 10.0f) return true;
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
if (int.TryParse(strValue, out iDummy) && iDummy >= 1000 && iDummy <= 8000) return true;
|
||||
break;
|
||||
|
||||
#if ORACLE_DB
|
||||
case 4: /// WMType_ID
|
||||
case 5: /// WMType_Rev
|
||||
if (int.TryParse(strValue, out iDummy)) return true;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
message = "Invalid index";
|
||||
return false;
|
||||
}
|
||||
|
||||
message = ParamName(i) + " is invalid";
|
||||
return false;
|
||||
}
|
||||
|
||||
void CopyContentTo(ProcParams prms)
|
||||
{
|
||||
prms.MeterType = this.MeterType;
|
||||
prms.CalibTarget = this.CalibTarget;
|
||||
prms.FactorLimitLo = this.FactorLimitLo;
|
||||
prms.FactorLimitHi = this.FactorLimitHi;
|
||||
#if ORACLE_DB
|
||||
prms.WMType_ID = this.WMType_ID;
|
||||
prms.WMType_Rev = this.WMType_Rev;
|
||||
#endif
|
||||
}
|
||||
|
||||
public IParamsProvider Clone()
|
||||
{
|
||||
ProcParams pars = new ProcParams();
|
||||
CopyContentTo(pars);
|
||||
return pars;
|
||||
}
|
||||
|
||||
public override void UpdateFromDbEntity(ComponentProcedure dbEntity)
|
||||
{
|
||||
if (dbEntity == null) return;
|
||||
try
|
||||
{
|
||||
ProcParams tmp = Serializer.Deserialize(new StringReader(dbEntity.Parameters)) as ProcParams;
|
||||
|
||||
procedureParamsEntity = dbEntity;
|
||||
componentName = dbEntity.CmpntName;
|
||||
procedure = dbEntity.Procedure;
|
||||
|
||||
if (tmp != null) tmp.CopyContentTo(this);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public ProcParams()
|
||||
{
|
||||
}
|
||||
|
||||
public ProcParams(bool initialize)
|
||||
{
|
||||
if (initialize) InitializeAll();
|
||||
}
|
||||
|
||||
public ProcParams(ComponentProcedure procParamsEntity, string componentName, Procedure procedure)
|
||||
{
|
||||
this.procedureParamsEntity = procParamsEntity;
|
||||
this.componentName = componentName;
|
||||
this.procedure = procedure;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2017 Sensus Metering Systems
|
||||
///
|
||||
using System;
|
||||
|
||||
namespace TBF.Rig.TestMethods.GenesisCommunication.GenesisHead
|
||||
{
|
||||
public class StatusStruct
|
||||
{
|
||||
public static readonly int Length = 48;
|
||||
|
||||
public Byte Version;
|
||||
public FlowState FlowState;
|
||||
public UInt32 BillingVolume;
|
||||
public UInt32 ForwardVolume;
|
||||
public UInt32 ReverseVolume;
|
||||
public UInt32 SecondsActive;
|
||||
public UInt32 SecondsIdle;
|
||||
public UInt32 SecondsUsed;
|
||||
public UInt32 UTC;
|
||||
public Int32 ScaledAvgFlowRate;
|
||||
public UInt16 PeakFlowRate;
|
||||
public UInt16 AlarmState;
|
||||
public byte RebootCount;
|
||||
public byte[] AlarmCount;
|
||||
public UInt16 FlipTime;
|
||||
|
||||
|
||||
public StatusStruct()
|
||||
{
|
||||
AlarmCount = new byte[7];
|
||||
}
|
||||
|
||||
public byte[] ToByteArray()
|
||||
{
|
||||
byte[] result = new byte[Length];
|
||||
|
||||
result[0] = Version;
|
||||
result[1] = (byte)FlowState;
|
||||
|
||||
result[2] = (byte)(BillingVolume & 0x000000FF);
|
||||
result[3] = (byte)((BillingVolume >> 8) & 0x000000FF);
|
||||
result[4] = (byte)((BillingVolume >> 16) & 0x000000FF);
|
||||
result[5] = (byte)((BillingVolume >> 24) & 0x000000FF);
|
||||
|
||||
result[6] = (byte)(ForwardVolume & 0x000000FF);
|
||||
result[7] = (byte)((ForwardVolume >> 8) & 0x000000FF);
|
||||
result[8] = (byte)((ForwardVolume >> 16) & 0x000000FF);
|
||||
result[9] = (byte)((ForwardVolume >> 24) & 0x000000FF);
|
||||
|
||||
result[10] = (byte)(ReverseVolume & 0x000000FF);
|
||||
result[11] = (byte)((ReverseVolume >> 8) & 0x000000FF);
|
||||
result[12] = (byte)((ReverseVolume >> 16) & 0x000000FF);
|
||||
result[13] = (byte)((ReverseVolume >> 24) & 0x000000FF);
|
||||
|
||||
result[14] = (byte)(SecondsActive & 0x000000FF);
|
||||
result[15] = (byte)((SecondsActive >> 8) & 0x000000FF);
|
||||
result[16] = (byte)((SecondsActive >> 16) & 0x000000FF);
|
||||
result[17] = (byte)((SecondsActive >> 24) & 0x000000FF);
|
||||
|
||||
result[18] = (byte)(SecondsIdle & 0x000000FF);
|
||||
result[19] = (byte)((SecondsIdle >> 8) & 0x000000FF);
|
||||
result[20] = (byte)((SecondsIdle >> 16) & 0x000000FF);
|
||||
result[21] = (byte)((SecondsIdle >> 24) & 0x000000FF);
|
||||
|
||||
result[22] = (byte)(SecondsUsed & 0x000000FF);
|
||||
result[23] = (byte)((SecondsUsed >> 8) & 0x000000FF);
|
||||
result[24] = (byte)((SecondsUsed >> 16) & 0x000000FF);
|
||||
result[25] = (byte)((SecondsUsed >> 24) & 0x000000FF);
|
||||
|
||||
result[26] = (byte)(UTC & 0x000000FF);
|
||||
result[27] = (byte)((UTC >> 8) & 0x000000FF);
|
||||
result[28] = (byte)((UTC >> 16) & 0x000000FF);
|
||||
result[29] = (byte)((UTC >> 24) & 0x000000FF);
|
||||
|
||||
result[30] = (byte)(ScaledAvgFlowRate & 0x000000FF);
|
||||
result[31] = (byte)((ScaledAvgFlowRate >> 8) & 0x000000FF);
|
||||
result[32] = (byte)((ScaledAvgFlowRate >> 16) & 0x000000FF);
|
||||
result[33] = (byte)((ScaledAvgFlowRate >> 24) & 0x000000FF); /// TODO: test with negative value
|
||||
|
||||
result[34] = (byte)(PeakFlowRate & 0x00FF);
|
||||
result[35] = (byte)((PeakFlowRate >> 8) & 0x00FF);
|
||||
|
||||
result[36] = (byte)(AlarmState & 0x00FF);
|
||||
result[37] = (byte)((AlarmState >> 8) & 0x00FF);
|
||||
|
||||
result[38] = RebootCount;
|
||||
|
||||
result[39] = AlarmCount[0];
|
||||
result[40] = AlarmCount[1];
|
||||
result[41] = AlarmCount[2];
|
||||
result[42] = AlarmCount[3];
|
||||
result[43] = AlarmCount[4];
|
||||
result[44] = AlarmCount[5];
|
||||
result[45] = AlarmCount[6];
|
||||
|
||||
result[46] = (byte)(FlipTime & 0x00FF);
|
||||
result[47] = (byte)((FlipTime >> 8) & 0x00FF);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static StatusStruct FromByteArray(byte[] data)
|
||||
{
|
||||
if (data.Length != Length) return null;
|
||||
|
||||
StatusStruct result = new StatusStruct();
|
||||
|
||||
result.Version = data[0];
|
||||
result.FlowState = (FlowState)data[1];
|
||||
result.BillingVolume = (((UInt32)data[5] * 256 + data[4]) * 256 + data[3]) * 256 + data[2];
|
||||
result.ForwardVolume = (((UInt32)data[9] * 256 + data[8]) * 256 + data[7]) * 256 + data[6];
|
||||
result.ReverseVolume = (((UInt32)data[13] * 256 + data[12]) * 256 + data[11]) * 256 + data[10];
|
||||
result.SecondsActive = (((UInt32)data[17] * 256 + data[16]) * 256 + data[15]) * 256 + data[14];
|
||||
result.SecondsIdle = (((UInt32)data[21] * 256 + data[20]) * 256 + data[19]) * 256 + data[18];
|
||||
result.SecondsUsed = (((UInt32)data[25] * 256 + data[24]) * 256 + data[23]) * 256 + data[22];
|
||||
result.UTC = (((UInt32)data[29] * 256 + data[28]) * 256 + data[27]) * 256 + data[26];
|
||||
result.ScaledAvgFlowRate = (((Int32)data[33] * 256 + data[32]) * 256 + data[31]) * 256 + data[30]; /// TODO: test with negative value
|
||||
result.PeakFlowRate = (UInt16)(data[34] + 256 * data[35]);
|
||||
result.AlarmState = (UInt16)(data[36] + 256 * data[37]);
|
||||
result.RebootCount = data[38];
|
||||
result.AlarmCount[0] = data[39];
|
||||
result.AlarmCount[1] = data[40];
|
||||
result.AlarmCount[2] = data[41];
|
||||
result.AlarmCount[3] = data[42];
|
||||
result.AlarmCount[4] = data[43];
|
||||
result.AlarmCount[5] = data[44];
|
||||
result.AlarmCount[6] = data[45];
|
||||
result.FlipTime = (UInt16)(data[46] * 256 + data[47]);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("Status: V{0} Flow={1} BillVol={2} ForwVol={3} RevVol={4} SecActive={5}s SecIdle={6}s SecUsed={7}s UTC={8} AvgFlowRate={9} PeekFlowRate={10} AlarmState={11} RebootCount={12} A0={13} A1={14} A2={15} A3={16} A4={17} A5={18} A6={19} FlipTime={20}",
|
||||
Version,
|
||||
FlowState,
|
||||
BillingVolume,
|
||||
ForwardVolume,
|
||||
ReverseVolume,
|
||||
SecondsActive,
|
||||
SecondsIdle,
|
||||
SecondsUsed,
|
||||
UTC,
|
||||
ScaledAvgFlowRate,
|
||||
PeakFlowRate,
|
||||
AlarmState,
|
||||
RebootCount,
|
||||
AlarmCount[0],
|
||||
AlarmCount[1],
|
||||
AlarmCount[2],
|
||||
AlarmCount[3],
|
||||
AlarmCount[4],
|
||||
AlarmCount[5],
|
||||
AlarmCount[6],
|
||||
FlipTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -373,7 +373,7 @@ namespace TBF.Rig.TestMethods.SmartMeterFlyingStartMassCollection
|
||||
/// Show the modeless dialog with error indication
|
||||
///
|
||||
string componentName = (method as IComponent)?.Name ?? string.Empty;
|
||||
Program.MainWnd.Invoke(new SmartCommFormDlgt(OpenSmartCommForm), new object[] { this, method/*componentName*/, test, testParams });
|
||||
Program.MainWnd.Invoke(new SmartCommFormDlgt(OpenSmartCommForm), new object[] { this, method, test, testParams });
|
||||
|
||||
//------------------------------------------------
|
||||
Bridge.OnActivity(this, Strings.iPerl_Communication_in_progress);
|
||||
|
||||
@@ -513,8 +513,8 @@ namespace TBF.Rig.TestMethods.StandingStart
|
||||
{
|
||||
GenericDevices.IRegReader rr = sensPath.RegisterReaders[i];
|
||||
|
||||
if (rr is ISmartReader)
|
||||
(rr as ISmartReader).BeginWMState = dataEntryCmpnt.WMStartState(i);
|
||||
if (rr is ICommonRegReader)
|
||||
(rr as ICommonRegReader).BeginWMState = dataEntryCmpnt.WMStartState(i);
|
||||
|
||||
if (rr is Rig.RegisterReaders.StandingStartStop.RegisterReader)
|
||||
(rr as Rig.RegisterReaders.StandingStartStop.RegisterReader).BeginWMState = dataEntryCmpnt.WMStartState(i);
|
||||
@@ -766,9 +766,9 @@ namespace TBF.Rig.TestMethods.StandingStart
|
||||
for (int i = 0; i < Data.WMsCount; i++)
|
||||
{
|
||||
GenericDevices.IRegReader rr = sensPath.RegisterReaders[i];
|
||||
|
||||
if (rr is ISmartReader)
|
||||
(rr as ISmartReader).EndWMState = dataEntryCmpnt.WMEndState(i);
|
||||
|
||||
if (rr is ICommonRegReader)
|
||||
(rr as ICommonRegReader).EndWMState = dataEntryCmpnt.WMEndState(i);
|
||||
|
||||
if (rr is Rig.RegisterReaders.StandingStartStop.RegisterReader)
|
||||
(rr as Rig.RegisterReaders.StandingStartStop.RegisterReader).EndWMState = dataEntryCmpnt.WMEndState(i);
|
||||
@@ -1017,6 +1017,13 @@ namespace TBF.Rig.TestMethods.StandingStart
|
||||
&& (tstRslt.ErrorFlags == 0);
|
||||
meterRslt.TestDone = true;
|
||||
tstRslt.TestDone = true;
|
||||
if (regReader is ICommonRegReader regReaderCommon)
|
||||
// if (meterRslt.WaterMeter != null
|
||||
// && tstRslt is ICommonRegReader tstRsltCommon
|
||||
// && !string.IsNullOrEmpty(tstRsltCommon.SerialNr))
|
||||
{
|
||||
meterRslt.WaterMeter.SerialNr = regReaderCommon.SerialNr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ using SchematicDrawing;
|
||||
using TBF.Rig.ControlBoard.Uni;
|
||||
using TBF.Boxes;
|
||||
using TBF.Resources;
|
||||
|
||||
using AppDiagnostic;
|
||||
|
||||
namespace TBF.Rig.Uni.FlowMeter
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
///
|
||||
///
|
||||
/// Copyright (c) 2021-2023 Sensus Slovensko a.s.
|
||||
///
|
||||
using System;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
///
|
||||
///
|
||||
/// Copyright (c) 2021 Sensus Slovensko a.s.
|
||||
///
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
///
|
||||
///
|
||||
/// Copyright (c) 2021 Sensus Slovensko a.s.
|
||||
///
|
||||
using System;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
///
|
||||
///
|
||||
/// Copyright (c) 2021 Sensus Slovensko a.s.
|
||||
///
|
||||
using System;
|
||||
@@ -7,6 +7,7 @@ using log4net;
|
||||
using SchematicDrawing;
|
||||
using TBF.Rig.ControlBoard.Uni;
|
||||
using TBF.Boxes;
|
||||
using SharedComponents;
|
||||
|
||||
namespace TBF.Rig.Uni.RegValveLowRegulTimeSaturation
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
///
|
||||
///
|
||||
/// Copyright (c) 2021 Sensus Slovensko a.s.
|
||||
///
|
||||
using System;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
///
|
||||
///
|
||||
/// Copyright (c) 2021 Sensus Slovensko a.s.
|
||||
///
|
||||
using System;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
///
|
||||
///
|
||||
/// Copyright (c) 2021 Sensus Slovensko a.s.
|
||||
///
|
||||
using System;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
///
|
||||
///
|
||||
/// Copyright (c) 2021-2022 Sensus Slovensko a.s.
|
||||
///
|
||||
using System;
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
|
||||
|
||||
using TBF.Rig.Configs.NameOnly;
|
||||
using TBF.Rig.Generic;
|
||||
using TBF.Rig.RegisterReaders.CommonRR.IPerl;
|
||||
|
||||
namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
|
||||
{
|
||||
public interface ISmartTestMethod
|
||||
{
|
||||
public void MeterCommMilestone(int iItem, bool bValue);
|
||||
public bool IsMeterCommMilestone(int iItem);
|
||||
|
||||
public ITestMethodCfg TestMethodCfg { get; }
|
||||
}
|
||||
}
|
||||
@@ -135,7 +135,7 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
|
||||
public static string SelectedTypeReader { get; set; }
|
||||
|
||||
private List<ICorrections> GetNewCorrectionList(ISmartTestMethod componentBase ,
|
||||
TestMethodCfg cfg, IList<Test> tests, IList<ITestParams> multiTestParams)
|
||||
ITestMethodCfg cfg, IList<Test> tests, IList<ITestParams> multiTestParams)
|
||||
{
|
||||
List<ICorrections> correctionsList = new List<ICorrections>();
|
||||
|
||||
@@ -154,7 +154,7 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
|
||||
{
|
||||
if (correctionsList.Any(x => x is SmartReader))
|
||||
continue;
|
||||
correctionsList.Add(new PoseidonCorrections(this));
|
||||
correctionsList.Add(new PoseidonCorrections(this,log, rfidDataLogger, componentBase, cfg, tests, multiTestParams));
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -297,7 +297,7 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
|
||||
ShuffleTextBoxes(ProcessData.WMsCount, ProcessData.LineSize);
|
||||
|
||||
|
||||
this.ContextMenu = Correction.GetContextMenu();
|
||||
//this.ContextMenu = Correction.GetContextMenu();
|
||||
|
||||
}
|
||||
|
||||
@@ -325,9 +325,11 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
|
||||
{
|
||||
checkBoxesEditMode = false;
|
||||
|
||||
ITestMethodCfg cfg = (componentBase as ITestMethodCfg);
|
||||
ISmartTestMethod smartTestMethod = componentBase as ISmartTestMethod;
|
||||
|
||||
//TODO get corrections based on defined meter
|
||||
_corrections = GetNewCorrectionList(componentBase as ISmartTestMethod,
|
||||
componentBase.Cfg as TestMethodCfg, tests, multiTestParams);
|
||||
_corrections = GetNewCorrectionList(smartTestMethod, smartTestMethod.TestMethodCfg, tests, multiTestParams);
|
||||
InitializeMeterTypeItems();
|
||||
UpdateHeads();
|
||||
|
||||
@@ -381,6 +383,27 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
|
||||
|
||||
private void UpdateHeads()
|
||||
{
|
||||
if (!(waterMeterPositions0 == null || waterMeterPositions0.Count <= 0)
|
||||
&& labels != null && counters != null && messages != null && checkBoxes != null)
|
||||
{
|
||||
foreach (int position in waterMeterPositions0)
|
||||
{
|
||||
try
|
||||
{
|
||||
labels[position].Visible = false;
|
||||
counters[position].Visible = false;
|
||||
messages[position].Visible = false;
|
||||
checkBoxes[position].Visible = false;
|
||||
ckbIndex[position] = 0;
|
||||
ckbState[position] = false;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.Error("UpdateHeads()", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
iperlHeads?.Clear();
|
||||
if (iperlHeads == null) iperlHeads = new List<ISmartReader>();
|
||||
waterMeterPositions0?.Clear();
|
||||
@@ -415,6 +438,21 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
|
||||
if (wmPos >= ProcessData.WMsCount) break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//we have items from the list, so we can enable the rows
|
||||
if (iperlHeads.Count > 0)
|
||||
{
|
||||
WaterMetersCount = iperlHeads.Count;
|
||||
ShuffleTextBoxes(WaterMetersCount, ProcessData.LineSize);
|
||||
|
||||
this.ContextMenu = Correction.GetContextMenu();
|
||||
Correction.PrepareForTestsActivities(WaterMetersCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.ContextMenu = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -458,6 +496,7 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
|
||||
/// this part works fine if we are on <b>test loop</b>
|
||||
/// - because ProcessData.RegisterReaders is initialized in test loop
|
||||
/// </summary>
|
||||
/// <param name="selectedTypeReader"></param>
|
||||
private static void InitializeSmartReaderLists()
|
||||
{
|
||||
iperlHeads = new List<ISmartReader>();
|
||||
@@ -501,43 +540,7 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
|
||||
/// <param name="lineSize">Number of watermeters in one line</param>
|
||||
void ShuffleTextBoxes(int wmsCount, int lineSize)
|
||||
{
|
||||
labels = new Label[MaxTextBoxesCount]
|
||||
{
|
||||
wmLabel1, wmLabel2, wmLabel3, wmLabel4, wmLabel5, wmLabel6, wmLabel7, wmLabel8, wmLabel9, wmLabel10,
|
||||
wmLabel11, wmLabel12, wmLabel13, wmLabel14, wmLabel15, wmLabel16, wmLabel17, wmLabel18, wmLabel19, wmLabel20,
|
||||
wmLabel21, wmLabel22, wmLabel23, wmLabel24, wmLabel25, wmLabel26, wmLabel27, wmLabel28, wmLabel29, wmLabel30,
|
||||
wmLabel31, wmLabel32, wmLabel33, wmLabel34, wmLabel35, wmLabel36, wmLabel37, wmLabel38, wmLabel39, wmLabel40,
|
||||
wmLabel41, wmLabel42, wmLabel43, wmLabel44, wmLabel45, wmLabel46, wmLabel47, wmLabel48,
|
||||
};
|
||||
counters = new PictureBox[MaxTextBoxesCount]
|
||||
{
|
||||
pictureBox1, pictureBox2, pictureBox3, pictureBox4, pictureBox5, pictureBox6, pictureBox7, pictureBox8, pictureBox9, pictureBox10,
|
||||
pictureBox11, pictureBox12, pictureBox13, pictureBox14, pictureBox15, pictureBox16, pictureBox17, pictureBox18, pictureBox19, pictureBox20,
|
||||
pictureBox21, pictureBox22, pictureBox23, pictureBox24, pictureBox25, pictureBox26, pictureBox27, pictureBox28, pictureBox29, pictureBox30,
|
||||
pictureBox31, pictureBox32, pictureBox33, pictureBox34, pictureBox35, pictureBox36, pictureBox37, pictureBox38, pictureBox39, pictureBox40,
|
||||
pictureBox41, pictureBox42, pictureBox43, pictureBox44, pictureBox45, pictureBox46, pictureBox47, pictureBox48,
|
||||
};
|
||||
messages = new TextBox[MaxTextBoxesCount]
|
||||
{
|
||||
wmTextBox1, wmTextBox2, wmTextBox3, wmTextBox4, wmTextBox5, wmTextBox6, wmTextBox7, wmTextBox8, wmTextBox9, wmTextBox10,
|
||||
wmTextBox11, wmTextBox12, wmTextBox13, wmTextBox14, wmTextBox15, wmTextBox16, wmTextBox17, wmTextBox18, wmTextBox19, wmTextBox20,
|
||||
wmTextBox21, wmTextBox22, wmTextBox23, wmTextBox24, wmTextBox25, wmTextBox26, wmTextBox27, wmTextBox28, wmTextBox29, wmTextBox30,
|
||||
wmTextBox31, wmTextBox32, wmTextBox33, wmTextBox34, wmTextBox35, wmTextBox36, wmTextBox37, wmTextBox38, wmTextBox39, wmTextBox40,
|
||||
wmTextBox41, wmTextBox42, wmTextBox43, wmTextBox44, wmTextBox45, wmTextBox46, wmTextBox47, wmTextBox48,
|
||||
};
|
||||
checkBoxes = new CheckBoxImage[MaxTextBoxesCount]
|
||||
{
|
||||
checkBoxImage1, checkBoxImage2, checkBoxImage3, checkBoxImage4, checkBoxImage5, checkBoxImage6, checkBoxImage7, checkBoxImage8, checkBoxImage9, checkBoxImage10,
|
||||
checkBoxImage11, checkBoxImage12, checkBoxImage13, checkBoxImage14, checkBoxImage15, checkBoxImage16, checkBoxImage17, checkBoxImage18, checkBoxImage19, checkBoxImage20,
|
||||
checkBoxImage21, checkBoxImage22, checkBoxImage23, checkBoxImage24, checkBoxImage25, checkBoxImage26, checkBoxImage27, checkBoxImage28, checkBoxImage29, checkBoxImage30,
|
||||
checkBoxImage31, checkBoxImage32, checkBoxImage33, checkBoxImage34, checkBoxImage35, checkBoxImage36, checkBoxImage37, checkBoxImage38, checkBoxImage39, checkBoxImage40,
|
||||
checkBoxImage41, checkBoxImage42, checkBoxImage43, checkBoxImage44, checkBoxImage45, checkBoxImage46, checkBoxImage47, checkBoxImage48,
|
||||
};
|
||||
ckbIndex = new int[MaxTextBoxesCount];
|
||||
ckbState = new bool[MaxTextBoxesCount];
|
||||
|
||||
|
||||
textBoxesCount = MaxTextBoxesCount;
|
||||
InitializeTextBoxArrays();
|
||||
///
|
||||
if (wmsCount < textBoxesCount && lineSize > 0)
|
||||
{
|
||||
@@ -576,7 +579,56 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
|
||||
ResizeDlgToFitEnabledControls();
|
||||
}
|
||||
|
||||
void ResizeDlgToFitEnabledControls()
|
||||
private void InitializeTextBoxArrays()
|
||||
{
|
||||
//if is initialized before we ignore initialization
|
||||
if (labels != null
|
||||
&& counters != null
|
||||
&& messages != null
|
||||
&& checkBoxes != null
|
||||
&& ckbIndex != null
|
||||
&& ckbState != null) return;
|
||||
|
||||
labels = new Label[MaxTextBoxesCount]
|
||||
{
|
||||
wmLabel1, wmLabel2, wmLabel3, wmLabel4, wmLabel5, wmLabel6, wmLabel7, wmLabel8, wmLabel9, wmLabel10,
|
||||
wmLabel11, wmLabel12, wmLabel13, wmLabel14, wmLabel15, wmLabel16, wmLabel17, wmLabel18, wmLabel19, wmLabel20,
|
||||
wmLabel21, wmLabel22, wmLabel23, wmLabel24, wmLabel25, wmLabel26, wmLabel27, wmLabel28, wmLabel29, wmLabel30,
|
||||
wmLabel31, wmLabel32, wmLabel33, wmLabel34, wmLabel35, wmLabel36, wmLabel37, wmLabel38, wmLabel39, wmLabel40,
|
||||
wmLabel41, wmLabel42, wmLabel43, wmLabel44, wmLabel45, wmLabel46, wmLabel47, wmLabel48,
|
||||
};
|
||||
counters = new PictureBox[MaxTextBoxesCount]
|
||||
{
|
||||
pictureBox1, pictureBox2, pictureBox3, pictureBox4, pictureBox5, pictureBox6, pictureBox7, pictureBox8, pictureBox9, pictureBox10,
|
||||
pictureBox11, pictureBox12, pictureBox13, pictureBox14, pictureBox15, pictureBox16, pictureBox17, pictureBox18, pictureBox19, pictureBox20,
|
||||
pictureBox21, pictureBox22, pictureBox23, pictureBox24, pictureBox25, pictureBox26, pictureBox27, pictureBox28, pictureBox29, pictureBox30,
|
||||
pictureBox31, pictureBox32, pictureBox33, pictureBox34, pictureBox35, pictureBox36, pictureBox37, pictureBox38, pictureBox39, pictureBox40,
|
||||
pictureBox41, pictureBox42, pictureBox43, pictureBox44, pictureBox45, pictureBox46, pictureBox47, pictureBox48,
|
||||
};
|
||||
messages = new TextBox[MaxTextBoxesCount]
|
||||
{
|
||||
wmTextBox1, wmTextBox2, wmTextBox3, wmTextBox4, wmTextBox5, wmTextBox6, wmTextBox7, wmTextBox8, wmTextBox9, wmTextBox10,
|
||||
wmTextBox11, wmTextBox12, wmTextBox13, wmTextBox14, wmTextBox15, wmTextBox16, wmTextBox17, wmTextBox18, wmTextBox19, wmTextBox20,
|
||||
wmTextBox21, wmTextBox22, wmTextBox23, wmTextBox24, wmTextBox25, wmTextBox26, wmTextBox27, wmTextBox28, wmTextBox29, wmTextBox30,
|
||||
wmTextBox31, wmTextBox32, wmTextBox33, wmTextBox34, wmTextBox35, wmTextBox36, wmTextBox37, wmTextBox38, wmTextBox39, wmTextBox40,
|
||||
wmTextBox41, wmTextBox42, wmTextBox43, wmTextBox44, wmTextBox45, wmTextBox46, wmTextBox47, wmTextBox48,
|
||||
};
|
||||
checkBoxes = new CheckBoxImage[MaxTextBoxesCount]
|
||||
{
|
||||
checkBoxImage1, checkBoxImage2, checkBoxImage3, checkBoxImage4, checkBoxImage5, checkBoxImage6, checkBoxImage7, checkBoxImage8, checkBoxImage9, checkBoxImage10,
|
||||
checkBoxImage11, checkBoxImage12, checkBoxImage13, checkBoxImage14, checkBoxImage15, checkBoxImage16, checkBoxImage17, checkBoxImage18, checkBoxImage19, checkBoxImage20,
|
||||
checkBoxImage21, checkBoxImage22, checkBoxImage23, checkBoxImage24, checkBoxImage25, checkBoxImage26, checkBoxImage27, checkBoxImage28, checkBoxImage29, checkBoxImage30,
|
||||
checkBoxImage31, checkBoxImage32, checkBoxImage33, checkBoxImage34, checkBoxImage35, checkBoxImage36, checkBoxImage37, checkBoxImage38, checkBoxImage39, checkBoxImage40,
|
||||
checkBoxImage41, checkBoxImage42, checkBoxImage43, checkBoxImage44, checkBoxImage45, checkBoxImage46, checkBoxImage47, checkBoxImage48,
|
||||
};
|
||||
ckbIndex = new int[MaxTextBoxesCount];
|
||||
ckbState = new bool[MaxTextBoxesCount];
|
||||
|
||||
|
||||
textBoxesCount = MaxTextBoxesCount;
|
||||
}
|
||||
|
||||
void ResizeDlgToFitEnabledControls()
|
||||
{
|
||||
int xMax = 0;
|
||||
int yMax = 0;
|
||||
@@ -645,7 +697,7 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
|
||||
}
|
||||
|
||||
/// Start communication process by incrementing 'currentGroup'.
|
||||
currentGroup++;
|
||||
//currentGroup++;
|
||||
|
||||
int wtId = 0;
|
||||
foreach (var wt in Correction.GetAllThreads())
|
||||
@@ -869,6 +921,7 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
|
||||
if (senderCombo == null) return;
|
||||
SelectedTypeReader = senderCombo.SelectedItem?.ToString();
|
||||
UpdateHeads();
|
||||
SmartCommunicationForm_Load(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,28 @@
|
||||
using TBF.Rig.Configs.NameOnly;
|
||||
using TBF.Rig.Generic;
|
||||
using TBF.Rig.RegisterReaders.CommonRR.IPerl;
|
||||
|
||||
namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication
|
||||
{
|
||||
public abstract class SmartComponentBase : ComponentBase, ISmartTestMethod
|
||||
{
|
||||
private ITestMethodCfg cfg;
|
||||
|
||||
public abstract void MeterCommMilestone(int iItem, bool bValue);
|
||||
public abstract bool IsMeterCommMilestone(int iItem);
|
||||
|
||||
public ITestMethodCfg TestMethodCfg { get => cfg; }
|
||||
|
||||
|
||||
public SmartComponentBase()
|
||||
: base()
|
||||
{
|
||||
cfg = null;
|
||||
}
|
||||
|
||||
public SmartComponentBase(IComponentCfg cfg)
|
||||
: base(cfg)
|
||||
{
|
||||
this.cfg = cfg as ITestMethodCfg;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations
|
||||
{
|
||||
public static class EnumExtensions
|
||||
{
|
||||
public static bool TryParseByDescription<TEnum>(string description, out TEnum result)
|
||||
where TEnum : struct, Enum
|
||||
{
|
||||
foreach (var field in typeof(TEnum).GetFields())
|
||||
{
|
||||
var attribute = Attribute.GetCustomAttribute(field,
|
||||
typeof(DescriptionAttribute)) as DescriptionAttribute;
|
||||
|
||||
if ((attribute != null && attribute.Description == description) ||
|
||||
field.Name == description)
|
||||
{
|
||||
result = (TEnum)field.GetValue(null);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
+458
-15
@@ -1,19 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Common;
|
||||
using Config.Entities;
|
||||
using log4net;
|
||||
using Results.Entities;
|
||||
using TBF.Rig.Generic;
|
||||
using TBF.Rig.RegisterReaders.CommonRR.IPerl;
|
||||
using TBF.Rig.RegisterReaders.PoseidonCmdStartStop;
|
||||
using TBF.Rig.RegisterReaders.PoseidonReader;
|
||||
using TBF.Rig.RegisterReaders.PoseidonReader.communication;
|
||||
using TBF.Rig.RegisterReaders.PoseidonReader.implementations;
|
||||
using TBF.Rig.Sequences;
|
||||
using TBF.Rig.TestMethods.iPerlCommunication.iPerlHead;
|
||||
using TBF.Rig.TestMethods.SmartTest;
|
||||
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.common;
|
||||
using CheckBoxImage = TBF.Boxes.CheckBoxImage;
|
||||
using Factory = TBF.Rig.RegisterReaders.iPerlReaderUNI.Factory;
|
||||
using PoseidonReader = TBF.Rig.RegisterReaders.PoseidonCmdStartStop.PoseidonReader;
|
||||
|
||||
namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations
|
||||
{
|
||||
@@ -32,6 +41,16 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations
|
||||
private IList<Test> tests;
|
||||
private IList<ITestParams> multiTestParams;
|
||||
private SmartCommunicationForm _parentFrom;
|
||||
|
||||
static IList<Thread> workerThreads;
|
||||
static bool stopWorkerThreads;
|
||||
static int currentActivityStep;
|
||||
static int currentGroup;
|
||||
|
||||
/// form -> worker thread (0 = none)
|
||||
static int lastGroup;
|
||||
|
||||
static int completedCommCount;
|
||||
|
||||
|
||||
public string TypeIdentificatorName()
|
||||
@@ -56,12 +75,122 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations
|
||||
|
||||
public IList<ISmartReader> iperlHeads { get => ParentFrom.Heads;}
|
||||
|
||||
private Label activityLabel { get => ParentFrom?.ActivityLabel;}
|
||||
private Label[] labels { get => ParentFrom?.Labels; }
|
||||
private PictureBox[] counters{get => ParentFrom?.Counters;}
|
||||
private TextBox[] messages{get => ParentFrom?.Messages;}
|
||||
private CheckBoxImage[] checkBoxes{get => ParentFrom?.CheckBoxes;}
|
||||
private int[] ckbIndex{get => ParentFrom?.CkbIndex;}
|
||||
private bool[] ckbState{get => ParentFrom?.CkbState;}
|
||||
|
||||
|
||||
|
||||
|
||||
public void Worker(object threadData)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
int threadID = (threadData as Boxes.IntBox)?.Val ?? -1;
|
||||
|
||||
int activityStep = 0; /// activity step > 0 in case multiTestParams are used
|
||||
|
||||
for (int iMultiTestParamsItem = 0; iMultiTestParamsItem < MultiTestParams.Count; iMultiTestParamsItem++)
|
||||
{
|
||||
Test currentTest = Tests[iMultiTestParamsItem];
|
||||
ITestParams currentTestParams = MultiTestParams[iMultiTestParamsItem];
|
||||
string currentActivity = currentTestParams.Activity; /// Current activity
|
||||
|
||||
TBF.UiBridge.TestProgressEventArgs.SetEstimatedTimes(new int[] { 0, 0, 10, 0, 140, 0, 0, 0 });
|
||||
TBF.UiBridge.Bridge.OnTestProgress(null,
|
||||
new TBF.UiBridge.TestProgressEventArgs(currentTest, Progress.JustStarted));
|
||||
|
||||
|
||||
if (threadID == 0)
|
||||
{
|
||||
StartDataStreamProcessingForActiveMeters(iMultiTestParamsItem);
|
||||
|
||||
/// A new activity starts - information into RFID data log
|
||||
rfidDataLogger.InfoFormat("");
|
||||
rfidDataLogger.WarnFormat("Activity = {0}", currentActivity);
|
||||
rfidDataLogger.InfoFormat("");
|
||||
}
|
||||
|
||||
for (int group = 1; group <= lastGroup; group++)
|
||||
{
|
||||
/// Synchronize with QuidoRS and other threads
|
||||
while (((group != currentGroup) || (activityStep != currentActivityStep)) &&
|
||||
!GetStopWorkerThreads())
|
||||
{
|
||||
Thread.Sleep(50);
|
||||
}
|
||||
|
||||
if (GetStopWorkerThreads()) break;
|
||||
|
||||
// #if TURA_SPECIAL
|
||||
int threadIx = threadID; /// Just one thread for TURA_SPECIAL
|
||||
// #else
|
||||
// for (int threadIx = threadID; threadIx < threadID + 4; threadIx += Cfg.NrThreads)
|
||||
// #endif
|
||||
{
|
||||
bool wmFound = false;
|
||||
|
||||
for (int wmNr0 = 0; wmNr0 < iperlHeads.Count; wmNr0++)
|
||||
{
|
||||
//TODO BUMI doplnit if podomienky - last grop je teraz 1 ak existuju readre
|
||||
if(iperlHeads[wmNr0] is SmartReader ihead)
|
||||
// if ((ihead.Group == group) && (threadIx < muxBrdOrGroup14Nrs.Count) &&
|
||||
// (ihead.MuxBoardNrOrGroup14 == muxBrdOrGroup14Nrs[threadIx]))
|
||||
{
|
||||
wmFound = true;
|
||||
|
||||
WaterMeter wm = null;
|
||||
if (ProcessData.BatchRslts.Batch.WaterMeters != null)
|
||||
{
|
||||
foreach (var w in ProcessData.BatchRslts.Batch.WaterMeters)
|
||||
{
|
||||
if (w.WMPosition == wmNr0 + 1)
|
||||
{
|
||||
wm = w;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Do worker activity
|
||||
CommErr error = CommErr.None;
|
||||
string resultStr = string.Empty;
|
||||
|
||||
|
||||
WorkerActivity(currentActivity, ihead, wm, currentTest,
|
||||
wmNr0, ref error, ref resultStr, ckbState, threadID, currentActivityStep);
|
||||
ProcessResultOfWorkerActivity(iMultiTestParamsItem, currentActivity,
|
||||
currentGroup, ihead, wm, wmNr0, error, resultStr, ckbState, threadID);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
TBF.UiBridge.Bridge.OnTestProgress(null,
|
||||
new TBF.UiBridge.TestProgressEventArgs(Tests[iMultiTestParamsItem],
|
||||
Progress.FlowSetting));
|
||||
}
|
||||
|
||||
if (!wmFound)
|
||||
{
|
||||
SmartCommunicationForm.OnCommCompleted(null,
|
||||
new CommCompletedEventArgs(threadID, -1, null, null, string.Empty,
|
||||
CommErr.None)); /// Send negative wmNr
|
||||
}
|
||||
|
||||
if (GetStopWorkerThreads()) break;
|
||||
}
|
||||
|
||||
if (GetStopWorkerThreads()) break;
|
||||
} /// for (int group
|
||||
|
||||
TBF.UiBridge.Bridge.OnTestProgress(null,
|
||||
new TBF.UiBridge.TestProgressEventArgs(Tests[iMultiTestParamsItem], Progress.Completed));
|
||||
activityStep++;
|
||||
|
||||
if (GetStopWorkerThreads()) break;
|
||||
}
|
||||
}
|
||||
|
||||
public bool WorkerActivity(string currentActivity, ISmartReader iHead, WaterMeter wm, Test currentTest, int wmNr0,
|
||||
@@ -78,17 +207,17 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations
|
||||
|
||||
public void StopWorkerThreads(bool bStopAllThreads)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
stopWorkerThreads = bStopAllThreads;
|
||||
}
|
||||
|
||||
public bool GetStopWorkerThreads()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
return stopWorkerThreads;
|
||||
}
|
||||
|
||||
public IList<Thread> GetAllThreads()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
return workerThreads;
|
||||
}
|
||||
|
||||
public ICorrections GetNewCorrection()
|
||||
@@ -100,37 +229,229 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public ContextMenu GetContextMenu()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
public void PrepareForTestsActivities( int waterMeterPositions0)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
StartTime = DateTime.Now;
|
||||
StartTimeSec = StateMachine.Time;
|
||||
|
||||
///
|
||||
/// Prepare worker threads, 'rfidPortNrs', 'lastGroup', etc..
|
||||
///
|
||||
currentActivityStep = 0;
|
||||
currentGroup = 0;
|
||||
completedCommCount = 0;
|
||||
stopWorkerThreads = false;
|
||||
lastGroup = 0;
|
||||
|
||||
if (iperlHeads != null)
|
||||
{
|
||||
foreach (var iSmartReader in iperlHeads)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (iSmartReader is SmartReader reader){
|
||||
if (reader != null ) lastGroup = 1;
|
||||
}
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
log.ErrorFormat("PrepareForTestsActivities: {0}", E.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
workerThreads = new List<Thread>();
|
||||
if (Cfg != null)
|
||||
{
|
||||
for (int i = 0; i < Cfg.NrThreads; i++)
|
||||
{
|
||||
Thread thread = new Thread(Worker);
|
||||
thread.CurrentCulture = CultureInfo.CurrentCulture;
|
||||
thread.CurrentUICulture = CultureInfo.CurrentUICulture;
|
||||
workerThreads.Add(thread);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void Load(Label[] labels, PictureBox[] counters, TextBox[] messages, CheckBoxImage[] checkBoxes, int[] ckbIndex,
|
||||
bool[] ckbState, IList<ISmartReader> iperlHeads, int textBoxesCount, bool checkBoxesEditMode)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
if (iperlHeads == null)
|
||||
{
|
||||
for (int i = 0; i < textBoxesCount; i++)
|
||||
{
|
||||
checkBoxes[i].Enabled = checkBoxes[i].Checked = ckbState[i] = true;
|
||||
messages[i].Text = "---";
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
///
|
||||
/// Set checkbox states accroding to iPerlHeads[i].Disabled states
|
||||
///
|
||||
for (int i = 0; i < textBoxesCount; i++)
|
||||
{
|
||||
labels[i].Visible = counters[i].Visible = messages[i].Visible = checkBoxes[i].Visible = true;
|
||||
|
||||
|
||||
ISmartReader iperlHead = iperlHeads[i];
|
||||
if (!checkBoxesEditMode && (iperlHead == null || iperlHead.Disabled))
|
||||
{
|
||||
/// iPerl position i+1 is disabled
|
||||
checkBoxes[i].Enabled = checkBoxes[i].Checked = ckbState[i] = false;
|
||||
counters[i].BackColor = iPerlCommunicationConstants.DisabledColor;
|
||||
messages[i].Text = "Strings.Head_was_disabled_by_the_user";
|
||||
}
|
||||
else
|
||||
{
|
||||
/// iPerl position i+1 is enabled
|
||||
checkBoxes[i].Enabled = checkBoxes[i].Checked = ckbState[i] = true;
|
||||
messages[i].Text = "---";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int GetHeadsCount()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
return ParentFrom?.Heads?.Count() ?? 0;
|
||||
}
|
||||
|
||||
public void StartDataStreamProcessingForActiveMeters(int iMultiTestParamsItem)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
/// Check whether previous activity was 'Set test mode A0' or 'A4'
|
||||
if (iMultiTestParamsItem > 0 &&
|
||||
MultiTestParams[iMultiTestParamsItem - 1].Activity.ToLower()
|
||||
.Contains(iPerlCommunicationConstants.SetTestModeStr.ToLower()) &&
|
||||
!MultiTestParams[iMultiTestParamsItem - 1].Activity.Contains("80"))
|
||||
{
|
||||
/// Start processing of opto-datastreams from all iPERL-s
|
||||
int count = 0;
|
||||
for (int wmNr0 = 0; wmNr0 < iperlHeads.Count; wmNr0++)
|
||||
{
|
||||
WaterMeter wm = (ProcessData.BatchRslts.Batch.WaterMeters != null &&
|
||||
ProcessData.BatchRslts.Batch.WaterMeters.Count > wmNr0)
|
||||
? ProcessData.BatchRslts.Batch.WaterMeters[wmNr0]
|
||||
: null;
|
||||
|
||||
ISmartReader ihead = iperlHeads[wmNr0];
|
||||
|
||||
if (ihead != null && wm != null && !wm.Disabled)
|
||||
{
|
||||
lock (ihead)
|
||||
{
|
||||
ihead.StartDataStreamProcessing();
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.WarnFormat("End of activity '{0}', StartDataStreamProcessing() of {1} heads was called.",
|
||||
MultiTestParams[iMultiTestParamsItem - 1].Activity, count);
|
||||
}
|
||||
}
|
||||
|
||||
public void DoOnCommCompleted(object sender, CommCompletedEventArgs data, IList<int> waterMeterPositions0)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
try
|
||||
{
|
||||
///
|
||||
/// Update the text message
|
||||
///
|
||||
if (data.WMNr0 >= 0) messages[data.WMNr0].Text = data.CommMessage;
|
||||
|
||||
///
|
||||
/// Update head active/inactive switch
|
||||
///
|
||||
if (data.WMNr0 >= 0 && data.CommErr == CommErr.HeadDisabledByUser)
|
||||
{
|
||||
/// iPerl head was disabled by the user
|
||||
ckbState[data.WMNr0] = false;
|
||||
checkBoxes[data.WMNr0].Checked = false;
|
||||
checkBoxes[data.WMNr0].Enabled = false;
|
||||
if (data.Ihead != null) data.Ihead.Disabled = true;
|
||||
if (data.Wm != null) data.Wm.Disabled = true;
|
||||
}
|
||||
else if (data.WMNr0 >= 0 && data.CommErr == CommErr.None)
|
||||
{
|
||||
/// One RFID communication successful => iPerl cannot be disabled by the user anymore
|
||||
ckbState[data.WMNr0] = true;
|
||||
checkBoxes[data.WMNr0].Checked = true;
|
||||
checkBoxes[data.WMNr0].Enabled = false;
|
||||
}
|
||||
|
||||
///
|
||||
/// Update opto-communication indication
|
||||
///
|
||||
for (int i = 0; i < iperlHeads.Count; i++)
|
||||
{
|
||||
if (iperlHeads[i] == null || iperlHeads[i].Disabled)
|
||||
{
|
||||
counters[i].BackColor = iPerlCommunicationConstants.DisabledColor;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (iperlHeads[i] is SmartReader iperlHead)
|
||||
{
|
||||
|
||||
OptoHeadState checkFlowDirection =
|
||||
((iperlHead == null) ? OptoHeadState.Disabled : iperlHead.CheckFlowDirection());
|
||||
switch (checkFlowDirection)
|
||||
{
|
||||
case OptoHeadState.OptoAndDirOK:
|
||||
counters[i].BackColor = iPerlCommunicationConstants.OptoAndDirOKColor;
|
||||
break;
|
||||
|
||||
case OptoHeadState.DirNok:
|
||||
counters[i].BackColor = iPerlCommunicationConstants.DirNokColor;
|
||||
break;
|
||||
|
||||
default:
|
||||
case OptoHeadState.OptoNok:
|
||||
counters[i].BackColor = iPerlCommunicationConstants.OptoNokColor;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if !TURA_SPECIAL
|
||||
///
|
||||
/// Branch
|
||||
///
|
||||
lock (this)
|
||||
{
|
||||
if (++completedCommCount < 4) return;
|
||||
completedCommCount = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (currentGroup < lastGroup)
|
||||
{
|
||||
/// Go to the next step / next group
|
||||
currentGroup++;
|
||||
}
|
||||
else if (currentActivityStep + 1 < MultiTestParams.Count)
|
||||
{
|
||||
currentGroup = 0;
|
||||
currentActivityStep++;
|
||||
activityLabel.Text = MultiTestParams[currentActivityStep].Activity;
|
||||
currentGroup++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/// Wait until all threads are finished
|
||||
workerThreads[data.ThreadId].Join(2000);
|
||||
ParentFrom.NormalClose();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.ErrorFormat("DoOnCommCompleted({0}) failed: {1}", data, e.Message);
|
||||
log.FatalFormat("StackTrace : {0}{1}", Environment.NewLine, e.StackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
public void NormalClose(IList<int> waterMeterPositions0)
|
||||
@@ -171,7 +492,129 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations
|
||||
this.cfg = cfg;
|
||||
this.multiTestParams = multiTestParams;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
///
|
||||
private MenuItem NewMenuItem(string text, string tag)
|
||||
{
|
||||
MenuItem menuItem = new MenuItem { Text = text, Tag = tag };
|
||||
menuItem.Click += OnClick_Optical_Heads_Settings_Menu;
|
||||
return menuItem;
|
||||
}
|
||||
|
||||
private async void OnClick_Optical_Heads_Settings_Menu(object sender, EventArgs e)
|
||||
{
|
||||
// Validate sender
|
||||
if (!(sender is MenuItem menuItem))
|
||||
{
|
||||
log?.Error("OnClick_Optical_Heads_Settings_Menu: sender is not a MenuItem");
|
||||
return;
|
||||
}
|
||||
|
||||
if (activityLabel != null)
|
||||
activityLabel.Text = menuItem.Text;
|
||||
|
||||
List<Task> tasks = new List<Task>();
|
||||
foreach (var iSmartReader in ProcessData.SmartHeadsUni)
|
||||
{
|
||||
if (!(iSmartReader is SmartReader iHead))
|
||||
{
|
||||
continue;//ignore different types of heads
|
||||
}
|
||||
|
||||
int position = iHead.Position;
|
||||
if (position < 0 || position >= checkBoxes.Length || position >= messages.Length)
|
||||
{
|
||||
continue; // Skip this head if position is out of range
|
||||
}
|
||||
if (!checkBoxes[position].Checked)
|
||||
{
|
||||
if (position < messages.Length) messages[position].Text = "";
|
||||
continue;
|
||||
}
|
||||
|
||||
messages[position].Text = $@"COM{iHead.RfidComPortNr}";
|
||||
Application.DoEvents(); // Refresh UI
|
||||
tasks.Add(Task.Run(async () =>
|
||||
{
|
||||
string result = await ProcessTask(iHead.RegPoseidonCfg, menuItem.Tag);
|
||||
ParentFrom?.Invoke((Action)(() =>
|
||||
{
|
||||
messages[position].Text = result;
|
||||
Application.DoEvents(); // Refresh UI
|
||||
}));
|
||||
|
||||
}));
|
||||
|
||||
}
|
||||
|
||||
await Task.WhenAll(tasks);
|
||||
}
|
||||
|
||||
public static bool TryParseByDescription(string description, out PoseidonImplHeadTestCtrl.Operations result)
|
||||
{
|
||||
foreach (PoseidonImplHeadTestCtrl.Operations op
|
||||
in Enum.GetValues(typeof(PoseidonImplHeadTestCtrl.Operations)))
|
||||
{
|
||||
// step-by-step compare
|
||||
var desc = ((Enum)op).ToDescription(); // uses extension above
|
||||
|
||||
// exact compare, you can use OrdinalIgnoreCase if you want
|
||||
if (string.Equals(desc, description, StringComparison.Ordinal))
|
||||
{
|
||||
result = op;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
result = PoseidonImplHeadTestCtrl.Operations.Empty;
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
private async Task<string> ProcessTask(IComponentCfg head, object tag)
|
||||
{
|
||||
string txt = "";
|
||||
PoseidonImplHeadTestCtrl.Operations operation;
|
||||
if (!TryParseByDescription((string)tag, out operation))
|
||||
{
|
||||
operation = PoseidonImplHeadTestCtrl.Operations.Empty;
|
||||
}
|
||||
|
||||
if (head is PoseidonCfg poseidonCfg)
|
||||
{
|
||||
switch (operation)
|
||||
{
|
||||
case PoseidonImplHeadTestCtrl.Operations.ReadSerialNo:
|
||||
txt = OpticalHeadTest.ReadRequest_SerialNo(poseidonCfg);
|
||||
break;
|
||||
case PoseidonImplHeadTestCtrl.Operations.SetTestModeOn:
|
||||
txt = OpticalHeadTest.SetTestMode(poseidonCfg);
|
||||
break;
|
||||
case PoseidonImplHeadTestCtrl.Operations.SetTestModeOff:
|
||||
txt = OpticalHeadTest.SetActiveMode(poseidonCfg);
|
||||
break;
|
||||
default:
|
||||
txt = "-";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return txt;
|
||||
}
|
||||
|
||||
public ContextMenu GetContextMenu()
|
||||
{
|
||||
ContextMenu cm = new ContextMenu();
|
||||
foreach (KeyValuePair<string, PoseidonImplHeadTestCtrl.Operations> itemsOperation in PoseidonImplHeadTestCtrl.ItemsOperations)
|
||||
{
|
||||
cm.MenuItems.Add(NewMenuItem(itemsOperation.Key, itemsOperation.Value.ToDescription()));
|
||||
}
|
||||
return cm;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
///
|
||||
/// Copyright (c) 2021-2023 Sensus Slovensko a.s.
|
||||
///
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using log4net;
|
||||
using TBF.Rig.ControlBoard.Uni;
|
||||
using TBF.Rig.GenericDevices;
|
||||
|
||||
namespace TBF.Rig.Uni.RegValveLowRegulTimeSaturation
|
||||
{
|
||||
public class ChangeRegValvePositionOp : IOperation
|
||||
{
|
||||
private static readonly ILog log = LogManager.GetLogger(typeof(ChangeRegValvePositionOp));
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("ChangeRegValvePositionOp({0},{1}s)", regV.Name, timePulseSec.ToString("F2"));
|
||||
}
|
||||
|
||||
/// Set by the constructor
|
||||
readonly UniCB uniCB;
|
||||
readonly RegValve regV;
|
||||
readonly int regulValveNr;
|
||||
readonly double timePulseSec;
|
||||
|
||||
/// <summary>
|
||||
/// Set required water flow.
|
||||
/// Events: FlowSet, FlowTimeOut
|
||||
/// </summary>
|
||||
/// <param name="cb">Control board device</param>
|
||||
/// <param name="rv">Regulation valve component</param>
|
||||
/// <param name="posLoPct">Lower limit of the position to be achieved</param>
|
||||
/// <param name="posHiPct">Upper limit of the position to be achieved</param>
|
||||
/// <param name="timeout">Timeout in sec. for setting the flow</param>
|
||||
/// <remarks>Only Elde.Valve flow are used, other flow on the lists are ignored</remarks>
|
||||
public ChangeRegValvePositionOp(UniCB uniCB, RegValve regV, double timePulseSec)
|
||||
{
|
||||
this.uniCB = uniCB;
|
||||
if (this.uniCB == null) throw new ArgumentNullException("ctrlBoard");
|
||||
|
||||
this.regV = regV as RegValve;
|
||||
if (this.regV == null) throw new ArgumentNullException("regValve is null or not Uni");
|
||||
regulValveNr = this.regV.Idx1;
|
||||
|
||||
this.timePulseSec = timePulseSec;
|
||||
|
||||
log.Debug(this.ToString());
|
||||
}
|
||||
|
||||
/// <summary>Start this operation</summary>
|
||||
public void Start()
|
||||
{
|
||||
uniCB.RegVlvIncrMove(false, regulValveNr, timePulseSec, this.regV.RegulationMinStep);
|
||||
}
|
||||
|
||||
/// <summary>Run this operation</summary>
|
||||
/// <returns>
|
||||
/// Event.SetFlowDone
|
||||
/// </returns>
|
||||
public Event Run()
|
||||
{
|
||||
return Event.PositionReached;
|
||||
}
|
||||
|
||||
/// <summary>Stop this operation</summary>
|
||||
public void Stop()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
///
|
||||
/// Copyright (c) 2021 Sensus Slovensko a.s.
|
||||
///
|
||||
using System.Collections.Generic;
|
||||
using TBF.Rig.Generic;
|
||||
|
||||
namespace TBF.Rig.Uni.RegValveLowRegulTimeSaturation
|
||||
{
|
||||
public class Factory : IComponentFactory
|
||||
{
|
||||
public string ClassName { get { return GetType().Namespace.Substring(12); } }
|
||||
public override string ToString() { return ClassName; }
|
||||
|
||||
public IComponent DummyComponent() { return new RegValve(); }
|
||||
|
||||
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components) { return new RegValve(cfg, components); }
|
||||
|
||||
public IComponentCfg DefaultConfig() { return new RegValveCfg("VR", this); }
|
||||
|
||||
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
|
||||
{
|
||||
return ComponentCfgBase.CreateFromDbEntity(RegValveCfg.Serializer, component, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
///
|
||||
/// Copyright (c) 2021 Sensus Slovensko a.s.
|
||||
///
|
||||
using System;
|
||||
using log4net;
|
||||
|
||||
namespace TBF.Rig.Uni.RegValveLowRegulTimeSaturation
|
||||
{
|
||||
static class Handlers
|
||||
{
|
||||
static readonly ILog log = LogManager.GetLogger(typeof(Handlers));
|
||||
|
||||
static Handlers()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called from the state machine when a procedure is selected and UI needs to be updated.
|
||||
/// </summary>
|
||||
public static void OnAdcChanged(object sender, CmdResponseArgs data)
|
||||
{
|
||||
if (AdcChangedHandler == null)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
AdcChangedHandler(sender, data);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.Error("AdcChangedHandler(...) failed", e);
|
||||
}
|
||||
}
|
||||
public static event EventHandler<CmdResponseArgs> AdcChangedHandler;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user