Merge branch 'main' into Dev_CUST

# Conflicts:
#	Common/CommonCore.Configuration/ServiceUrls.cs
This commit is contained in:
Thomas Wiedebusch 2025-11-10 15:22:59 +01:00
commit 9a97d78c68
338 changed files with 38878 additions and 32091 deletions

1
.gitignore vendored
View File

@ -400,3 +400,4 @@ FodyWeavers.xsd
/Common/CommonConsole
/Common/Common.v3.ncrunchsolution
/TBF_V2/Sources/TBF/TBF/BenchControl/TestMethods/GenesisCommunication.zip
/Common/Hardware/WaterMeter/Genesis/GenesisCore/configuration2013.json

View File

@ -3,84 +3,84 @@
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<variable name="BasePath" value="\\delaz1fsops01\cordonelds$"/>
<targets>
<!--CalibrationHelper-->
<target name="CalibrationHelper" xsi:type="File" fileName="${BasePath}\${shortdate}\${processname}\CalibrationHelper.log" CreateDirs="True" layout ="${longdate} | ${level} | ${message} ${exception:format=toString}" archiveAboveSize="50000000" archiveFileName="C:\GenesisLog\${shortdate}\${processname}\{##}_CalibrationHelper.log" />
<variable name="BasePath" value="\\DELAZ1FSOPS01-1\CordonelDS$\${loggerpc}" />
<targets>
<!--LedRawData-->
<target xsi:type="BufferingWrapper"
name="TargetLedRawDataBase"
bufferSize="10000"
flushTimeout="-1"
slidingTimeout="true"
<!--CalibrationHelper-->
<target name="CalibrationHelper" xsi:type="File" fileName="${BasePath}\${shortdate}\${processname}\CalibrationHelper.log" CreateDirs="True" layout ="${longdate} | ${level} | ${message} ${exception:format=toString}" archiveAboveSize="50000000" archiveFileName="${BasePath}\${shortdate}\${processname}\{##}CalibrationHelper.log" />
<!--LedRawData-->
<target xsi:type="BufferingWrapper"
name="TargetLedRawDataBase"
bufferSize="10000"
flushTimeout="-1"
slidingTimeout="true"
>
<target name="LedRawDataBase" xsi:type="File" fileName="${BasePath}\${shortdate}\${processname}\LedRawData_BASE.log" CreateDirs="True" layout ="${longdate} | ${message} ${exception:format=toString}" archiveAboveSize="50000000" archiveFileName="C:\GenesisLog\${shortdate}\${processname}\{##}_LedRawData_BASE.log" />
</target>
<!--C:\GenesisLog\${shortdate}
<target name="LedRawDataBase" xsi:type="File" fileName="${BasePath}\${shortdate}\${processname}\LedRawData_BASE.log" CreateDirs="True" layout ="${longdate} | ${message} ${exception:format=toString}" archiveAboveSize="50000000" archiveFileName="${BasePath}\${shortdate}\${processname}\{##}_LedRawData_BASE.log" />
</target>
<!--C:\GenesisLog\${shortdate}
C:\GenesisLog\${shortdate}-->
<!--MeterBatch-->
<target name="MeterBatch" xsi:type="File" fileName="${BasePath}\${shortdate}\${processname}\Meter_BASE.log" CreateDirs="True" layout ="${longdate} | ${level} | ${message} ${exception:format=toString}" archiveAboveSize="50000000" archiveFileName="C:\GenesisLog\${shortdate}\${processname}\{##}_Meter_BASE.log" />
<!--MeterBatch-->
<target name="MeterBatch" xsi:type="File" fileName="${BasePath}\${shortdate}\${processname}\Meter_BASE.log" CreateDirs="True" layout ="${longdate} | ${level} | ${message} ${exception:format=toString}" archiveAboveSize="50000000" archiveFileName="${BasePath}\${shortdate}\${processname}\{##}_Meter_BASE.log" />
<!--Meter-->
<target name="MeterBase" xsi:type="File" fileName="${BasePath}\${shortdate}\${processname}\Meter_BASE.log" CreateDirs="True" layout ="${longdate} | ${level} | ${message} ${exception:format=toString}" archiveAboveSize="50000000" archiveFileName="C:\GenesisLog\${shortdate}\${processname}\{##}_Meter_BASE.log" />
<target name="Slot:0" xsi:type="File" fileName="${BasePath}\${shortdate}\${processname}\Meter_SlotSlot:0.log" CreateDirs="True" layout ="${longdate} | ${level} | ${message} ${exception:format=toString}" archiveAboveSize="50000000" archiveFileName="C:\GenesisLog\${shortdate}\${processname}\{##}_Meter_SlotSlot:0.log" />
<!--Meter-->
<target name="MeterBase" xsi:type="File" fileName="${BasePath}\${shortdate}\${processname}\Meter_BASE.log" CreateDirs="True" layout ="${longdate} | ${level} | ${message} ${exception:format=toString}" archiveAboveSize="50000000" archiveFileName="${BasePath}\${shortdate}\${processname}\{##}_Meter_BASE.log" />
<target name="Slot:0" xsi:type="File" fileName="${BasePath}\${shortdate}\${processname}\Meter_SlotSlot:0.log" CreateDirs="True" layout ="${longdate} | ${level} | ${message} ${exception:format=toString}" archiveAboveSize="50000000" archiveFileName="${BasePath}\${shortdate}\${processname}\{##}_Meter_SlotSlot:0.log" />
<!--COM-->
<target name="COMBase" xsi:type="File" fileName="${BasePath}\${shortdate}\${processname}\COM_BASE.log" CreateDirs="True" layout ="${longdate} | ${level} | ${message} ${exception:format=toString}" archiveAboveSize="50000000" archiveFileName="C:\GenesisLog\${shortdate}\${processname}\{##}_COM_BASE.log" />
<!--ServiceFwUpdateBuilder-->
<target name="ServiceFwUpdateBuilder" xsi:type="File" fileName="${BasePath}\${shortdate}\${processname}\ServiceFwUpdateBuilder.log" CreateDirs="True" layout ="${longdate} | ${level} | ${message} ${exception:format=toString}" archiveAboveSize="50000000" archiveFileName="C:\GenesisLog\${shortdate}\${processname}\{##}_ServiceFwUpdateBuilder.log" />
<!--COM-->
<target name="COMBase" xsi:type="File" fileName="${BasePath}\${shortdate}\${processname}\COM_BASE.log" CreateDirs="True" layout ="${longdate} | ${level} | ${message} ${exception:format=toString}" archiveAboveSize="50000000" archiveFileName="${BasePath}\${shortdate}\${processname}\{##}_COM_BASE.log" />
<!--ServiceFwUpdateLoader-->
<target name="ServiceFwUpdateLoader" xsi:type="File" fileName="${BasePath}\${shortdate}\${processname}\ServiceFwUpdateLoader.log" CreateDirs="True" layout ="${longdate} | ${level} | ${message} ${exception:format=toString}" archiveAboveSize="50000000" archiveFileName="C:\GenesisLog\${shortdate}\${processname}\{##}_ServiceFwUpdateLoader.log" />
<!--ServiceFwUpdateBuilder-->
<target name="ServiceFwUpdateBuilder" xsi:type="File" fileName="${BasePath}\${shortdate}\${processname}\ServiceFwUpdateBuilder.log" CreateDirs="True" layout ="${longdate} | ${level} | ${message} ${exception:format=toString}" archiveAboveSize="50000000" archiveFileName="${BasePath}\${shortdate}\${processname}\{##}_ServiceFwUpdateBuilder.log" />
<!--ServiceFwUpdateSw-->
<target name="ServiceFwUpdateSw" xsi:type="File" fileName="${BasePath}\${shortdate}\${processname}\ServiceFwUpdateSw.log" CreateDirs="True" layout ="${longdate} | ${level} | ${message} ${exception:format=toString}" archiveAboveSize="50000000" archiveFileName="C:\GenesisLog\${shortdate}\${processname}\{##}_ServiceFwUpdateSw.log" />
<!--ServiceFwUpdateLoader-->
<target name="ServiceFwUpdateLoader" xsi:type="File" fileName="${BasePath}\${shortdate}\${processname}\ServiceFwUpdateLoader.log" CreateDirs="True" layout ="${longdate} | ${level} | ${message} ${exception:format=toString}" archiveAboveSize="50000000" archiveFileName="${BasePath}\${shortdate}\${processname}\{##}_ServiceFwUpdateLoader.log" />
<!--default-->
<target name="default" xsi:type="File" fileName="${BasePath}\${shortdate}\${processname}\default.log" CreateDirs="True" layout ="${longdate} | ${level} | ${message} ${exception:format=toString}" archiveAboveSize="50000000" archiveFileName="C:\GenesisLog\${shortdate}\${processname}\{##}_default.log" />
<target name="PreAdjWr" xsi:type="File" fileName="${BasePath}\${shortdate}\${processname}\PreAdjWr.log" CreateDirs="True" layout ="${longdate} | ${level} | ${message} ${exception:format=toString}" />
<!--ServiceFwUpdateSw-->
<target name="ServiceFwUpdateSw" xsi:type="File" fileName="${BasePath}\${shortdate}\${processname}\ServiceFwUpdateSw.log" CreateDirs="True" layout ="${longdate} | ${level} | ${message} ${exception:format=toString}" archiveAboveSize="50000000" archiveFileName="${BasePath}\${shortdate}\${processname}\{##}_ServiceFwUpdateSw.log" />
<target name="ctlBatch" xsi:type="File" fileName="${BasePath}\${shortdate}\${processname}\ctlBatch.log" CreateDirs="True" layout ="${longdate} | ${level} | ${message} ${exception:format=toString}" archiveAboveSize="50000000" archiveFileName="C:\GenesisLog\${shortdate}\${processname}\{##}_ctlBatch.log" />
<target name="StreamingQualityFile" xsi:type="File" fileName="${BasePath}\${shortdate}\${processname}\StreamingQuality.log" CreateDirs="True" layout ="${longdate} | ${level} | ${message} ${exception:format=toString}" />
<target name="ProductionUIFile" xsi:type="File" fileName="${BasePath}\${shortdate}\${processname}\ProductionUIFile.log" CreateDirs="True" layout ="${longdate} | ${level} | ${message} ${exception:format=toString}" />
</targets>
<rules>
<!--ServiceFwUpdateBuilder-->
<logger name="ServiceFwUpdateBuilder" minLevel="Trace" appendTo="ServiceFwUpdateSw"/>
<!--ServiceFwUpdateLoader-->
<logger name="ServiceFwUpdateLoader" minLevel="Trace" appendTo="ServiceFwUpdateLoader"/>
<!--ServiceFwUpdateSw-->
<logger name="ServiceFwUpdateSw" minLevel="Trace" appendTo="ServiceFwUpdateSw"/>
<!--CalibrationHelper-->
<logger name="CalibrationHelper" minLevel="Trace" appendTo="CalibrationHelper"/>
<!--LedRawData-->
<logger name="LedRawDataBase" minLevel="Trace" appendTo="TargetLedRawDataBase"/>
<!--MeterBatch-->
<logger name="MeterBatch" minLevel="Trace" appendTo="MeterBatch"/>
<!--Meter-->
<logger name="MeterBase" minLevel="Trace" appendTo="MeterBase"/>
<logger name="Slot:0" minLevel="Trace" appendTo="Slot:0"/>
<logger name="GenesisRequestProtocolBase" minLevel="Trace" appendTo="MeterBase"/>
<logger name="MeasurementBase" minLevel="Trace" appendTo="MeterBase"/>
<!--COM-->
<logger name="SerialComPortBase" minLevel="Trace" appendTo="COMBase"/>
<logger name="IrdaBase" minLevel="Trace" appendTo="COMBase"/>
<logger name="RfidBase" minLevel="Trace" appendTo="COMBase"/>
<logger name="TransmitProtocolBase" minLevel="Trace" appendTo="COMBase"/>
<!--default-->
<logger name="*" minLevel="Debug" appendTo="default"/>
<!--default-->
<target name="default" xsi:type="File" fileName="${BasePath}\${shortdate}\${processname}\default.log" CreateDirs="True" layout ="${longdate} | ${level} | ${message} ${exception:format=toString}" archiveAboveSize="50000000" archiveFileName="${BasePath}\${shortdate}\${processname}\{##}_default.log" />
<target name="PreAdjWr" xsi:type="File" fileName="${BasePath}\${shortdate}\${processname}\PreAdjWr.log" CreateDirs="True" layout ="${longdate} | ${level} | ${message} ${exception:format=toString}" />
<!--Ui logger-->
<logger name="ctlBatch" minLevel="Trace" appendTo="ctlBatch"/>
<logger name="StreamingQuality" minLevel="Trace" appendTo="StreamingQualityFile"/>
<logger name="PreAdjWr" minLevel="Trace" appendTo="PreAdjWr"/>
<target name="ctlBatch" xsi:type="File" fileName="${BasePath}\${shortdate}\${processname}\ctlBatch.log" CreateDirs="True" layout ="${longdate} | ${level} | ${message} ${exception:format=toString}" archiveAboveSize="50000000" archiveFileName="${BasePath}\${shortdate}\${processname}\{##}_ctlBatch.log" />
<target name="StreamingQualityFile" xsi:type="File" fileName="${BasePath}\${shortdate}\${processname}\StreamingQuality.log" CreateDirs="True" layout ="${longdate} | ${level} | ${message} ${exception:format=toString}" />
<target name="ProductionUIFile" xsi:type="File" fileName="${BasePath}\${shortdate}\${processname}\ProductionUIFile.log" CreateDirs="True" layout ="${longdate} | ${level} | ${message} ${exception:format=toString}" />
</targets>
<rules>
<!--ServiceFwUpdateBuilder-->
<logger name="ServiceFwUpdateBuilder" minLevel="Trace" appendTo="ServiceFwUpdateSw"/>
<!--ServiceFwUpdateLoader-->
<logger name="ServiceFwUpdateLoader" minLevel="Trace" appendTo="ServiceFwUpdateLoader"/>
<!--ServiceFwUpdateSw-->
<logger name="ServiceFwUpdateSw" minLevel="Trace" appendTo="ServiceFwUpdateSw"/>
<!--CalibrationHelper-->
<logger name="CalibrationHelper" minLevel="Trace" appendTo="CalibrationHelper"/>
<!--LedRawData-->
<logger name="LedRawDataBase" minLevel="Trace" appendTo="TargetLedRawDataBase"/>
<!--MeterBatch-->
<logger name="MeterBatch" minLevel="Trace" appendTo="MeterBatch"/>
<!--Meter-->
<logger name="MeterBase" minLevel="Trace" appendTo="MeterBase"/>
<logger name="Slot:0" minLevel="Trace" appendTo="Slot:0"/>
<logger name="ProductionUI" minLevel="Trace" appendTo="ProductionUIFile"/>
</rules>
<logger name="GenesisRequestProtocolBase" minLevel="Trace" appendTo="MeterBase"/>
<logger name="MeasurementBase" minLevel="Trace" appendTo="MeterBase"/>
<!--COM-->
<logger name="SerialComPortBase" minLevel="Trace" appendTo="COMBase"/>
<logger name="IrdaBase" minLevel="Trace" appendTo="COMBase"/>
<logger name="RfidBase" minLevel="Trace" appendTo="COMBase"/>
<logger name="TransmitProtocolBase" minLevel="Trace" appendTo="COMBase"/>
<!--default-->
<logger name="*" minLevel="Debug" appendTo="default"/>
<!--Ui logger-->
<logger name="ctlBatch" minLevel="Trace" appendTo="ctlBatch"/>
<logger name="StreamingQuality" minLevel="Trace" appendTo="StreamingQualityFile"/>
<logger name="PreAdjWr" minLevel="Trace" appendTo="PreAdjWr"/>
<logger name="ProductionUI" minLevel="Trace" appendTo="ProductionUIFile"/>
</rules>
</nlog>

View File

@ -13,4 +13,4 @@ using System.Reflection;
//
//[assembly: AssemblyVersion("1.2.*.0")]
[assembly: AssemblyVersion("2.7.6.*")]
[assembly: AssemblyVersion("2.8.10.*")]

View File

@ -160,6 +160,22 @@
<bindings>
<binding protocol="http" bindingInformation="*:56011:localhost" />
</bindings>
</site>
<site name="MeterProcessState(1)" id="3">
<application path="/" applicationPool="Clr4IntegratedAppPool">
<virtualDirectory path="/" physicalPath="E:\REPO\lab\la_operations\laa_production\Common\Service\MeterProcessState" />
</application>
<bindings>
<binding protocol="http" bindingInformation="*:56015:localhost" />
</bindings>
</site>
<site name="MeterProcessState(2)" id="4">
<application path="/" applicationPool="Clr4IntegratedAppPool">
<virtualDirectory path="/" physicalPath="D:\Projekte\SENSUS_GitLab\LAA_PRODUCTION\Common\Service\MeterProcessState" />
</application>
<bindings>
<binding protocol="http" bindingInformation="*:50075:localhost" />
</bindings>
</site>
<siteDefaults>
<!-- To enable logging, please change the below attribute "enabled" to "true" -->

View File

@ -155,7 +155,7 @@
</site>
<site name="MeterProcessState" id="2">
<application path="/" applicationPool="Clr4IntegratedAppPool">
<virtualDirectory path="/" physicalPath="C:\Users\SZLATEV\source\repos\laa_production\Common\Service\MeterProcessState" />
<virtualDirectory path="/" physicalPath="E:\REPO\lab\la_operations\laa_production\Common\Service\MeterProcessState" />
</application>
<bindings>
<binding protocol="http" bindingInformation="*:56011:localhost" />
@ -168,6 +168,30 @@
<bindings>
<binding protocol="http" bindingInformation="*:59615:localhost" />
</bindings>
</site>
<site name="MeterProcessState(1)" id="4">
<application path="/" applicationPool="Clr4IntegratedAppPool">
<virtualDirectory path="/" physicalPath="E:\REPO\lab\la_operations\laa_production\Common\Service\MeterProcessState" />
</application>
<bindings>
<binding protocol="http" bindingInformation="*:56015:localhost" />
</bindings>
</site>
<site name="MeterProcessState(2)" id="5">
<application path="/" applicationPool="Clr4IntegratedAppPool">
<virtualDirectory path="/" physicalPath="E:\REPO\lab\la_operations\laa_production\Common\Service\MeterProcessState" />
</application>
<bindings>
<binding protocol="http" bindingInformation="*:50015:localhost" />
</bindings>
</site>
<site name="MeterProcessState(3)" id="6">
<application path="/" applicationPool="Clr4IntegratedAppPool">
<virtualDirectory path="/" physicalPath="C:\Users\SZLATEV\source\repos\laa_production\Common\Service\MeterProcessState" />
</application>
<bindings>
<binding protocol="http" bindingInformation="*:50075:localhost" />
</bindings>
</site>
<siteDefaults>
<!-- To enable logging, please change the below attribute "enabled" to "true" -->

File diff suppressed because it is too large Load Diff

View File

@ -24,6 +24,7 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=Battey/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=binfile/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=BUGFIX/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=BUPS/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Calib/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=catalogue/@EntryIndexedValue">True</s:Boolean>
@ -62,9 +63,11 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=PCBID/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=perc/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=PERIODICLOG/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=POWEMON/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=POWERMON/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Preadjustment/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=prot/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Pwds/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=restorable/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=RFID/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Sensus/@EntryIndexedValue">True</s:Boolean>
@ -75,6 +78,7 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=TESTMANAGER/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Thermo/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Uart/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=uintxx/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Uniontown/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Vako/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=walarms/@EntryIndexedValue">True</s:Boolean>

View File

@ -37,22 +37,30 @@
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration" />
<Reference Include="System.Core" />
<Reference Include="System.Net.Http">
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.Net.Http.dll</HintPath>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="PAM03.cs" />
<Compile Include="RFTelegrams\AlarmMask.cs" />
<Compile Include="RFTelegrams\AppCode.cs" />
<Compile Include="RFTelegrams\DisplayUnits.cs" />
<Compile Include="RFTelegrams\Epoch20000101.cs" />
<Compile Include="RFTelegrams\Extensions.cs" />
<Compile Include="RFTelegrams\LogContent.cs" />
<Compile Include="RFTelegrams\MeterTypes.cs" />
<Compile Include="RFTelegrams\PAMStatus.cs" />
<Compile Include="RFTelegrams\Pams\ChangeWakeUp.cs" />
<Compile Include="RFTelegrams\Pams\DummyPam.cs" />
<Compile Include="RFTelegrams\Pams\ResetAlarms.cs" />
<Compile Include="RFTelegrams\Pams\WakeUpMode.cs" />
<Compile Include="RFTelegrams\RFTask.cs" />
<Compile Include="RFTelegrams\RSSI.cs" />
<Compile Include="RFTelegrams\SEMI.cs" />
<Compile Include="RFTelegrams\SIRTServer.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Hardware\Common.Hardware.SIRT\Common.Hardware.SIRT.csproj">
@ -63,35 +71,6 @@
<Project>{4e8bb839-d40a-488c-88ce-f21811f1f476}</Project>
<Name>Common.Hardware.WaterMeter.eRegister</Name>
</ProjectReference>
<ProjectReference Include="..\Hardware\WaterMeter\Genesis\Registers\Registers.csproj">
<Project>{f4aaf7e6-7333-4284-b735-e32deb076c64}</Project>
<Name>Registers</Name>
</ProjectReference>
<ProjectReference Include="..\LaaPackages\LaaPackages.SqlClient\LaaPackages.SqlClient.csproj">
<Project>{F90B940C-9A83-496D-AAE0-11CD02CE0A22}</Project>
<Name>LaaPackages.SqlClient</Name>
</ProjectReference>
<ProjectReference Include="..\Stichproben\Stichproben.csproj">
<Project>{F69A79FA-548D-4E21-887E-01FABDAD9E73}</Project>
<Name>Stichproben</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions">
<Version>8.3.0</Version>
</PackageReference>
<PackageReference Include="Microsoft.SharePointOnline.CSOM">
<Version>16.1.26121.12000</Version>
</PackageReference>
<PackageReference Include="NUnit">
<Version>4.3.2</Version>
</PackageReference>
<PackageReference Include="NUnit3TestAdapter">
<Version>5.0.0</Version>
</PackageReference>
<PackageReference Include="SpecFlow.NUnit">
<Version>3.9.74</Version>
</PackageReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@ -0,0 +1,201 @@
namespace CommonConsole
{
using Common.Hardware.SIRT;
using Common.Hardware.SIRT.Parameters;
using Common.Hardware.SIRT.Tasks;
using Common.Hardware.WaterMeter.eRegister;
using Common.Hardware.WaterMeter.eRegister.Features;
using System;
using System.IO.Ports;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
public class PAM03
{
private string portName;
private uint address;
private byte[] key;
public int Run(params string[] args)
{
/// <summary>
/// Process.ExitCode:
/// 0 - OK
/// 1 - Execution Error
/// 2 - Connection Error
/// 3 - Invalid Arguments
/// </summary>
var exitCode = this.ParseArguments(args);
if (exitCode == 0)
{
var processAwaiter = new ManualResetEventSlim();
var sirtBroadcaster = new SIRTBroadcaster(this.portName);
var pinI = new ProvidePin { AuthLevel = AuthLevel.I };
void SIRTBroadcaster_Connected(SIRTBroadcaster sirt)
{
var task = new CordonelTask(sirt.Frequency)
{
DelPamSemi = true,
WakeUpCmd = true,
WakeUpModul = true,
RequestAddress = address,
EncryptionKey = key,
IsEncrypted = true
};
task.SetPending();
sirt.Start(task);
task.Wait();
void ResetAlarms(byte alarmMask)
{
if (exitCode != 0)
{
return;
}
task.WakeUpCmd = false;
task.WakeUpModul = false;
task.Data = new ResetAlarms(alarmMask).Append(pinI);
task.SetPending();
sirt.Start(task);
task.Wait();
if (task.State != SIRTTaskState.Completed)
{
Console.WriteLine($"{nameof(SIRTTaskState)}.{task.State}");
exitCode = 1;
}
exitCode = 0;
}
task.SetPending();
sirt.Start(task);
task.Wait();
if (task.State != SIRTTaskState.Completed)
{
exitCode = 1;
}
ResetAlarms(new AlarmsMask(0xFF)
{
MediumAbsent = false
});
ResetAlarms(0xFE);
processAwaiter.Set();
}
void SIRTBroadcaster_Disconnected(SIRTBroadcaster _)
=> processAwaiter.Set();
sirtBroadcaster.Connected += SIRTBroadcaster_Connected;
sirtBroadcaster.Disconnected += SIRTBroadcaster_Disconnected;
sirtBroadcaster.Open();
processAwaiter.Wait();
sirtBroadcaster.Close();
sirtBroadcaster.Disconnected -= SIRTBroadcaster_Disconnected;
sirtBroadcaster.Connected -= SIRTBroadcaster_Connected;
}
return exitCode;
}
public int ParseArguments(string[] args)
{
if (args.Length != 3)
{
Console.WriteLine($"Falsche anzahl an parameter: '{string.Join("', '", args)}'");
Console.WriteLine($"Expected: [COM..n as string] [Address as uint] [EncryptionKey as string]");
return 3;
}
this.portName = args[0];
if (Regex.IsMatch($"{this.portName}", "[Cc][Oo][Mm][0-9]+"))
{
this.portName = this.portName.ToUpper();
}
else if (SerialPort.GetPortNames().Any(x => x.Equals(this.portName, StringComparison.CurrentCultureIgnoreCase)))
{
Console.WriteLine($"COM Port: '{this.portName}' - nicht vorhanden");
return 3;
}
else
{
Console.WriteLine($"Falsche COM PortName: '{this.portName}' - erwartet: [Cc][Oo][Mm][0-9]+");
return 3;
}
if (!uint.TryParse($"{args[1]}", out this.address))
{
Console.WriteLine($"Ungültige Funkadresse: '{args[1]}'");
return 3;
}
this.key = $"{args[2]}".GetBytes();
if (this.key.Length != 16)
{
Console.WriteLine($"Ungültige Funkschlüssel: '{BitConverter.ToString(this.key)}'");
return 3;
}
return 0;
}
public class CordonelTask : EregisterTask
{
public CordonelTask(int frequency) : base(frequency)
{
}
public override Byte[] Start()
{
Console.WriteLine($"TX|{BitConverter.ToString(this.request)}");
return base.Start();
}
public override void Push(SIRTMessage response)
{
base.Push(response);
Console.WriteLine($"RX|{BitConverter.ToString(response)}");
try
{
if (this.SEMIMessage != null)
{
Console.WriteLine($"=========================================");
Console.WriteLine($"AlarmsMask");
Console.WriteLine($"-----------------------------------------");
Console.WriteLine($"{new AlarmsMask(response.Payload[10])}");
Console.WriteLine($"=========================================");
Console.WriteLine($"RSSI.PAM {response.P2}");
Console.WriteLine($"RSSI.SEMI {response.Payload[12]}");
Console.WriteLine($"PAMStatus {new PAMStatus(response.Payload[11])}");
Console.WriteLine($"=========================================");
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
}
}

View File

@ -1,250 +1,299 @@
namespace CommonConsole
{
using System;
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.RFTelegrams;
public static class Program
{
public static void Main()
static void Main()
{
var bytes = new byte[] { 0x01, 0x82, 0x14, 0x94, 0x12, 0x10, 0x61, 0x20, 0x01, 0x34, 0xA6, 0x71, 0xB8, 0xFF, 0xE1, 0x09 };
var bits = string.Empty;
// Console.WriteLine(BitConverter.ToInt32(new byte[] { 0xEC, 0xFF, 0xFF, 0xFF }, 0));
foreach (var _byte in bytes)
{
for (int i = 7; i >= 0; i--)
{
bits += $"{(_byte >> i) & 1}";
}
}
var last = 1;
for (int i = 0; i < bits.Length; i++)
{
last *= 2;
}
var x = "1";
var r = 0;
for (var i = 0; i < 128; i++)
{
var t = string.Empty;
for (var a = x.Length - 1; a >= 0; a--)
{
var xs = (byte)(x[a] - '0') * 2;
t = $"{xs % 10 + r}{t}";
r = xs / 10;
}
x = t;
if (r > 0)
{
x = $"{r}{x}";
}
}
Console.WriteLine();
SIRTServer.StartServer(Console.WriteLine, Console.WriteLine, 6, 8);
// SIRTServer.StartProgramming(433, 412013443, "0E9FACC6A0E1EF1C3B27A49BAC216535");
// SIRTServer.StartProgramming(433, 412013444, "0E9FACC6A0E1EF1C3B27A49BAC216535");
// SIRTServer.StartProgramming(433, 412013356, "80D46C00E1BED73FE0DA85D95CA4BEE3");
// SIRTServer.StartProgramming(433, 412013081, "7B5F2F606155C670BD9891231A598EF3");
// SIRTServer.StartProgramming(433, 412013082, "A10BB3C32B71894BD8BB17884973E616");
// SIRTServer.StartProgramming(433, 412013083, "15EEC94741740FB1EA736CF6468A4790");
// SIRTServer.StartProgramming(433, 412013084, "6E742330A56149E8CF94ABD70576573D");
// SIRTServer.StartProgramming(433, 412013087, "C4D1DC170D7E219C26FDE76F9B2DC89A");
// SIRTServer.StartProgramming(433, 412013078, "4E788CF5F57FF977C85F458049D00387");
// SIRTServer.StartProgramming(868, 402001154, "0E9FACC6A0E1EF1C3B27A49BAC216535");
// SIRTServer.StartProgramming(433, 412012695, "867DD2A34C382B7D1190DD563E6B52C4");
// SIRTServer.StartProgramming(433, 412013356, "80D46C00E1BED73FE0DA85D95CA4BEE3");
}
//public static void Main()
public static void MainRF(params string[] args)
{
//var pam03 = new PAM03();
//pam03.Run("COM6", "402010030", "E6C88800DEB868C0D6A84880CE982840");
//pam03.Run("COM6", "402010027", "D9C154DC274966AB71AD5D804A322178");
//return pam03.Run("COM7", "412004190", "0E9FACC6A0E1EF1C3B27A49BAC216535");
// 10402010030 E6C88800DEB868C0D6A84880CE982840
//try
//{
// return pam03.Run("COM10", "402009768", "3CB64CBCB71F8D0F9F69FF18DF5D24D3");
//}
//catch (System.Exception e)
//{
// return -1;
//}
}
class FDRMask
{
public const byte LOG_ALARM_STATE = 0; // 0x00000001, //!< AlarmState (16 bits)
public const byte LOG_BILLING_COUNTER = 1; // 0x00000002, //!< BillingCounter
public const byte LOG_REVERSE_COUNTER = 2; // 0x00000004, //!< Backward or ReverseCounter
public const byte LOG_MAX_FLOW_VAL = 3; // 0x00000008, //!< Value of MaxFlow
public const byte LOG_MAX_FLOW_TIME = 4; // 0x00000010, //!< Date/Time of MaxFlow
public const byte LOG_PEAK_FLOW_VAL = 5; // 0x00000020, //!< Value of PeakFlow
public const byte LOG_PEAK_FLOW_TIME = 6; // 0x00000040, //!< Date/Time of PeakFlow
public const byte LOG_CUR_FLOW_VAL = 7; // 0x00000080, //!< Current Flow Value (Average of Period)
public const byte LOG_BROKEN_PIPE_FLOW_VAL = 8; // 0x00000100, //!< Value of BrokenPipe
public const byte LOG_BROKEN_PIPE_FLOW_TIME = 9; // 0x00000200, //!< Date/Time of BrokenPipe
public const byte LOG_MIN_FLOW_VAL = 10; // 0x00000400, //!< Value of FlowMin
public const byte LOG_MIN_FLOW_TIME = 11; // 0x00000800, //!< Date/Time of FlowMin
public const byte LOG_FORWARD_COUNTER = 12; // 0x00001000, //!< ForwardCounter
public const byte LOG_MIN_PRESS_VAL = 13; // 0x00010000, //!< Pressure Minimum
public const byte LOG_MIN_PRESS_TIME = 14; // 0x00020000, //!< Pressure Minimum Time
public const byte LOG_MAX_PRESS_VAL = 15; // 0x00040000, //!< Pressure Maximum
public const byte LOG_MAX_PRESS_TIME = 16; // 0x00080000, //!< Pressure Maximum Time
public const byte LOG_MIN_TEMP_VAL = 17; // 0x00100000, //!< Temperature Minimum
public const byte LOG_MIN_TEMP_TIME = 18; // 0x00200000, //!< Temperature Minimum
public const byte LOG_MAX_TEMP_VAL = 19; // 0x00400000, //!< Temperature Maximum
public const byte LOG_MAX_TEMP_TIME = 20; // 0x00800000, //!< Temperature Maximum
public const byte LOG_CUR_PRESS_VAL = 21; // 0x01000000, //!< Pressure Current Value
public const byte LOG_CUR_TEMP_VAL = 22; // 0x02000000, //!< Temperature Current Value
public const byte LOG_EXT_ALARM_STATE = 23; // 0x04000000,    //<! Extended Alarm Status
};
class AlarmMask
{
public const byte ALARM_REBOOT = 0; // immer An
public const byte ALARM_LOW_BATTERY = 1;
public const byte ALARM_VERY_LOW_BATTERY = 2; /* For consistency with st_alarm_bit_t only */
public const byte ALARM_CONFIG_ERROR = 3;
public const byte ALARM_EMPTY_PIPE = 4;
public const byte ALARM_MAGNETIC_TAMPER = 5; /* For consistency with st_alarm_bit_t only */
public const byte ALARM_REVERSE_FLOW = 6;
public const byte ALARM_SUSPECT_LEAK = 7;
public const byte ALARM_BROKEN_PIPE = 8;
public const byte ALARM_LOW_PRESSURE = 9;
public const byte ALARM_HIGH_PRESSURE = 10;
public const byte ALARM_LOW_TEMPERATURE = 11;
public const byte ALARM_HIGH_TEMPERATURE = 12;
public const byte ALARM_RADIO_ERROR = 13;
public const byte ALARM_METROLOGY_PARAMS = 14;
public const byte ALARM_METROLOGY_MEASURE = 15;
public const byte ALARM_MAX = 16;
}; // ' CSD ', IIF(i.CSD_Wert IS NULL, i.CSD_Charcode, 'mit neue konfiguration')
public static void Main1()
{
Console.WriteLine(BitConverter.ToInt32(new byte[] { 0xE9, 0xFF, 0xFF, 0xFF }, 0));
Console.WriteLine(BitConverter.ToInt32(new byte[] { 0xAD, 0xFF, 0xFF, 0xFF }, 0));
Console.WriteLine(BitConverter.ToInt32(new byte[] { 0xE6, 0xFF, 0xFF, 0xFF }, 0));
Console.WriteLine(BitConverter.ToInt32(new byte[] { 0x03, 0x00, 0x00, 0x00 }, 0));
//var alarmMask = 1 << AlarmMask.ALARM_REBOOT
// | 1 << AlarmMask.ALARM_LOW_BATTERY
// | 0 << AlarmMask.ALARM_VERY_LOW_BATTERY
// | 0 << AlarmMask.ALARM_CONFIG_ERROR
// | 1 << AlarmMask.ALARM_EMPTY_PIPE
// | 0 << AlarmMask.ALARM_MAGNETIC_TAMPER
// | 1 << AlarmMask.ALARM_REVERSE_FLOW
// | 1 << AlarmMask.ALARM_SUSPECT_LEAK
// | 1 << AlarmMask.ALARM_BROKEN_PIPE
// | 0 << AlarmMask.ALARM_LOW_PRESSURE
// | 0 << AlarmMask.ALARM_HIGH_PRESSURE
// | 0 << AlarmMask.ALARM_LOW_TEMPERATURE
// | 0 << AlarmMask.ALARM_HIGH_TEMPERATURE
// | 0 << AlarmMask.ALARM_RADIO_ERROR
// | 0 << AlarmMask.ALARM_METROLOGY_PARAMS
// | 0 << AlarmMask.ALARM_METROLOGY_MEASURE
// | 0 << AlarmMask.ALARM_MAX;
//var alarmBytes = BitConverter.GetBytes(alarmMask);
//Array.Reverse(alarmBytes);
//Console.WriteLine($"ALARM_MASK: {alarmMask} - {BitConverter.ToString(alarmBytes).Replace("-", "")}");
//var dataLogger = 1 << FDRMask.LOG_ALARM_STATE
// | 1 << FDRMask.LOG_BILLING_COUNTER
// | 0 << FDRMask.LOG_REVERSE_COUNTER
// | 0 << FDRMask.LOG_MAX_FLOW_VAL
// | 0 << FDRMask.LOG_MAX_FLOW_TIME
// | 0 << FDRMask.LOG_PEAK_FLOW_VAL
// | 0 << FDRMask.LOG_PEAK_FLOW_TIME
// | 1 << FDRMask.LOG_CUR_FLOW_VAL
// | 0 << FDRMask.LOG_BROKEN_PIPE_FLOW_VAL
// | 0 << FDRMask.LOG_BROKEN_PIPE_FLOW_TIME
// | 1 << FDRMask.LOG_MIN_FLOW_VAL
// | 0 << FDRMask.LOG_MIN_FLOW_TIME
// | 0 << FDRMask.LOG_FORWARD_COUNTER
// | 0 << FDRMask.LOG_MIN_PRESS_VAL
// | 0 << FDRMask.LOG_MIN_PRESS_TIME
// | 0 << FDRMask.LOG_MAX_PRESS_VAL
// | 0 << FDRMask.LOG_MAX_PRESS_TIME
// | 0 << FDRMask.LOG_MIN_TEMP_VAL
// | 0 << FDRMask.LOG_MIN_TEMP_TIME
// | 0 << FDRMask.LOG_MAX_TEMP_VAL
// | 0 << FDRMask.LOG_MAX_TEMP_TIME
// | 0 << FDRMask.LOG_CUR_PRESS_VAL
// | 0 << FDRMask.LOG_CUR_TEMP_VAL
// | 1 << FDRMask.LOG_EXT_ALARM_STATE;
//var dataLoggerBytes = BitConverter.GetBytes(dataLogger);
//Array.Reverse(dataLoggerBytes);
//Console.WriteLine($"DATA_LOGGER: {dataLogger} - {BitConverter.ToString(dataLoggerBytes).Replace("-", "")}");
//var fixDateReading = 1 << FDRMask.LOG_ALARM_STATE
// | 1 << FDRMask.LOG_BILLING_COUNTER
// | 0 << FDRMask.LOG_REVERSE_COUNTER
// | 0 << FDRMask.LOG_MAX_FLOW_VAL
// | 0 << FDRMask.LOG_MAX_FLOW_TIME
// | 0 << FDRMask.LOG_PEAK_FLOW_VAL
// | 0 << FDRMask.LOG_PEAK_FLOW_TIME
// | 1 << FDRMask.LOG_CUR_FLOW_VAL
// | 0 << FDRMask.LOG_BROKEN_PIPE_FLOW_VAL
// | 0 << FDRMask.LOG_BROKEN_PIPE_FLOW_TIME
// | 1 << FDRMask.LOG_MIN_FLOW_VAL
// | 0 << FDRMask.LOG_MIN_FLOW_TIME
// | 0 << FDRMask.LOG_FORWARD_COUNTER
// | 0 << FDRMask.LOG_MIN_PRESS_VAL
// | 0 << FDRMask.LOG_MIN_PRESS_TIME
// | 0 << FDRMask.LOG_MAX_PRESS_VAL
// | 0 << FDRMask.LOG_MAX_PRESS_TIME
// | 0 << FDRMask.LOG_MIN_TEMP_VAL
// | 0 << FDRMask.LOG_MIN_TEMP_TIME
// | 0 << FDRMask.LOG_MAX_TEMP_VAL
// | 0 << FDRMask.LOG_MAX_TEMP_TIME
// | 0 << FDRMask.LOG_CUR_PRESS_VAL
// | 0 << FDRMask.LOG_CUR_TEMP_VAL
// | 1 << FDRMask.LOG_EXT_ALARM_STATE;
//var fixDateReadingBytes = BitConverter.GetBytes(fixDateReading);
//Array.Reverse(fixDateReadingBytes);
//Console.WriteLine($"FDR_LOGGER: {fixDateReading} - {BitConverter.ToString(fixDateReadingBytes).Replace("-", "")}");
//var x1 = 0xD29F;
//var x2 = 0xD39F;
//Console.WriteLine(new string('=', 50));
//Console.WriteLine($"ALARM_REBOOT: [{(int)AlarmMask.ALARM_REBOOT,2}] {(x1 >> AlarmMask.ALARM_REBOOT) % 2} {(x2 >> AlarmMask.ALARM_REBOOT) % 2} ");
//Console.WriteLine($"ALARM_LOW_BATTERY: [{(int)AlarmMask.ALARM_LOW_BATTERY,2}] {(x1 >> AlarmMask.ALARM_LOW_BATTERY) % 2} {(x2 >> AlarmMask.ALARM_LOW_BATTERY) % 2} ");
//Console.WriteLine($"ALARM_VERY_LOW_BATTERY: [{(int)AlarmMask.ALARM_VERY_LOW_BATTERY,2}] {(x1 >> AlarmMask.ALARM_VERY_LOW_BATTERY) % 2} {(x2 >> AlarmMask.ALARM_VERY_LOW_BATTERY) % 2} ");
//Console.WriteLine($"ALARM_CONFIG_ERROR: [{(int)AlarmMask.ALARM_CONFIG_ERROR,2}] {(x1 >> AlarmMask.ALARM_CONFIG_ERROR) % 2} {(x2 >> AlarmMask.ALARM_CONFIG_ERROR) % 2} ");
//Console.WriteLine($"ALARM_EMPTY_PIPE: [{(int)AlarmMask.ALARM_EMPTY_PIPE,2}] {(x1 >> AlarmMask.ALARM_EMPTY_PIPE) % 2} {(x2 >> AlarmMask.ALARM_EMPTY_PIPE) % 2} ");
//Console.WriteLine($"ALARM_MAGNETIC_TAMPER: [{(int)AlarmMask.ALARM_MAGNETIC_TAMPER,2}] {(x1 >> AlarmMask.ALARM_MAGNETIC_TAMPER) % 2} {(x2 >> AlarmMask.ALARM_MAGNETIC_TAMPER) % 2} ");
//Console.WriteLine($"ALARM_REVERSE_FLOW: [{(int)AlarmMask.ALARM_REVERSE_FLOW,2}] {(x1 >> AlarmMask.ALARM_REVERSE_FLOW) % 2} {(x2 >> AlarmMask.ALARM_REVERSE_FLOW) % 2} ");
//Console.WriteLine($"ALARM_SUSPECT_LEAK: [{(int)AlarmMask.ALARM_SUSPECT_LEAK,2}] {(x1 >> AlarmMask.ALARM_SUSPECT_LEAK) % 2} {(x2 >> AlarmMask.ALARM_SUSPECT_LEAK) % 2} ");
//Console.WriteLine($"ALARM_BROKEN_PIPE: [{(int)AlarmMask.ALARM_BROKEN_PIPE,2}] {(x1 >> AlarmMask.ALARM_BROKEN_PIPE) % 2} {(x2 >> AlarmMask.ALARM_BROKEN_PIPE) % 2} ");
//Console.WriteLine($"ALARM_LOW_PRESSURE: [{(int)AlarmMask.ALARM_LOW_PRESSURE,2}] {(x1 >> AlarmMask.ALARM_LOW_PRESSURE) % 2} {(x2 >> AlarmMask.ALARM_LOW_PRESSURE) % 2} ");
//Console.WriteLine($"ALARM_HIGH_PRESSURE: [{(int)AlarmMask.ALARM_HIGH_PRESSURE,2}] {(x1 >> AlarmMask.ALARM_HIGH_PRESSURE) % 2} {(x2 >> AlarmMask.ALARM_HIGH_PRESSURE) % 2} ");
//Console.WriteLine($"ALARM_LOW_TEMPERATURE: [{(int)AlarmMask.ALARM_LOW_TEMPERATURE,2}] {(x1 >> AlarmMask.ALARM_LOW_TEMPERATURE) % 2} {(x2 >> AlarmMask.ALARM_LOW_TEMPERATURE) % 2} ");
//Console.WriteLine($"ALARM_HIGH_TEMPERATURE: [{(int)AlarmMask.ALARM_HIGH_TEMPERATURE,2}] {(x1 >> AlarmMask.ALARM_HIGH_TEMPERATURE) % 2} {(x2 >> AlarmMask.ALARM_HIGH_TEMPERATURE) % 2} ");
//Console.WriteLine($"ALARM_RADIO_ERROR: [{(int)AlarmMask.ALARM_RADIO_ERROR,2}] {(x1 >> AlarmMask.ALARM_RADIO_ERROR) % 2} {(x2 >> AlarmMask.ALARM_RADIO_ERROR) % 2} ");
//Console.WriteLine($"ALARM_METROLOGY_PARAMS: [{(int)AlarmMask.ALARM_METROLOGY_PARAMS,2}] {(x1 >> AlarmMask.ALARM_METROLOGY_PARAMS) % 2} {(x2 >> AlarmMask.ALARM_METROLOGY_PARAMS) % 2} ");
//Console.WriteLine($"ALARM_METROLOGY_MEASURE: [{(int)AlarmMask.ALARM_METROLOGY_MEASURE,2}] {(x1 >> AlarmMask.ALARM_METROLOGY_MEASURE) % 2} {(x2 >> AlarmMask.ALARM_METROLOGY_MEASURE) % 2}");
//Console.WriteLine($"ALARM_MAX: [{(int)AlarmMask.ALARM_MAX,2}] {(x1 >> AlarmMask.ALARM_MAX) % 2} {(x2 >> AlarmMask.ALARM_MAX) % 2} ");
//Console.WriteLine(int.MaxValue);
//Console.WriteLine(uint.MaxValue);
//Console.WriteLine(long.MaxValue);
}
//public static void /*MainCSD()*/ Main()
//{
// ////var x = (625L * 65536) | 0x80_00_00_00;
// var alarmEnableMask = 0xD39F0000;
// var ix = 0;
// ////Console.WriteLine((int)x);
// ////var semiBytes25747925 = new byte[] { 0x08, 0x03, 0x12, 0x6B, 0x78, 0x41, 0x00, 0x00, 0x01, 0xF4, 0x00, 0x00, 0x83, 0x0C, 0x00, 0x0F, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x13, 0x01, 0x88, 0xE1, 0xD5, 0x07, 0x0E, 0x10, 0xEC, 0x56, 0x13, 0xDA, 0x4C, 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x1E, 0x00, 0x03, 0x01, 0x2F, 0xBE, 0xCA, 0x47, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0xEF, 0xA6 };
// ////var semi25747925 = new SEMI(semiBytes25747925, 868, 0);
// ////var debugBytes25747925 = new byte[] { 0x0B, 0x10, 0x12, 0x6B, 0x78, 0x41, 0x00, 0x0C, 0x11, 0x0B, 0x11, 0x08, 0x04, 0x02, 0x7C, 0x4C, 0x12, 0x84, 0x15, 0x00, 0x66, 0x00, 0x35, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4A, 0x8F, 0xD2, 0x02, 0x01, 0x01, 0x16, 0x00, 0x1B, 0x02, 0x71, 0x00, 0x00, 0x82, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xA0, 0xA5 };
// ////var debug25747925 = new DEBUG(debugBytes25747925, 0);
// ////var siteUrl = "https://1xylemeur.sharepoint.com/sites/geckoSrc/customer/Pub_CSD/Forms/AllItems.aspx";
// ////var userName = "stoyan.zlatev@xylem.com";
// ////var password = "****************";
// ////var securePassword = new SecureString();
// ////foreach (var c in password)
// ////{
// //// securePassword.AppendChar(c);
// ////}
// ////using (var context = new ClientContext(siteUrl))
// ////{
// //// context.Credentials = new SharePointOnlineCredentials(userName, securePassword);
// //// var web = context.Web;
// //// context.Load(web);
// //// context.ExecuteQuery();
// //// Console.WriteLine("Site Title: " + web.Title);
// ////}
//}
//public static void Main()
//{
// SIRTLogger.State += Console.WriteLine;
// var sirtHub = new SIRTHub();
// if (sirtHub.TryOpen("COM6", out var sirtId, out var frequency))
// foreach (var item in Enum.GetValues(typeof(AlarmMask)).Cast<AlarmMask>().OrderBy(x => (uint)x).ToArray())
// {
// SIRTLogger.State -= Console.WriteLine;
// SIRTLogger.Message += Console.WriteLine;
// Console.WriteLine($"Listening on: COM6 - {frequency} - {sirtId}");
// var task = new LEDTask(frequency, 319017453)
// {
// //WakeUpCmd = true,
// //WakeUpModul = true,
// //DelPamSemi = true,
// Data = new byte[] { 0x1F, 0x01, 0x08, 0x43, 0x03, 0x63, 0x93, 0x73, 0x22 },
// EncryptionKey = "E6C88800DEB868C0D6A84880CE982840".GetBytes(),
// IsEncrypted = true,
// };
// sirtHub.Start(task);
// task.Wait();
// Console.ReadKey();
// sirtHub.Close("COM6");
// }
//}
//public class LEDTask : EregisterTask
//{
// public LEDTask(int frequency, uint address) : base(frequency)
// {
// this.RequestAddress = address;
// Console.WriteLine($"{item,23} = {item:X} = {(uint)item,5} = {(alarmEnableMask << ix++) & 1}");
// }
// public byte P811
// foreach (var item in Enum.GetValues(typeof(FDRMask)).Cast<FDRMask>().OrderBy(x => x).ToArray())
// {
// get => this.p811;
// set => this.p811 = value;
// Console.WriteLine($"{item} = {item:X} = {(uint)item}");
// }
//}
//internal enum AlarmMask
//{
// ALARM_REBOOT = 1 << 0, // immer An
// ALARM_LOW_BATTERY = 1 << 1,
// ALARM_VERY_LOW_BATTERY = 1 << 2, /* For consistency with st_alarm_bit_t only */
// ALARM_CONFIG_ERROR = 1 << 3,
// ALARM_EMPTY_PIPE = 1 << 4,
// ALARM_MAGNETIC_TAMPER = 1 << 5, /* For consistency with st_alarm_bit_t only */
// ALARM_REVERSE_FLOW = 1 << 6,
// ALARM_SUSPECT_LEAK = 1 << 7,
// ALARM_BROKEN_PIPE = 1 << 8,
// ALARM_LOW_PRESSURE = 1 << 9,
// ALARM_HIGH_PRESSURE = 1 << 10,
// ALARM_LOW_TEMPERATURE = 1 << 11,
// ALARM_HIGH_TEMPERATURE = 1 << 12,
// ALARM_RADIO_ERROR = 1 << 13,
// ALARM_METROLOGY_PARAMS = 1 << 14,
// ALARM_METROLOGY_MEASURE = 1 << 15,
// ALARM_MAX = 1 << 16
//};
// ushort value = 3;
//internal enum FDRMask
//{
// LOG_BILLING_COUNTER = 0x00000002, //!< BillingCounter
// LOG_FORWARD_COUNTER = 0x00001000, //!< ForwardCounter
// LOG_REVERSE_COUNTER = 0x00000004, //!< Backward or ReverseCounter
// LOG_MIN_FLOW_TIME = 0x00000800, //!< Date/Time of FlowMin
// LOG_MIN_FLOW_VAL = 0x00000400, //!< Value of FlowMin
// LOG_BROKEN_PIPE_FLOW_TIME = 0x00000200, //!< Date/Time of BrokenPipe
// LOG_BROKEN_PIPE_FLOW_VAL = 0x00000100, //!< Value of BrokenPipe
// LOG_CUR_FLOW_VAL = 0x00000080, //!< Current Flow Value (Average of Period)
// LOG_PEAK_FLOW_TIME = 0x00000040, //!< Date/Time of PeakFlow
// LOG_PEAK_FLOW_VAL = 0x00000020, //!< Value of PeakFlow
// LOG_MAX_FLOW_TIME = 0x00000010, //!< Date/Time of MaxFlow
// LOG_MAX_FLOW_VAL = 0x00000008, //!< Value of MaxFlow
// LOG_CUR_TEMP_VAL = 0x02000000, //!< Temperature Current Value
// LOG_MAX_TEMP_TIME = 0x00800000, //!< Temperature Maximum
// LOG_MAX_TEMP_VAL = 0x00400000, //!< Temperature Maximum
// LOG_MIN_TEMP_TIME = 0x00200000, //!< Temperature Minimum
// LOG_MIN_TEMP_VAL = 0x00100000, //!< Temperature Minimum
// LOG_CUR_PRESS_VAL = 0x01000000, //!< Pressure Current Value
// LOG_MAX_PRESS_TIME = 0x00080000, //!< Pressure Maximum Time
// LOG_MAX_PRESS_VAL = 0x00040000, //!< Pressure Maximum
// LOG_MIN_PRESS_TIME = 0x00020000, //!< Pressure Minimum Time
// LOG_MIN_PRESS_VAL = 0x00010000, //!< Pressure Minimum
// LOG_ALARM_STATE = 0x00000001, //!< AlarmState (16 bits)
// LOG_EXT_ALARM_STATE = 0x04000000,    //<! Extended Alarm Status
//};
// Console.WriteLine($"0: {value >> 0 & 1}");
// Console.WriteLine($"0: {value >> 1 & 1}");
// Console.WriteLine($"0: {value >> 2 & 1}");
//var alarm
// = FDRMask.LOG_BILLING_COUNTER
// | FDRMask.LOG_REVERSE_COUNTER
// | FDRMask.LOG_BROKEN_PIPE_FLOW_TIME
// | FDRMask.LOG_BROKEN_PIPE_FLOW_VAL
// | FDRMask.LOG_PEAK_FLOW_TIME
// | FDRMask.LOG_PEAK_FLOW_VAL
// | FDRMask.LOG_MAX_FLOW_TIME
// | FDRMask.LOG_MAX_FLOW_VAL
// | FDRMask.LOG_MAX_TEMP_TIME
// | FDRMask.LOG_MAX_TEMP_VAL
// | FDRMask.LOG_ALARM_STATE
// | FDRMask.LOG_EXT_ALARM_STATE;
// Console.WriteLine("CSD CSD 772161_MW");
// Console.WriteLine("=============================================================================");
//public static void Main()
//{
// var alarm = AlarmMask.ALARM_REBOOT
// | AlarmMask.ALARM_EMPTY_PIPE
// | AlarmMask.ALARM_SUSPECT_LEAK
// | AlarmMask.ALARM_BROKEN_PIPE
// | AlarmMask.ALARM_LOW_BATTERY
// | AlarmMask.ALARM_REVERSE_FLOW
// | AlarmMask.ALARM_HIGH_TEMPERATURE;
// | AlarmMask.ALARM_REVERSE_FLOW;
// Console.WriteLine($"Alarm: {alarm}");
// Console.WriteLine(BitConverter.ToString(BitConverter.GetBytes((int)alarm)));
// Console.WriteLine();
// Console.WriteLine($"CUSTOMER_AlarmVisualMask: {BitConverter.ToString(BitConverter.GetBytes((int)alarm))}");
// var fdr = FDRMask.LOG_BILLING_COUNTER
// | FDRMask.LOG_REVERSE_COUNTER
// | FDRMask.LOG_BROKEN_PIPE_FLOW_TIME
// | FDRMask.LOG_BROKEN_PIPE_FLOW_VAL
// | FDRMask.LOG_PEAK_FLOW_TIME
// | FDRMask.LOG_PEAK_FLOW_VAL
// | FDRMask.LOG_MAX_FLOW_TIME
// | FDRMask.LOG_MAX_FLOW_VAL
// | FDRMask.LOG_MAX_TEMP_TIME
// | FDRMask.LOG_MAX_TEMP_VAL
// var dlg = FDRMask.LOG_BILLING_COUNTER
// | FDRMask.LOG_MIN_FLOW_VAL
// | FDRMask.LOG_CUR_FLOW_VAL // ... AverageFlow !?
// | FDRMask.LOG_ALARM_STATE
// | FDRMask.LOG_EXT_ALARM_STATE;
// Console.WriteLine($"FDR: {fdr}");
// Console.WriteLine(BitConverter.ToString(BitConverter.GetBytes((int)fdr)));
// Console.WriteLine();
// Console.WriteLine($"PERIODICLOG_DataLogContents: {BitConverter.ToString(BitConverter.GetBytes((int)dlg))}");
// Console.WriteLine($"HErrL: {BitConverter.ToString(BitConverter.GetBytes((short)90))}");
// Console.WriteLine();
// var fdr = FDRMask.LOG_BILLING_COUNTER
// | FDRMask.LOG_MIN_FLOW_VAL
// | FDRMask.LOG_CUR_FLOW_VAL // ... AverageFlow !?
// | FDRMask.LOG_ALARM_STATE
// | FDRMask.LOG_EXT_ALARM_STATE;
// Console.WriteLine("LeakageThreshold");
// Console.WriteLine($"DN 40 100 l/h = 100 * 256 = {BitConverter.ToString(BitConverter.GetBytes(100 * 256))}");
// Console.WriteLine($"DN 50 100 l/h = 100 * 256 = {BitConverter.ToString(BitConverter.GetBytes(100 * 256))}");
// Console.WriteLine($"DN 65 125 l/h = 125 * 256 = {BitConverter.ToString(BitConverter.GetBytes(125 * 256))}");
// Console.WriteLine($"DN 80 125 l/h = 125 * 256 = {BitConverter.ToString(BitConverter.GetBytes(125 * 256))}");
// Console.WriteLine($"DN 100 125 l/h = 125 * 256 = {BitConverter.ToString(BitConverter.GetBytes(125 * 256))}");
// Console.WriteLine($"DN 125 500 l/h = 500 * 256 = {BitConverter.ToString(BitConverter.GetBytes(500 * 256))}");
// Console.WriteLine($"DN 150 375 l/h = 375 * 256 = {BitConverter.ToString(BitConverter.GetBytes(375 * 256))}");
// Console.WriteLine();
// Console.WriteLine("BrokenPipeThreshold");
// Console.WriteLine($"DN 40 50 m³/h = 50 * 256 * 1000 = {BitConverter.ToString(BitConverter.GetBytes( 50 * 256 * 1000))}");
// Console.WriteLine($"DN 80 125 m³/h = 125 * 256 * 1000 = {BitConverter.ToString(BitConverter.GetBytes(125 * 256 * 1000))}");
// Console.WriteLine($"DN 150 250 m³/h = 250 * 256 * 1000 = {BitConverter.ToString(BitConverter.GetBytes(250 * 256 * 1000))}");
// Console.WriteLine();
// Console.WriteLine($"PERIODICLOG_FixedDateReadingContents: {BitConverter.ToString(BitConverter.GetBytes((int)fdr))}");
//}
/// <summary>
/// CSD 769400 Arqiva Thames Water
/// </summary>
public static void Main1231231()
{
Console.WriteLine("CSD 769400 Arqiva Thames Water");
Console.WriteLine("=============================================================================");
Console.WriteLine("--- DN50 --------------------------------------------------------------------");
Console.WriteLine($"CUSTOMER_ExcessFlowVolumeThreshold: {BitConverter.ToString(BitConverter.GetBytes((int)(37.5 * 1000) / 256))}");
var alarm = 1 << AlarmMask.ALARM_EMPTY_PIPE
| 1 << AlarmMask.ALARM_SUSPECT_LEAK
| 1 << AlarmMask.ALARM_LOW_BATTERY
| 1 << AlarmMask.ALARM_HIGH_TEMPERATURE
| 1 << AlarmMask.ALARM_LOW_TEMPERATURE
| 1 << AlarmMask.ALARM_HIGH_PRESSURE
| 1 << AlarmMask.ALARM_LOW_PRESSURE;
Console.WriteLine($"CUSTOMER_AlarmVisualMask: {BitConverter.ToString(BitConverter.GetBytes(alarm))}");
var dlg = 1 <<FDRMask.LOG_BILLING_COUNTER
| 1 <<FDRMask.LOG_REVERSE_COUNTER
| 1 <<FDRMask.LOG_MIN_FLOW_TIME
| 1 <<FDRMask.LOG_MIN_FLOW_VAL
| 1 <<FDRMask.LOG_CUR_FLOW_VAL
| 1 <<FDRMask.LOG_PEAK_FLOW_TIME
| 1 <<FDRMask.LOG_PEAK_FLOW_VAL
| 1 <<FDRMask.LOG_MAX_FLOW_TIME
| 1 <<FDRMask.LOG_MAX_FLOW_VAL
| 1 <<FDRMask.LOG_ALARM_STATE;
Console.WriteLine($"PERIODICLOG_DataLogContents: {BitConverter.ToString(BitConverter.GetBytes(dlg))}");
var fdr = 1 << FDRMask.LOG_BILLING_COUNTER
| 1 << FDRMask.LOG_ALARM_STATE;
Console.WriteLine($"PERIODICLOG_FixedDateReadingContents: {BitConverter.ToString(BitConverter.GetBytes(fdr))}");
}
}
}

View File

@ -0,0 +1,13 @@
namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.RFTelegrams
{
public enum AppCode
{
BUP = 0x00,
LAT = 0x01,
SEMI = 0x08,
LoggerTelegram = 0x09,
TestTelegram = 0x0A,
DEBUG = 0x0B,
EncapsulatedFlexNet = 0x10
}
}

View File

@ -0,0 +1,11 @@
namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.RFTelegrams
{
public enum DisplayUnits
{
NA = 0,
m3 = 19,
CF = 35,
GAL = 24,
IGAL = 144,
}
}

View File

@ -0,0 +1,35 @@
namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.RFTelegrams
{
using System;
public class Epoch20000101
{
private static readonly DateTime epoch = new DateTime(2000, 01, 01, 00, 00, 00, DateTimeKind.Utc);
private readonly byte[] bytes;
public Epoch20000101(DateTimeKind dateTimeKind = DateTimeKind.Utc)
=> this.bytes = new byte[4];
public Epoch20000101(uint secondsSince, DateTimeKind dateTimeKind = DateTimeKind.Utc) : this(dateTimeKind)
=> this.SecondsSince = secondsSince;
public uint SecondsSince
{
get => BitConverter.ToUInt32(this.bytes, 0);
set => BitConverter.GetBytes(value).CopyTo(this.bytes, 0);
}
public DateTime DateTime
{
get => epoch.AddSeconds(this.SecondsSince);
set => this.SecondsSince = (uint)(value - epoch).TotalSeconds;
}
public static uint UTCNow => new Epoch20000101 { DateTime = DateTime.UtcNow }.SecondsSince;
public static implicit operator DateTime(Epoch20000101 epoch) => epoch.DateTime;
public static implicit operator uint(Epoch20000101 epoch) => epoch.SecondsSince;
}
}

View File

@ -0,0 +1,623 @@
namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.RFTelegrams
{
using System;
using System.Collections.Generic;
public static class Extensions
{
private const int ByteSize = 8;
private const int SByteSize = 16;
private const int Int16Size = 16;
private const int UInt16Size = 16;
private const int Int32Size = 32;
private const int UInt32Size = 32;
private const int Int64Size = 64;
private const int UInt64Size = 64;
public static byte[] GetBitsBE(this byte value)
{
var bits = new byte[ByteSize];
for (int i = 7, x = 0; i >= 0; i--, x++)
{
bits[x] = (byte)((value >> i) & 1);
}
return bits;
}
public static byte[] GetBitsLE(this byte value)
{
var bits = new byte[ByteSize];
for (var i = 0; i < ByteSize; i++)
{
bits[i] = (byte)((value >> i) & 1);
}
return bits;
}
public static byte[] GetBitsLE(this ushort value)
{
var bits = new byte[UInt16Size];
for (var i = 0; i < UInt16Size; i++)
{
bits[i] = (byte)((value >> i) & 1);
}
return bits;
}
public static byte GetByteLE(this byte[] bits)
{
if (bits is null)
{
return default(byte);
}
var value = default(byte);
for (var i = 0; i < ByteSize; i++)
{
value ^= (byte)(bits[i] << i);
}
return value;
}
public static byte GetByteLE(this byte[] bits, int start = 0, int count = 0)
{
if (bits is null)
{
return default(byte);
}
if (count == 0)
{
count = bits.Length;
}
var length = start + count;
var _byte = default(byte);
for (int i = start, x = 0; i < length; i++, x++)
{
_byte ^= (byte)(bits[i] << x);
}
return _byte;
}
public static void SetBitsLE(this byte value, byte[] bits, int start = 0, int count = 0)
{
if (bits is null)
{
return;
}
if (count == 0 || count > bits.Length)
{
count = bits.Length;
}
for (int i = start, x = 0; i < count; i++, x++)
{
bits[i] = (byte)((value >> x) % 2);
}
}
public static byte[] GetBytesBE(this sbyte value)
{
var bytes = new byte[2];
var index = 0;
bytes[index++] = (byte)(value >> 8);
bytes[index] = (byte)value;
return bytes;
}
public static byte[] GetBytesBE(this short value)
{
var bytes = new byte[2];
var index = 0;
bytes[index++] = (byte)(value >> 8);
bytes[index] = (byte)value;
return bytes;
}
public static byte[] GetBytesBE(this int value)
{
var bytes = new byte[4];
var index = 0;
bytes[index++] = (byte)(value >> 24);
bytes[index++] = (byte)(value >> 16);
bytes[index++] = (byte)(value >> 8);
bytes[index] = (byte)value;
return bytes;
}
public static byte[] GetBytesBE(this long value)
{
var bytes = new byte[8];
var index = 0;
bytes[index++] = (byte)(value >> 56);
bytes[index++] = (byte)(value >> 48);
bytes[index++] = (byte)(value >> 40);
bytes[index++] = (byte)(value >> 32);
bytes[index++] = (byte)(value >> 24);
bytes[index++] = (byte)(value >> 16);
bytes[index++] = (byte)(value >> 8);
bytes[index] = (byte)value;
return bytes;
}
public static byte[] GetBytesBE(this ushort value)
{
var bytes = new byte[2];
var index = 0;
bytes[index++] = (byte)(value >> 8);
bytes[index] = (byte)value;
return bytes;
}
public static byte[] GetBytesBE(this uint value)
{
var bytes = new byte[4];
var index = 0;
bytes[index++] = (byte)(value >> 24);
bytes[index++] = (byte)(value >> 16);
bytes[index++] = (byte)(value >> 8);
bytes[index] = (byte)value;
return bytes;
}
public static byte[] GetBytesBE(this ulong value)
{
var bytes = new byte[8];
var index = 0;
bytes[index++] = (byte)(value >> 56);
bytes[index++] = (byte)(value >> 48);
bytes[index++] = (byte)(value >> 40);
bytes[index++] = (byte)(value >> 32);
bytes[index++] = (byte)(value >> 24);
bytes[index++] = (byte)(value >> 16);
bytes[index++] = (byte)(value >> 8);
bytes[index] = (byte)value;
return bytes;
}
public static byte[] GetBytesLE(this sbyte value)
{
var bytes = new byte[2];
var index = 0;
bytes[index++] = (byte)value;
bytes[index] = (byte)(value >> 8);
return bytes;
}
public static byte[] GetBytesLE(this short value)
{
var bytes = new byte[2];
var index = 0;
bytes[index++] = (byte)value;
bytes[index] = (byte)(value >> 8);
return bytes;
}
public static byte[] GetBytesLE(this int value)
{
var bytes = new byte[4];
var index = 0;
bytes[index++] = (byte)value;
bytes[index++] = (byte)(value >> 8);
bytes[index++] = (byte)(value >> 16);
bytes[index] = (byte)(value >> 24);
return bytes;
}
public static byte[] GetBytesLE(this long value)
{
var bytes = new byte[8];
var index = 0;
bytes[index++] = (byte)value;
bytes[index++] = (byte)(value >> 8);
bytes[index++] = (byte)(value >> 16);
bytes[index++] = (byte)(value >> 24);
bytes[index++] = (byte)(value >> 32);
bytes[index++] = (byte)(value >> 40);
bytes[index++] = (byte)(value >> 48);
bytes[index] = (byte)(value >> 56);
return bytes;
}
public static byte[] GetBytesLE(this ushort value)
{
var bytes = new byte[2];
var index = 0;
bytes[index++] = (byte)value;
bytes[index] = (byte)(value >> 8);
return bytes;
}
public static byte[] GetBytesLE(this uint value)
{
var bytes = new byte[4];
var index = 0;
bytes[index++] = (byte)value;
bytes[index++] = (byte)(value >> 8);
bytes[index++] = (byte)(value >> 16);
bytes[index] = (byte)(value >> 24);
return bytes;
}
public static byte[] GetBytesLE(this ulong value)
{
var bytes = new byte[8];
var index = 0;
bytes[index++] = (byte)value;
bytes[index++] = (byte)(value >> 8);
bytes[index++] = (byte)(value >> 16);
bytes[index++] = (byte)(value >> 24);
bytes[index++] = (byte)(value >> 32);
bytes[index++] = (byte)(value >> 40);
bytes[index++] = (byte)(value >> 48);
bytes[index] = (byte)(value >> 56);
return bytes;
}
public static sbyte ToSByteBE(this byte[] bytes, int start = 0)
{
var value = default(sbyte);
value ^= (sbyte)(bytes[start++] << 8);
value ^= (sbyte)bytes[start];
return value;
}
public static short ToInt16BE(this byte[] bytes, int start = 0)
{
var value = default(short);
value ^= (short)(bytes[start++] << 8);
value ^= bytes[start];
return value;
}
public static int ToInt32BE(this byte[] bytes, int start = 0)
{
var value = default(int);
value ^= bytes[start++] << 24;
value ^= bytes[start++] << 16;
value ^= bytes[start++] << 8;
value ^= bytes[start];
return value;
}
public static long ToInt64BE(this byte[] bytes, int start = 0)
{
var value = default(long);
value ^= bytes[start++] << 56;
value ^= bytes[start++] << 48;
value ^= bytes[start++] << 40;
value ^= bytes[start++] << 32;
value ^= bytes[start++] << 24;
value ^= bytes[start++] << 16;
value ^= bytes[start++] << 8;
value ^= bytes[start];
return value;
}
public static ushort ToUInt16BE(this byte[] bytes, int start = 0)
{
var value = default(ushort);
value ^= (ushort)(bytes[start++] << 8);
value ^= bytes[start];
return value;
}
public static uint ToUInt32BE(this byte[] bytes, int start = 0)
{
var value = default(uint);
value ^= (uint)(bytes[start++] << 24);
value ^= (uint)(bytes[start++] << 16);
value ^= (uint)(bytes[start++] << 8);
value ^= bytes[start];
return value;
}
public static ulong ToUInt64BE(this byte[] bytes, int start = 0)
{
var value = default(ulong);
value ^= (ulong)(bytes[start++] << 56);
value ^= (ulong)(bytes[start++] << 48);
value ^= (ulong)(bytes[start++] << 40);
value ^= (ulong)(bytes[start++] << 32);
value ^= (ulong)(bytes[start++] << 24);
value ^= (ulong)(bytes[start++] << 16);
value ^= (ulong)(bytes[start++] << 8);
value ^= bytes[start];
return value;
}
public static sbyte ToSByteLE(this byte[] bytes, int start = 0)
{
var value = default(sbyte);
value ^= (sbyte)bytes[start++];
value ^= (sbyte)(bytes[start] << 8);
return value;
}
public static short ToInt16LE(this byte[] bytes, int start = 0)
{
var value = default(short);
value ^= bytes[start++];
value ^= (short)(bytes[start] << 8);
return value;
}
public static int ToInt32LE(this byte[] bytes, int start = 0)
{
var value = default(int);
value ^= bytes[start++];
value ^= bytes[start++] << 8;
value ^= bytes[start++] << 16;
value ^= bytes[start] << 24;
return value;
}
public static long ToInt64LE(this byte[] bytes, int start = 0)
{
var value = default(long);
value ^= bytes[start++];
value ^= bytes[start++] << 8;
value ^= bytes[start++] << 16;
value ^= bytes[start++] << 24;
value ^= bytes[start++] << 32;
value ^= bytes[start++] << 40;
value ^= bytes[start++] << 48;
value ^= bytes[start] << 56;
return value;
}
public static ushort ToUInt16LE(this byte[] bytes, int start = 0)
{
var value = default(ushort);
value ^= bytes[start++];
value ^= (ushort)(bytes[start] << 8);
return value;
}
public static ushort ToUIint16LEFromBits(this byte[] bits)
{
if (bits is null)
{
bits = new byte[UInt16Size];
}
Array.Resize(ref bits, UInt16Size);
ushort value = 0;
for (var i = 0; i < UInt16Size; i++)
{
value ^= (ushort)(bits[i] << i);
}
return value;
}
public static uint ToUInt32LE(this byte[] bytes, int start = 0)
{
var value = default(uint);
value ^= bytes[start++];
value ^= (uint)(bytes[start++] << 8);
value ^= (uint)(bytes[start++] << 16);
value ^= (uint)(bytes[start] << 24);
return value;
}
public static ulong ToUInt64LE(this byte[] bytes, int start = 0)
{
var value = default(ulong);
value ^= bytes[start++];
value ^= (ulong)(bytes[start++] << 8);
value ^= (ulong)(bytes[start++] << 16);
value ^= (ulong)(bytes[start++] << 24);
value ^= (ulong)(bytes[start++] << 32);
value ^= (ulong)(bytes[start++] << 40);
value ^= (ulong)(bytes[start++] << 48);
value ^= (ulong)(bytes[start] << 56);
return value;
}
public static ushort CRCCCITT(this byte[] bytes, int start = 0, int length = 0)
{
if (length == 0)
{
length = bytes.Length;
}
var crc = (ushort)0xFFFF;
for (var b = start; b < length; b++)
{
var _byte = bytes[b];
var token = (ushort)((_byte << 8) & 0xFF00);
for (var i = 0; i < 8; i++)
{
if (0x8000 == ((crc ^ token) & 0x8000))
{
crc <<= 1;
crc ^= 0x1021;
}
else
{
crc <<= 1;
}
token <<= 1;
}
}
return crc;
}
public static byte[] GetBytes(this string hexString)
{
var bytes = new List<byte>();
if (!string.IsNullOrWhiteSpace(hexString))
{
// not needed, only valid hex bytes are processed // hexString = Regex.Replace(hexString, "[^a-fA-F0-9]*", string.Empty);
var first = true;
var x = 0;
foreach (var hex in hexString)
{
if ('0' <= hex && hex <= '9')
{
x += hex - '0';
}
else if ('A' <= hex && hex <= 'F')
{
x += hex - 'A' + 10;
}
else if ('a' <= hex && hex <= 'f')
{
x = hex - 'a' + 10;
}
else
{
continue;
}
if (first)
{
x *= 16;
}
else
{
bytes.Add((byte)x);
x = 0;
}
first = !first;
}
}
return bytes.ToArray();
}
public static byte[] GetEncryptionKey(this string hexString, int requiredLength = 16)
{
var bytes = hexString.GetBytes();
if (bytes?.Length != requiredLength)
{
return default(byte[]);
}
return bytes;
}
public static uint GetAddress(this byte[] bytes, int index)
{
var value = default(uint);
var _index = index;
value ^= (uint)(bytes[_index++] << 24);
value ^= (uint)(bytes[_index++] << 16);
value ^= (uint)(bytes[_index++] << 8);
value ^= bytes[_index];
return value;
}
public static ushort GetCrc(this byte[] bytes, int index)
{
var value = default(ushort);
var _index = index;
value ^= (ushort)(bytes[_index++] << 8);
value ^= bytes[_index];
return value;
}
public static void SetAddress(this byte[] bytes, int index, uint address)
{
var _index = index;
bytes[_index++] = (byte)(address >> 24);
bytes[_index++] = (byte)(address >> 16);
bytes[_index++] = (byte)(address >> 8);
bytes[_index] = (byte)address;
}
public static void SetCrc(this byte[] bytes, int index, ushort crc)
{
var _index = index;
bytes[_index++] = (byte)(crc >> 8);
bytes[_index] = (byte)crc;
}
}
}

View File

@ -0,0 +1,97 @@
namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.RFTelegrams
{
public class LogContent
{
private readonly byte[] bits = new byte[16];
public LogContent(ushort value = 0)
=> this.bits = value.GetBitsLE();
public bool ForwardCounter
{
get => this.bits[12] == 1;
set => this.bits[12] = (byte)(value ? 1 : 0);
}
public bool TimeOfMinimumFlow
{
get => this.bits[11] == 1;
set => this.bits[11] = (byte)(value ? 1 : 0);
}
public bool MinimumFlow
{
get => this.bits[10] == 1;
set => this.bits[10] = (byte)(value ? 1 : 0);
}
public bool TimeOfBrokenPipe
{
get => this.bits[9] == 1;
set => this.bits[9] = (byte)(value ? 1 : 0);
}
public bool BrokenPipeFlow
{
get => this.bits[8] == 1;
set => this.bits[8] = (byte)(value ? 1 : 0);
}
public bool CurrentFlow
{
get => this.bits[7] == 1;
set => this.bits[7] = (byte)(value ? 1 : 0);
}
public bool TimeOfPeakFlow
{
get => this.bits[6] == 1;
set => this.bits[6] = (byte)(value ? 1 : 0);
}
public bool PeakFlow
{
get => this.bits[5] == 1;
set => this.bits[5] = (byte)(value ? 1 : 0);
}
public bool TimeOfMaximumFlow
{
get => this.bits[4] == 1;
set => this.bits[4] = (byte)(value ? 1 : 0);
}
public bool MaximumFlow
{
get => this.bits[3] == 1;
set => this.bits[3] = (byte)(value ? 1 : 0);
}
public bool BackwardVolume
{
get => this.bits[2] == 1;
set => this.bits[2] = (byte)(value ? 1 : 0);
}
public bool Counter
{
get => this.bits[1] == 1;
set => this.bits[1] = (byte)(value ? 1 : 0);
}
public bool AlarmState
{
get => this.bits[0] == 1;
set => this.bits[0] = (byte)(value ? 1 : 0);
}
public override string ToString()
=> string.Join(string.Empty, this.bits);
public static implicit operator LogContent(ushort value)
=> new LogContent(value);
public static implicit operator ushort(LogContent value)
=> value.bits.ToUIint16LEFromBits();
}
}

View File

@ -0,0 +1,11 @@
namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.RFTelegrams
{
public enum MeterTypes : byte
{
Residential = 0,
CandI = 1,
Cordonel = 0x09,
Residential__0x0B = 11,
CandI__0x0C = 12,
}
}

View File

@ -0,0 +1,62 @@
namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.RFTelegrams
{
public class PAMStatus
{
private readonly byte[] bits;
public PAMStatus(byte _byte)
=> this.bits = _byte.GetBitsLE();
public bool CMD_UNKNOWN => this.bits[0] == 1;
public bool WRONG_AUTH => this.bits[1] == 1;
public bool EXPIRED_AUTH => this.bits[2] == 1;
public bool MIXED_TYPES => this.bits[3] == 1;
public bool OUT_OF_RANGE => this.bits[4] == 1;
public override string ToString()
{
if (this.bits.GetByteLE() == 0)
{
return nameof(OK);
}
if (this.OUT_OF_RANGE)
{
return nameof(this.OUT_OF_RANGE);
}
else if (this.MIXED_TYPES)
{
return nameof(this.MIXED_TYPES);
}
else if (this.CMD_UNKNOWN)
{
return nameof(this.CMD_UNKNOWN);
}
else if (this.EXPIRED_AUTH)
{
return nameof(this.EXPIRED_AUTH);
}
else if (this.WRONG_AUTH)
{
return nameof(this.WRONG_AUTH);
}
else
{
return string.Join(string.Empty, this.bits);
}
}
public static byte OK = 0;
public static byte EXPIREDAUTH = 4;
public static implicit operator byte(PAMStatus status)
=> status?.bits?.GetByteLE() ?? 0xFF;
public static implicit operator string(PAMStatus status)
=> status?.ToString();
}
}

View File

@ -0,0 +1,7 @@
namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.RFTelegrams.Pams
{
public class DummyPam
{
public static implicit operator byte[](DummyPam dummyPam) => new byte[0];
}
}

View File

@ -0,0 +1,70 @@
namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.RFTelegrams.Pams
{
public class ResetAlarms
{
private readonly byte[] bits;
public ResetAlarms(byte _byte = 0xFF)
=> this.bits = _byte.GetBitsLE();
public bool SpecificError
{
get => this.bits[0] == 1;
set => this.bits[0] = (byte)(value ? 1 : 0);
}
public bool MediumAbsent
{
get => this.bits[1] == 1;
set => this.bits[1] = (byte)(value ? 1 : 0);
}
public bool BrokenPipe
{
get => this.bits[2] == 1;
set => this.bits[2] = (byte)(value ? 1 : 0);
}
public bool Backflow
{
get => this.bits[3] == 1;
set => this.bits[3] = (byte)(value ? 1 : 0);
}
public bool MetrologyUnavailable
{
get => this.bits[4] == 1;
set => this.bits[4] = (byte)(value ? 1 : 0);
}
public bool MagneticTamper
{
get => this.bits[5] == 1;
set => this.bits[5] = (byte)(value ? 1 : 0);
}
public bool Leak
{
get => this.bits[6] == 1;
set => this.bits[6] = (byte)(value ? 1 : 0);
}
public bool LowBattery
{
get => this.bits[7] == 1;
set => this.bits[7] = (byte)(value ? 1 : 0);
}
public static implicit operator byte[] (ResetAlarms resetAlarms) => new byte[]
{
0x03,
resetAlarms.bits.GetByteLE(),
0x43,
0x01,
0x14,
0x30,
0x68,
0xD0
};
}
}

View File

@ -0,0 +1,86 @@
namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.RFTelegrams
{
using global::Common.Hardware.SIRT;
using global::Common.Hardware.SIRT.Tasks;
using System;
using System.Collections.Generic;
public class RFTask : WritePamTask
{
private readonly Stack<SIRTMessage> messages = new Stack<SIRTMessage>();
public SIRTMessage AKN { get; private set; }
public SIRTMessage BUP { get; private set; }
public SIRTMessage LAT { get; private set; }
public SIRTMessage DEBUG { get; private set; }
public SIRTMessage SEMI { get; private set; }
public SIRTMessage LastOrDefault()
=> this.messages.Count > 0
? this.messages.Peek()
: new SIRTMessage();
public override string ToString()
=> BitConverter.ToString(this.request.Payload);
protected override void OnMessageSent(SIRTMessage request)
=> this.messages.Push(request);
protected override void OnUnknownReceived(SIRTMessage unknown)
=> this.messages.Push(unknown);
protected override void OnAKNReceived(SIRTMessage akn)
{
this.AKN = akn;
this.messages.Push(akn);
}
protected override void OnBUPReceived(SIRTMessage bup)
{
this.BUP = bup;
this.messages.Push(bup);
}
protected override void OnLATReceived(SIRTMessage lat)
{
this.LAT = lat;
this.messages.Push(lat);
}
protected override void OnDEBUGReceived(SIRTMessage debug)
{
this.DEBUG = debug;
this.messages.Push(debug);
}
protected override void OnSEMIReceived(SIRTMessage semi)
{
this.SEMI = semi;
this.messages.Push(semi);
if (semi.Payload.Length > 11)
{
var pamStatus = new PAMStatus(semi.Payload[11]);
if (pamStatus == PAMStatus.OK)
{
base.OnSEMIReceived(semi);
}
else
{
this.SetError();
}
}
}
}
}

View File

@ -0,0 +1,42 @@
namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.RFTelegrams
{
public class RSSI
{
public RSSI(byte value, int mhz)
{
this.Value = value;
if (mhz == 433)
{
this.Dbm = value * 0.5 - 140;
this.Percent = value * 0.7333 - 57.6667;
}
else if (mhz == 868)
{
this.Dbm = value * 0.5 - 131.3;
this.Percent = value * 0.66 - 40.316;
}
if (this.Percent > 100)
{
this.Percent = 100;
}
else if (this.Percent < 0)
{
this.Percent = 0;
}
}
public byte Value { get; }
public double Dbm { get; }
public double Percent { get; }
public override string ToString() => $"{this.Dbm}dBm ({this.Percent:0.0}%)";
public static implicit operator byte(RSSI rssi) => rssi?.Value ?? 0;
public static implicit operator string(RSSI rssi) => rssi?.ToString();
}
}

View File

@ -0,0 +1,176 @@
namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.RFTelegrams
{
using Pams;
using System;
using System.Text;
/// <summary>
/// TODO: SEMI from the SirtDLL is not complete,
/// </summary>
public class SEMI
{
//public const int MIN_LENGTH = 120;
public const int MIN_LENGTH = 97;
public SEMI(byte[] payload, int mhz)
{
this.AppCode = (AppCode)payload[0];
this.Counter = payload[1];
this.Address = payload.ToUInt32BE(2);
this.Reading = payload.ToInt32BE(6);
this.MainAlarmByte = new ResetAlarms(payload[10]);
this.PAMStatus = new PAMStatus(payload[11]);
this.RSSI = new RSSI(payload[12], mhz);
this.MeterType = (MeterTypes)payload[13];
this.TransmissionInterval = payload.ToUInt16BE(14);
this.LATInterval = payload[16];
this.ActualFlow = payload.ToUInt16BE(17);
this.BackwardVolume = payload.ToUInt32BE(19);
this.Units = (DisplayUnits)payload[23];
this.MBusStatus = payload[24];
this.MBusTransmissionInterval = payload.ToUInt16BE(25);
this.MainAlarmMask = new ResetAlarms(payload[27]);
this.LeakageDetectionParameters = payload[28];
this.BrokenPipeDetectionParameters = payload[29];
this.BatteryRemainingYears = payload.ToUInt16BE(30) / (4D * 365);
this.ReminingBatteryCapacity = payload[32];
this.MaximumFlow = payload.ToUInt16BE(33);
this.TimeSinceMaximumFlow = payload.ToUInt16BE(35);
this.TimeSinceLowBattery = payload.ToUInt16BE(37);
this.AlarmLeakage = new Epoch20000101(payload.ToUInt32BE(39), DateTimeKind.Local);
this.AlarmAirInPipe = new Epoch20000101(payload.ToUInt32BE(43), DateTimeKind.Local);
this.AlarmReverseFlow = new Epoch20000101(payload.ToUInt32BE(47), DateTimeKind.Local);
this.AlarmBrokenPipe = new Epoch20000101(payload.ToUInt32BE(51), DateTimeKind.Local);
this.DataLogContent = payload.ToUInt16BE(55);
this.DataLoggingInterval = payload.ToUInt16BE(57);
this.FDRContent = payload.ToUInt16BE(59);
this.FDRDayOfMonth = payload[61];
this.ActualDateTime = new Epoch20000101(payload.ToUInt32BE(62), DateTimeKind.Local);
this.HistoricalErrorDays = payload[66];
this.CustomerSpecificText = Encoding.ASCII.GetString(payload, 67, 9);
this.TimeOfFDRReset = payload.ToUInt16BE(76);
this.TimeOfLogReset = payload.ToUInt16BE(78);
this.ActualPressure = payload.ToUInt16BE(80);
this.ActualTemperature = payload[82];
this.PressureParameter = Encoding.ASCII.GetString(payload, 83, 7);
this.TemperatureParameter = payload.ToInt32BE(90);
this.PulseOutParameter = payload[94];
this.AlarmByteExtended = payload[95];
this.AlarmMaskExtended = payload[96];
//this.AlarmMaxPressureTime = payload.ToUInt32BE(97);
//this.AlarmMinPressureTime = payload.ToUInt32BE(101);
//this.AlarmMaxTemperatureTime = payload.ToUInt32BE(105);
//this.AlarmMinTemperatureTime = payload.ToUInt32BE(109);
//this.LogContentPressureTemperature = payload.ToUInt16BE(113);
//this.FDRContentPressureTemperature = payload.ToUInt16BE(115);
//this.UnitExtraFlags = payload[117];
//this.MeterSize = payload[118];
//this.PressureCalibrationOffset = payload[119];
}
public AppCode AppCode { get; }
public byte Counter { get; }
public uint Address { get; }
public int Reading { get; }
public ResetAlarms MainAlarmByte { get; }
public PAMStatus PAMStatus { get; }
public RSSI RSSI { get; }
public MeterTypes MeterType { get; }
public ushort TransmissionInterval { get; }
public byte LATInterval { get; }
public ushort ActualFlow { get; }
public uint BackwardVolume { get; }
public DisplayUnits Units { get; }
public byte MBusStatus { get; }
public ushort MBusTransmissionInterval { get; }
public ResetAlarms MainAlarmMask { get; }
public byte LeakageDetectionParameters { get; }
public byte BrokenPipeDetectionParameters { get; }
public double BatteryRemainingYears { get; }
public byte ReminingBatteryCapacity { get; }
public ushort MaximumFlow { get; }
public ushort TimeSinceMaximumFlow { get; }
public ushort TimeSinceLowBattery { get; }
public DateTime AlarmLeakage { get; }
public DateTime AlarmAirInPipe { get; }
public DateTime AlarmReverseFlow { get; }
public DateTime AlarmBrokenPipe { get; }
public LogContent DataLogContent { get; }
public ushort DataLoggingInterval { get; }
public LogContent FDRContent { get; }
public byte FDRDayOfMonth { get; }
public DateTime ActualDateTime { get; }
public byte HistoricalErrorDays { get; }
public string CustomerSpecificText { get; }
public ushort TimeOfFDRReset { get; }
public ushort TimeOfLogReset { get; }
public ushort ActualPressure { get; }
public byte ActualTemperature { get; }
public string PressureParameter { get; }
public int TemperatureParameter { get; }
public byte PulseOutParameter { get; }
public byte AlarmByteExtended { get; }
public byte AlarmMaskExtended { get; }
//public uint AlarmMaxPressureTime { get; }
//public uint AlarmMinPressureTime { get; }
//public uint AlarmMaxTemperatureTime { get; }
//public uint AlarmMinTemperatureTime { get; }
//public ushort LogContentPressureTemperature { get; }
//public ushort FDRContentPressureTemperature { get; }
//public byte UnitExtraFlags { get; }
//public byte MeterSize { get; }
//public byte PressureCalibrationOffset { get; }
}
}

View File

@ -0,0 +1,201 @@
namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.RFTelegrams
{
using CommonConsole.RFTelegrams.Pams;
using global::Common.Hardware.SIRT;
using global::Common.Hardware.SIRT.Tasks;
using Pams;
using System;
internal class SIRTServer
{
private static Action<string> messageCallback;
private static Action<string> errorMessageCallback;
private static readonly SIRTHub sirtHub = new SIRTHub();
/// <summary>
/// Connects SIRT's globaly for the application
/// </summary>
/// <param name="messageHandler">Action that receives info messages</param>
/// <param name="errorMessageHandler">Action that receives error messages</param>
/// <param name="comPorts">The COM-Ports to be connected</param>
/// <returns><c>true</c> - if all ports connected otherwise <c>false</c></returns>
public static bool StartServer(Action<string> messageHandler, Action<string> errorMessageHandler, params int[] comPorts)
{
string sirtId;
int frequency;
bool succeeded = true;
messageHandler?.Invoke(new string('-', 100));
foreach (var comport in comPorts)
{
succeeded = ConnectSIRT(comport, out sirtId, out frequency);
if (succeeded)
{
messageHandler?.Invoke($"COM{comport}|{sirtId}|{frequency}MHz - connected");
messageHandler?.Invoke(new string('-', 100));
}
else
{
errorMessageHandler?.Invoke($"SIRT at COM{comport} not connected!");
errorMessageHandler?.Invoke(new string('-', 100));
break;
}
}
if (succeeded)
{
messageCallback = messageHandler;
errorMessageCallback = errorMessageHandler;
}
return succeeded;
}
public static bool StartProgramming(int frequency, uint address, string encryptionKey, int repeatsCount = 3)
{
var succeeded = true;
var encryptionBytes = encryptionKey.GetBytes();
if (succeeded)
{
succeeded = SendPAM(task =>
{
task.WakeUpCmd = true;
task.DelPamSemi = true;
task.WakeUpModul = true;
task.IsEncrypted = true;
task.Frequency = frequency;
task.RequestAddress = address;
task.EncryptionKey = encryptionBytes;
task.Data = new DummyPam();
}
, repeatsCount);
}
if (succeeded)
{
succeeded = SendPAM(task =>
{
task.DelPamSemi = true;
task.IsEncrypted = true;
task.Frequency = frequency;
task.RequestAddress = address;
task.EncryptionKey = encryptionBytes;
task.Data = new ResetAlarms(0xFF);
}
, repeatsCount);
}
if (succeeded)
{
succeeded = SendPAM(task =>
{
task.DelPamSemi = true;
task.IsEncrypted = true;
task.Frequency = frequency;
task.RequestAddress = address;
task.EncryptionKey = encryptionBytes;
task.Data = new ResetAlarms(0xFE);
}
, repeatsCount);
}
//if (succeeded)
//{
// succeeded = SendPAM(task =>
// {
// task.DelPamSemi = true;
// task.IsEncrypted = true;
// task.Frequency = frequency;
// task.RequestAddress = address;
// task.EncryptionKey = encryptionBytes;
// task.Data = ChangeWakeUp.GoSleepAutoOn;
// }
// , repeatsCount);
//}
return succeeded;
}
/// <summary>
/// Dispose all SIRT's globaly for the application.
/// </summary>
public static void Dispose()
{
void LogState(object state) => messageCallback?.Invoke(state?.ToString());
sirtHub.StateLogging += LogState;
sirtHub.Stop();
sirtHub.StateLogging -= LogState;
messageCallback = null;
errorMessageCallback = null;
}
private static bool ConnectSIRT(int portno, out string sirtId, out int frequency)
=> sirtHub.TryOpen($"COM{portno}", out sirtId, out frequency);
private static bool SendPAM(Action<RFTask> taskOptions, int repeatsCount = 3)
{
void LogMessage(SIRTMessage message) => messageCallback?.Invoke(message.ToString());
var dashes = new string('-', 100);
var cordonelTask = new RFTask();
var succeeded = false;
taskOptions(cordonelTask);
cordonelTask.MessageSent += LogMessage;
cordonelTask.MessageReceived += LogMessage;
for (var i = 1; i <= repeatsCount && cordonelTask.State != SIRTTaskState.Completed && cordonelTask.State != SIRTTaskState.Cancelled; i++)
{
if (sirtHub.Start(cordonelTask))
{
cordonelTask.Wait();
}
}
cordonelTask.MessageReceived -= LogMessage;
cordonelTask.MessageSent -= LogMessage;
if (cordonelTask.State == SIRTTaskState.Completed)
{
succeeded = true;
messageCallback?.Invoke($"{"CMD",20}: {cordonelTask}");
messageCallback?.Invoke($"{"State",20}: {cordonelTask.State}");
var pam = new PAMStatus(cordonelTask.SEMI.Payload[11]);
messageCallback?.Invoke($"{"PAM Status",20}: {pam}");
var alarm = new AlarmMask(cordonelTask.SEMI.Payload[10]);
messageCallback?.Invoke(alarm.ToString());
messageCallback?.Invoke(dashes);
var semi = new SEMI(cordonelTask.SEMI.Payload, 868);
}
else
{
succeeded = false;
messageCallback?.Invoke($"{"CMD",20}: {cordonelTask}");
messageCallback?.Invoke($"{"State",20}: {cordonelTask.State}");
var pam = new PAMStatus(cordonelTask.SEMI.Payload[11]);
messageCallback?.Invoke($"{"PAM Status",20}: {pam}");
var alarm = new AlarmMask(cordonelTask.SEMI.Payload[10]);
messageCallback?.Invoke(alarm.ToString());
messageCallback?.Invoke(dashes);
}
return succeeded;
}
}
}

View File

@ -21,7 +21,7 @@
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DefineConstants>TRACE;DEBUG</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<LangVersion>7.0</LangVersion>
@ -38,7 +38,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == '_MANUAL_CONTROL|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\_MANUAL_CONTROL\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DefineConstants>TRACE;DEBUG</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
@ -81,6 +81,25 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug-local IIS-CUST|x64'">
<OutputPath>bin\x64\Debug-local IIS-CUST\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\VPN_Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG;URI_OLD_DNS</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<LangVersion>7.0</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.0</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.13.0.3\lib\net40\Newtonsoft.Json.dll</HintPath>
@ -98,12 +117,17 @@
<Link>Properties\SharedAssemblyInfo.cs</Link>
</Compile>
<Compile Include="ServiceUrls.cs" />
<Compile Include="ServiceUrlsBackUp_New.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PreBuildEvent>
</PreBuildEvent>
</PropertyGroup>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">

View File

@ -0,0 +1,871 @@
using System;
using System.Configuration;
namespace Xylem.Common.CommonCore.Configuration
{
/// <summary>
/// Urls for data base accesses
/// </summary>
public static class ServiceUrls
{
//#if URI_OLD_DNS // this is defined in build configuration 'VPN_Debug' as the new DNS cannot be reached via VPN
// private const String ServerDns = "http://sla12iis01.emea.sensus.net";
//#else
private const String ServerDns = "http://delaz1web01.world.fluidtechnology.net";
//#endif
private static readonly String DefaultInspectCordonelRequirementInfoUrl =
$"http://sla12iis01.emea.sensus.net/LaaProductionWeb/";
// return code: 404 not found, 400 Error with text, 200 okay
private static readonly String DefaultEolDataForSentinelServiceUrl =
$"http://sla12iis01.emea.sensus.net/LaaProductionWeb/api/cordonel/eolprogress/";
private static readonly String DefaultGetPcbIdsFromSafeServiceUrl =
$"{ServerDns}/MeterProcessState/GetPcbIdsFromSafe?ContainerDbId=";
private static readonly String DefaultGetExportDataServiceUrl =
$"{ServerDns}/MeterProcessState/api/Password/GetExportData?PcbId=";
private static readonly String DefaultGetCordonelMappingServiceUrl =
$"{ServerDns}/MeterProcessState/api/Order/GetCordonelMapping?PcbId=";
private static readonly String DefaultAddPcbIdsToSafeServiceUrl =
$"{ServerDns}/MeterProcessState/AddPcbIdsToSafe?ContainerDbId=";
private static readonly String DefaultGetOrderOverviewServiceUrl =
$"{ServerDns}/MeterProcessState/api/FinalCheck/GetOrderOverview?ProductionOrderNumber=";
private static readonly String DefaultGetOrderDetailsServiceUrl =
$"{ServerDns}/MeterProcessState/api/FinalCheck/GetOrderDetails?ProductionOrderNumber=";
private static readonly String DefaultDownloadFilesPartsServiceUrl =
$"{ServerDns}/MeterProcessState/api/FileUpToDate/GetFileParts?ParentFileId=";
private static readonly String DefaultGetLutUrl =
$"{ServerDns}/MeterProcessState/api/FileUpToDate/GetLutFiles";
private static readonly String DefaultListAllFwPackagesServiceUrl =
$"{ServerDns}/MeterProcessState/api/FileUpToDate/GetFwFiles?FileIsForDeveloperOnly=false&FileCategoryID=1";
private static readonly String DefaultListAllSwPackagesServiceUrl =
$"{ServerDns}/MeterProcessState/api/FileUpToDate/GetFwFiles?FileIsForDeveloperOnly=false&FileCategoryID=5";
private static readonly String DefaultListAllConfigFilePackagesServiceUrl =
$"{ServerDns}/MeterProcessState/api/FileUpToDate/GetFwFiles?FileIsForDeveloperOnly=false&FileCategoryID=6";
private static readonly String DefaultListAllFwUpdateSafesServiceUrl =
$"{ServerDns}/MeterProcessState/api/FileUpToDate/GetFwFiles?FileIsForDeveloperOnly=false&FileCategoryID=4";
private static readonly String DefaultSetCordonelAppVersionServiceUrl =
$"{ServerDns}/MeterProcessState/api/ProccesState/SetCordonelProgress?PcbId=";
private static readonly String DefaultGetCordonelRequirementInfoUrl =
"http://sla12iis01.emea.sensus.net/LaaProductionWeb/api/cordonel/requirements/pcbid/";
private static readonly String DefaultGetCordonelAppVersionServiceUrl =
$"{ServerDns}/MeterProcessState/api/ProccesState/GetCordonelAppVersion?PcbId=";
private static readonly String DefaultListAllCordonelCustomersWithFilterServiceUrl =
$"{ServerDns}/MeterProcessState/api/Order/GetCordonelCustomers?FilterName=";
private static readonly String DefaultListAllCordonelCustomerOrdersServiceUrl =
$"{ServerDns}/MeterProcessState/api/Order/GetCustomersCordonelOrders?CustomerNumber=";
private static readonly String DefaultListCordonelOrderDetailsServiceUrl =
$"{ServerDns}/MeterProcessState/api/Order/GetCordonelOrderDetails?OrderNr=";
private static readonly String DefaultListAllOrderCordonelsServiceUrl =
$"{ServerDns}/MeterProcessState/api/Order/GetCordonelOrderList?CustomerOrderNumber=";
private static readonly String DefaultDownloadFwUpdateSafeServiceUrl =
$"{ServerDns}/MeterProcessState/GetFWUpdateSafeContainerContent?SafeContainerId=";
private static readonly String DefaultListAllFwUpdateSafesForUserServiceUrl =
$"{ServerDns}/MeterProcessState/GetFWUpdateSafeContainers?UserId=";
private static readonly String DefaultFileContentDownloadServiceUrl =
$"{ServerDns}/MeterProcessState/GetFileContent?FileId=";
private static readonly String DefaultFwUpdateReportUploadServiceUrl =
$"{ServerDns}/MeterProcessState/PostFWUpdateReportFile";
private static readonly String DefaultFwUpdateReportDownloadServiceUrl =
$"{ServerDns}/MeterProcessState/GetFWUpdateReportFile?";
private static readonly String DefaultFwUpdateSafeContainerUploadServiceUrl =
$"{ServerDns}/MeterProcessState/PostFWUpdateSafeOdd";
private static readonly String DefaultEditFwUpdateUserValidityServiceUrl =
$"{ServerDns}/MeterProcessState/EditUserValidity?Id=";
private static readonly String DefaultRefreshFwUpdateUsersHardwareIdServiceUrl =
$"{ServerDns}/MeterProcessState/RefreshUsersHardwareId?Id=";
private static readonly String DefaultRefreshFwUpdateUsersPasswordHashServiceUrl =
$"{ServerDns}/MeterProcessState/RefreshUsersPasswordHash?Id=";
private static readonly String DefaultCreateNewFwUpdateUserServiceUrl =
$"{ServerDns}/MeterProcessState/AddNewUser?";
private static readonly String DefaultListAllFwUpdateUsersServiceUrl =
$"{ServerDns}/MeterProcessState/GetUserList";
private static readonly String DefaultListAllFwUpdateBuilderOperatorsServiceUrl =
$"{ServerDns}/MeterProcessState/GetAllBuilderOperator";
private static readonly String DefaultGetFwUpdateUserByIdServiceUrl =
$"{ServerDns}/MeterProcessState/GetUserList?Id=";
private static readonly String DefaultGetFwUpdateUserByLoginNameServiceUrl =
$"{ServerDns}/MeterProcessState/GetUserList?LogInName=";
private static readonly String DefaultRegisterWatchServiceUrl =
$"{ServerDns}/MeterProcessState/api/RegisterWatch/";
private static readonly String DefaultGenesisGetOrderNumberServiceUrl =
$"{ServerDns}/MeterProcessState/api/Password/ordernumber?PcbId=";
private static readonly String DefaultGenesisGetRadioAddressServiceUrl =
$"{ServerDns}/MeterProcessState/api/Password/radioadress?PcbId=";
private static readonly String DefaultGenesisGetKeySetIdServiceUrl =
$"{ServerDns}/MeterProcessState/api/Password/getkeysetid?PcbId=";
private static readonly String DefaultGenesisSetPickingStateServiceUrl =
$"{ServerDns}/MeterProcessState/api/ProccesState/SetPickingState?PcbID=";
private static readonly String DefaultGenesisGetPasswordServiceUrl =
$"{ServerDns}/MeterProcessState/api/Password/GetPassword?PcbId=";
private static readonly String DefaultGenesisSetPasswordServiceUrl =
$"{ServerDns}/MeterProcessState/api/Password/setpassword?PcbId=";
private static readonly String DefaultGenesisPasswordContainerServiceUrl =
$"{ServerDns}/MeterProcessState/api/Password/GetPasswordHashFileContent?PcbId=";
private static readonly String DefaultMarriageServiceUrl =
$"{ServerDns}/MeterProcessState/api/Marriage/";
private static readonly String DefaultMeterProcessStateUrl =
$"{ServerDns}/MeterProcessState/api/ProccesState/";
private static readonly String DefaultGenesisFinalCheckServiceUrl =
$"{ServerDns}/MeterProcessState/api/FinalCheck/";
private static readonly String DefaultGenesisRadioCheckServiceUrl =
$"{ServerDns}/MeterProcessState/api/RadioCheck/";
private static readonly String DefaultGetSoftwareStartUpAccessUrl =
$"{ServerDns}/MeterProcessState/api/SoftwareAccess/GetVersionIsValid";
private static readonly String DefaultSetSoftwareLicenseUrl =
$"{ServerDns}/MeterProcessState/api/SoftwareAccess/SetVersionIsValid?Program=";
private static readonly String DefaultGetSoftwareLicenseUrl =
$"{ServerDns}/MeterProcessState/api/SoftwareAccess/GetCurrentVersion?Program=";
private static readonly String DefaultGenesisCalibrationResult =
$"{ServerDns}/MeterProcessState/api/GenesisMeter/PostCalibrationResult";
private static readonly String DefaultGetGenesisCalibrationResults =
$"{ServerDns}/MeterProcessState/api/FinalCheck/CalibrationResults/";
private static readonly String DefaultGenesisMeter =
$"{ServerDns}/MeterProcessState/api/GenesisMeter/";
private static readonly String DefaultFileContentController =
$"{ServerDns}/MeterProcessState/api/FileUpToDate/";
private static readonly String DefaultKeyServerCustom =
"https://nodes.sms-esaap.com/keygenproxy/api/v3/custom/";
private static readonly String DefaultMeterInfoForTestBench =
$"{ServerDns}/MeterProcessState/api/TestBench/GetMeterInfoForTestBench?PcbID=";
private static readonly String DefaultCordonelFwInfoUrl =
$"{ServerDns}/MeterProcessState/api/FileUpToDate/GetCordonelFw";
private static readonly String DefaultDbDataAtEolServiceUrl =
$"http://sla12iis01.emea.sensus.net/MeterProcessState/api/fwupdate/databaseateol/";
public static readonly String PressureSensorTestURL_GetTestSpec
= $"{ServerDns}/MeterProcessState/api/CordonelPressureSensorTest/GetTestSpec";
public static readonly String PressureSensorTestURL_PostTestResults
= $"{ServerDns}/MeterProcessState/api/CordonelPressureSensorTest/PostTestResults";
/// <summary>
/// usage: string.Format(CordonelPressureSensorTestURL_GetTestResults, pcbId);
/// </summary>
public static readonly String PressureSensorTestURL_GetTestResults
= $"{ServerDns}/MeterProcessState/api/CordonelPressureSensorTest/GetTestResults/{0}";
public const String LaaProductionAPI
#if DEBUG == false // when false uses always the production url.
= "http://localhost:52822";
#else
= "http://sla12iis01.emea.sensus.net";
#endif
/// <summary>
/// GET: test specification for water meter with pressure sensor.
/// </summary>
public static String GetPressureSensorSpecificationURL
#if DEBUG
=> "http://localhost:56011/api/CordonelPressureSensorTest/GetTestSpec";
#else
=> ConfigurationManager.AppSettings[nameof(GetPressureSensorSpecificationURL)]
?? PressureSensorTestURL_GetTestSpec;
#endif
/// <summary>
/// POST: test result for water meter with pressure sensor.
/// </summary>
public static String PostPressureSensorResultURL
#if DEBUG
=> "http://localhost:56011/api/CordonelPressureSensorTest/PostTestResults";
public static String Q3CalibrationResultURL { get; set; }
#else
=> ConfigurationManager.AppSettings[nameof(PostPressureSensorResultURL)]
?? PressureSensorTestURL_PostTestResults;
#endif
/// <summary>
/// GET: a list of test results for the water meter with specified pcbId.
/// </summary>
public static String PressureSensorResultsURL<T>(this T pcbId)
{
#if DEBUG
var url = "http://localhost:56011/api/CordonelPressureSensorTest/GetTestResults/{0}";
#else
var url = ConfigurationManager.AppSettings[nameof(PressureSensorResultsURL)] ?? PressureSensorTestURL_GetTestResults;
#endif
return string.Format(url, pcbId);
}
/// <summary>
/// Get export data
/// </summary>
/// <returns></returns>
public static String GetExportDataServiceUrl()
{
return ConfigurationManager.AppSettings["GetExportDataServiceUrl"] ??
DefaultGetExportDataServiceUrl;
}
/// <summary>
/// Get Cordonel mapping
/// </summary>
/// <returns></returns>
public static String GetCordonelMappingServiceUrl()
{
return ConfigurationManager.AppSettings["GetCordonelMappingServiceUrl"] ??
DefaultGetCordonelMappingServiceUrl;
}
/// <summary>
/// Get Cordonel order overview to check the assignment state
/// </summary>
/// <returns></returns>
public static String GetOrderOverviewServiceUrl()
{
return ConfigurationManager.AppSettings["GetOrderOverviewServiceUrl"] ??
DefaultGetOrderOverviewServiceUrl;
}
/// <summary>
/// Get Cordonel order details to check for order dependent requirements like
/// - MeterSize,
/// - FrequencyIndicator,
/// - PressurePresent.
/// </summary>
/// <returns></returns>
public static String GetOrderDetailsServiceUrl()
{
return ConfigurationManager.AppSettings["GetOrderDetailsServiceUrl"] ??
DefaultGetOrderDetailsServiceUrl;
}
/// <summary>
/// List all Cordonel FW packages.
/// </summary>
/// <returns></returns>
public static String GetLutUrl()
{
return ConfigurationManager.AppSettings["GetLutUrl"] ??
DefaultGetLutUrl;
}
/// <summary>
/// List all Cordonel FW packages.
/// </summary>
/// <returns></returns>
public static String ListAllCordonelFwPackagesUrl()
{
return ConfigurationManager.AppSettings["CordonelFwInfoUrl"] ??
DefaultCordonelFwInfoUrl;
}
/// <summary>
/// List all PCB IDs from a safe. As the safe may be deleted, this information is still accessible.
/// </summary>
/// <returns></returns>
public static String MeterInfoForTestBench()
{
return ConfigurationManager.AppSettings["MeterInfoForTestBenchServiceUrl"] ??
DefaultMeterInfoForTestBench;
}
/// <summary>
/// List all PCB IDs from a safe. As the safe may be deleted, this information is still accessible.
/// </summary>
/// <returns></returns>
public static String ListAllPcbIdsFromSafe()
{
return ConfigurationManager.AppSettings["GetPcbIdsFromSafeServiceUrl"] ??
DefaultGetPcbIdsFromSafeServiceUrl;
}
/// <summary>
/// Add PCB IDs to a safe. As the safe may be deleted, this information is still accessible.
/// </summary>
/// <returns></returns>
public static String AddPcbIdsToSafeServiceUrl()
{
return ConfigurationManager.AppSettings["AddPcbIdsToSafeServiceUrl"] ??
DefaultAddPcbIdsToSafeServiceUrl;
}
/// <summary>
/// Get all Cordonel FW package.
/// </summary>
/// <returns></returns>
public static String DownloadFileParts()
{
return ConfigurationManager.AppSettings["DownloadFilePartsServiceUrl"] ??
DefaultDownloadFilesPartsServiceUrl;
}
/// <summary>
/// FW-Update Safe container list for specific user
/// </summary>
/// <returns></returns>
public static String ListAllFwUpdateSafesForUserServiceUrl()
{
return ConfigurationManager.AppSettings["ListAllFwUpdateSafesForUserServiceUrl"] ??
DefaultListAllFwUpdateSafesForUserServiceUrl;
}
/// <summary>
/// FW-Update Safe container
/// </summary>
/// <returns></returns>
public static String DownloadFwUpdateSafeServiceUrl()
{
return ConfigurationManager.AppSettings["DownloadFwUpdateSafeServiceUrl"] ??
DefaultDownloadFwUpdateSafeServiceUrl;
}
/// <summary>
/// Download the EOL logging data for power correction of overestimated power consumption
/// </summary>
/// <returns></returns>
public static String DownloadDbDataAtEolServiceUrl()
{
return ConfigurationManager.AppSettings["DownloadDbDataAtEolServiceUrl"] ??
DefaultDbDataAtEolServiceUrl;
}
/// <summary>
/// Get EOL data for sentinel
/// </summary>
/// <returns></returns>
public static String EolDataForSentinelServiceUrl()
{
return ConfigurationManager.AppSettings["EolDataForSentinelServiceUrl"] ??
DefaultEolDataForSentinelServiceUrl;
}
/// <summary>
/// Get all Cordonel safes description files.
/// </summary>
/// <returns></returns>
public static String ListAllFwUpdateSafes()
{
return ConfigurationManager.AppSettings["ListAllFwUpdateSafesServiceUrl"] ??
DefaultListAllFwUpdateSafesServiceUrl;
}
/// <summary>
/// Get all Cordonel FW package description files.
/// </summary>
/// <returns></returns>
public static String ListAllFwPackages()
{
return ConfigurationManager.AppSettings["ListAllFwPackagesServiceUrl"] ??
DefaultListAllFwPackagesServiceUrl;
}
/// <summary>
/// Get all Cordonel FW update SW package description files.
/// </summary>
/// <returns></returns>
public static String ListAllSwPackages()
{
return ConfigurationManager.AppSettings["ListAllSwPackagesServiceUrl"] ??
DefaultListAllSwPackagesServiceUrl;
}
/// <summary>
/// Get all Cordonel FW update SW package description files.
/// </summary>
/// <returns></returns>
public static String ListAllConfigurationFilePackages()
{
return ConfigurationManager.AppSettings["ListAllConfigFilePackagesServiceUrl"] ??
DefaultListAllConfigFilePackagesServiceUrl;
}
/// <summary>
/// Set all applications versions installed to a specific Cordonel.
/// </summary>
/// <returns></returns>
public static String UploadCordonelAppVersionServiceUrl()
{
return ConfigurationManager.AppSettings["SetCordonelAppVersionServiceUrl"] ??
DefaultSetCordonelAppVersionServiceUrl;
}
/// <summary>
/// Inspect a specific requirement (read only).
/// </summary>
/// <returns></returns>
public static String InspectCordonelRequirementInfoServiceUrl()
{
return ConfigurationManager.AppSettings["InspectCordonelRequirementInfoServiceUrl"] ??
DefaultInspectCordonelRequirementInfoUrl;
}
/// <summary>
/// Get all production infos for skip process checks or limits for production like:
/// - Battery drained percentage upper limit,
/// - Production due date for a special register,
/// - Required lifetime for assembly line,
/// - Required lifetime for shipping line.
/// </summary>
/// <returns></returns>
public static String GetCordonelRequirementInfoServiceUrl()
{
return ConfigurationManager.AppSettings["GetCordonelRequirementInfoServiceUrl"] ??
DefaultGetCordonelRequirementInfoUrl;
}
/// <summary>
/// Get all production infos for skip process checks or limits for production like:
/// - Battery drained percentage upper limit,
/// - Production due date for a special register,
/// - Required lifetime for assembly line,
/// - Required lifetime for shipping line.
/// </summary>
/// <returns></returns>
public static String GetCordonelRequirementByFANrInfoServiceUrl(String ponr)
{
return $"http://sla12iis01.emea.sensus.net/LaaProductionWeb/api/cordonel/requirements/pono/{ponr}";
}
/// <summary>
/// Get all production infos for skip process checks or limits for production like:
/// - Battery drained percentage upper limit,
/// - Production due date for a special register,
/// - Required lifetime for assembly line,
/// - Required lifetime for shipping line.
/// </summary>
/// <returns></returns>
public static String GetCordonelRequirementByMeterSizeInfoServiceUrl(Int32 size)
{
return $"http://sla12iis01.emea.sensus.net/LaaProductionWeb/api/cordonel/requirements/isize/{size}";
}
/// <summary>
/// Get all applications versions installed to a specific Cordonel.
/// </summary>
/// <returns></returns>
public static String DownloadCordonelAppVersionServiceUrl()
{
return ConfigurationManager.AppSettings["GetCordonelAppVersionServiceUrl"] ??
DefaultGetCordonelAppVersionServiceUrl;
}
/// <summary>
/// List all Cordonel customers with search filter (e.g. %sus% where % is a filter for 0 to multiple
/// alphanumeric characters) to get the customer names and the order numbers.
/// </summary>
/// <returns></returns>
public static String ListAllCordonelCustomersWithFilterServiceUrl()
{
return ConfigurationManager.AppSettings["ListAllCordonelCustomersWithFilterServiceUrl"] ??
DefaultListAllCordonelCustomersWithFilterServiceUrl;
}
/// <summary>
/// Get Cordonel order details to capture the production order
/// </summary>
/// <returns></returns>
public static String ListCordonelOrderDetailsServiceUrl()
{
return ConfigurationManager.AppSettings["ListCordonelOrderDetailsServiceUrl"] ??
DefaultListCordonelOrderDetailsServiceUrl;
}
/// <summary>
/// List all Cordonel orders of a selected customer
/// </summary>
/// <returns></returns>
public static String ListAllCordonelCustomerOrdersServiceUrl()
{
return ConfigurationManager.AppSettings["ListAllCordonelCustomerOrdersServiceUrl"] ??
DefaultListAllCordonelCustomerOrdersServiceUrl;
}
/// <summary>
/// List all Cordonels of a specific order number to get the customer serial number and the Pcb ID.
/// </summary>
/// <returns></returns>
public static String ListAllOrderCordonelsServiceUrl()
{
return ConfigurationManager.AppSettings["ListAllOrderCordonelsServiceUrl"] ??
DefaultListAllOrderCordonelsServiceUrl;
}
/// <summary>
/// Register watch service
/// </summary>
/// <returns></returns>
public static String RegisterWatchServiceUrl()
{
return ConfigurationManager.AppSettings["RegisterWatchServiceUrl"] ??
DefaultRegisterWatchServiceUrl;
}
/// <summary>
/// File content download
/// </summary>
/// <returns></returns>
public static String DownloadFileContentServiceUrl()
{
return ConfigurationManager.AppSettings["FileContentDownloadServiceUrl"] ??
DefaultFileContentDownloadServiceUrl;
}
/// <summary>
/// FW-Update report download as string
/// </summary>
/// <returns></returns>
public static String DownloadFwUpdateReportServiceUrl()
{
return ConfigurationManager.AppSettings["FwUpdateReportDownloadServiceUrl"] ??
DefaultFwUpdateReportDownloadServiceUrl;
}
/// <summary>
/// FW-Update report upload as string
/// </summary>
/// <returns></returns>
public static String UploadFwUpdateReportServiceUrl()
{
return ConfigurationManager.AppSettings["FwUpdateReportUploadServiceUrl"] ??
DefaultFwUpdateReportUploadServiceUrl;
}
/// <summary>
/// FW-Update Safe container upload
/// </summary>
/// <returns></returns>
public static String UploadFwUpdateSafeContainerServiceUrl()
{
return ConfigurationManager.AppSettings["FwUpdateSafeContainerUploadServiceUrl"] ??
DefaultFwUpdateSafeContainerUploadServiceUrl;
}
/// <summary>
/// FW-Update user validation url
/// </summary>
/// <returns></returns>
public static String EditFwUpdateUserValidityServiceUrl()
{
return ConfigurationManager.AppSettings["EditFwUpdateUserValidityServiceUrl"] ??
DefaultEditFwUpdateUserValidityServiceUrl;
}
/// <summary>
/// FW-Update user HW-Id url
/// </summary>
/// <returns></returns>
public static String RefreshFwUpdateUsersHardwareIdServiceUrl()
{
return ConfigurationManager.AppSettings["RefreshFwUpdateUsersHardwareIdServiceUrl"] ??
DefaultRefreshFwUpdateUsersHardwareIdServiceUrl;
}
/// <summary>
/// FW-Update user password hash for encryption url
/// </summary>
/// <returns></returns>
public static String RefreshFwUpdateUsersPasswordHashServiceUrl()
{
return ConfigurationManager.AppSettings["RefreshFwUpdateUsersPasswordHashServiceUrl"] ??
DefaultRefreshFwUpdateUsersPasswordHashServiceUrl;
}
/// <summary>
/// FW-Update create new user url
/// </summary>
/// <returns></returns>
public static String CreateNewFwUpdateUserServiceUrl()
{
return ConfigurationManager.AppSettings["CreateNewFwUpdateUserServiceUrl"] ??
DefaultCreateNewFwUpdateUserServiceUrl;
}
/// <summary>
/// FW-Update list all users url
/// </summary>
/// <returns></returns>
public static String ListAllFwUpdateUsersServiceUrl()
{
return ConfigurationManager.AppSettings["ListAllFwUpdateUsersServiceUrl"] ??
DefaultListAllFwUpdateUsersServiceUrl;
}
/// <summary>
/// FW-Update list all users url
/// </summary>
/// <returns></returns>
public static String ListAllFwUpdateBuilderOperatorsServiceUrl()
{
return ConfigurationManager.AppSettings["ListAllFwUpdateBuilderOperatorsServiceUrl"] ??
DefaultListAllFwUpdateBuilderOperatorsServiceUrl;
}
/// <summary>
/// FW-Update get user information by user Id url
/// </summary>
/// <returns></returns>
public static String GetFwUpdateUserByIdServiceUrl()
{
return ConfigurationManager.AppSettings["GetFwUpdateUserByIdServiceUrl"] ??
DefaultGetFwUpdateUserByIdServiceUrl;
}
/// <summary>
/// FW-Update get user information by user login name url
/// </summary>
/// <returns></returns>
public static String GetFwUpdateUserByLoginNameServiceUrl()
{
return ConfigurationManager.AppSettings["GetFwUpdateUserByLoginNameServiceUrl"] ??
DefaultGetFwUpdateUserByLoginNameServiceUrl;
}
/// <summary>
/// Genesis check radio parameter url
/// </summary>
/// <returns></returns>
public static String GenesisRadioCheckServiceUrl()
{
return ConfigurationManager.AppSettings["GenesisRadioCheckServiceUrl"] ??
DefaultGenesisRadioCheckServiceUrl;
}
/// <summary>
/// Genesis radio parameter get url
/// </summary>
/// <returns></returns>
public static String GenesisFinalCheckServiceUrl()
{
return ConfigurationManager.AppSettings["GenesisFinalCheckServiceUrl"] ??
DefaultGenesisFinalCheckServiceUrl;
}
/// <summary>
/// Marriage service url
/// </summary>
/// <returns></returns>
public static String MarriageServiceUrl()
{
return ConfigurationManager.AppSettings["MarriageServiceUrl"] ??
DefaultMarriageServiceUrl;
}
/// <summary>
/// Genesis process status url
/// </summary>
/// <returns></returns>
public static String MeterProcessStateUrl()
{
return ConfigurationManager.AppSettings["MeterProcessStateUrl"] ??
DefaultMeterProcessStateUrl;
}
/// <summary>
/// Genesis get radio address url
/// </summary>
/// <returns></returns>
public static String GenesisGetRadioAddressServiceUrl()
{
return ConfigurationManager.AppSettings["GenesisGetRadioAddressServiceUrl"] ??
DefaultGenesisGetRadioAddressServiceUrl;
}
/// <summary>
/// Genesis get key set id url
/// </summary>
/// <returns></returns>
public static String GenesisGetOrderNumberServiceUrl()
{
return ConfigurationManager.AppSettings["GenesisGetOrderNumberServiceUrl"] ??
DefaultGenesisGetOrderNumberServiceUrl;
}
/// <summary>
/// Genesis get key set id url
/// </summary>
/// <returns></returns>
public static String GenesisGetKeySetIdServiceUrl()
{
return ConfigurationManager.AppSettings["GenesisGetKeySetIdServiceUrl"] ??
DefaultGenesisGetKeySetIdServiceUrl;
}
/// <summary>
/// Genesis get password url
/// </summary>
/// <returns></returns>
public static String GenesisSetPickingStateServiceUrl()
{
return ConfigurationManager.AppSettings["GenesisSetPickingStateServiceUrl"] ??
DefaultGenesisSetPickingStateServiceUrl;
}
/// <summary>
/// Genesis get password url
/// </summary>
/// <returns></returns>
public static String GenesisGetPasswordServiceUrl()
{
return ConfigurationManager.AppSettings["GenesisGetPasswordServiceUrl"] ??
DefaultGenesisGetPasswordServiceUrl;
}
/// <summary>
/// Genesis get password url
/// </summary>
/// <returns></returns>
public static String GenesisGetPasswordContainerServiceUrl()
{
return ConfigurationManager.AppSettings["GenesisPasswordContainerServiceUrl"] ??
DefaultGenesisPasswordContainerServiceUrl;
}
/// <summary>
/// Genesis set password url
/// </summary>
/// <returns></returns>
public static String GenesisSetPasswordServiceUrl()
{
return ConfigurationManager.AppSettings["GenesisSetPasswordServiceUrl"] ??
DefaultGenesisSetPasswordServiceUrl;
}
/// <summary>
/// Set the SW license
/// </summary>
/// <returns></returns>
public static String SetSoftwareLicenseUrl()
{
return ConfigurationManager.AppSettings["SetSoftwareLicenseUrl"] ??
DefaultSetSoftwareLicenseUrl;
}
/// <summary>
/// Set the SW license
/// </summary>
/// <returns></returns>
public static String GetSoftwareLicenseUrl()
{
return ConfigurationManager.AppSettings["GetSoftwareLicenseUrl"] ??
DefaultGetSoftwareLicenseUrl;
}
/// <summary>
/// Check the SW license with a given name and version
/// </summary>
/// <returns></returns>
public static String GetSoftwareStartUpAccessUrl()
{
return ConfigurationManager.AppSettings["GetSoftwareStartUpAccessUrl"] ??
DefaultGetSoftwareStartUpAccessUrl;
}
/// <summary>
/// Get Genesis calibration results for final check if those have been correctly set
/// </summary>
/// <returns></returns>
public static String GetGenesisCalibrationResultsUrl()
{
return ConfigurationManager.AppSettings["GetGenesisCalibrationResults"] ??
DefaultGetGenesisCalibrationResults;
}
/// <summary>
/// Post Genesis calibration results
/// </summary>
/// <returns></returns>
public static String PostGenesisCalibrationResultUrl()
{
return ConfigurationManager.AppSettings["GenesisCalibrationResult"] ??
DefaultGenesisCalibrationResult;
}
/// <summary>
/// Post Genesis calibration results
/// </summary>
/// <returns></returns>
public static String FileContentControllerUrl()
{
return ConfigurationManager.AppSettings["DefaultFileContentController"] ??
DefaultFileContentController;
}
/// <summary>
/// Root for all function regarding the BSI Key generation service
/// </summary>
/// <returns></returns>
public static String KeyServerCustom()
{
return ConfigurationManager.AppSettings["DefaultKeyServerCustom"] ??
DefaultKeyServerCustom;
}
/// <summary>
/// Root for all function regarding the meter itself
/// </summary>
/// <returns></returns>
public static String GenesisMeter()
{
return ConfigurationManager.AppSettings["GenesisMeter"] ??
DefaultGenesisMeter;
}
public static String GetQ3CalibrationsURI(String currentPcbId)
{
throw new NotImplementedException();
}
}
}

View File

@ -82,6 +82,25 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug-local IIS-CUST|x64'">
<OutputPath>bin\x64\Debug-local IIS-CUST\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<LangVersion>7.0</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.0</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\.shared\SharedAssemblyInfo.cs">
<Link>Properties\SharedAssemblyInfo.cs</Link>

View File

@ -22,7 +22,12 @@ namespace Xylem.Common.CommonCore.Consts
/// <summary>
/// Name for meter config
/// </summary>
public const String ConfigFileName = "MeterConfig.json";
public const String MeterConfigFileName = "MeterConfig.json";
/// <summary>
/// Name for SIRT config
/// </summary>
public const String SirtConfigFileName = "SirtConfig.json";
/// <summary>
/// Name for offline information e.g. Passwords

View File

@ -66,6 +66,25 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug-local IIS-CUST|x64'">
<OutputPath>bin\x64\Debug-local IIS-CUST\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<LangVersion>7.0</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.0</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\..\packages\Newtonsoft.Json.13.0.3\lib\net40\Newtonsoft.Json.dll</HintPath>

View File

@ -36,6 +36,16 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="GLWpfControl, Version=3.3.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\OpenTK.GLWpfControl.3.3.0\lib\net452\GLWpfControl.dll</HintPath>

View File

@ -81,7 +81,7 @@
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup>
<ManifestCertificateThumbprint>5586F8F849F79C1CEB990ED4E3ACB22CDF595CB5</ManifestCertificateThumbprint>
<ManifestCertificateThumbprint>305BF210A6BBE3C987AD135C96F7B55EC538E555</ManifestCertificateThumbprint>
</PropertyGroup>
<PropertyGroup>
<ManifestKeyFile>CordonelAssemblyLine_TemporaryKey.pfx</ManifestKeyFile>
@ -90,10 +90,33 @@
<GenerateManifests>true</GenerateManifests>
</PropertyGroup>
<PropertyGroup>
<SignManifests>true</SignManifests>
<SignManifests>false</SignManifests>
</PropertyGroup>
<PropertyGroup>
<SignAssembly>true</SignAssembly>
<SignAssembly>false</SignAssembly>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DocumentationFile>bin\Debug\CordonelAssemblyLine.xml</DocumentationFile>
<NoWarn>IDE0003;IDE0021;IDE0049;CS1591;</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
@ -184,6 +207,7 @@
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<None Include="CordonelAssemblyLine_TemporaryKey.pfx" />
<None Include="packages.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>

View File

@ -292,7 +292,7 @@ namespace CordonelAssemblyLine.Model
{
InputIsEnabled = false;
Result = new PressureResultDataNotifyable() { Remark = "loading", TestPoints = new ObservableCollection<PressureTestPoints>(), PcbId = "" };
Task<PressureResultDataNotifyable>.Run(() =>
Task<PressureResultDataNotifyable>.Run((Func<PressureResultDataNotifyable>)(() =>
{
try
{
@ -331,7 +331,7 @@ namespace CordonelAssemblyLine.Model
return new PressureResultDataNotifyable();
}
}).ContinueWith((a) =>
})).ContinueWith((a) =>
{
if (a == null)
{
@ -362,7 +362,7 @@ namespace CordonelAssemblyLine.Model
InputIsEnabled = false;
var isStored = "";
Result.TesterName = TesterName;
Task.Run(() =>
Task.Run((Func<Boolean>)(() =>
{
var url = ServiceUrls.MeterProcessStateUrl();
var status = DisplayCodes.PressureTestedFailed;
@ -422,7 +422,7 @@ namespace CordonelAssemblyLine.Model
OnStoreDone?.Invoke(null, new StringPressureArgs("Bitte erneut testen oder Linienleitung und QS informieren.", true));
return false;
});
}));
}
return false;

View File

@ -1,5 +1,4 @@
using LaaPackages.Features.Cordonel.Models;
using Logic.ProductionToProductMapper.Cordonel;
using Logic.ProductionToProductMapper.Cordonel;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
@ -11,6 +10,7 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using LaaPackages.Features.Cordonel.Models;
using Xylem.Common.CommonCore.Configuration;
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore;
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile;
@ -18,6 +18,7 @@ using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisStatus;
using Xylem.Common.Hardware.WaterMeter.Genesis.Registers;
using Xylem.Common.Hardware.WaterMeter.WaterMeterCore;
using Xylem.Common.Hardware.WaterMeter.WaterMeterCore.Consts;
using Xylem.Common.Logic.ProductionOrderCore.OrderData;
using Xylem.Common.Logic.SoftwareAccessHelper;
using static Ui.ProductionControls.ctlPictureProgressBar;
@ -626,15 +627,14 @@ namespace CordonelAssemblyLine.Model
if (genesisStatus.AlternativeRequiredBatteryLoadPercent != null &&
genesisStatus.AlternativeRequiredBatteryLoadPercent > requirements.MaxDrainedBatteryLoadPercentAssembly)
{
sbMSG.AppendLine($"{nameof(genesisStatus.AlternativeRequiredBatteryLoadPercent)}: " +
$"{genesisStatus.AlternativeRequiredBatteryLoadPercent} > " +
$"{requirements.MaxDrainedBatteryLoadPercentAssembly}");
ret = false;
}
else sbMSG.AppendLine($"Alternative Batterieverbrauch Montage i.O.");
//if (genesisStatus.AlternativeRequiredBatteryLoadPercent != null &&
// genesisStatus.AlternativeRequiredBatteryLoadPercent > requirements.MaxDrainedBatteryLoadPercentAssembly)
//{
// sbMSG.AppendLine($"{nameof(genesisStatus.AlternativeRequiredBatteryLoadPercent)}: " +
// $"{genesisStatus.AlternativeRequiredBatteryLoadPercent} > " + $"{requirements.MaxDrainedBatteryLoadPercentAssembly}");
// ret = false;
//}
//else sbMSG.AppendLine($"Alternative Batterieverbrauch Montage i.O.");
// max bat verbrauch - MaxDrainedBatteryLoadPercentAssembly
if (genesisStatus.DrainedBatteryLoadPercent > requirements.MaxDrainedBatteryLoadPercentAssembly)
@ -652,9 +652,9 @@ namespace CordonelAssemblyLine.Model
// lagerzeit - MaxStorageMonths
if (genesisStatus.StorageMonths > requirements.MaxStorageMonths)
{
lblS08Text = $"{nameof(genesisStatus.DrainedBatteryLoadPercent)}: " +
$"{genesisStatus.DrainedBatteryLoadPercent} > " +
$"{requirements.MaxDrainedBatteryLoadPercentAssembly}";
lblS08Text = $"{nameof(genesisStatus.StorageMonths)}: " +
$"{genesisStatus.StorageMonths} > " +
$"{requirements.MaxStorageMonths}";
lblS08Color = _progressError;
ret = false;
sbMSG.AppendLine($"{nameof(genesisStatus.StorageMonths)}: " +
@ -745,7 +745,7 @@ namespace CordonelAssemblyLine.Model
StringBuilder sbUrl = new StringBuilder();
sbUrl.Append("http://10.49.40.25/MeterProcessState/api/FileUpToDate/GetLutFiles");
sbUrl.Append(ServiceUrls.GetLutUrl());
sbUrl.Append($"?Metersize={_orderDetails.MeterSize}");
sbUrl.Append("&ForProd=true");
//?Metersize=2&Region=EMEA&
@ -822,7 +822,7 @@ namespace CordonelAssemblyLine.Model
meter.ReLogin();
}
meter.SetProcessState(DisplayCodes.PickingTested);
var url = $"{ServiceUrls.MeterProcessStateUrl()}SetPickingState?PcbID={meter.PcbId}&FertigungsauftragsNr={_order}";
var url = $"{ServiceUrls.MeterProcessStateUrl()}SetPickingState?PcbID={meter.PcbId}&FertigungsauftragsNr={_order}&successful=1";
var retString = LocalWebRequest.PostRequestAsyncAndGetContent(url);
if (bool.TryParse(retString, out var result))
@ -922,7 +922,7 @@ namespace CordonelAssemblyLine.Model
lblS06Color = _progressError;
return false;
}
if (meter.InstalledFwVersion.Value != checkAppsIdVersion.FirstOrDefault().Value)
@ -934,7 +934,7 @@ namespace CordonelAssemblyLine.Model
return false;
}
}
else
{
@ -1113,7 +1113,7 @@ namespace CordonelAssemblyLine.Model
}
catch (Exception e)
{
Log($"Error occur.{ Environment.NewLine} {e.Message}");
Log($"Error occur.{Environment.NewLine} {e.Message}");
}
}
}
@ -1157,7 +1157,7 @@ namespace CordonelAssemblyLine.Model
}
catch (Exception e)
{
Log($"Error occur.{ Environment.NewLine} {e.Message}");
Log($"Error occur.{Environment.NewLine} {e.Message}");
}
}
}
@ -1221,7 +1221,7 @@ namespace CordonelAssemblyLine.Model
_state = PickingStateMachine.Compare;
lblS03Text = $"Nr {_orderOverview.OrderOverViewCordonel.AssignedPicking + 1 } von {_orderOverview.OrderOverViewCordonel.Count}";
lblS03Text = $"Nr {_orderOverview.OrderOverViewCordonel.AssignedPicking + 1} von {_orderOverview.OrderOverViewCordonel.Count}";
lblS03Color = _progressDone;
lblS04Color = _progressCurrent;
@ -1297,7 +1297,7 @@ namespace CordonelAssemblyLine.Model
Scanner = $"Öffne {_scannerPort}";
_barScanner = new BarScanner(_scannerPort, token);
HistoryText = $"{HistoryText} {Environment.NewLine}{_order}({_orderOverview.OrderOverViewCordonel.AssignedPicking + 1 }/{ _orderOverview.OrderOverViewCordonel.Count})";
HistoryText = $"{HistoryText} {Environment.NewLine}{_order}({_orderOverview.OrderOverViewCordonel.AssignedPicking + 1}/{_orderOverview.OrderOverViewCordonel.Count})";
_barScanner.Start();
_state = PickingStateMachine.WaitForBuildingMeterReady;
Thread.Sleep(10000);
@ -1383,7 +1383,7 @@ namespace CordonelAssemblyLine.Model
{
Log(ex.Message);
}
}
}
@ -1392,7 +1392,7 @@ namespace CordonelAssemblyLine.Model
// ReSharper disable once UnusedParameter.Local
private void Log(String v)
{
}
}

View File

@ -5,7 +5,7 @@
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{D0C8D887-ED52-40AB-A069-90BCE0E801E2}</ProjectGuid>
<OutputType>WinExe</OutputType>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Xylem.Common.Ui.CordonelPreadjustmentUi</RootNamespace>
<AssemblyName>Xylem.Common.Ui.CordonelPreadjustmentUi</AssemblyName>
@ -128,9 +128,29 @@
<PropertyGroup />
<PropertyGroup />
<PropertyGroup />
<PropertyGroup />
<PropertyGroup>
<NoWin32Manifest>true</NoWin32Manifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<LangVersion>7.0</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.0</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.13.0.3\lib\net40\Newtonsoft.Json.dll</HintPath>

View File

@ -45,6 +45,12 @@ namespace Xylem.Common.Ui.CordonelPreadjustmentUi.Parameters
FlowrateQmH = 400;
DurationS = 60;
break;
case MeterSize.US8:
case MeterSize.DN200:
FlowrateQmH = 400;
DurationS = 60;
break;
default:
Message = $"Warning no parameter for meter size {meterSize.GetHashCode()} use default!{Environment.NewLine}";
FlowrateQmH = 40;

View File

@ -58,6 +58,25 @@ namespace CordonelPreadjustmentUi.Processes.Actions
pp.DebugMessage($"Read out", meterctl.Slot, "CC");
Thread.Sleep(1000);
try
{
if (meterctl.Meter.GetRegistersDic().Any(a => a.Key.RegisterName == "GENESISFLOW_DelayedLedOff"))
{
meterctl.Meter.WriteRegister("GENESISFLOW_DelayedLedOff", 60 * 60 * 2, true);
meterctl.Meter.WriteLog($"GENESISFLOW_DelayedLedOff to {60 * 60 * 2}S");
}
else
{
meterctl.Meter.WriteLog($"GENESISFLOW_DelayedLedOff is not present");
}
}
catch (Exception ex)
{
meterctl.Meter.WriteLog($"GENESISFLOW_DelayedLedOff got error {ex.Message}");
}
}
else
{
@ -71,33 +90,33 @@ namespace CordonelPreadjustmentUi.Processes.Actions
var readsOk = new List<bool>();
byte[] retByte;
readsOk.Add(ReadRegister(meterctl.Meter, "MeterSize", Register.Genesisflow.MeterSize, out retByte));
readsOk.Add(ReadRegisterRetry(meterctl.Meter, "MeterSize", Register.Genesisflow.MeterSize, out retByte));
meterctl.Meter.calibrationResult.MeterSize = RegisterConverter.ByteArrayToValue<ushort>(retByte);
readsOk.Add(ReadRegister(meterctl.Meter, "CalFactor1", Register.Genesisflow.CalFactor1, out retByte));
readsOk.Add(ReadRegisterRetry(meterctl.Meter, "CalFactor1", Register.Genesisflow.CalFactor1, out retByte));
meterctl.Meter.calibrationResult.CalFactor1 = RegisterConverter.ByteArrayToValue<uint>(retByte);
readsOk.Add(ReadRegister(meterctl.Meter, "CalFactor2", Register.Genesisflow.CalFactor2, out retByte));
readsOk.Add(ReadRegisterRetry(meterctl.Meter, "CalFactor2", Register.Genesisflow.CalFactor2, out retByte));
meterctl.Meter.calibrationResult.CalFactor2 = RegisterConverter.ByteArrayToValue<uint>(retByte);
readsOk.Add(ReadRegister(meterctl.Meter, "CalFactor3", Register.Genesisflow.CalFactor3, out retByte));
readsOk.Add(ReadRegisterRetry(meterctl.Meter, "CalFactor3", Register.Genesisflow.CalFactor3, out retByte));
meterctl.Meter.calibrationResult.CalFactor3 = RegisterConverter.ByteArrayToValue<uint>(retByte);
readsOk.Add(ReadRegister(meterctl.Meter, "ZeroOffset1", Register.Genesisflow.ZeroOffset1, out retByte));
readsOk.Add(ReadRegisterRetry(meterctl.Meter, "ZeroOffset1", Register.Genesisflow.ZeroOffset1, out retByte));
meterctl.Meter.calibrationResult.ZeroOffset1 = RegisterConverter.ByteArrayToValue<int>(retByte);
readsOk.Add(ReadRegister(meterctl.Meter, "ZeroOffset2", Register.Genesisflow.ZeroOffset2, out retByte));
readsOk.Add(ReadRegisterRetry(meterctl.Meter, "ZeroOffset2", Register.Genesisflow.ZeroOffset2, out retByte));
meterctl.Meter.calibrationResult.ZeroOffset2 = RegisterConverter.ByteArrayToValue<int>(retByte);
readsOk.Add(ReadRegister(meterctl.Meter, "ZeroOffset3", Register.Genesisflow.ZeroOffset3, out retByte));
readsOk.Add(ReadRegisterRetry(meterctl.Meter, "ZeroOffset3", Register.Genesisflow.ZeroOffset3, out retByte));
meterctl.Meter.calibrationResult.ZeroOffset3 = RegisterConverter.ByteArrayToValue<int>(retByte);
readsOk.Add(ReadRegister(meterctl.Meter, "FirstHitUpdatePeriod", Register.Genesisflow.FirstHitUpdatePeriod, out retByte));
readsOk.Add(ReadRegisterRetry(meterctl.Meter, "FirstHitUpdatePeriod", Register.Genesisflow.FirstHitUpdatePeriod, out retByte));
meterctl.Meter.calibrationResult.FirstHitUpdatePeriod = RegisterConverter.ByteArrayToValue<ushort>(retByte);
readsOk.Add(ReadRegister(meterctl.Meter, "FirstHitShift", Register.Genesisflow.FirstHitShift, out retByte));
readsOk.Add(ReadRegisterRetry(meterctl.Meter, "FirstHitShift", Register.Genesisflow.FirstHitShift, out retByte));
meterctl.Meter.calibrationResult.FirstHitShift = RegisterConverter.ByteArrayToValue<ushort>(retByte);
readsOk.Add(ReadRegister(meterctl.Meter, "FirstHitPercent1", Register.Genesisflow.FirstHitPercent1, out retByte));
readsOk.Add(ReadRegisterRetry(meterctl.Meter, "FirstHitPercent1", Register.Genesisflow.FirstHitPercent1, out retByte));
meterctl.Meter.calibrationResult.FirstHitPercent1 = RegisterConverter.ByteArrayToValue<ushort>(retByte);
readsOk.Add(ReadRegister(meterctl.Meter, "FirstHitPercent2", Register.Genesisflow.FirstHitPercent2, out retByte));
readsOk.Add(ReadRegisterRetry(meterctl.Meter, "FirstHitPercent2", Register.Genesisflow.FirstHitPercent2, out retByte));
meterctl.Meter.calibrationResult.FirstHitPercent2 = RegisterConverter.ByteArrayToValue<ushort>(retByte);
readsOk.Add(ReadRegister(meterctl.Meter, "FirstHitPercent3", Register.Genesisflow.FirstHitPercent3, out retByte));
readsOk.Add(ReadRegisterRetry(meterctl.Meter, "FirstHitPercent3", Register.Genesisflow.FirstHitPercent3, out retByte));
meterctl.Meter.calibrationResult.FirstHitPercent3 = RegisterConverter.ByteArrayToValue<ushort>(retByte);
readsOk.Add(ReadRegister(meterctl.Meter, "ToFTempOffset1", Register.Genesisflow.ToFTempOffset1, out retByte));
readsOk.Add(ReadRegisterRetry(meterctl.Meter, "ToFTempOffset1", Register.Genesisflow.ToFTempOffset1, out retByte));
meterctl.Meter.calibrationResult.ToFTempOffset1 = RegisterConverter.ByteArrayToValue<int>(retByte);
readsOk.Add(ReadRegister(meterctl.Meter, "ToFTempOffset2", Register.Genesisflow.ToFTempOffset2, out retByte));
readsOk.Add(ReadRegisterRetry(meterctl.Meter, "ToFTempOffset2", Register.Genesisflow.ToFTempOffset2, out retByte));
meterctl.Meter.calibrationResult.ToFTempOffset2 = RegisterConverter.ByteArrayToValue<int>(retByte);
readsOk.Add(ReadRegister(meterctl.Meter, "ToFTempOffset3", Register.Genesisflow.ToFTempOffset3, out retByte));
meterctl.Meter.calibrationResult.ToFTempOffset3 = RegisterConverter.ByteArrayToValue<int>(retByte);

View File

@ -42,6 +42,9 @@ namespace CordonelPreadjustmentUi.Processes.Actions
}
Thread.Sleep(1000);
}
var doneTime = DateTime.UtcNow.AddMinutes(1);
while (DateTime.UtcNow > doneTime)
{ Thread.Sleep(1000); }
return true;
}));

View File

@ -58,7 +58,7 @@ namespace CordonelPreadjustmentUi.Processes.Actions
//(pp.Setting.OffsetTestNumberOfLines * number of path) / 1000
//((9000 * 3) / 1000 ) = 27 min
var pataDataActivitCheck = new MultiPathDataLogContainer<int>(pp.Setting.NumberOfPaths);
var MaxTimeoutWarnings = 300;
pataDataActivitCheck.Update(null, -1);
@ -105,7 +105,7 @@ namespace CordonelPreadjustmentUi.Processes.Actions
if (MaxTimeoutWarnings <= 0)
{
pp.DebugMessage($"Fatal timeout while collecting data. Please check LED singnal. Has {offsetRecords.Count} from {pp.Setting.OffsetTestNumberOfLines * 3}", meterctl.Slot, "DC", meterctl.Meter.PcbId);
// Ok = false;
// Ok = false;
}
if (CheckAbort(Ok, meterctl)) { return Ok; }
@ -168,7 +168,7 @@ namespace CordonelPreadjustmentUi.Processes.Actions
{
Ok = false;
}
}
if (CheckAbort(Ok, meterctl)) { return Ok; }
@ -197,9 +197,12 @@ namespace CordonelPreadjustmentUi.Processes.Actions
pp.DebugMessage($"Average positive amplitude, PATH{(Path + 1)}: {Math.Round(amplitudeValuesMeanUp.Get(Path), 2).ToString("000.00")}mV", meterctl.Meter.Slot, "DC", meterctl.Meter.PcbId);
pp.DebugMessage($"Average negative amplitude, PATH{(Path + 1)}: {Math.Round(amplitudeValuesMeanDown.Get(Path), 2).ToString("000.00")}mV", meterctl.Meter.Slot, "DC", meterctl.Meter.PcbId);
meterctl.Meter.calibrationResult.AddAdditionalLog($"Offset Average positive amplitude PATH { (Path + 1)}", $"{ Math.Round(amplitudeValuesMeanUp.Get(Path), 2).ToString("000.00")}mV");
meterctl.Meter.calibrationResult.AddAdditionalLog($"Offset Average negative amplitude PATH { (Path + 1)}", $"{ Math.Round(amplitudeValuesMeanDown.Get(Path), 2).ToString("000.00")}mV");
meterctl.Meter.calibrationResult.AddAdditionalLog($"Offset Average positive amplitude PATH {(Path + 1)}", $"{Math.Round(amplitudeValuesMeanUp.Get(Path), 2).ToString("000.00")}mV");
meterctl.Meter.calibrationResult.AddAdditionalLog($"Offset Average negative amplitude PATH {(Path + 1)}", $"{Math.Round(amplitudeValuesMeanDown.Get(Path), 2).ToString("000.00")}mV");
if (pp.Setting.MeterSize == Xylem.Common.Logic.ProductionOrderCore.OrderData.MeterSize.DN200 || pp.Setting.MeterSize == Xylem.Common.Logic.ProductionOrderCore.OrderData.MeterSize.US8)
{
pp.Setting.OffsetTestLowerVoltageLimitMV = 180;
}
if ((amplitudeValuesMeanUp.Get(Path) > pp.Setting.OffsetTestUpperVoltageLimitMV) ||
(amplitudeValuesMeanUp.Get(Path) < pp.Setting.OffsetTestLowerVoltageLimitMV) ||
(amplitudeValuesMeanDown.Get(Path) < pp.Setting.OffsetTestLowerVoltageLimitMV) ||
@ -209,9 +212,9 @@ namespace CordonelPreadjustmentUi.Processes.Actions
pp.DebugMessage($"Amplitude check failed!", meterctl.Meter.Slot, "APP", meterctl.Meter.PcbId);
}
pp.DebugMessage($"Average delta time of flight valuePATH{(Path + 1)}: Raw{DeltaTimeOfFlightAverage.Get(Path)} -> in picoseconds= { Math.Round((DeltaTimeOfFlightAverage.Get(Path) / (Math.Pow(2, 38) * Math.Pow(10, 12))), 2).ToString("000.00")}", meterctl.Meter.Slot, "APP", meterctl.Meter.PcbId);
meterctl.Meter.calibrationResult.AddAdditionalLog($"Offset Average delta time of flight value PATH { (Path + 1)} RAW ", $"{DeltaTimeOfFlightAverage.Get(Path)}");
meterctl.Meter.calibrationResult.AddAdditionalLog($"Offset Average delta time of flight value PATH { (Path + 1)} picoseconds ", $"{Math.Round((DeltaTimeOfFlightAverage.Get(Path) / (Math.Pow(2, 38) * Math.Pow(10, 12))), 2).ToString("000.00")}");
pp.DebugMessage($"Average delta time of flight valuePATH{(Path + 1)}: Raw{DeltaTimeOfFlightAverage.Get(Path)} -> in picoseconds= {Math.Round((DeltaTimeOfFlightAverage.Get(Path) / (Math.Pow(2, 38) * Math.Pow(10, 12))), 2).ToString("000.00")}", meterctl.Meter.Slot, "APP", meterctl.Meter.PcbId);
meterctl.Meter.calibrationResult.AddAdditionalLog($"Offset Average delta time of flight value PATH {(Path + 1)} RAW ", $"{DeltaTimeOfFlightAverage.Get(Path)}");
meterctl.Meter.calibrationResult.AddAdditionalLog($"Offset Average delta time of flight value PATH {(Path + 1)} picoseconds ", $"{Math.Round((DeltaTimeOfFlightAverage.Get(Path) / (Math.Pow(2, 38) * Math.Pow(10, 12))), 2).ToString("000.00")}");
if ((DeltaTimeOfFlightAverage.Get(Path) > pp.Setting.OffsetTestOffsetLimitPS) ||
(DeltaTimeOfFlightAverage.Get(Path) < -pp.Setting.OffsetTestOffsetLimitPS))
@ -233,7 +236,7 @@ namespace CordonelPreadjustmentUi.Processes.Actions
{
if (CheckAbort(false, meterctl)) { return false; }
}
}
Ok = meterctl.Meter.ReLogin();
@ -270,7 +273,7 @@ namespace CordonelPreadjustmentUi.Processes.Actions
Ok = WriteRegisterSafe(meterctl.Meter, $"Zero flow offset Path {Path + 1}", RegValue, OffsetValue);
Ok = true;
}
}
return Ok;
}));

View File

@ -7,10 +7,10 @@ using CordonelPreadjustmentUi.Processes.Itinerary;
using System.Threading;
using static CordonelPreadjustmentUi.PreAdjustmentControl;
using System.Threading.Tasks;
using Xylem.Common.Hardware.WaterMeter.Genesis.Registers;
using Xylem.Common.Logic.SoftwareAccessHelper;
using Xylem.Common.CommonCore.Configuration;
using Newtonsoft.Json;
using Xylem.Common.Hardware.WaterMeter.Genesis.Registers;
namespace CordonelPreadjustmentUi.Processes.Actions
{
@ -122,9 +122,21 @@ namespace CordonelPreadjustmentUi.Processes.Actions
var r = LocalWebRequest.GetRequest($"{ ServiceUrls.GenesisFinalCheckServiceUrl()}GetMetersizeProgrammingData?MeterSize={pp.Setting.MeterSize.GetHashCode()}", 2000);
var dt = JsonConvert.DeserializeObject<Dictionary<string, UInt32>>(r);
try
{
if (meterctl.Meter.GetRegistersDic().Any(a => a.Key.RegisterName == "GENESISFLOW_DelayedLedOff"))
{
Ok = WriteRegisterSafe(meterctl.Meter, "ledDelay", "GENESISFLOW_DelayedLedOff", 60 * 60 * 2, false);
if (CheckAbort(Ok, meterctl)) { return Ok; }
}
}
catch (Exception)
{
//Ok = WriteRegisterSafe(meterctl.Meter, "ledDelay", "GENESISFLOW_DelayedLedOff", 60 * 60* 2, false);
//if (CheckAbort(Ok, meterctl)) { return Ok; }
}
foreach (var item in dt)

View File

@ -7,10 +7,11 @@ using CordonelPreadjustmentUi.Processes.Itinerary;
using System.Threading;
using static CordonelPreadjustmentUi.PreAdjustmentControl;
using System.Threading.Tasks;
using Xylem.Common.Hardware.WaterMeter.Genesis.Registers;
using Xylem.Common.Logic.SoftwareAccessHelper;
using Xylem.Common.CommonCore.Configuration;
using Newtonsoft.Json;
using Xylem.Common.Hardware.WaterMeter.Genesis.Registers;
namespace CordonelPreadjustmentUi.Processes.Actions
{

View File

@ -321,7 +321,17 @@ namespace CordonelPreadjustmentUi.Processes
return false;
}
public bool ReadRegisterRetry(ZeroFlowGenesisMeter m, string displayName, string registerName, out byte[] ret)
{
var retRet = ReadRegister(m, displayName, registerName, out byte[] rr);
if (!retRet)
{
retRet = ReadRegister(m, displayName, registerName, out rr);
}
ret = rr;
return retRet;
}
public bool ReadRegister(ZeroFlowGenesisMeter m, string displayName, string registerName, out byte[] ret)
{
Thread.Sleep(100);

View File

@ -59,6 +59,25 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug-local IIS-CUST|x64'">
<OutputPath>bin\x64\Debug-local IIS-CUST\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="BouncyCastle.Crypto, Version=1.8.1.0, Culture=neutral, PublicKeyToken=0e99375e54769942">
<HintPath>..\..\packages\BouncyCastle.Crypto.dll.1.8.1\lib\BouncyCastle.Crypto.dll</HintPath>

View File

@ -31,6 +31,16 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<NoWarn>IDE0003;IDE0011;IDE0049;IDE1005;</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
@ -55,7 +65,6 @@
<Compile Include="Parameters\SirtOperating.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SIRTBroadcaster.cs" />
<Compile Include="SIRTChannel.cs" />
<Compile Include="SIRTConstants.cs" />
<Compile Include="SIRTExtensions.cs" />
<Compile Include="SIRTHub.cs" />

View File

@ -1,4 +1,6 @@
namespace Common.Hardware.SIRT.Parameters
using System.Text;
namespace Common.Hardware.SIRT.Parameters
{
public class PAMStatus
{
@ -23,7 +25,7 @@
{
return nameof(OK);
}
if (this.OUT_OF_RANGE)
else if (this.OUT_OF_RANGE)
{
return nameof(this.OUT_OF_RANGE);
}
@ -49,6 +51,38 @@
}
}
public string ToString(bool extended)
{
var stringBuilder = new StringBuilder();
if (this.bits.GetByteLE() == 0)
{
stringBuilder.AppendLine(nameof(OK));
}
if (this.OUT_OF_RANGE)
{
stringBuilder.AppendLine(nameof(this.OUT_OF_RANGE));
}
if (this.MIXED_TYPES)
{
stringBuilder.AppendLine(nameof(this.MIXED_TYPES));
}
if (this.CMD_UNKNOWN)
{
stringBuilder.AppendLine(nameof(this.CMD_UNKNOWN));
}
if (this.EXPIRED_AUTH)
{
stringBuilder.AppendLine(nameof(this.EXPIRED_AUTH));
}
if (this.WRONG_AUTH)
{
stringBuilder.AppendLine(nameof(this.WRONG_AUTH));
}
return stringBuilder.ToString().Trim();
}
public static byte OK = 0;
public static byte EXPIREDAUTH = 4;

View File

@ -4,6 +4,8 @@
{
public RSSI(byte value, int mhz)
{
this.Value = value;
if (mhz == 433)
{
this.Dbm = value * 0.5 - 140;
@ -25,6 +27,8 @@
}
}
public byte Value { get; }
public double Dbm { get; }
public double Percent { get; }

View File

@ -66,7 +66,7 @@
Try(this.tasks.Clear);
Try(this.pampool.Clear);
Try(this.cancellationTokenSource.Cancel);
Try((this.cancellationTokenSource ?? new CancellationTokenSource()).Cancel);
var disconnectedEvent = this.Disconnected;
@ -127,8 +127,11 @@
if (addresses.Any(x => x == 0 || x == address))
{
task.SirtId = this.Id;
this.tasks
.AddOrUpdate(task.RequestAddress, addr => task, (addr, oldTask) => task);
var bytes = this.tasks
.AddOrUpdate(address, addr => task, (addr, oldTask) => task)
.AddOrUpdate(task.ResponseAddress, addr => task, (addr, oldTask) => task)
.Start();
this.sirtStream.Write(bytes);
SIRTLogger.LogMessage($"{this.PortName}|TX: {BitConverter.ToString(bytes)}");
@ -200,7 +203,13 @@
if (this.tasks.TryGetValue(message.Address, out var task))
{
task?.Push(message);
task.Push(message);
if (task.State == SIRTTaskState.Completed || task.State == SIRTTaskState.Cancelled)
{
this.tasks.TryRemove(task.RequestAddress, out _);
this.tasks.TryRemove(task.ResponseAddress, out _);
}
}
if (messageReceivedEvent != null)

View File

@ -1,20 +0,0 @@
namespace Common.Hardware.SIRT
{
using Common.Hardware.SIRT.Tasks;
using System;
public class SIRTChannel
{
public event Action<SIRTMessage> MessageReceived;
public uint RequestAddress { get; set; }
public uint ResponseAddress { get; set; }
public Action<SIRTTask> WriteHandler { get; set; }
internal void Enqueue(SIRTMessage message)
=> this.MessageReceived?.Invoke(message);
}
}

View File

@ -20,12 +20,14 @@
public const byte LEN_IX = 8;
public const byte DATA_IX = 9;
public static byte AKN_ANS = 0x12;
public static byte FROM_AIR = 0x11;
public const byte ACKN_ANSW = 0x12;
public const byte FROM_AIR = 0x11;
public static byte LAT = 0x01;
public static byte BUP = 0x00;
public static byte DEBUG = 0x0B;
public static byte SEMI = 0x08;
public const byte LAT = 0x01;
public const byte BUP = 0x00;
public const byte DEBUG = 0x0B;
public const byte SEMI = 0x08;
public const byte ENC_KEY_LEN = 16;
}
}

View File

@ -1,6 +1,5 @@
namespace Common.Hardware.SIRT
{
using Common.Hardware.SIRT.Parameters;
using Common.Hardware.SIRT.Tasks;
using System;
@ -596,13 +595,27 @@
return value;
}
public static ushort GetCrc(this byte[] bytes, int index)
public static ushort GetCrc(this byte[] bytes, int index = -1)
{
var value = default(ushort);
var _index = index;
value ^= (ushort)(bytes[_index++] << 8);
value ^= bytes[_index];
if (bytes != null)
{
var length = bytes.Length;
if (index < 0)
{
index = length - 2;
}
var _index = index;
if (_index >= 0)
{
value ^= (ushort)(bytes[_index++] << 8);
value ^= bytes[_index];
}
}
return value;
}
@ -667,5 +680,88 @@
return done;
}
public static byte[] DecryptResponse(this byte[] encryptedData, byte[] encryptionKey)
{
if (encryptionKey?.Length != 16)
{
return encryptedData;
}
var length = encryptedData?.Length ?? 0;
if (length == 0)
{
return encryptedData;
}
var decryptedData = new byte[length];
Array.Copy(encryptedData, 0, decryptedData, 0, length);
var token = decryptedData[1];
for (var x = 6; x < length; x++)
{
token += (byte)(decryptedData[x - (token & 0x3) - 1] >> ((token >> 6) & 0x1));
decryptedData[x] ^= encryptionKey[(token >> 2) & 0x0F];
if (token >= 0x80)
{
decryptedData[x] = (byte)~decryptedData[x];
}
}
return decryptedData;
}
public static byte[] EncryptRequest(this byte[] plainData, byte[] encryptionKey, uint address)
{
if (plainData?.Length <= 0 || encryptionKey?.Length != 16 || address <= 0)
{
return plainData;
}
var dataLength = plainData.Length;
var telegramLength = dataLength + 2;
var encryptedData = new byte[telegramLength];
Array.Copy(plainData, 0, encryptedData, 0, dataLength);
var telegramForCRCLength = telegramLength + 4;
var telegramForCRC = new byte[telegramForCRCLength];
telegramForCRC[0] = (byte)(address >> 24);
telegramForCRC[1] = (byte)(address >> 16);
telegramForCRC[2] = (byte)(address >> 8);
telegramForCRC[3] = (byte)(address >> 0);
Array.Copy(encryptedData, 0, telegramForCRC, 4, telegramLength);
var telegramCRC = telegramForCRC.CRCCCITT(1, telegramForCRCLength - 2);
encryptedData[telegramLength - 2] = (byte)(telegramCRC >> 8);
encryptedData[telegramLength - 1] = (byte)(telegramCRC >> 0);
var reference = address;
var token = (byte)0xFF;
for (var i = 0; i < telegramLength; i++)
{
token += (byte)(((reference >> ((token & 0x3) << 3)) & 0xFF) >> ((token >> 6) & 1));
reference <<= 8;
reference += encryptedData[i];
encryptedData[i] ^= encryptionKey[(token >> 2) & 0x0F];
if (token >= 0x80)
{
encryptedData[i] = (byte)~encryptedData[i];
}
}
return encryptedData;
}
}
}

View File

@ -93,17 +93,12 @@
public DateTimeOffset Timestamp { get; set; } = DateTimeOffset.UtcNow;
public override string ToString()
=> $"{this.Timestamp}|{this.SirtId}|{this.Frequency}|{BitConverter.ToString(this.GetBytes())}";
=> $"{this.Timestamp:yyyy-MM-ddTHH:mm:ssZ}|{this.SirtId}|{this.Frequency}|{BitConverter.ToString(this.GetBytes())}";
public byte[] GetBytes()
{
var crc = this.bytes.CRCCCITT(1, this.bytes.Length - 3);
if (this.Direction == PC_SIRT)
{
this.Crc = crc;
this.End = MSG_END;
}
this.Crc = this.bytes.CRCCCITT(1, this.bytes.Length - 3);
this.End = MSG_END;
return this.bytes;
}

View File

@ -66,7 +66,7 @@
}
}
public IEnumerable<byte[]> Read()
public IEnumerable<byte[]> ReadAsEnumerable()
{
var buffer = Array.Empty<byte>();
var length = default(int);

View File

@ -1,5 +1,6 @@
namespace Common.Hardware.SIRT
{
using System;
using System.Collections.Generic;
public sealed class SIRTStream
@ -27,7 +28,7 @@
var messageLength = default(int);
var message = default(byte[]);
foreach (var bytes in this.sirtPort.Read())
foreach (var bytes in this.sirtPort.ReadAsEnumerable())
{
buffer.AddRange(bytes);
bufferLength = buffer.Count;
@ -35,10 +36,9 @@
// until can parse messages from the buffer
while (bufferLength >= 12)
{
// reset the start index if needed
if (startIndex < 0)
if (startIndex < 0 || bufferLength < startIndex)
{
startIndex = 0;
startIndex = Math.Min(Math.Max(startIndex, 0), bufferLength - 1);
}
startIndex = buffer.IndexOf(SIRTConstants.SIRT_PC, startIndex);
@ -94,7 +94,6 @@
// in case there are more messages in the buffer
bufferLength = buffer.Count;
startIndex = 0;
}
}
}

View File

@ -10,10 +10,10 @@
this.ResponseAddress = 0x20000000;
this.Payload = new byte[]
{
new SirtOperating { /* default */ },
new SirtOperating { /* default */ },
new BluetoothOperating { BtOff = true },
new RFModuleOperating { RfOff = true },
new RFModuleOperating { OpMode = OperatingModes.ReceiveF1TransmitSensusRFF3 },
new RFModuleOperating { OpMode = OperatingModes.ReceiveF1TransmitSensusRFF3 }, // ReceiveF1TransmitSensusRFF3
new PamTimeout { Minutes = 1 }
};
}

View File

@ -13,7 +13,7 @@
public override void Push(SIRTMessage response)
{
if (response.Command == SIRTConstants.AKN_ANS)
if (response.Command == SIRTConstants.ACKN_ANSW)
{
this.Payload = response.Payload;

View File

@ -12,7 +12,7 @@
public override void Push(SIRTMessage response)
{
if (response.Command == SIRTConstants.AKN_ANS && response.P1 == 0)
if (response.Command == SIRTConstants.ACKN_ANSW && response.P1 == 0)
{
this.Payload = response.Payload;

View File

@ -15,7 +15,7 @@
public override void Push(SIRTMessage response)
{
if (response.Command == SIRTConstants.AKN_ANS)
if (response.Command == SIRTConstants.ACKN_ANSW)
{
this.Payload = response.Payload;

View File

@ -63,6 +63,13 @@
public abstract void Push(SIRTMessage response);
public void SetError()
{
this.State = SIRTTaskState.Error;
this.awaiter.Set();
}
public void SetCancelled()
{
this.State = SIRTTaskState.Cancelled;
@ -80,8 +87,6 @@
public void SetPending()
{
this.State = SIRTTaskState.Pending;
this.awaiter.Set();
}
public void SetRunning()
@ -103,13 +108,19 @@
public void Wait()
{
if (this.awaiter.IsSet)
{
this.awaiter.Reset();
}
this.awaiter.Wait(this.Timeout);
this.awaiter.Reset();
}
public override bool Equals(object other)
=> other is SIRTTask _task && _task.taskId == this.taskId;
public override int GetHashCode() => (int)this.RequestAddress;
public static implicit operator SIRTMessage(SIRTTask task) => task.request;
}
}

View File

@ -5,6 +5,7 @@
Pending = 0,
Running = 1,
Completed = 2,
Cancelled = 4
Cancelled = 4,
Error = 5
}
}

View File

@ -6,14 +6,43 @@
public class WritePamTask : SIRTTask
{
private event Action<SIRTMessage> AKNReceived;
private event Action<SIRTMessage> BUPReceived;
private event Action<SIRTMessage> LATReceived;
private event Action<SIRTMessage> DEBUGReceived;
private event Action<SIRTMessage> SEMIReceived;
private event Action<SIRTMessage> UnknownReceived;
private bool debugReceived;
private bool latReceived;
protected P811 p811;
public WritePamTask()
{
this.request.Command = SIRTConstants.W_PAM;
this.p811 = this.request.P1;
this.request.Command = SIRTConstants.W_PAM;
this.MessageSent += this.OnMessageSent;
this.AKNReceived += this.OnAKNReceived;
this.BUPReceived += this.OnBUPReceived;
this.LATReceived += this.OnLATReceived;
this.DEBUGReceived += this.OnDEBUGReceived;
this.SEMIReceived += this.OnSEMIReceived;
this.UnknownReceived += this.OnUnknownReceived;
this.RequireLAT = true;
}
public event Action<SIRTMessage> MessageSent;
public event Action<SIRTMessage> MessageReceived;
public bool RequireLAT { get; set; }
public bool RequireDEBUG { get; set; }
public bool IsEncrypted { get; set; }
public byte[] EncryptionKey { get; set; }
public bool WakeUpModul
{
get => this.p811.WakeUpModul;
@ -62,19 +91,179 @@
set => this.request.Payload = value;
}
public bool AnyTelegramReceived { get; set; }
public override void Push(SIRTMessage response)
{
this.AnyTelegramReceived = true;
if (response.Command == SIRTConstants.ACKN_ANSW) // command sent
{
this.DecriptResponse(response);
this.AKNReceived?.Invoke(response);
}
else if (response.Command == SIRTConstants.FROM_AIR)
{
var payload = response.Payload;
if (payload != null && payload.Length > 0)
{
var type = payload[0];
if (type == SIRTConstants.BUP) // bubble up message
{
this.DecriptResponse(response, payload);
this.BUPReceived?.Invoke(response);
}
else if (type == SIRTConstants.LAT) // command received
{
this.latReceived = true;
this.DecriptResponse(response, payload);
this.LATReceived?.Invoke(response);
}
else if (type == SIRTConstants.DEBUG) // received only on specific commands
{
this.debugReceived = true;
this.DecriptResponse(response, payload);
this.DEBUGReceived?.Invoke(response);
}
else if (type == SIRTConstants.SEMI) // always the last answer of the command
{
this.DecriptResponse(response, payload);
this.SEMIReceived?.Invoke(response);
}
else
{
this.DecriptResponse(response, payload);
this.UnknownReceived?.Invoke(response);
}
}
else
{
this.DecriptResponse(response, payload);
this.UnknownReceived?.Invoke(response);
}
}
else
{
this.DecriptResponse(response);
this.UnknownReceived?.Invoke(response);
}
this.MessageReceived?.Invoke(response);
}
public override byte[] Start()
{
this.MessageSent?.Invoke(this.request);
var message = new SIRTMessage
{
Direction = this.request.Direction,
Command = this.request.Command,
P1 = this.request.P1,
P2 = this.request.P2,
Address = this.request.Address,
Payload = this.EncryptRequest(),
Frequency = this.Frequency,
SirtId = this.SirtId,
};
this.MessageSent?.Invoke(message);
this.SetRunning();
return message.GetBytes();
}
protected virtual void OnMessageSent(SIRTMessage request)
{
}
protected virtual void OnAKNReceived(SIRTMessage akn)
{
}
protected virtual void OnBUPReceived(SIRTMessage bup)
{
}
protected virtual void OnLATReceived(SIRTMessage lat)
{
}
protected virtual void OnDEBUGReceived(SIRTMessage debug)
{
}
protected virtual void OnSEMIReceived(SIRTMessage semi)
{
if (this.RequireLAT && !this.latReceived)
{
this.SetPending();
}
else if (this.RequireDEBUG && !this.debugReceived)
{
this.SetPending();
}
else
{
this.SetCompleted();
}
}
protected virtual void OnUnknownReceived(SIRTMessage unknown)
{
}
private byte[] EncryptRequest()
{
var requestPayload = this.request.Payload;
var payloadLength = requestPayload.Length;
var payload = new byte[payloadLength];
Array.Copy(requestPayload, 0, payload, 0, payloadLength);
if (this.IsEncrypted)
{
payload = payload.EncryptRequest(this.EncryptionKey, this.RequestAddress);
}
return payload;
}
private void DecriptResponse(SIRTMessage response, params byte[] payload)
{
if (payload == null || payload.Length == 0)
{
payload = response.Payload;
}
this.IsEncrypted = payload.GetCrc() != default(ushort);
if (this.IsEncrypted)
{
if (this.EncryptionKey != null && this.EncryptionKey.Length == SIRTConstants.ENC_KEY_LEN)
{
response.Payload = payload.DecryptResponse(this.EncryptionKey);
}
else
{
this.SetCancelled();
}
}
}
private void SetP811(Action<P811> p811Setter)
{
p811Setter.Invoke(this.p811);
this.request.P1 = this.p811;
}
public override void Push(SIRTMessage response)
{
if (response.Length > 0 && response.Payload[0] == SIRTConstants.SEMI)
{
this.SetCompleted();
}
}
}
}

View File

@ -17,7 +17,7 @@
public override void Push(SIRTMessage response)
{
if (response.Command == SIRTConstants.AKN_ANS)
if (response.Command == SIRTConstants.ACKN_ANSW)
{
this.SetCompleted();
}

View File

@ -91,6 +91,29 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug-local IIS-CUST|x64'">
<OutputPath>bin\x64\Debug-local IIS-CUST\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\VPN_Debug\</OutputPath>
<DefineConstants>CODE_ANALYSIS;DEBUG;TRACE</DefineConstants>
<DocumentationFile>bin\x86\Debug\Xylem.Common.Hardware.Interfaces.Ports.PortCore.xml</DocumentationFile>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<RunCodeAnalysis>true</RunCodeAnalysis>
<LangVersion>7.0</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\VPN_Debug\</OutputPath>
<DefineConstants>CODE_ANALYSIS;CODE_ANALYSIS;DEBUG;TRACE</DefineConstants>
<DocumentationFile>bin\x86\Debug\Xylem.Common.Hardware.Interfaces.Ports.PortCore.xml</DocumentationFile>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<RunCodeAnalysis>true</RunCodeAnalysis>
<LangVersion>7.0</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\..\..\..\.shared\SharedAssemblyInfo.cs">
<Link>Properties\SharedAssemblyInfo.cs</Link>

View File

@ -212,6 +212,38 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug-local IIS-CUST|x64'">
<OutputPath>bin\x64\Debug-local IIS-CUST\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\VPN_Debug\</OutputPath>
<DefineConstants>CODE_ANALYSIS;TRACE;DEBUG</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<RunCodeAnalysis>true</RunCodeAnalysis>
<LangVersion>7.0</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DocumentationFile>bin\x86\Debug\Xylem.Common.Hardware.Interfaces.Ports.SerialPorts.xml</DocumentationFile>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<LangVersion>6</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\VPN_Debug\</OutputPath>
<DefineConstants>CODE_ANALYSIS;CODE_ANALYSIS;DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<RunCodeAnalysis>true</RunCodeAnalysis>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\..\..\..\.shared\SharedAssemblyInfo.cs">
<Link>Properties\SharedAssemblyInfo.cs</Link>

View File

@ -182,6 +182,36 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug-local IIS-CUST|x64'">
<OutputPath>bin\x64\Debug-local IIS-CUST\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<LangVersion>7.0</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DocumentationFile>bin\x86\Debug\Xylem.Common.Hardware.Interfaces.Protocols.ProtocolCore.xml</DocumentationFile>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<LangVersion>6</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\..\..\..\packages\Newtonsoft.Json.13.0.3\lib\net40\Newtonsoft.Json.dll</HintPath>

View File

@ -102,6 +102,25 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug-local IIS-CUST|x64'">
<OutputPath>bin\x64\Debug-local IIS-CUST\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<LangVersion>7.0</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.0</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\..\..\..\packages\Newtonsoft.Json.13.0.3\lib\net40\Newtonsoft.Json.dll</HintPath>

View File

@ -92,6 +92,25 @@
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<LangVersion>7.0</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.0</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="NLog, Version=5.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\..\..\..\..\packages\NLog.5.2.2\lib\net45\NLog.dll</HintPath>

View File

@ -131,6 +131,26 @@
<LangVersion>7.0</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<CodeAnalysisRules>-Microsoft.Design#CA1021;-Microsoft.Design#CA1031;-Microsoft.Design#CA1002;-Microsoft.Design#CA1014;-Microsoft.Design#CA1024;-Microsoft.Usage#CA1801</CodeAnalysisRules>
<LangVersion>7.0</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<CodeAnalysisRules>-Microsoft.Design#CA1021;-Microsoft.Design#CA1031;-Microsoft.Design#CA1002;-Microsoft.Design#CA1014;-Microsoft.Design#CA1024;-Microsoft.Usage#CA1801</CodeAnalysisRules>
<LangVersion>7.0</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<ItemGroup>
<Reference Include="NLog, Version=5.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\..\..\..\..\packages\NLog.5.2.2\lib\net45\NLog.dll</HintPath>

View File

@ -135,6 +135,27 @@
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\VPN_Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<LangVersion>7.0</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\VPN_Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<LangVersion>7.0</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="NLog, Version=5.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\..\..\..\..\packages\NLog.5.2.2\lib\net45\NLog.dll</HintPath>

View File

@ -31,16 +31,6 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Applications
/// </summary>
public Int32? AppVersion;
/// <summary>
/// Max supported version of configuration.json for region EMEA.
/// </summary>
public String InterfaceMaxEmeaVersion;
/// <summary>
/// Max supported version of configuration.json for region NA.
/// </summary>
public String InterfaceMaxNaVersion;
/// <summary>
/// Get application name
/// </summary>

View File

@ -65,6 +65,21 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug-local IIS-CUST|x64'">
<OutputPath>bin\x64\Debug-local IIS-CUST\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<LangVersion>7.0</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\VPN_Debug\</OutputPath>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\..\..\..\packages\Newtonsoft.Json.13.0.3\lib\net40\Newtonsoft.Json.dll</HintPath>

View File

@ -220,6 +220,38 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug-local IIS-CUST|x64'">
<OutputPath>bin\x64\Debug-local IIS-CUST\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DocumentationFile>bin\Debug\Xylem.Common.Hardware.WaterMeter.Genesis.DataPackages.xml</DocumentationFile>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<LangVersion>7.0</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DocumentationFile>bin\x86\Debug\Xylem.Common.Hardware.WaterMeter.Genesis.DataPackages.xml</DocumentationFile>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<LangVersion>6</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DocumentationFile>bin\Debug\Xylem.Common.Hardware.WaterMeter.Genesis.DataPackages.xml</DocumentationFile>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\..\..\..\.shared\SharedAssemblyInfo.cs">
<Link>Properties\SharedAssemblyInfo.cs</Link>

View File

@ -49,7 +49,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisConfig
/// <summary>
/// Send delay between records in milliseconds before
/// new record is going to be send or between retries,
/// new record is going to be sent or between retries,
/// this time is independent of the timeout, it is
/// used to delay the next send record after successful
/// response from meter.

View File

@ -82,6 +82,25 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug-local IIS-CUST|x64'">
<OutputPath>bin\x64\Debug-local IIS-CUST\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<LangVersion>7.0</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.0</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\..\..\..\packages\Newtonsoft.Json.13.0.3\lib\net40\Newtonsoft.Json.dll</HintPath>
@ -100,10 +119,15 @@
</Compile>
<Compile Include="CommunicationConfig.cs" />
<Compile Include="Const\MeterConfig.cs" />
<Compile Include="SirtConfig.cs" />
<Compile Include="ProcessConfig.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\CommonCore\CommonCore.csproj">
<Project>{1B02C79E-0B19-43E2-8F6B-71EF0C786C97}</Project>
<Name>CommonCore</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\Interfaces\Ports\PortCore\PortCore.csproj">
<Project>{2E139F63-B6FE-4EA9-A098-85364FE9B26C}</Project>
<Name>PortCore</Name>

View File

@ -2,6 +2,7 @@
using System.ComponentModel;
using System.IO;
using Newtonsoft.Json;
using Xylem.Common.CommonCore.Consts;
namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisConfig
{
@ -10,35 +11,26 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisConfig
/// </summary>
public class ProcessConfig
{
/// <summary>
/// ctor
/// </summary>
public ProcessConfig()
{
UseRegisterWatchService = false;
UseErrorLogger = false;
AutoUpdateFiles = false;
ProductionMode = true;
}
/// <summary>
/// Load configuration file from AppRoaming or working directory
/// </summary>
/// <param name="file"></param>
public ProcessConfig(String file)
public Boolean ReadProcessConfig()
{
// check for AppRoaming
var configFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), nameof(Genesis), file);
// Check for AppRoaming
var configFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
nameof(Genesis), ProgramConfig.MeterConfigFileName);
if (!File.Exists(configFile))
{
// take actual working directory
configFile = Path.Combine(file);
// Take actual working directory
configFile = Path.Combine(ProgramConfig.MeterConfigFileName);
if (!File.Exists(configFile))
{
UseRegisterWatchService = false;
UseErrorLogger = false;
return;
AutoUpdateFiles = false;
ProductionMode = true;
return false;
}
}
@ -54,21 +46,21 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisConfig
CalibrationLoggerServiceUrl = meterConfig.CalibrationLoggerServiceUrl;
AutoUpdateFiles = meterConfig.AutoUpdateFiles;
ProductionMode = meterConfig.ProductionMode;
}
return true;
}
/// <summary>
/// Write file to AppRoaming and backup it to actual working directory
/// </summary>
/// <param name="file"></param>
public void Update(String file)
public void Update()
{
var configFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), nameof(Genesis), file);
var configFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
nameof(Genesis), ProgramConfig.MeterConfigFileName);
File.WriteAllText(configFile, JsonConvert.SerializeObject(this));
File.WriteAllText(file, JsonConvert.SerializeObject(this));
File.WriteAllText(ProgramConfig.MeterConfigFileName, JsonConvert.SerializeObject(this));
}
/// <summary>
@ -114,6 +106,6 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisConfig
[DefaultValue(true)]
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
public Boolean ProductionMode { get; set; } = true;
public Boolean ProductionMode { get; set; }
}
}

View File

@ -0,0 +1,96 @@
using System;
using System.IO;
using Newtonsoft.Json;
using Xylem.Common.CommonCore.Consts;
namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisConfig
{
/// <summary>
/// Configuration of SIRT
/// </summary>
public class SirtConfig
{
/// <summary>
/// Load SIRT configuration file from AppRoaming or working directory
/// </summary>
public Boolean ReadSirtConfig()
{
// Check for AppRoaming
var configFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
nameof(Genesis), ProgramConfig.SirtConfigFileName);
if (!File.Exists(configFile))
{
// Take actual working directory
configFile = Path.Combine(ProgramConfig.SirtConfigFileName);
if (!File.Exists(configFile))
{
SirtComport433MHz = null;
SirtComport868MHz = null;
ServiceSirtComport868MHz = null;
ServiceSirtComport433MHz = null;
SirtBoxNo = null;
StationId = null;
return false;
}
}
using (var tr = new StreamReader(configFile))
{
var sirtConfig = JsonConvert.DeserializeObject<SirtConfig>(tr.ReadToEnd());
SirtComport433MHz = sirtConfig.SirtComport433MHz;
SirtComport868MHz = sirtConfig.SirtComport868MHz;
ServiceSirtComport433MHz = sirtConfig.ServiceSirtComport433MHz; ;
ServiceSirtComport868MHz = sirtConfig.ServiceSirtComport868MHz; ;
SirtBoxNo = sirtConfig.SirtBoxNo;
StationId = sirtConfig.StationId;
}
return true;
}
/// <summary>
/// Write file to AppRoaming and backup it to actual working directory
/// </summary>
public void Update()
{
var configFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
nameof(Genesis), ProgramConfig.SirtConfigFileName);
File.WriteAllText(configFile, JsonConvert.SerializeObject(this));
File.WriteAllText(ProgramConfig.SirtConfigFileName, JsonConvert.SerializeObject(this));
}
/// <summary>
/// Comport for SIRT interface with 433MHz radio frequency
/// </summary>
public String SirtComport433MHz { get; set; }
/// <summary>
/// Comport for SIRT interface with 868MHz radio frequency
/// </summary>
public String SirtComport868MHz { get; set; }
/// <summary>
/// Box number for calibration settings
/// </summary>
public Int32? SirtBoxNo { get; set; }
/// <summary>
/// Station ID where the SIRT is used
/// </summary>
public Int32? StationId { get; set; }
/// <summary>
/// Service Comport for SIRT interface with 433MHz radio frequency
/// </summary>
public String ServiceSirtComport433MHz { get; set; }
/// <summary>
/// Service Comport for SIRT interface with 868MHz radio frequency
/// </summary>
public String ServiceSirtComport868MHz { get; set; }
}
}

View File

@ -30,7 +30,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore.Consts
METROLOGY_PARAMS = 1 << 14, //Bit 14
METROLOGY_MEASURE = 1 << 15, //Bit 15
ALL = 0xFFFFFF,
ALL = 0x7FFFFFFF //enum is defined as Int32
#pragma warning restore CS1591
// ReSharper restore InconsistentNaming
}

View File

@ -1,4 +1,6 @@
namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
using System.Text.RegularExpressions;
namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
{
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
@ -31,10 +33,16 @@
public List<ApplicationDefinition> ConfigApplicationDefinitions { get; }
= new List<ApplicationDefinition>();
/// <summary>
/// Information collected during 'configuration.json' read
/// </summary>
public readonly InterfaceInfo InterfaceInfo = new InterfaceInfo();
/// <summary>
/// Ctor
/// </summary>
public GenesisConfigurationReader() {}
public GenesisConfigurationReader() { }
/// <summary>
/// Ctor
@ -60,6 +68,9 @@
/// <param name="configurationJson"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
/// <remarks date="??" author="Stoyan Slatev">
/// - Initial.
/// </remarks>
/// <remarks date="2025-Aug-05" author="Thomas Wiedebusch">
/// - AppId from Byte to UInt16 including typecast for Byte[] return. To external, it will be used as Byte
/// as before this change. But being able to parse the configuration.json with OPTICALINTERFACE using the
@ -69,6 +80,13 @@
/// <remarks date="2025-Aug-07" author="Thomas Wiedebusch">
/// - Extract the max supported versions for EMEA and NA to check the supported FW.
/// </remarks>
/// <remarks date="2025-Sep-30" author="Thomas Wiedebusch">
/// - Supported application list introduced.
/// </remarks>
/// <remarks date="2025-Oct-10" author="Thomas Wiedebusch">
/// - Data size introduced including the new 'ByteArray' type and size to get rid of new defined 'uintxx_t'
/// data types.
/// </remarks>
public void BuildRegisterList(String configurationJson)
{
IDictionary<String, AppSection> sections;
@ -79,7 +97,7 @@
.DeserializeObject<IDictionary<String, AppSection>>(configurationJson, SerializerSettings)
?? new Dictionary<String, AppSection>();
}
catch (Exception )
catch (Exception)
{
sections = new Dictionary<String, AppSection>();
}
@ -94,20 +112,16 @@
var builds = sectionKVP.Value.Builds;
var emeaBuilds = builds["emea"];
var naBuilds = builds["na"];
String maxSupportedEmeaVersion = "";
String maxSupportedNaVersion = "";
if (emeaBuilds.Count > 0)
maxSupportedEmeaVersion = emeaBuilds[emeaBuilds.Count - 1].FW;
if (naBuilds.Count > 0)
maxSupportedNaVersion = naBuilds[naBuilds.Count - 1].FW;
ConfigApplicationDefinitions.Add(new ApplicationDefinition
InterfaceInfo.SupportedFwVersions = new List<String>();
foreach (var build in emeaBuilds)
{
AppId = appId,
AppName = appName,
AppVersion = appVersion,
InterfaceMaxEmeaVersion = maxSupportedEmeaVersion,
InterfaceMaxNaVersion = maxSupportedNaVersion
});
InterfaceInfo.SupportedFwVersions.Add(build.FW);
}
foreach (var build in naBuilds)
{
InterfaceInfo.SupportedFwVersions.Add(build.FW);
}
InterfaceInfo.InterfaceVersion = GenesisMeter.BuildFwVersionStringFromDec(appVersion);
continue;
}
@ -116,7 +130,7 @@
AppId = appId,
AppName = appName,
AppVersion = appVersion,
});
});
var section = sectionKVP.Value;
@ -154,6 +168,7 @@
AppAddress = appId,
AppName = appName,
DataType = GetType(detail.Type),
DataSize = GetSize(detail.Type),
Default = values?.Default is Int64 d ? d : default(Int64?),
IsAvailable = false,
Maximum = values?.Maximum is Int64 max ? max : default(Int64?),
@ -183,30 +198,107 @@
},
};
/// <summary>
/// Convert data types from interface 'configuration.json' to CLR type or array
/// </summary>
/// <param name="value"></param>
/// <returns>type</returns>
/// <exception cref="Exception"></exception>
/// <remarks date="??" author="Stoyan Slatev">
/// - Initial.
/// </remarks>
/// <remarks date="2025-Oct-10" author="Thomas Wiedebusch">
/// - Parsed all 'uintxx_t' which are not based on CLR types to byte-array
/// </remarks>
private static Type GetType(String value)
{
switch (value.ToLower())
// Catch all uintxx_t to split to standard CLR or to array
var lowStrValue = value.ToLower();
if (lowStrValue.Contains("uint") && lowStrValue.Contains("_t"))
{
switch (lowStrValue)
{
case "uint8_t": return typeof(Byte);
case "uint16_t": return typeof(UInt16);
case "uint32_t": return typeof(UInt32);
case "uint64_t": return typeof(UInt64);
default:
return typeof(ByteArray);
}
}
// Catch the signed standard CLR and some special types
switch (lowStrValue)
{
// CLR types
case "bool_t": return typeof(Boolean);
case "rpc": return typeof(Rpc);
case "string": return typeof(String);
case "uint32_t": return typeof(UInt32);
case "time_t": return typeof(TimeT);
case "status_t": return typeof(StatusT);
case "uint16_t": return typeof(UInt16);
case "uint8_t": return typeof(Byte);
case "enum8": return typeof(Enum8);
case "uint64_t": return typeof(UInt64);
case "uint96_t": return typeof(UInt96);
case "uint128_t": return typeof(UInt128);
case "int8_t": return typeof(SByte);
case "int16_t": return typeof(Int16);
case "int32_t": return typeof(Int32);
case "int64_t": return typeof(Int64);
case "int16_t": return typeof(Int16);
case "uint72_t": return typeof(UInt72);
case "uint48_t": return typeof(UInt48);
case "uint88_t": return typeof(UInt88);
default: throw new Exception($"Type {value} not recognized!");
case "string": return typeof(String);
// Special types defined in FW interface file 'configuration.json'
case "rpc": return typeof(Rpc);
case "time_t": return typeof(TimeT);
case "status_t": return typeof(StatusT);
case "enum8": return typeof(Enum8);
default:
throw new Exception($"Data type {value} in unknown!");
}
}
/// <summary>
/// Build the data size
/// </summary>
/// <param name="value"></param>
/// <returns>size</returns>
/// <remarks date="2025-Oct-10" author="Thomas Wiedebusch">
/// - Initial: - parsed all 'uintxx_t' which are not based on CLR types to byte-array
/// </remarks>
private static Int32 GetSize(String value)
{
// Catch all uintxx_t to split to standard CLR or to array
var lowStrValue = value.ToLower();
if (lowStrValue.Contains("uint") && lowStrValue.Contains("_t"))
{
switch (lowStrValue)
{
case "uint8_t": return sizeof(Byte);
case "uint16_t": return sizeof(UInt16);
case "uint32_t": return sizeof(UInt32);
case "uint64_t": return sizeof(UInt64);
default:
// Extract the size from the string
var dataSizeStr = Regex.Replace(lowStrValue, "[^0-9]", string.Empty);
if (Int32.TryParse(dataSizeStr, out var dataSize))
return dataSize / 8;
throw new Exception($"Data size {lowStrValue} cannot be converted!");
}
}
// Catch the signed standard CLR and some special types
switch (lowStrValue)
{
// CLR types
case "bool_t": return sizeof(Boolean);
case "int8_t": return sizeof(SByte);
case "int16_t": return sizeof(Int16);
case "int32_t": return sizeof(Int32);
case "int64_t": return sizeof(Int64);
// Take just some value as the string length is unknown
case "string": return 6 * 4;
// Special types defined in FW interface file 'configuration.json'
// Remote procedure call is always a 4 byte value
case "rpc": return sizeof(UInt32);
// Time will be in seconds since 01. Jan 2000 00:00:00 UTC as signed Int32
case "time_t": return sizeof(Int32);
case "status_t": return sizeof(UInt32);
case "enum8": return sizeof(Byte);
default:
throw new Exception($"Data type {value} in unknown!");
}
}
}

View File

@ -224,6 +224,41 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug-local IIS-CUST|x64'">
<OutputPath>bin\x64\Debug-local IIS-CUST\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DocumentationFile>bin\Debug\Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore.xml</DocumentationFile>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<GenerateSerializationAssemblies>On</GenerateSerializationAssemblies>
<LangVersion>7.0</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DocumentationFile>bin\x86\Debug\Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore.xml</DocumentationFile>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<LangVersion>6</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DocumentationFile>bin\Debug\Xylem.Common.Hardware.WaterMeter.Genesis.Core.xml</DocumentationFile>
<RegisterForComInterop>true</RegisterForComInterop>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<GenerateSerializationAssemblies>On</GenerateSerializationAssemblies>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\..\..\..\.shared\SharedAssemblyInfo.cs">
<Link>Properties\SharedAssemblyInfo.cs</Link>
@ -232,6 +267,7 @@
<Compile Include="Consts\PowCorrConst.cs" />
<Compile Include="Consts\MetrologyDefinition.cs" />
<Compile Include="IGenesisMeter.cs" />
<Compile Include="InterfaceInfo.cs" />
<Compile Include="PowerCorrectionCalc.cs" />
<Compile Include="PowerCorrection.cs" />
<Compile Include="Consts\ErrorState.cs" />
@ -378,6 +414,7 @@
<EmbeddedResource Include="Properties\Resources.de.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.de.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>

View File

@ -1,5 +1,6 @@
using Logic.ProductionToProductMapper.Cordonel;
using Newtonsoft.Json;
using NLog;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
@ -14,7 +15,6 @@ using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Timers;
using NLog;
using Xylem.Common.CommonCore.Configuration;
using Xylem.Common.CommonCore.Consts;
using Xylem.Common.CommonCore.ThreadWatcher;
@ -49,6 +49,7 @@ using Xylem.Common.Metrology.Measurements;
using Xylem.Common.Metrology.Measurements.Consts;
using Xylem.Common.Utils.Logging;
using Access = Xylem.Common.Hardware.WaterMeter.Genesis.Registers.Access;
using Register = Xylem.Common.Hardware.WaterMeter.Genesis.Registers.Register;
using Timer = System.Timers.Timer;
namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
@ -139,10 +140,20 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
private ILogger _loggerRawData;
/// <summary>
/// Optional request to use the offline passwords
/// </summary>
public Boolean UseOfflinePasswords { set; get; }
/// <summary>
/// Remind the offline password for comparison if this is actively used
/// </summary>
public String OfflinePassword { protected set; get; } = "";
/// <summary>
/// Process configuration
/// </summary>
public ProcessConfig Configuration { internal set; get; } = new ProcessConfig();
public ProcessConfig Configuration { internal set; get; } //= new ProcessConfig();
/// <summary>
/// Transmit protocol access for underlie objects to change response timeout
@ -190,7 +201,11 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
}
/// <inheritdoc />
public List<MeterApplications> MeterAppListVersion { protected set; get; } = new List<MeterApplications>();
public List<MeterApplications> MeterAppListVersion
{
protected set; get;
} = new List<MeterApplications>();
/// <inheritdoc />
public Int32? CoreRevision
@ -198,6 +213,12 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
protected set; get;
}
/// <inheritdoc />
public InterfaceInfo InterfaceInfo
{
get; internal set;
}
/// <inheritdoc />
public String StrCoreRevision
{
@ -217,30 +238,16 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
}
/// <inheritdoc />
public String LutCrc
{
protected set; get;
}
/// <inheritdoc />
public String MeterSize
{
protected set; get;
}
/// <inheritdoc />
public String InterfaceVersion
{
public String LutCrc {
protected set;
get;
} = "?";
/// <inheritdoc />
public String InterfaceMaxFwVersion
{
/// <inheritdoc />
public String MeterSize {
protected set;
get;
}
} = "?";
/// <inheritdoc />
public Boolean InterfaceSupportsFwVersion
@ -250,10 +257,10 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
}
/// <inheritdoc />
public String Region
{
protected set; get;
}
public String Region {
protected set;
get;
} = "?";
/// <inheritdoc />
public String MeterLength
@ -492,6 +499,15 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
}
}
/// <summary>
/// Unlocked the property change ability for special sequences.
/// </summary>
public Boolean UnlockEssentialProperties
{
get;
protected set;
}
#endregion
#region Setup
@ -522,6 +538,61 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
}
}
/// <summary>
/// Unlocked the property change ability for special sequences.
/// </summary>
/// <param name="unlockPropertyChange">true if unlock required</param>
/// <returns>true if possible</returns>
public Boolean EnablePropertyChangeAbility(Boolean unlockPropertyChange)
{
UnlockEssentialProperties = unlockPropertyChange;
return true;
}
/// <summary>
/// Set the meter size if previously unlocked
/// </summary>
/// <param name="meterSize">true if setting is allowed</param>
/// <returns>true if possible</returns>
public virtual Boolean SetMeterSize<T>(T meterSize)
{
if (!UnlockEssentialProperties)
return false;
if (meterSize is String)
{
var ms = meterSize.ToString();
if (Logic.ProductionOrderCore.OrderData.MeterSize.NA == MeterSizeConverter.ConvertMeterSizeNameToEnum(ms))
return false;
MeterSize = ms;
}
else if (meterSize.GetType() == typeof(MeterSize))
{
var ms = Convert.ToInt32(meterSize);
MeterSize = MeterSizeConverter.ConvertMeterSizeEnumToSizeName((MeterSize)ms);
}
else // Type is unknown
{
return false;
}
return true;
}
/// <summary>
/// Set the pressure sensor if previously unlocked
/// </summary>
/// <param name="pressureSensorAssembled">true if setting is allow</param>
/// <returns>true if possible</returns>
public Boolean SetPressureSensorAssembled(Boolean pressureSensorAssembled)
{
if (!UnlockEssentialProperties)
return false;
PressureSensorAssembled = pressureSensorAssembled;
return true;
}
/// <summary>
/// Returns meter registers
/// </summary>
@ -532,7 +603,6 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
}
/// <inheritdoc />
//void IWaterMeterWithRegisters.LoadConfiguration(String location)
public void LoadConfiguration(String location)
{
var configFile = ProgramConfig.RegisterDefinitionFileName;
@ -594,12 +664,29 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
Logger.Warn(ex, $"Slot:{Slot} - Register definition file update went wrong.");
}
//builds a configuration file reader from configuration.json and reads all registers definitions
//and application definitions
var registerReader = new GenesisConfigurationReader(configFilePath);
try
{
SetConfigRegisterDefinitions(registerReader.ConfigRegistersDefinitions);
SetConfigApplicationDefinitions(registerReader.ConfigApplicationDefinitions);
//builds a configuration file reader from configuration.json and reads all registers definitions
//and application definitions
var registerReader = new GenesisConfigurationReader(configFilePath);
InterfaceInfo = new InterfaceInfo
{
SupportedFwVersions = new List<String>()
};
InterfaceInfo.SupportedFwVersions.AddRange(registerReader.InterfaceInfo.SupportedFwVersions);
InterfaceInfo.InterfaceVersion = registerReader.InterfaceInfo.InterfaceVersion;
SetConfigRegisterDefinitions(registerReader.ConfigRegistersDefinitions);
SetConfigApplicationDefinitions(registerReader.ConfigApplicationDefinitions);
}
catch (Exception ex)
{
var msg = $"\'configuration.json\' file is incompatible!\nConfig Reader reports: {ex.Message}";
Logger.Error(ex, $"Slot:{Slot} - {msg}.");
throw new Exception(msg);
}
}
event EventHandler IMeter.OnDisposeCompleted
@ -798,7 +885,8 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
ledTransmit.GetTransmitPortSettings());
StreamingProtocol = new StreamingProtocol(streamingIdent, ignoreCorruptedData);
}
Configuration = new ProcessConfig(ProgramConfig.ConfigFileName);
Configuration = new ProcessConfig();
Configuration.ReadProcessConfig();
Logger.Debug($"Slot:{Slot} - Setup done");
}
@ -1133,6 +1221,12 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
/// <remarks date="2023-Feb-28" author="T.Wiedebusch">
/// - Used <see cref="MeterPwdHandlerDb.GetPasswordFromDb"/>
/// </remarks>
/// <remarks date="2025-Oct-10" author="T.Wiedebusch">
/// - Optional the offline passwords will be used.
/// </remarks>
/// <remarks date="2025-Oct-21" author="T.Wiedebusch">
/// - BUGFIX: Avoid request of password from DB if offline password usage fored.
/// </remarks>
private String GetPassword()
{
// without PCB ID it is not possible to login,
@ -1150,15 +1244,18 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
}
}
// on unknown password try to get it from DB
if (MeterPwdHandlerDb.GetPasswordFromDb(PcbId, out var password))
var password = "";
// if NOT offline password usage required try to get it from DB
if (!UseOfflinePasswords && MeterPwdHandlerDb.GetPasswordFromDb(PcbId, out password) )
{
Logger.Info($"Slot:{Slot} - Got password from GenesisPasswordService, " +
$"URL({ServiceUrls.GenesisGetPasswordServiceUrl() + PcbId})");
OfflinePassword = "";
}
else
{
Logger.Info($"Slot:{Slot} - Cannot get password from GenesisPasswordService, " +
if (!UseOfflinePasswords)
Logger.Info($"Slot:{Slot} - Cannot get password from GenesisPasswordService, " +
$"URL({ServiceUrls.GenesisGetPasswordServiceUrl() + PcbId}))");
// try to read the password from an offline password file
var offlinePwdPathName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
@ -1168,12 +1265,17 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
var listOfOfflinePasswords = JsonConvert.DeserializeObject<List<OfflinePasswordItem>>(
File.ReadAllText(offlinePwdPathName));
if (listOfOfflinePasswords != null)
if (listOfOfflinePasswords != null && listOfOfflinePasswords.Any(x => x.PcbId == PcbId ))
password = listOfOfflinePasswords.First(x => x.PcbId == PcbId).Password;
if (!string.IsNullOrEmpty(password))
{
Logger.Info($"Slot:{Slot} - Got password for PcbId:{PcbId} from password file!");
Logger.Info($"Slot:{Slot} - Got password for PcbId:{PcbId} from 'offline password' file!");
OfflinePassword = password;
}
else
{
Logger.Info($"Slot:{Slot} - 'offline password' file does not contain a password for PcbId:{PcbId} !");
}
}
@ -1302,8 +1404,13 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
}
/// <summary>
/// Building the FW Version string and the hexadecimal version out of 2 bytes of data or from an
/// input string like "1107", "11.07", "R1.1.07", "B1.1.07", "1.3.0B" or "9.0.2D".
/// Building the FW Version:
/// - string like "R1.1.07" or "B1.1.07" or optional reduced form for configuration capability check "1107",
/// - hexadecimal version like 0x1107 or 0x9107 for the 'B' version.
///
/// Input:
/// - optional string like "1107", "11.07", "R1.1.07", "B1.1.07", "1.3.0B" or "9.0.2D".
/// - optional 2 bytes representing the msb and lsb like 0x11 and 0x07.
///
/// REASON: FLEXNETVERSION is one application which does not follow the same rule of decimal numbers.
/// Instead, it uses hexadecimal digits.
@ -1312,6 +1419,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
/// <param name="strVersion">any string to evaluate like "11.07" or "R1.1.07" or "1.3.0B"</param>
/// <param name="msb">most significant byte representing the major and minor version</param>
/// <param name="lsb">last significant byte representing the built version</param>
/// <param name="buildShortVersion">will force to reduce the string output of FW version to e.g. "1107"</param>
/// <returns>FLEXNET version string e.g. "R1.2.47" or "B1.2.0C" </returns>
/// <remarks date="2023-Mar-02" author="Thomas Wiedebusch">
/// - Initial.
@ -1319,8 +1427,11 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
/// <remarks date="2023-Mar-08" author="Thomas Wiedebusch">
/// - Removed the optional leading "B" or "R" on strVersion input to create the fwVersion.
/// </remarks>
/// <remarks date="2025-Sep-30" author="Thomas Wiedebusch">
/// - .
/// </remarks>
public static String BuildFlexnetFwVersion(out UInt32 fwVersion, String strVersion, Byte? msb = null,
Byte? lsb = null)
Byte? lsb = null, Boolean buildShortVersion = false)
{
var major = 0;
var minor = 0;
@ -1338,7 +1449,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
minor = (Int32)(msb & 0x0F);
builtMajor = (Int32)((lsb & 0xF0) >> 4);
builtMinor = (Int32)(lsb & 0x0F);
fwVersion = (UInt32)((msb << 8) + lsb);
fwVersion = (UInt32)(((msb & 0xFF) << 8) + lsb);
}
else if (!string.IsNullOrEmpty(strVersion))
{
@ -1381,13 +1492,18 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
major += majorAdd;
}
// release version marked with "R"
if (major < majorIndicatorForB)
return $"R{major:X0}.{minor:X0}.{builtMajor:X0}{builtMinor:X0}";
// Build the release type id: 'R' for released version or 'B' for test version
var releaseTypeId = "R";
if (major >= majorIndicatorForB)
{
releaseTypeId = "B";
// Debug version marked with 'B'
major -= majorIndicatorForB;
}
// debug version marked with "B"
major -= majorIndicatorForB;
return $"B{major:X0}.{minor:X0}.{builtMajor:X0}{builtMinor:X0}";
return buildShortVersion ?
$"{major:X0}{minor:X0}{builtMajor:X0}{builtMinor:X0}" :
$"{releaseTypeId}{major:X0}.{minor:X0}.{builtMajor:X0}{builtMinor:X0}";
}
/// <summary>
@ -1651,6 +1767,9 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
/// AppId 256, which exceeds the byte range as this isn't a real application, but will be used to identify
/// the interface (configuration.json) version.
/// </remarks>
/// <remarks date="2025-Sep-30" author="Thomas Wiedebusch">
/// - Handle the interface compatibility FW version with short string like "1421" and discrete FW versions.
/// </remarks>
protected virtual void ReadMeterFirmwareAndAssignRegisters()
{
// Avoid overwriting of list if this already exits
@ -1667,29 +1786,13 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
CheckRegionSizeLutCrc();
UInt32 interfaceMaxEmeaVersion = 0;
UInt32 interfaceMaxNaVersion = 0;
var strShortFwVersion = "";
// Get all existing applications from meter register dictionary
foreach (var meterApp in ConfigApplications.OrderBy(o => o.AppId))
{
// The "OPTICALINTERFACE" isn't a real application as it identifies exclusively the configuration.json
if (meterApp.AppName.Equals("OPTICALINTERFACE"))
{
// Build the interface id for information of compatibility from FW to configuration.json
InterfaceVersion = BuildFwVersionStringFromDec(meterApp.AppVersion);
// Build the max supported versions for EMEA and NA to check the supported FW
if (Region.Equals("EMEA"))
InterfaceMaxFwVersion = BuildFlexnetFwVersion(out interfaceMaxEmeaVersion,
meterApp.InterfaceMaxEmeaVersion);
if (Region.Equals("NA"))
InterfaceMaxFwVersion = BuildFlexnetFwVersion(out interfaceMaxNaVersion,
meterApp.InterfaceMaxNaVersion);
continue;
}
UInt32 readFwVersion = 0;
UInt16 readFwCrc = 0;
var isInstalled = false;
var installationStatus = MeterAppState.MeterAppNotInstalled;
var versionString = "";
@ -1710,6 +1813,8 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
readFwVersionBytes[0]);
versionString = FwVersion;
InstalledFwVersion = readFwVersion;
// create a short FW version info being able to compare the interface compatibility
strShortFwVersion = BuildFlexnetFwVersion(out _, FwVersion, buildShortVersion: true);
}
else
{
@ -1815,20 +1920,17 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
Logger.Info($"Slot:{Slot} - Meter size: {MeterSize}");
Logger.Info($"Slot:{Slot} - Upgrade permission: {MetrologyUpgradePermission:X2}");
Logger.Info($"Slot:{Slot} - Interface (configuration.json) version: {InterfaceVersion}");
if (InstalledFwVersion != null &&
((Region.Equals("EMEA") && interfaceMaxEmeaVersion >= InstalledFwVersion) ||
(Region.Equals("NA") && interfaceMaxNaVersion >= InstalledFwVersion)))
Logger.Info($"Slot:{Slot} - Interface (configuration.json) version: {InterfaceInfo.InterfaceVersion}");
if (InterfaceInfo.SupportedFwVersions.Any(strFwVersion => strFwVersion.Contains(strShortFwVersion)))
{
InterfaceSupportsFwVersion = true;
Logger.Info($"Slot:{Slot} - Interface supports FW version: {FwVersion}");
Logger.Info($"Slot:{Slot} - Interface supports this FW version: {FwVersion}");
}
else
{
InterfaceSupportsFwVersion = false;
Logger.Warn($"Slot:{Slot} - Interface does not support FW version! Installed FW version: {FwVersion}, " +
$"Interface supports max FW version: {InterfaceMaxFwVersion}");
Logger.Warn($"Slot:{Slot} - Interface does not support this FW version: {FwVersion}");
}
// initial list of ALL registers defined in configuration.json
@ -2081,6 +2183,48 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
return fullAlarm;
}
/// <inheritdoc/>
public void ClearAlarm()
{
var beforeCancelAlarmEnableMask = RegisterConverter.ByteArrayToValue<UInt32>(ReadRegister("CUSTOMER_AlarmEnableMask"));
var beforeCancelAlarmBroadcastMask = RegisterConverter.ByteArrayToValue<UInt32>(ReadRegister("CUSTOMER_AlarmBroadcastMask"));
WriteRegister("CUSTOMER_AlarmEnableMask", Alarm.ALL);
WriteRegister("CUSTOMER_AlarmBroadcastMask", Alarm.ALL);
WriteRegister(Register.Customer.TriggerAlarmCancel, Alarm.ALL);
if (GetRegistersDic().Any(a => a.Key.RegisterName == "PersistenceGroup1"))
{
// ReSharper disable once UnusedVariable used for debug
var x = ReadRegister("SENSUSRADIO_PersistenceGroup1");
WriteRegister("SENSUSRADIO_PersistenceGroup1", new Byte[] { 0x00, 0xff, 0x00, 0xff });
}
if (GetRegistersDic().Any(a => a.Key.RegisterName == "PersistenceGroup2"))
{
WriteRegister("SENSUSRADIO_PersistenceGroup2", new Byte[] { 0x00, 0xff, 0x00, 0xff });
}
if (GetRegistersDic().Any(a => a.Key.RegisterName == "PersistenceGroup3"))
{
WriteRegister("SENSUSRADIO_PersistenceGroup3", new Byte[] { 0x00, 0xff, 0x00, 0xff });
}
if (GetRegistersDic().Any(a => a.Key.RegisterName == "PersistenceGroup4"))
{
WriteRegister("SENSUSRADIO_PersistenceGroup4", new Byte[] { 0x00, 0xff, 0x00, 0xff });
}
if (GetRegistersDic().Any(a => a.Key.RegisterName == "PersistenceGroup5"))
{
WriteRegister("SENSUSRADIO_PersistenceGroup5", new Byte[] { 0x00, 0xff, 0x00, 0xff });
}
if (GetRegistersDic().Any(a => a.Key.RegisterName == "PersistenceGroup6"))
{
WriteRegister("SENSUSRADIO_PersistenceGroup6", new Byte[] { 0x00, 0xff, 0x00, 0xff });
}
WriteRegister("CUSTOMER_AlarmEnableMask", beforeCancelAlarmEnableMask);
WriteRegister("CUSTOMER_AlarmBroadcastMask", beforeCancelAlarmBroadcastMask);
}
/// <summary>
/// Reset the empty pipe alarm
/// </summary>
@ -2266,6 +2410,9 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
/// <remarks date="2024-May-17" author="Thomas Wiedebusch">
/// - Changed sensitive information from "*****" to SHA256.
/// </remarks>
/// <remarks date="2025-Oct-13" author="Thomas Wiedebusch">
/// - Date size directly from register object.
/// </remarks>
public virtual Byte[] ReadRegister(String regName, Int32? expectedLength = null,
UInt16 skipRetryErrorCode = CommunicationConfig.SkipRetryErrorCode)
{
@ -2274,14 +2421,13 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
{
var regDef = ConfigRegister.GetRegisterDefinitionByName(regName);
ConfigRegister.Set(regDef, null);
//_logger.Info($"Slot:{Slot} - Read register({regDef.GetIdent()})");
var hideDataInLog = regDef.RegisterName.Contains("EncryptionKey");
// setup length based on data type
if (!expectedLength.HasValue)
{
expectedLength = RegisterConverter.SizeOf(regDef);
expectedLength = regDef.DataSize;
}
var dataLengthPreset = expectedLength.Value;
@ -2875,6 +3021,17 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
}
}
/// <summary>
/// Dummy
/// </summary>
/// <remarks date="???" author="Roland Drabesch">
/// - Initial.
/// </remarks>
public void BuildAndCheckCalibFactorsAllChannels(Double refVolumeCm, Double? refTimeS = null, Double reqDeviationPercent = 0, Double maxCalibFactorTolerancePercent = 0)
{
throw new NotImplementedException();
}
#endregion
}
}

View File

@ -25,10 +25,26 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
get;
}
/// <summary>
/// Interface information
/// </summary>
InterfaceInfo InterfaceInfo
{
get;
}
/// <summary>
/// This FW version is supported by the interface "configuration.json".
/// </summary>
Boolean InterfaceSupportsFwVersion
{
get;
}
/// <summary>
/// Transmit protocol access for underlie objects to change response timeout
/// </summary>
ITransmitProtocol TransmitProtocol{ get; }
ITransmitProtocol TransmitProtocol { get; }
/// <summary>
/// List of all present meter applications installed in meter
@ -89,35 +105,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
/// <summary>
/// This is the meter size.
/// </summary>
String MeterSize
{
get;
}
/// <summary>
/// This is the version of the interface "configuration.json".
/// </summary>
String InterfaceVersion
{
get;
}
/// <summary>
/// This is the max supported firmware version of the interface "configuration.json".
/// It is the max version for a specific region.
/// </summary>
String InterfaceMaxFwVersion
{
get;
}
/// <summary>
/// This FW version is supported by the interface "configuration.json".
/// </summary>
Boolean InterfaceSupportsFwVersion
{
get;
}
String MeterSize { get; }
/// <summary>
/// Length of the meter.
@ -127,10 +115,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
/// <summary>
/// Pressure sensor assembled to meter.
/// </summary>
Boolean PressureSensorAssembled
{
get;
}
Boolean PressureSensorAssembled { get; }
/// <summary>
/// Region (EMEA, NA or China).
@ -188,6 +173,14 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
get; set;
}
/// <summary>
/// Unlocked the property change ability for special sequences.
/// </summary>
Boolean UnlockEssentialProperties
{
get;
}
#endregion
#region methods
@ -198,6 +191,22 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
/// </summary>
void CheckRegionSizeLutCrc();
/// <summary>
/// Unlocked the property change ability for special sequences.
/// </summary>
Boolean EnablePropertyChangeAbility(Boolean unlockPropertyChange);
/// <summary>
/// Set the meter size if previously unlocked.
/// The data types are: - String like "DN50" or
/// </summary>
Boolean SetMeterSize<T>(T meterSize);
/// <summary>
/// Set the pressure sensor if previously unlocked
/// </summary>
Boolean SetPressureSensorAssembled(Boolean pressureSensorAssembled);
/// <summary>
/// Reset the empty pipe alarm
/// </summary>
@ -232,7 +241,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
/// </summary>
/// <returns></returns>
MeterRegisters GetConfigRegistersDefinitions();
/// <summary>
/// Common routine for reboot being able to override this routine which will be called in
/// MeteResetPsu to simulate a reboot.
@ -264,6 +273,14 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
Byte[] ReadRegister(String regName, Int32? expectedLength = null,
UInt16 skipRetryErrorCode = CommunicationConfig.SkipRetryErrorCode);
/// <summary>
/// Clear all pending alarms.
/// </summary>
/// <remarks date="2025-Aug-26" author="Roland Drabesch">
/// - Initial.
/// </remarks>
void ClearAlarm();
#endregion
}
}

View File

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
{
/// <summary>
/// Collection of interface information
/// </summary>
public class InterfaceInfo
{
/// <summary>
/// The interface version
/// </summary>
public String InterfaceVersion { get; set; }
/// <summary>
/// List of supported FW versions by this interface
/// </summary>
public List<String> SupportedFwVersions { get; set; }
}
}

View File

@ -70,6 +70,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
/// <summary>
/// List for un-reversed parameters which can be written, all others need to be swapped byte-wise
/// </summary>
//TODO THW take configuration.json and use for String and Array type, see RegisterConverter
private static readonly List<String> _unReversedParameters = new List<String>
{
"SENSUSRADIO_Authentification", //UInt96
@ -95,7 +96,6 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
private static readonly List<String> _excludedFromCompareParameters = new List<String>
{
"CUSTOMER_AlarmVisualMask", // Fully hard coded, cannot be overwritten
//"CUSTOMER_AlarmEnableMask", //Depending on FW version Will be overwritten by SENSUSRADIO if set System state to 0xFF
"CUSTOMER_AppArrangement", // Is read only, makes no sense to compare anything
"SENSUSRADIO_UpgFWVersion" // After a FW-Update the FW version has changed
};
@ -111,7 +111,6 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
/// </summary>
private static readonly List<String> _fieldUpdateBlacklist = new List<String>
{
//TODO THW "CUSTOMER_AlarmEnableMask", // Under discussion
"CUSTOMER_AlarmVisualMask",
"CUSTOMER_BackupCalendarSeconds",
"CUSTOMER_InstallationTime",
@ -574,6 +573,23 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
}
// Take this parameter as is
//TODO THW take configuration.json and use for String and Array type, see RegisterConverter
//take the register properties from configuration.json
//get the pre-defined dictionary
//var meterRegisters = MockGenesis based on FW version .GetConfigRegistersDefinitions();
//var regDef = meterRegisters.GetRegisterDefinitionByName(proPar.RegisterName);
//if (regDef.DataType.Name.Equals("Int32"))
//{
// Add parameter if it is not in the list
//if (sortableProgrammingParameters.All(a => !proPar.RegisterName.Equals(a.RegisterName)))
//{
// sortableProgrammingParameters.Add(proPar);
// continue;
//}
//}
if (_unReversedParameters.Contains(proPar.RegisterName))
{
// Add parameter if it is not in the list
@ -1673,6 +1689,9 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
/// <remarks date="2025-Apr-07" author="Thomas Wiedebusch">
/// - CancellationToken.
/// </remarks>
/// <remarks date="2025-Oct-13" author="Thomas Wiedebusch">
/// - Date size directly from register object.
/// </remarks>
private Boolean ReadRegistersSet(ref List<RecoveryRegisterItem> registers, CancellationToken cancellationToken)
{
if (_currentGenesis == null)
@ -1708,7 +1727,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
try
{
var rawRegister = _currentGenesis.ReadRegister(regName, RegisterConverter.SizeOf(regDef));
var rawRegister = _currentGenesis.ReadRegister(regName, regDef.DataSize);
try
{
if (register != null && rawRegister != null)

View File

@ -65,7 +65,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
}
/// <inheritdoc />
public void BuildAndCheckCalibFactorsAllChannels(Double refVolumeCm, Double? refTimeS, Double reqDeviationPercent, Double maxCalibFactorTolerancePercent = MeterConfig.DefaultMaxCalibFactorTolerancePercent)
public void BuildAndCheckCalibFactorsAllChannels(Double refVolumeCm, Double? refTimeS, Double reqDeviationPercent, Double maxCalibFactorTolerancePercent = MeterConfig.DefaultMaxCalibFactorTolerancePercent, int? testrunNr = null)
{
for (var channel = 0; channel < MeterConfig.CalibChannels; channel++)
{
@ -107,7 +107,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
Logger.Info($"Slot:{Slot}, Channel:{channel} - New calibration factor({_calibFactor[channel - 1].GetRelativeCalibFactor()}rel/{calibFactorRel})");
Logger.Info($"Slot:{Slot}, Channel:{channel} - Calc /{ _calibFactor[channel - 1].GetMeterRawCalibFactor()} * {calibFactorRel.Value}) -> UInt16");
Logger.Info($"Slot:{Slot}, Channel:{channel} - Calc /{_calibFactor[channel - 1].GetMeterRawCalibFactor()} * {calibFactorRel.Value}) -> UInt16");
//Setup the required tolerance value to check against
@ -125,7 +125,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
var warnMessage = $"Slot:{Slot}, Channel:{channel} - " +
$"Calibration factor is out of range({calibFactorRel.Value}rel)";
Logger.Warn(warnMessage);
throw new ApplicationException(warnMessage);
// throw new ApplicationException(warnMessage);
}
@ -138,7 +138,9 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
p2Value = _calibFactor[1].GetMeterRawCalibFactor(),
p3Target = reqDeviationPercent,
p3Value = _calibFactor[2].GetMeterRawCalibFactor(),
dt = DateTime.UtcNow
dt = DateTime.UtcNow,
testrunNr = testrunNr
};
@ -146,14 +148,14 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
try
{
var tmpUrl = "http://10.49.40.25/MeterProcessState/api/TestBench/SetCalibrationValues";
Logger.Info($"Request Url: { tmpUrl}");
Logger.Info($"Request Url: {tmpUrl}");
//ToDO: Update to service URl
LocalWebRequest.PostAsJson<JustageResults>(t, tmpUrl);
}
catch (Exception ex)
{
Logger.Error($"Request Url: { ex.Message}");
Logger.Error($"Request Url: {ex.Message}");
}
@ -209,10 +211,30 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
//WriteRegister<UInt16>(Register.Genesisflow.ForwardArrow, 0, checkRegister: true);
WriteRegister<UInt16>(Register.Genesisflow.StoreCalibration, 1);
Logger.Info($"Slot:{Slot} - StoreCalibration { RegisterConverter.ByteArrayToValue<UInt16>(ReadRegister(Register.Genesisflow.StoreCalibration))}");
Logger.Info($"Slot:{Slot} - StoreCalibration {RegisterConverter.ByteArrayToValue<UInt16>(ReadRegister(Register.Genesisflow.StoreCalibration))}");
WriteRegister<UInt16>(Register.Genesisflow.TriggerActive, 1);
Logger.Info($"Slot:{Slot} - Set forward arrow of LCD, reset accumulators, set sample rate to 2Hz");
WriteRegister<Byte>(Register.Genesisflow.SampleRate, 10, checkRegister: true);
try
{
if (GetRegistersDic().Any(a => a.Key.RegisterName == "GENESISFLOW_DelayedLedOff"))
{
WriteRegister("GENESISFLOW_DelayedLedOff", 60 * 60 * 2, true);
Logger.Info($"Slot:{Slot} - GENESISFLOW_DelayedLedOff to {60 * 60 * 2}S");
}
else
{
Logger.Info($"Slot:{Slot} - GENESISFLOW_DelayedLedOff is not present");
}
}
catch (Exception ex)
{
Logger.Info($"Slot:{Slot} - {ex}");
}
}
}
}

View File

@ -95,6 +95,19 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore
//WriteRegister(Register.Genesisflow.StoreCalibration, 1);
//WriteRegister(Register.Genesisflow.StoreConfiguration, 1);
try
{
if (GetRegistersDic().Any(a => a.Key.RegisterName == "GENESISFLOW_DelayedLedOff"))
{
WriteRegister("GENESISFLOW_DelayedLedOff", 60 * 60 * 2, false);
}
}
catch (Exception)
{
}
}
else

View File

@ -91,6 +91,25 @@
<OutputPath>bin\x64\Debug-local IIS-CUST\</OutputPath>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<LangVersion>7.0</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.0</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\..\..\..\packages\Newtonsoft.Json.13.0.3\lib\net40\Newtonsoft.Json.dll</HintPath>

View File

@ -58,6 +58,25 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug-local IIS-CUST|x64'">
<OutputPath>bin\x64\Debug-local IIS-CUST\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\..\..\..\packages\Newtonsoft.Json.13.0.3\lib\net40\Newtonsoft.Json.dll</HintPath>

View File

@ -37,6 +37,15 @@
<OutputPath>bin\Debug-local IIS-CUST\</OutputPath>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\..\..\..\packages\Newtonsoft.Json.13.0.3\lib\net40\Newtonsoft.Json.dll</HintPath>
@ -64,7 +73,7 @@
<Name>CommonCore.Configuration</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\..\LaaPackages\LaaPackages.Features.Cordonel\LaaPackages.Features.Cordonel.csproj">
<Project>{8befd3ac-bb21-4b62-8d9a-cf8cbfd439eb}</Project>
<Project>{8BEFD3AC-BB21-4B62-8D9A-CF8CBFD439EB}</Project>
<Name>LaaPackages.Features.Cordonel</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\..\Logic\ProductionOrderCore\ProductionOrderCore.csproj">

View File

@ -1,13 +1,14 @@
using System;
using LaaPackages.Features.Cordonel.Models;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Net;
using LaaPackages.Features.Cordonel.Models;
using Newtonsoft.Json;
using System.Text;
using Xylem.Common.CommonCore.Configuration;
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore;
using Xylem.Common.Hardware.WaterMeter.Genesis.Registers;
using Xylem.Common.Logic.SoftwareAccessHelper;
using Xylem.Common.Logic.ProductionOrderCore.TestResults;
using Xylem.Common.Logic.SoftwareAccessHelper;
namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisStatus
{
@ -20,6 +21,11 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisStatus
/// </summary>
public static class GenesisStatusHandler
{
/// <summary>
/// Used to mark an error
/// </summary>
public const String ERROR_MARKER = "ERROR";
/// <summary>
/// Average days years
/// </summary>
@ -111,7 +117,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisStatus
return false;
}
public static Boolean GetCordonelRequirementInfoFromDbByFANr(String fanr, CordonelRequirements prodRequirements, out string errorMsg)
public static Boolean GetCordonelRequirementInfoFromDbByFANr(String fanr, CordonelRequirements prodRequirements, out String errorMsg)
{
errorMsg = "";
if (null == prodRequirements || string.IsNullOrEmpty(fanr))
@ -149,7 +155,8 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisStatus
return false;
}
public static Boolean GetCordonelRequirementInfoFromDbByMeterSize(int size, CordonelRequirements prodRequirements, out string errorMsg)
public static Boolean GetCordonelRequirementInfoFromDbByMeterSize(Int32 size, CordonelRequirements prodRequirements,
out String errorMsg)
{
errorMsg = "";
@ -397,5 +404,48 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisStatus
status.StorageMonths = timeDifference.GetValueOrDefault().TotalSeconds * MONTHS_PER_SECONDS;
return true;
}
/// <summary>
/// String of lifetime calculation results.
/// </summary>
/// <param name="currentGenesis"></param>
/// <param name="genesisStatus"></param>
/// <returns>true if all calculations could be executed</returns>
/// <remarks date="2023-Mar-02" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
public static String LifeTimeInformationString(IGenesisMeter currentGenesis,GenesisStatus genesisStatus)
{
var sbMSG = new StringBuilder();
if (genesisStatus == null ||
currentGenesis == null ||
!BuildLifeTimeInformation(currentGenesis, genesisStatus, out _))
{
sbMSG.AppendLine($"{ERROR_MARKER}: Unable to calculate storage time and battery power consumption!");
return sbMSG.ToString();
}
sbMSG.AppendLine($"POWERMON_TotalUsedSeconds: {genesisStatus.ExceededLifeTime_s:N0} s");
sbMSG.AppendLine($"POWERMON_TotalUsedCharge: {genesisStatus.DrainedBatteryLoad_uAs:N0} µAs");
sbMSG.AppendLine($"POWERMON_BatteryQuantity: {genesisStatus.BatteryQuantity} pieces");
sbMSG.AppendLine($"POWERMON_BatteryMilliAHrRating: {genesisStatus.InitialBatteryLoad_mAh:N0} mAh");
sbMSG.AppendLine(genesisStatus.FwCalculatedRemainingLifeTimeYears != null ?
$"POWERMON_RemainingSeconds: {genesisStatus.FwCalculatedRemainingLifeTime_s:N0} s" :
"POWERMON_RemainingSeconds: unsupported");
sbMSG.AppendLine("");
sbMSG.AppendLine($"Actual storage time: {genesisStatus.StorageMonths:F1} months");
sbMSG.AppendLine("SW estimated remaining lifetime based on average power consumption: " +
$"{genesisStatus.RemainingLifeTimeYears:F2} years");
sbMSG.AppendLine(genesisStatus.FwCalculatedRemainingLifeTimeYears != null
? "FW calculated remaining lifetime based on 'remaining seconds': " +
$"{genesisStatus.FwCalculatedRemainingLifeTimeYears:F2} years"
: "FW calculated remaining lifetime based on 'remaining seconds' unsupported by FW: " +
$"{currentGenesis.FwVersion}");
sbMSG.AppendLine($"Totally drained battery load: {genesisStatus.DrainedBatteryLoadPercent:F2} %");
return sbMSG.ToString();
}
}
}

View File

@ -12,6 +12,7 @@ using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore;
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile;
using Xylem.Common.Hardware.WaterMeter.Genesis.Registers;
using Xylem.Common.Hardware.WaterMeter.Genesis.Registers.DataTypes;
using Xylem.Common.Logic.ProductionOrderCore.OrderData;
using Xylem.Common.Logic.ProductionOrderCore.TestResults;
namespace Xylem.Common.Hardware.WaterMeter.Genesis.MockGenesis
@ -96,7 +97,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.MockGenesis
/// </summary>
private const String RootMockFwPath = "MockFwExamples";
/// <summary>
/// <summary>
/// Mock object can overwrite PcbId for test purposes and set password to null to avoid
/// usage of wrong password and lock of the device trying to log in with the wrong password
/// </summary>
@ -169,7 +170,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.MockGenesis
/// </summary>
public new String MeterSize
{
set => base.MeterSize = value;
private set => base.MeterSize = value;
get => base.MeterSize;
}
@ -187,7 +188,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.MockGenesis
/// </summary>
public new Boolean PressureSensorAssembled
{
set => base.PressureSensorAssembled = value;
private set => base.PressureSensorAssembled = value;
get => base.PressureSensorAssembled;
}
@ -217,7 +218,6 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.MockGenesis
/// Fw package path relative to solution main folder.
/// </summary>
private readonly String _mockFwPackageRootPath;
#endregion ----------------------------- Properties -----------------------------------------------------------
#region --------------------------------- Default package description file ------------------------------------
@ -450,6 +450,9 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.MockGenesis
/// <remarks date="2025-Aug-07" author="Thomas Wiedebusch">
/// - Check interface compatibility.
/// </remarks>
/// <remarks date="2025-Sep-30" author="Thomas Wiedebusch">
/// - Handle the interface compatibility FW version with short string like "1421" and discrete FW versions.
/// </remarks>
protected override void ReadMeterFirmwareAndAssignRegisters()
{
// Avoid overwriting of list if this already exits
@ -473,26 +476,10 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.MockGenesis
return;
}
UInt32 interfaceMaxEmeaVersion = 0;
UInt32 interfaceMaxNaVersion = 0;
var strInterfaceMaxEmeaVersion = "";
var strInterfaceMaxNaVersion = "";
var strShortFwVersion = "";
//Get all existing applications from meter register dictionary
foreach (var meterApp in ConfigApplications.OrderBy(o => o.AppId))
{
if (meterApp.AppName.Equals("OPTICALINTERFACE"))
{
// Build the interface id for information of compatibility from FW to configuration.json
InterfaceVersion = BuildFwVersionStringFromDec(meterApp.AppVersion);
// Build the max supported versions for EMEA and NA to check the supported FW
strInterfaceMaxEmeaVersion = BuildFlexnetFwVersion(out interfaceMaxEmeaVersion,
meterApp.InterfaceMaxEmeaVersion);
strInterfaceMaxNaVersion = BuildFlexnetFwVersion(out interfaceMaxNaVersion,
meterApp.InterfaceMaxNaVersion);
continue;
}
// Take all listed config apps even if not installed
var app = new MeterApplications
{
@ -521,6 +508,8 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.MockGenesis
{
InstalledFwVersion = fileApp.Version;
FwVersion = fileApp.StrVersion;
// create a short FW version info being able to compare the interface compatibility
strShortFwVersion = BuildFlexnetFwVersion(out _, FwVersion, buildShortVersion: true);
}
}
@ -550,28 +539,17 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.MockGenesis
Region = "EMEA";
}
}
// Assign the max supported FW version of the interface depending on the region
if (Region.Equals("EMEA"))
InterfaceMaxFwVersion = strInterfaceMaxEmeaVersion;
if (Region.Equals("NA"))
InterfaceMaxFwVersion = strInterfaceMaxNaVersion;
// Check if the interface supports the FW
if (InstalledFwVersion != null &&
((Region.Equals("EMEA") && interfaceMaxEmeaVersion >= InstalledFwVersion) ||
(Region.Equals("NA") && interfaceMaxNaVersion >= InstalledFwVersion)))
if (InterfaceInfo.SupportedFwVersions.Any( strFwVersion => strFwVersion.Contains(strShortFwVersion)))
{
InterfaceSupportsFwVersion = true;
Logger.Info($"Slot:{Slot} - Interface supports FW version: {FwVersion}");
Logger.Info($"Slot:{Slot} - Interface supports this FW version: {FwVersion}");
}
else
{
InterfaceSupportsFwVersion = false;
Logger.Warn($"Slot:{Slot} - Interface does not support FW version! Installed FW version: {FwVersion}, " +
$"Interface supports max FW version: {InterfaceMaxFwVersion}");
Logger.Warn($"Slot:{Slot} - Interface does not support this FW version: {FwVersion}");
}
}
catch (Exception ex)
{
@ -759,6 +737,45 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.MockGenesis
return IsLoggedOn;
}
/// <inheritdoc />
/// <summary>
/// Set the meter size if previously unlocked.
/// - MockGenesis allows additional empty string or question mark string!
/// </summary>
/// <param name="meterSize">true if setting is allowed</param>
/// <returns>true if possible</returns>
public override Boolean SetMeterSize<T>(T meterSize)
{
if (!UnlockEssentialProperties)
return false;
if (meterSize is String)
{
var ms = meterSize.ToString();
// MockGenesis allows 'killing' of MeterSize
if (Equals(meterSize,"") || Equals(meterSize,"?"))
{
}
else if (Logic.ProductionOrderCore.OrderData.MeterSize.NA == MeterSizeConverter.ConvertMeterSizeNameToEnum(ms))
{
return false;
}
MeterSize = ms;
}
else if (meterSize.GetType() == typeof(MeterSize))
{
var ms = Convert.ToInt32(meterSize);
MeterSize = MeterSizeConverter.ConvertMeterSizeEnumToSizeName((MeterSize)ms);
}
else // Type is unknown
{
return false;
}
return true;
}
/// <inheritdoc />
/// <summary>
/// Simulate login with password to mock Genesis for test purposes

View File

@ -31,6 +31,15 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<ItemGroup>
<Reference Include="NCrunch.Framework, Version=5.11.0.0, Culture=neutral, PublicKeyToken=01d101bf6f3e0aea, processorArchitecture=MSIL">
<HintPath>..\..\..\..\packages\NCrunch.Framework.5.11.0\lib\net35\NCrunch.Framework.dll</HintPath>

View File

@ -215,6 +215,38 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug-local IIS-CUST|x64'">
<OutputPath>bin\x64\Debug-local IIS-CUST\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DocumentationFile>bin\Debug\Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.RequestProtocol.xml</DocumentationFile>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<LangVersion>7.0</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DocumentationFile>bin\x86\Debug\Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.RequestProtocol.xml</DocumentationFile>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<LangVersion>6</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DocumentationFile>bin\Debug\Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.Request.xml</DocumentationFile>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\..\..\..\..\.shared\SharedAssemblyInfo.cs">
<Link>Properties\SharedAssemblyInfo.cs</Link>

View File

@ -212,6 +212,38 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug-local IIS-CUST|x64'">
<OutputPath>bin\x64\Debug-local IIS-CUST\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DocumentationFile>bin\Debug\Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.StreamingProtocol.xml</DocumentationFile>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<LangVersion>7.0</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DocumentationFile>bin\Debug\Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.Streaming.xml</DocumentationFile>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<LangVersion>6</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DocumentationFile>bin\Debug\Xylem.Common.Hardware.WaterMeter.Genesis.Protocols.Streaming.xml</DocumentationFile>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\..\..\..\..\.shared\SharedAssemblyInfo.cs">
<Link>Properties\SharedAssemblyInfo.cs</Link>

View File

@ -0,0 +1,6 @@
namespace Xylem.Common.Hardware.WaterMeter.Genesis.Registers.DataTypes
{
public struct ByteArray
{
}
}

View File

@ -1,8 +0,0 @@
using System;
namespace Xylem.Common.Hardware.WaterMeter.Genesis.Registers.DataTypes
{
public struct UInt128
{
}
}

View File

@ -1,8 +0,0 @@
using System;
namespace Xylem.Common.Hardware.WaterMeter.Genesis.Registers.DataTypes
{
public struct UInt48
{
}
}

View File

@ -2,7 +2,7 @@
namespace Xylem.Common.Hardware.WaterMeter.Genesis.Registers.DataTypes
{
public struct UInt88
public struct UInt672
{
}
}

View File

@ -1,8 +0,0 @@
using System;
namespace Xylem.Common.Hardware.WaterMeter.Genesis.Registers.DataTypes
{
public struct UInt72
{
}
}

View File

@ -1,8 +0,0 @@
using System;
namespace Xylem.Common.Hardware.WaterMeter.Genesis.Registers.DataTypes
{
public struct UInt96
{
}
}

View File

@ -87,6 +87,10 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Registers
/// <remarks date="2024-Mar-20" author="Thomas Wiedebusch">
/// - Hash password and encryption key with SHA256.
/// </remarks>
/// <remarks date="2025-Oct-10" author="Thomas Wiedebusch">
/// - Data size introduced including the new 'ByteArray' type and size to get rid of new defined 'uintxx_t'
/// data types.
/// </remarks>
public static String GetRegisterRawText(RegisterDefinition registerDefinition, Byte[] regRawByteArray,
Boolean encryptData = false)
{
@ -100,11 +104,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Registers
// reverse the list if it is not a string or the UInt48, UInt72, UInt88,UInt96 or UInt128 which
// will be used as placeholder for a string
if (registerDefinition.DataType != typeof(String) &&
registerDefinition.DataType != typeof(UInt48) &&
registerDefinition.DataType != typeof(UInt72) &&
registerDefinition.DataType != typeof(UInt88) &&
registerDefinition.DataType != typeof(UInt96) &&
registerDefinition.DataType != typeof(UInt128))
registerDefinition.DataType != typeof(ByteArray))
{
tmpList.Reverse();
}
@ -165,6 +165,10 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Registers
/// - Used <see cref="TimeT"/> to calculate time in UTC based on 01. Jan 2000
/// and the given offset in seconds.
/// </remarks>
/// <remarks date="2025-Oct-10" author="Thomas Wiedebusch">
/// - Data size introduced including the new 'ByteArray' type and size to get rid of new defined 'uintxx_t'
/// data types.
/// </remarks>
public static Byte[] ValueToByteArray<T>(T value)
{
var converted = new Byte[] { 0 };
@ -238,98 +242,19 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Registers
return BitConverter.GetBytes(Convert.ToSByte(value));
}
else if (value is Byte[])
else if (value is Byte[] || value is ByteArray)
{
return (Byte[])Convert.ChangeType(value, typeof(Byte[]));
}
else
{
throw new ApplicationException($"Data type {typeof(T)} not implemented");
throw new ApplicationException($"Data type {typeof(T)} is unknown!");
}
return converted;
}
/// <summary>
/// Get size of type
/// </summary>
/// <param name="registerDefinition"></param>
/// <returns>size in bytes</returns>
/// <remarks date="2023-Sep-05" author="Thomas Wiedebusch">
/// - Init.
/// </remarks>
public static Int32 SizeOf(RegisterDefinition registerDefinition)
{
var size = 4;
if (registerDefinition.DataType == typeof(Boolean))
{
size = sizeof(Boolean);
}
if (registerDefinition.DataType == typeof(Byte) ||
registerDefinition.DataType == typeof(SByte) ||
registerDefinition.DataType == typeof(Char) ||
registerDefinition.DataType == typeof(Enum8))
{
size = sizeof(Byte);
}
else if (registerDefinition.DataType == typeof(Int16) ||
registerDefinition.DataType == typeof(UInt16))
{
size = sizeof(Int16);
}
else if (registerDefinition.DataType == typeof(Int32) ||
registerDefinition.DataType == typeof(UInt32) ||
registerDefinition.DataType == typeof(TimeT))
{
size = sizeof(Int32);
}
else if (registerDefinition.DataType == typeof(Int64) ||
registerDefinition.DataType == typeof(UInt64))
{
size = sizeof(Int64);
}
else if (registerDefinition.DataType == typeof(UInt48))
{
// 48 Bits / 8 Bits/Byte
size = 6;
}
else if (registerDefinition.DataType == typeof(UInt72))
{
// 72 Bits / 8 Bits/Byte
size = 9;
}
else if (registerDefinition.DataType == typeof(UInt88))
{
// 88 Bits / 8 Bits/Byte
size = 11;
}
else if (registerDefinition.DataType == typeof(UInt96))
{
// 96 Bits / 8 Bits/Byte
size = 3 * 4;
}
else if (registerDefinition.DataType == typeof(UInt128))
{
// 128 Bits / 8 Bits/Byte
size = 4 * 4;
}
else if (registerDefinition.DataType == typeof(String))
{
// just some value
size = 6 * 4;
}
return size;
}
/// <summary>
/// Build the result of the array as text.
/// </summary>
@ -343,6 +268,10 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Registers
/// - Used <see cref="TimeT"/> to calculate time in UTC based on 01. Jan 2000
/// and the given offset in seconds.
/// </remarks>
/// <remarks date="2025-Oct-10" author="Thomas Wiedebusch">
/// - Data size introduced including the new 'ByteArray' type and size to get rid of new defined 'uintxx_t'
/// data types.
/// </remarks>
public static String ConvertToText(Byte[] rawByteArray, Type type)
{
try
@ -385,23 +314,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Registers
{
return ByteArrayToValue<Byte>(rawByteArray).ToString();
}
if (type == typeof(UInt48))
{
return "";
}
if (type == typeof(UInt72))
{
return "";
}
if (type == typeof(UInt88))
{
return "";
}
if (type == typeof(UInt96))
{
return "";
}
if (type == typeof(UInt128))
if (type == typeof(ByteArray) || type == typeof(Byte[]))
{
return "";
}
@ -440,6 +353,10 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Registers
/// <remarks date="2025-Jun-16" author="Thomas Wiedebusch/Roland Drabesch">
/// - Padding bytes if input doesn't fit the required size;
/// </remarks>
/// <remarks date="2025-Oct-10" author="Thomas Wiedebusch">
/// - Data size introduced including the new 'ByteArray' type and size to get rid of new defined 'uintxx_t'
/// data types.
/// </remarks>
public static T ByteArrayToValue<T>(Byte[] rawByteArray)
{
if (rawByteArray == null)
@ -450,28 +367,6 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Registers
Object convertedObj = null;
var type = typeof(T);
// For non-numerical or single byte values use the standard implementation
if (type == typeof(UInt48))
{
return default(T);
}
if (type == typeof(UInt72))
{
return default(T);
}
if (type == typeof(UInt88))
{
return default(T);
}
if (type == typeof(UInt96))
{
return default(T);
}
if (type == typeof(UInt128))
{
return default(T);
}
if (type == typeof(Byte) || type == typeof(Enum8))
{
convertedObj = rawByteArray[0];

View File

@ -37,6 +37,11 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.Registers
/// data type of register
/// </summary>
public Type DataType;
/// <summary>
/// size of the data to support the SizeOf implementation
/// </summary>
public Int32 DataSize;
/// <summary>
/// length of one chunk during communication

View File

@ -88,6 +88,27 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug-local IIS-CUST|x64'">
<OutputPath>bin\x64\Debug-local IIS-CUST\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<LangVersion>7.0</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VPN_Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\VPN_Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.0</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\..\..\..\packages\Newtonsoft.Json.13.0.3\lib\net40\Newtonsoft.Json.dll</HintPath>
@ -113,11 +134,7 @@
<Compile Include="DataTypes\st_radio_dewa.cs" />
<Compile Include="DataTypes\st_radio_tfx.cs" />
<Compile Include="DataTypes\TimeT.cs" />
<Compile Include="DataTypes\UInt48.cs" />
<Compile Include="DataTypes\UInt72.cs" />
<Compile Include="DataTypes\UInt128.cs" />
<Compile Include="DataTypes\UInt88.cs" />
<Compile Include="DataTypes\UInt96.cs" />
<Compile Include="DataTypes\ByteArray.cs" />
<Compile Include="Json\AppsDictionary.cs" />
<Compile Include="Json\AppSection.cs" />
<Compile Include="Json\Build.cs" />

Some files were not shown because too many files have changed in this diff Show More