Compare commits
40
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
302a7a682c | ||
|
|
e4b42b5b51 | ||
|
|
234bd39ed5 | ||
|
|
59cd5f9dde | ||
|
|
2fd2697e3b | ||
|
|
f51fd4709e | ||
|
|
d5c50189ba | ||
|
|
5a1db14e2a | ||
|
|
5ea88265b9 | ||
|
|
2b9a207342 | ||
|
|
c4b61d885b | ||
|
|
06a401a1ff | ||
|
|
3a2fc50fec | ||
|
|
38a58ed8b7 | ||
|
|
c7cba20de0 | ||
|
|
6311df49c3 | ||
|
|
f1d32a39ba | ||
|
|
224b53f774 | ||
|
|
1e2777c5e7 | ||
|
|
c3c21649fb | ||
|
|
99ccabc142 | ||
|
|
f1e6e94450 | ||
|
|
320cddb177 | ||
|
|
42002e3fa4 | ||
|
|
77cabfd712 | ||
|
|
c933e2d759 | ||
|
|
f3f0a46627 | ||
|
|
b5fb4c2947 | ||
|
|
f6cce9df3c | ||
|
|
c0385c0782 | ||
|
|
db43bdb652 | ||
|
|
6bdc10f4a7 | ||
|
|
6795793858 | ||
|
|
a2c564d789 | ||
|
|
3bc9e731e8 | ||
|
|
95c5f09238 | ||
|
|
0a45d66c0b | ||
|
|
96408eaef3 | ||
|
|
4395516216 | ||
|
|
9281b52464 |
@@ -311,6 +311,9 @@ namespace Common
|
||||
(userName.Equals("jan") && password.Equals("jaugust")) ||
|
||||
(userName.Equals("JCermak") && password.Equals("Zt6911")) ||
|
||||
(userName.Equals("gilles") && password.Equals("alibaba")) ||
|
||||
#if DEBUG
|
||||
(userName.Equals("Sensus Developers") && password.Equals("5fbg12gf5hn8nhy1fr")) ||
|
||||
#endif
|
||||
(userName.Equals(passwordOfDay) && password.Equals(passwordOfDay));
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>TRACE;DEBUG;HEAT_METERS;</DefineConstants>
|
||||
<DefineConstants>TRACE;DEBUG;</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
|
||||
@@ -30,7 +30,7 @@
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;JUZNA_AFRIKA_NEW;HEAT_METERS;</DefineConstants>
|
||||
<DefineConstants>TRACE;JUZNA_AFRIKA_NEW;</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE;HEAT_METERS;</DefineConstants>
|
||||
<DefineConstants>DEBUG;TRACE;</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
@@ -32,7 +32,7 @@
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;HEAT_METERS;</DefineConstants>
|
||||
<DefineConstants>TRACE;</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net8.0</TargetFrameworks>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||
<WarningLevel>0</WarningLevel>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2023.3.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="3.10.4" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="3.10.4" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\NfcC7_DLL\NfcC7_DLL.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,102 @@
|
||||
using System;
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using NfcC7_DLL.NfcHandler;
|
||||
using NfcC7_DLL.NfcHandler.Protocols;
|
||||
using NfcC7_DLL.NfcHandler.Utils;
|
||||
using NfcC7_DLL.NfcHandler;
|
||||
|
||||
namespace NfcC7_DLL.Tests.NfcHanler;
|
||||
|
||||
[TestClass]
|
||||
[TestSubject(typeof(NfcHeadService))]
|
||||
public class NfcHeadServiceTest
|
||||
{
|
||||
|
||||
[TestMethod]
|
||||
public void SetTestingMode_Optohead_C7_ON_LiveMeterTest()
|
||||
{
|
||||
SerialPortData serialPortData = new SerialPortData(
|
||||
"COM5",
|
||||
"HatCliDemo.exe",
|
||||
74);
|
||||
|
||||
NfcHeadService service = new NfcHeadService(serialPortData);
|
||||
OptoHeadStatus status = service.SetTestingMode(OptoHeadStatus.OptoHeadC7);
|
||||
Assert.AreEqual(OptoHeadStatus.OptoHeadC7, status);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SetTestingMode_Optohead_OFF_LiveMeterTest()
|
||||
{
|
||||
SerialPortData serialPortData = new SerialPortData(
|
||||
"COM5",
|
||||
"HatCliDemo.exe",
|
||||
74);
|
||||
|
||||
NfcHeadService service = new NfcHeadService(serialPortData);
|
||||
OptoHeadStatus status = service.SetTestingMode(OptoHeadStatus.OptoHeadDisabled);
|
||||
Assert.AreEqual(OptoHeadStatus.OptoHeadDisabled, status);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SetTestingMode_LiveMeterTest()
|
||||
{
|
||||
SerialPortData serialPortData = new SerialPortData(
|
||||
"COM5",
|
||||
"HatCliDemo.exe",
|
||||
74);
|
||||
|
||||
NfcHeadService service = new NfcHeadService(serialPortData);
|
||||
OptoHeadStatus status = service.SetTestingMode(OptoHeadStatus.OptoHeadC2);
|
||||
Assert.AreEqual(OptoHeadStatus.OptoHeadC2, status);
|
||||
|
||||
status = service.SetTestingMode(OptoHeadStatus.OptoHeadC7);
|
||||
Assert.AreEqual(OptoHeadStatus.OptoHeadC7, status);
|
||||
|
||||
status = service.SetTestingMode(OptoHeadStatus.OptoHeadDisabled);
|
||||
Assert.AreEqual(OptoHeadStatus.OptoHeadDisabled, status);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GetSerialNr_LiveMeterTest()
|
||||
{
|
||||
SerialPortData serialPortData = new SerialPortData(
|
||||
"COM5",
|
||||
"HatCliDemo.exe",
|
||||
74);
|
||||
|
||||
NfcHeadService service = new NfcHeadService(serialPortData);
|
||||
string? serialNr = service.GetSerialNr();
|
||||
Assert.IsFalse(string.IsNullOrEmpty(serialNr));
|
||||
Console.WriteLine("Found serial no: {0}",serialNr);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GetSerialNrAsync_LiveMeterTest()
|
||||
{
|
||||
SerialPortData serialPortData = new SerialPortData(
|
||||
"COM5",
|
||||
"HatCliDemo.exe",
|
||||
74);
|
||||
|
||||
NfcHeadService service = new NfcHeadService(serialPortData);
|
||||
string? serialNr = service.GetSerialNrAsync().GetAwaiter().GetResult();
|
||||
Assert.IsFalse(string.IsNullOrEmpty(serialNr));
|
||||
Console.WriteLine("Found serial no: {0}",serialNr);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GetTestingMode_LiveMeterTest()
|
||||
{
|
||||
SerialPortData serialPortData = new SerialPortData(
|
||||
"COM5",
|
||||
"HatCliDemo.exe",
|
||||
74);
|
||||
|
||||
NfcHeadService service = new NfcHeadService(serialPortData);
|
||||
OptoHeadStatus status = service.GetTestingMode();
|
||||
Assert.IsFalse(OptoHeadStatus.Unknown == status);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using NfcC7_DLL.NfcHandler;
|
||||
using NfcC7_DLL.NfcHandler.Protocols;
|
||||
using NfcC7_DLL.NfcHandler.Utils;
|
||||
|
||||
namespace NfcC7_DLL.Tests.NfcHanler;
|
||||
|
||||
[TestClass]
|
||||
[TestSubject(typeof(OptoHeadService))]
|
||||
public class OptoHeadServiceTest
|
||||
{
|
||||
|
||||
[TestMethod]
|
||||
public void RunLoop_Test()
|
||||
{
|
||||
//Switch meter to Optohead C7 testing mode
|
||||
SerialPortData serialPortData = new SerialPortData(
|
||||
"COM5",
|
||||
"HatCliDemo.exe",
|
||||
74);
|
||||
|
||||
NfcHeadService service = new NfcHeadService(serialPortData);
|
||||
OptoHeadStatus status = service.SetTestingMode(OptoHeadStatus.OptoHeadC7);
|
||||
Assert.AreEqual(OptoHeadStatus.OptoHeadC7, status);
|
||||
//Open serial connection to Optohead
|
||||
OptoHeadService.Con con = new OptoHeadService.Con();
|
||||
con.com = "COM6";
|
||||
OptoHeadService optoHeadService = new OptoHeadService(con);
|
||||
Assert.IsTrue(optoHeadService.CreateSerialConnection());
|
||||
//start loop to receive data
|
||||
optoHeadService.RunLoop();
|
||||
WaterMetrologyData lastData = null;
|
||||
int iCycles = 0, iCyclesMax = 10;
|
||||
for (int i = 0; i < iCyclesMax; i++)
|
||||
{
|
||||
|
||||
bool finished = false;
|
||||
while (!finished)
|
||||
{
|
||||
//optoHeadService.Run();
|
||||
if (optoHeadService.WaterMetrologyData != null
|
||||
&& lastData != optoHeadService.WaterMetrologyData
|
||||
&& optoHeadService.WaterMetrologyData.OptoHeadStatus != OptoHeadStatus.Unknown)
|
||||
{
|
||||
lastData = optoHeadService.WaterMetrologyData;
|
||||
finished = true;
|
||||
iCycles++;
|
||||
if (lastData.OptoHeadStatus.HasFlag(OptoHeadStatus.OptoHeadC7))
|
||||
{
|
||||
Assert.IsNotNull(lastData.C7Data);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.IsNotNull(lastData.C2Data);
|
||||
}
|
||||
System.Console.WriteLine("Cycle: {0} lastData: {1}", iCycles, lastData);
|
||||
}
|
||||
}
|
||||
}
|
||||
optoHeadService.CloseSerialConnection();
|
||||
|
||||
Assert.IsTrue(iCycles > 0);
|
||||
Assert.IsTrue(iCycles == iCyclesMax);
|
||||
|
||||
//Close Optohead
|
||||
status = service.SetTestingMode(OptoHeadStatus.OptoHeadDisabled);
|
||||
Assert.AreEqual(OptoHeadStatus.OptoHeadDisabled, status);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
using System;
|
||||
using System.IO.Ports;
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using NfcC7_DLL.NfcHandler.Utils;
|
||||
|
||||
namespace NfcC7_DLL.Tests.NfcHanler.Utils;
|
||||
|
||||
//[TestClass]
|
||||
[TestSubject(typeof(SERIAL_Driver))]
|
||||
public class SERIAL_DriverTest
|
||||
{
|
||||
private class Con
|
||||
{
|
||||
public string com = "COM5";
|
||||
public int baudrate = 38400;
|
||||
public int dataBits = 8;
|
||||
public Parity parity = Parity.None;
|
||||
public StopBits stopbits = StopBits.Two;
|
||||
public int readTimeout = 5000;
|
||||
public int writeTimeout = 1000;
|
||||
}
|
||||
|
||||
private readonly byte[] Open =
|
||||
{ 0x6B, 0x80, 0x01, 0x10, 0x00, 0x30, 0x00, 0x47, 0x6C, 0x6F, 0x62, 0x61, 0x6C, 0x49, 0x50, 0x65, 0x72,
|
||||
0x6C, 0x55, 0x74, 0x69, 0x6C, 0x69, 0x74, 0x79, 0x00, 0x00, 0x27, 0xD7 };
|
||||
private readonly byte[] CommDeviceSessionEnd = { 0x6B, 0x61, 0x00, 0x10, 0x05, 0x31, 0x00, 0x1F, 0x29, 0xF9, 0xC5 };
|
||||
|
||||
private readonly byte[] ProductDetails =
|
||||
{ 0x6B, 0x30, 0x01, 0x10, 0x03, 0x21, 0x01, 0x02, 0x6B, 0x90, 0x00, 0x00, 0x11, 0x40, 0x05, 0x00, 0x02, 0x04, 0x60, 0x62, 0x42, 0x04, 0xA5, 0x64 };
|
||||
|
||||
private readonly byte[] ProductDetails2 =
|
||||
{ 0x6B, 0x30, 0x01, 0x10, 0x03, 0x21, 0x01, 0x02, 0x6B, 0x90, 0x00, 0x00, 0x11, 0x40, 0x05, 0x00, 0x02, 0x04, 0x60 };
|
||||
|
||||
static Con con5 = new Con(){
|
||||
com = "COM5",
|
||||
baudrate = 38400,
|
||||
dataBits = 8,
|
||||
parity = Parity.None,
|
||||
stopbits = StopBits.Two,
|
||||
readTimeout = 5000,
|
||||
writeTimeout = 1000
|
||||
};
|
||||
static Con con6 = new Con()
|
||||
{
|
||||
com = "COM6",
|
||||
baudrate = 38400,
|
||||
dataBits = 8,
|
||||
parity = Parity.None,
|
||||
stopbits = StopBits.Two,
|
||||
readTimeout = 5000,
|
||||
writeTimeout = 1000
|
||||
};
|
||||
|
||||
|
||||
|
||||
//[TestMethod]
|
||||
public void SendMessage_Test()
|
||||
{
|
||||
Con con = con5;
|
||||
|
||||
byte[] message = Open;
|
||||
byte[] bytesReceived;
|
||||
|
||||
SERIAL_Driver driver = new SERIAL_Driver();
|
||||
bool isopen = driver.OpenConnection(
|
||||
con.com,
|
||||
con.baudrate,
|
||||
con.dataBits,
|
||||
con.parity,
|
||||
con.stopbits,
|
||||
con.readTimeout,
|
||||
con.writeTimeout);
|
||||
Assert.IsTrue(isopen);
|
||||
driver.SendMessage(message, message.Length);
|
||||
//Assert.IsTrue(driver.GetRawData().Length == 0);
|
||||
bytesReceived = driver.GetRawData();
|
||||
//Assert.IsTrue(bytesReceived.Length > 0);
|
||||
Console.WriteLine("IsOpened: {0}", driver.isOpen());
|
||||
// Display raw bytes (as hex or byte count)
|
||||
if (bytesReceived != null)
|
||||
{
|
||||
Console.WriteLine(string.Format("Bytes received: {0}", bytesReceived.Length));
|
||||
Console.WriteLine(string.Format("Bytes (hex): {0}", BitConverter.ToString(bytesReceived)));
|
||||
string response = System.Text.Encoding.UTF8.GetString(bytesReceived);
|
||||
Console.WriteLine("Bytes string: {0}", response);
|
||||
}
|
||||
|
||||
// --- Get Serial No ---
|
||||
message = ProductDetails;
|
||||
// Send Open message
|
||||
bool sendSuccess = driver.SendMessage(message, message.Length);
|
||||
Assert.IsTrue(sendSuccess, "Failed to send Open message");
|
||||
Console.WriteLine("Sent message for product details: {0}", message.ToString());
|
||||
bytesReceived = driver.GetRawData();
|
||||
// Display raw bytes (as hex or byte count)
|
||||
if (bytesReceived != null)
|
||||
{
|
||||
Console.WriteLine(string.Format("Bytes received: {0}", bytesReceived.Length));
|
||||
Console.WriteLine(string.Format("Bytes (hex): {0}", BitConverter.ToString(bytesReceived)));
|
||||
string response = System.Text.Encoding.UTF8.GetString(bytesReceived);
|
||||
Console.WriteLine("Bytes string: {0}", response);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Response not received!");
|
||||
}
|
||||
|
||||
message = CommDeviceSessionEnd;
|
||||
driver.SendMessage(message, message.Length);
|
||||
|
||||
driver.Close();
|
||||
|
||||
}
|
||||
|
||||
|
||||
//[TestMethod]
|
||||
public void SendMessage_TestLoop()
|
||||
{
|
||||
Con con = con6;
|
||||
|
||||
byte[] message = {0x00};
|
||||
byte[] bytesReceived;
|
||||
|
||||
SERIAL_Driver driver = new SERIAL_Driver();
|
||||
bool isopen = driver.OpenConnection(
|
||||
con.com,
|
||||
con.baudrate,
|
||||
con.dataBits,
|
||||
con.parity,
|
||||
con.stopbits,
|
||||
con.readTimeout,
|
||||
con.writeTimeout);
|
||||
Assert.IsTrue(isopen);
|
||||
|
||||
for (int iStep = 0; iStep < 100; iStep++)
|
||||
{
|
||||
driver.SendMessage(message, message.Length);
|
||||
//Assert.IsTrue(driver.GetRawData().Length == 0);
|
||||
bytesReceived = driver.GetRawData();
|
||||
Assert.IsTrue(bytesReceived.Length > 0);
|
||||
Console.WriteLine("IsOpened: {0}", driver.isOpen());
|
||||
// Display raw bytes (as hex or byte count)
|
||||
Console.WriteLine(string.Format("Bytes received: {0}", bytesReceived.Length));
|
||||
Console.WriteLine(string.Format("Bytes (hex): {0}", BitConverter.ToString(bytesReceived)));
|
||||
string response = System.Text.Encoding.UTF8.GetString(bytesReceived);
|
||||
Console.WriteLine("Bytes string: {0}", response);
|
||||
}
|
||||
|
||||
//message = CommDeviceSessionEnd;
|
||||
//driver.SendMessage(message, message.Length);
|
||||
|
||||
driver.CloseConnection();
|
||||
|
||||
}
|
||||
|
||||
|
||||
//[TestMethod]
|
||||
public void SendMessage_TestGetSerialNo()
|
||||
{
|
||||
Con con = con6;
|
||||
byte[] message = Open;
|
||||
byte[] bytesReceived;
|
||||
|
||||
SERIAL_Driver driver = new SERIAL_Driver();
|
||||
bool isopen = driver.OpenConnection(
|
||||
con.com,
|
||||
con.baudrate,
|
||||
con.dataBits,
|
||||
con.parity,
|
||||
con.stopbits,
|
||||
con.readTimeout,
|
||||
con.writeTimeout);
|
||||
Assert.IsTrue(isopen);
|
||||
|
||||
driver.SendMessage(message, message.Length,con.readTimeout);
|
||||
//Assert.IsTrue(driver.GetRawData().Length == 0);
|
||||
bytesReceived = driver.GetRawData();
|
||||
Assert.IsTrue(bytesReceived.Length > 0);
|
||||
if (bytesReceived[0] == 0xFF)
|
||||
Console.WriteLine("Error message: {0}", driver.ErrorMessage);
|
||||
// Display raw bytes (as hex or byte count)
|
||||
Console.WriteLine("IsOpened: {0}", driver.isOpen());
|
||||
Console.WriteLine(string.Format("Bytes received: {0}", bytesReceived.Length));
|
||||
Console.WriteLine(string.Format("Bytes (hex): {0}", BitConverter.ToString(bytesReceived)));
|
||||
string response = System.Text.Encoding.UTF8.GetString(bytesReceived);
|
||||
Console.WriteLine("Bytes string: {0}",response);
|
||||
|
||||
// --- Get Serial No ---
|
||||
message = ProductDetails;
|
||||
driver.SendMessage(message, message.Length,con.readTimeout);
|
||||
bytesReceived = driver.GetRawData();
|
||||
Assert.IsTrue(bytesReceived.Length > 0);
|
||||
if (bytesReceived[0] == 0xFF)
|
||||
Console.WriteLine("Error message: {0}", driver.ErrorMessage);
|
||||
// Display raw bytes (as hex or byte count)
|
||||
Console.WriteLine("IsOpened: {0}", driver.isOpen());
|
||||
Console.WriteLine(string.Format("Bytes received: {0}", bytesReceived.Length));
|
||||
Console.WriteLine(string.Format("Bytes (hex): {0}", BitConverter.ToString(bytesReceived)));
|
||||
response = System.Text.Encoding.UTF8.GetString(bytesReceived);
|
||||
Console.WriteLine("Bytes string: {0}",response);
|
||||
|
||||
// --- Get Serial No ---
|
||||
message = ProductDetails2;
|
||||
driver.SendMessage(message, message.Length,con.readTimeout);
|
||||
bytesReceived = driver.GetRawData();
|
||||
Assert.IsTrue(bytesReceived.Length > 0);
|
||||
if (bytesReceived[0] == 0xFF)
|
||||
Console.WriteLine("Error message: {0}", driver.ErrorMessage);
|
||||
// Display raw bytes (as hex or byte count)
|
||||
Console.WriteLine("IsOpened: {0}", driver.isOpen());
|
||||
Console.WriteLine(string.Format("Bytes received: {0}", bytesReceived.Length));
|
||||
Console.WriteLine(string.Format("Bytes (hex): {0}", BitConverter.ToString(bytesReceived)));
|
||||
response = System.Text.Encoding.UTF8.GetString(bytesReceived);
|
||||
Console.WriteLine("Bytes string: {0}",response);
|
||||
|
||||
|
||||
message = CommDeviceSessionEnd;
|
||||
driver.SendMessage(message, message.Length);
|
||||
|
||||
driver.Close();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,57 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>false</ImplicitUsings>
|
||||
<Nullable>disable</Nullable>
|
||||
<Copyright>Copyright © 2025</Copyright>
|
||||
<AssemblyVersion>1.1.0.0</AssemblyVersion>
|
||||
<FileVersion>1.1.0.0</FileVersion>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||
<DefineConstants>TRACE;</DefineConstants>
|
||||
<DefineConstants>TRACE;IPERL;</DefineConstants>
|
||||
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
|
||||
<DebugType>full</DebugType>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||
<DefineConstants>TRACE;IPERL;</DefineConstants>
|
||||
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
|
||||
<PackageReference Include="System.IO.Ports" Version="10.0.0-rc.1.25451.107" />
|
||||
<PackageReference Include="System.Security.Cryptography.Cng" Version="5.0.0" />
|
||||
<PackageReference Include="System.Threading" Version="4.3.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.Build.Utilities.v4.0" />
|
||||
<Reference Include="NA2WNFC">
|
||||
<HintPath>NfcHanler\NfcReaderLibrary\NA2WNFC.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="OBIDISC4NET">
|
||||
<HintPath>NfcHanler\NfcReaderLibrary\OBIDISC4NET.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="OBIDISC4NETnative">
|
||||
<HintPath>NfcHanler\NfcReaderLibrary\OBIDISC4NETnative.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="OBIDISC4NET_API">
|
||||
<HintPath>NfcHanler\NfcReaderLibrary\OBIDISC4NET_API.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="PresentationCore">
|
||||
<HintPath>..\..\..\..\..\Windows\Microsoft.NET\assembly\GAC_32\PresentationCore\v4.0_4.0.0.0__31bf3856ad364e35\PresentationCore.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="PresentationFramework">
|
||||
<HintPath>..\..\..\..\..\Windows\Microsoft.NET\assembly\GAC_MSIL\PresentationFramework\v4.0_4.0.0.0__31bf3856ad364e35\PresentationFramework.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Sensus">
|
||||
<HintPath>NfcHanler\FieldLogicLibrary\Sensus.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
using NfcC7_DLL.NfcHandler.Protocols;
|
||||
|
||||
namespace NfcC7_DLL.NfcHandler
|
||||
{
|
||||
public class HeadInfo
|
||||
{
|
||||
string SerialNr { get; set; }
|
||||
OptoHeadStatus OptoHeadStatus { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
|
||||
|
||||
namespace NfcC7_DLL.NfcHandler
|
||||
{
|
||||
public class JsonDataFromPoseidon
|
||||
{
|
||||
public bool? NfcTagDetected { get; set; }
|
||||
public int? ProductType { get; set; }
|
||||
public string ProductTypeVersion { get; set; }
|
||||
public string DeviceId { get; set; }
|
||||
public string Reading { get; set; }
|
||||
public string Reading_Totalizer { get; set; }
|
||||
public string Reading_Digits { get; set; }
|
||||
public string Reading_Shift { get; set; }
|
||||
public string Reading_Resolution { get; set; }
|
||||
public string Reading_Units { get; set; }
|
||||
public string Reading_FlowDirection { get; set; }
|
||||
public string Reading_FlowRate { get; set; }
|
||||
public string CalibrationFactor { get; set; }
|
||||
public bool? ReadingComplete { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using NfcC7_DLL.NfcHandler.Protocols;
|
||||
using NfcC7_DLL.NfcHandler.Utils;
|
||||
|
||||
namespace NfcC7_DLL.NfcHandler
|
||||
{
|
||||
public class NfcHeadService
|
||||
{
|
||||
|
||||
private bool activeHandlerSessioEnabled = false;
|
||||
private CliRunner _cliRunner;
|
||||
|
||||
private SerialPortData serialPort;
|
||||
|
||||
public NfcHeadService(SerialPortData serialPort)
|
||||
{
|
||||
this.serialPort = serialPort;
|
||||
this._cliRunner = null;
|
||||
ValidateCliFileExistence(true);
|
||||
}
|
||||
|
||||
private CliRunner CliRunner
|
||||
{
|
||||
get { return (_cliRunner != null ? _cliRunner : (_cliRunner = new CliRunner(CliLogging))); }
|
||||
}
|
||||
|
||||
private bool CliLogging
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
private static readonly Regex OpticalDataModeRegex = new Regex(
|
||||
@"(?im)(?:" +
|
||||
@"^\s*OpticalDataMode\s*Id\s*:\s*([^\r\n]+)\s*$" + // old format
|
||||
@"|" +
|
||||
@"""OpticalDataMode""\s*:\s*""?(0x[0-9A-Fa-f]+|\d+)""?" + // JSON format (handles hex and decimal)
|
||||
@")",
|
||||
RegexOptions.Compiled);
|
||||
|
||||
public bool TryGetOpticalDataMode(string result, out string s)
|
||||
{
|
||||
s = null;
|
||||
if (string.IsNullOrEmpty(result))
|
||||
return false;
|
||||
|
||||
var m = OpticalDataModeRegex.Match(result);
|
||||
if (!m.Success)
|
||||
return false;
|
||||
|
||||
// one of the groups will be filled
|
||||
s = !string.IsNullOrEmpty(m.Groups[1].Value)
|
||||
? m.Groups[1].Value.Trim()
|
||||
: m.Groups[2].Value.Trim();
|
||||
return true;
|
||||
}
|
||||
|
||||
private static readonly Regex DeviceIdRegex = new Regex(
|
||||
@"(?im)(?:" +
|
||||
@"^\s*Device\s*Id\s*:\s*([^\r\n]+)\s*$" + // old format
|
||||
@"|" +
|
||||
@"""DeviceId""\s*:\s*""?([0-9]+)""?" + // JSON format
|
||||
@")",
|
||||
RegexOptions.Compiled);
|
||||
|
||||
public bool TryGetDeviceId(string result, out string s)
|
||||
{
|
||||
s = null;
|
||||
if (string.IsNullOrEmpty(result))
|
||||
return false;
|
||||
|
||||
var m = DeviceIdRegex.Match(result);
|
||||
if (!m.Success)
|
||||
return false;
|
||||
|
||||
// one of the groups will be filled
|
||||
s = !string.IsNullOrEmpty(m.Groups[1].Value)
|
||||
? m.Groups[1].Value.Trim()
|
||||
: m.Groups[2].Value.Trim();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private void ValidateCliFileExistence(bool showErrorIfMissing)
|
||||
{
|
||||
if (serialPort != null)
|
||||
{
|
||||
if (!serialPort.CliExists)
|
||||
{
|
||||
throw new Exception("CLI file " + serialPort.SerialPortCmdClientPath +
|
||||
" does not exist! Current path: " + Environment.CurrentDirectory);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// ////////////
|
||||
/// </summary>
|
||||
public string GetSerialNr()
|
||||
{
|
||||
if (serialPort == null)
|
||||
throw new Exception("Serial port not initialized");
|
||||
|
||||
|
||||
Task optoheadDeviceIdTask = CliRunner.AddSendAsync(serialPort, SerialPortData.EMeterArg.DeviceId);
|
||||
var timeOut = CliRunner.AddTimeOut(5000);
|
||||
var doneTask = CliRunner.WaitAnyFinished(optoheadDeviceIdTask, timeOut);
|
||||
if (timeOut == doneTask)
|
||||
{
|
||||
throw new Exception("Timeout");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (optoheadDeviceIdTask is Task<string>)
|
||||
{
|
||||
string serialNr;
|
||||
if (optoheadDeviceIdTask.Status == TaskStatus.Faulted)
|
||||
throw new Exception("Error TaskStatus.Faulted");
|
||||
string result = (optoheadDeviceIdTask as Task<string>).Result;
|
||||
if (TryGetDeviceId(result, out serialNr))
|
||||
{
|
||||
return serialNr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public async Task<string> GetSerialNrAsync()
|
||||
{
|
||||
if (serialPort == null)
|
||||
throw new Exception("Serial port not initialized");
|
||||
|
||||
var cts = new CancellationTokenSource(); // we own the token
|
||||
var sendTask = CliRunner.AddSendAsync(serialPort, SerialPortData.EMeterArg.DeviceId, cts.Token);
|
||||
|
||||
string output;
|
||||
try
|
||||
{
|
||||
output = await CliRunner.WithTimeout(sendTask, TimeSpan.FromSeconds(15), cts);
|
||||
}
|
||||
catch (TimeoutException)
|
||||
{
|
||||
throw new Exception("Timeout");
|
||||
}
|
||||
|
||||
if (TryGetDeviceId(output, out var serialNr))
|
||||
return serialNr;
|
||||
|
||||
throw new Exception("Failed to parse DeviceId from output.");
|
||||
}
|
||||
|
||||
public OptoHeadStatus SetTestingMode(OptoHeadStatus status)
|
||||
{
|
||||
if (serialPort == null)
|
||||
throw new Exception("Serial port not initialized");
|
||||
|
||||
|
||||
Task optoheadMode =
|
||||
CliRunner.AddSendAsync(serialPort, SerialPortData.EMeterArg.Optohead, $"0x{((byte)status):X2}");
|
||||
var timeOut = CliRunner.AddTimeOut(5000);
|
||||
var doneTask = CliRunner.WhenAny();
|
||||
if (timeOut == doneTask)
|
||||
{
|
||||
throw new Exception("Timeout");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (optoheadMode is Task<string>)
|
||||
{
|
||||
string strOpticalDataMode;
|
||||
if (optoheadMode.Status == TaskStatus.Faulted)
|
||||
throw new Exception("Error TaskStatus.Faulted");
|
||||
string result = (optoheadMode as Task<string>).Result;
|
||||
if (TryGetOpticalDataMode(result, out strOpticalDataMode))
|
||||
{
|
||||
byte value;
|
||||
|
||||
if (strOpticalDataMode.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
|
||||
value = Convert.ToByte(strOpticalDataMode, 16); // interpret as hex
|
||||
else
|
||||
value = Convert.ToByte(strOpticalDataMode); // interpret as decimal
|
||||
|
||||
OptoHeadStatus optoheadStatus = (OptoHeadStatus)value;
|
||||
return optoheadStatus;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return OptoHeadStatus.Unknown;
|
||||
}
|
||||
|
||||
public OptoHeadStatus GetTestingMode()
|
||||
{
|
||||
if (serialPort == null)
|
||||
throw new Exception("Serial port not initialized");
|
||||
|
||||
|
||||
Task optoheadMode = CliRunner.AddSendAsync(serialPort, SerialPortData.EMeterArg.Optohead);
|
||||
var timeOut = CliRunner.AddTimeOut(5000);
|
||||
var doneTask = CliRunner.WhenAny();
|
||||
if (timeOut == doneTask)
|
||||
{
|
||||
throw new Exception("Timeout");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (optoheadMode is Task<string>)
|
||||
{
|
||||
string strOpticalDataMode;
|
||||
if (optoheadMode.Status == TaskStatus.Faulted)
|
||||
throw new Exception("Error TaskStatus.Faulted");
|
||||
string result = (optoheadMode as Task<string>).Result;
|
||||
if (TryGetOpticalDataMode(result, out strOpticalDataMode))
|
||||
{
|
||||
byte value;
|
||||
|
||||
if (strOpticalDataMode.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
|
||||
value = Convert.ToByte(strOpticalDataMode, 16); // interpret as hex
|
||||
else
|
||||
value = Convert.ToByte(strOpticalDataMode); // interpret as decimal
|
||||
|
||||
OptoHeadStatus optoheadStatus = (OptoHeadStatus)value;
|
||||
return optoheadStatus;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return OptoHeadStatus.Unknown;
|
||||
}
|
||||
|
||||
private void SendCommand()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private string RawDataAnswer()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
using System;
|
||||
using System.IO.Ports;
|
||||
using System.Threading.Tasks;
|
||||
using NfcC7_DLL.NfcHandler.Protocols;
|
||||
using NfcC7_DLL.NfcHandler.Utils;
|
||||
|
||||
namespace NfcC7_DLL.NfcHandler
|
||||
{
|
||||
public class OptoHeadService
|
||||
{
|
||||
|
||||
public class Con
|
||||
{
|
||||
public string com = "COM5";
|
||||
public int baudrate = 38400;
|
||||
public int dataBits = 8;
|
||||
public Parity parity = Parity.None;
|
||||
public StopBits stopbits = StopBits.Two;
|
||||
public int readTimeout = 5000;
|
||||
public int writeTimeout = 1000;
|
||||
}
|
||||
|
||||
private Con Connection { get; set; }
|
||||
private SERIAL_Driver driver;
|
||||
/// <summary>
|
||||
/// Filed After Run() is called.
|
||||
/// </summary>
|
||||
public WaterMetrologyData WaterMetrologyData { get; private set; }
|
||||
|
||||
public OptoHeadService(Con con)
|
||||
{
|
||||
Connection = con;
|
||||
driver = new SERIAL_Driver();
|
||||
}
|
||||
|
||||
public bool CreateSerialConnection()
|
||||
{
|
||||
bool isopen = false;
|
||||
Con con = Connection;
|
||||
|
||||
byte[] message = {0x00};
|
||||
byte[] bytesReceived;
|
||||
|
||||
if (!driver.isOpen())
|
||||
{
|
||||
|
||||
isopen = driver.OpenConnection(
|
||||
con.com,
|
||||
con.baudrate,
|
||||
con.dataBits,
|
||||
con.parity,
|
||||
con.stopbits,
|
||||
con.readTimeout,
|
||||
con.writeTimeout);
|
||||
}
|
||||
|
||||
return isopen;
|
||||
}
|
||||
|
||||
public void CloseSerialConnection()
|
||||
{
|
||||
dissableRunLoop = true;
|
||||
driver.Close();
|
||||
}
|
||||
|
||||
public void RunLoop()
|
||||
{
|
||||
Task.Run(() => Run());
|
||||
}
|
||||
|
||||
|
||||
private bool dissableRunLoop = false;
|
||||
/// <summary>
|
||||
/// Run the service. Catch one communication to WaterMetrologyData field.
|
||||
/// </summary>
|
||||
public void Run()
|
||||
{
|
||||
while (!dissableRunLoop)
|
||||
{
|
||||
WaterMetrologyData = ParseData(RunReading());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
byte[] RunReading()
|
||||
{
|
||||
if (driver.isOpen())
|
||||
{
|
||||
driver.SendMessage(new byte[] {0x00}, 1);
|
||||
return driver.GetRawData();
|
||||
}
|
||||
else
|
||||
{
|
||||
dissableRunLoop = true;
|
||||
}
|
||||
|
||||
return new byte[] {0xFF};
|
||||
}
|
||||
|
||||
public WaterMetrologyData ParseData(byte[] data)
|
||||
{
|
||||
try
|
||||
{
|
||||
return WaterMetrologyData.Parse(data, DateTime.Now, "");
|
||||
}catch(Exception e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace NfcC7_DLL.NfcHandler.Protocols
|
||||
{
|
||||
public enum OptoHeadStatus : byte
|
||||
{
|
||||
Unknown = 0xFF,
|
||||
OptoHeadDisabled = 0x00,
|
||||
OptoHeadC2 = 0xC2,
|
||||
OptoHeadC7 = 0xC7,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
|
||||
namespace NfcC7_DLL.NfcHandler.Protocols
|
||||
{
|
||||
public class WaterMetrologyData
|
||||
{
|
||||
private OptoHeadStatus _optoHeadStatus;
|
||||
private WaterMetrologyDataC7 c7Data;
|
||||
private WaterMetrologyDataC2 c2Data;
|
||||
|
||||
public WaterMetrologyDataC7 C7Data { get => c7Data; }
|
||||
public WaterMetrologyDataC2 C2Data { get => c2Data; }
|
||||
public OptoHeadStatus OptoHeadStatus { get => _optoHeadStatus; }
|
||||
|
||||
public static WaterMetrologyData Parse(byte[] data, DateTime dt, string dutinfo)
|
||||
{
|
||||
if (data.Length < 24)
|
||||
{
|
||||
throw new ArgumentException("Invalid data length for WaterMetrologyData C2.");
|
||||
}
|
||||
WaterMetrologyData waterMetrologyData = new WaterMetrologyData();
|
||||
waterMetrologyData._optoHeadStatus = OptoHeadStatus.Unknown;
|
||||
// Probably C2
|
||||
if(data.Length > 24 && data.Length < 48)
|
||||
{
|
||||
waterMetrologyData.c2Data = WaterMetrologyDataC2.Parse(data, dt, dutinfo);
|
||||
waterMetrologyData._optoHeadStatus = OptoHeadStatus.OptoHeadC2;
|
||||
}
|
||||
// Probably C7
|
||||
else if(data.Length >= 48)
|
||||
{
|
||||
waterMetrologyData.c7Data = WaterMetrologyDataC7.Parse(data, dt, dutinfo);
|
||||
waterMetrologyData._optoHeadStatus = OptoHeadStatus.OptoHeadC7;
|
||||
}
|
||||
|
||||
return waterMetrologyData;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Status: {_optoHeadStatus}, C7Data: {c7Data}, C2Data: {c2Data}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
using System;
|
||||
|
||||
namespace NfcC7_DLL.NfcHandler.Protocols
|
||||
{
|
||||
public class WaterMetrologyDataC2
|
||||
{
|
||||
public string DutInfo { get; set; }
|
||||
public DateTime Dt { get; set; }
|
||||
public int AdcSample { get; set; }
|
||||
public short LastField { get; set; }
|
||||
public short FlowRate { get; set; }
|
||||
public uint Accumulator { get; set; }
|
||||
public ushort FlipPeriod { get; set; }
|
||||
public ushort VinfStart { get; set; }
|
||||
public ushort VinfEnd { get; set; }
|
||||
public short ElectrodeDelta { get; set; }
|
||||
public ushort Impedance { get; set; }
|
||||
public byte FieldDriveTime { get; set; }
|
||||
public bool IsInLowFlow { get; set; }
|
||||
public bool IsInEmptyPipe { get; set; }
|
||||
public bool FastHPFC { get; set; }
|
||||
public bool FieldPolarity { get; set; }
|
||||
public bool ImpedancePolarity { get; set; }
|
||||
|
||||
public double CalcFlowmLps
|
||||
{
|
||||
get { return FlowRate / 4.0; } // FlowRate is in 1/4 mL/s
|
||||
}
|
||||
public double CalcFlowGPM
|
||||
{
|
||||
get { return CalcFlowmLps * 0.015850323141489; } // mL/s to gal/min conversion
|
||||
}
|
||||
public double CalcAccGal
|
||||
{
|
||||
get { return (Accumulator / 4.0) * 0.000264172; } // Accumulator is in 1/4 mL, convert to gallons
|
||||
}
|
||||
|
||||
public static WaterMetrologyDataC2 Parse(string base64Data, DateTime dt, string dutinfo)
|
||||
{
|
||||
byte[] data = Convert.FromBase64String(base64Data);
|
||||
return Parse(data, dt, dutinfo);
|
||||
}
|
||||
|
||||
public static WaterMetrologyDataC2 Parse(byte[] data, DateTime dt, string dutinfo)
|
||||
{
|
||||
if (data.Length < 24)
|
||||
{
|
||||
throw new ArgumentException("Invalid data length for WaterMetrologyData C2.");
|
||||
}
|
||||
|
||||
|
||||
WaterMetrologyDataC2 result = new WaterMetrologyDataC2();
|
||||
|
||||
result.DutInfo = dutinfo;
|
||||
result.Dt = dt;
|
||||
result.AdcSample = BitConverter.ToInt32(data, 0);
|
||||
result.LastField = BitConverter.ToInt16(data, 4);
|
||||
result.FlowRate = BitConverter.ToInt16(data, 6);
|
||||
result.Accumulator = BitConverter.ToUInt32(data, 8);
|
||||
result.FlipPeriod = BitConverter.ToUInt16(data, 12);
|
||||
result.VinfStart = BitConverter.ToUInt16(data, 14);
|
||||
result.VinfEnd = BitConverter.ToUInt16(data, 16);
|
||||
result.ElectrodeDelta = BitConverter.ToInt16(data, 18);
|
||||
result.Impedance = BitConverter.ToUInt16(data, 20);
|
||||
result.FieldDriveTime = data[22];
|
||||
|
||||
byte flags = data[23];
|
||||
result.IsInLowFlow = (flags & 0x01) != 0;
|
||||
result.IsInEmptyPipe = (flags & 0x02) != 0;
|
||||
result.FastHPFC = (flags & 0x04) != 0; // Fast High Pass Filter Constant in bit 2
|
||||
result.FieldPolarity = (flags & 0x08) != 0; // Field Polarity in bit 3
|
||||
result.ImpedancePolarity = (flags & 0x10) != 0; // Impedance Polarity in bit 4
|
||||
return result;
|
||||
}
|
||||
|
||||
//public override string ToString()
|
||||
//{
|
||||
// return $"ADC Sample: {AdcSample}, Last Field: {LastField}, Flow Rate: {FlowRate}, Accumulator: {Accumulator}, " +
|
||||
// $"Flip Period Ticks: {FlipPeriodTicks}, Vinf Start: {VinfStart}, Vinf End: {VinfEnd}, Electrode Delta: {ElectrodeDelta}, " +
|
||||
// $"Impedance: {Impedance}, Field Drive Time: {FieldDriveTime}, Is Low Flow: {IsInLowFlow}, Is Empty Pipe: {IsInEmptyPipe}, " +
|
||||
// $"Fast High Pass Filter: {FastHighPassFilterConstant}, Field Polarity: {FieldPolarity}, Impedance Polarity: {ImpedancePolarity}";
|
||||
//}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"DutInfo: {DutInfo}, Dt: {Dt}, ADC Sample: {AdcSample}, Last Field: {LastField}, Flow Rate: {FlowRate}, Accumulator: {Accumulator}, " +
|
||||
$"Flip Period: {FlipPeriod}, Vinf Start: {VinfStart}, Vinf End: {VinfEnd}, Electrode Delta: {ElectrodeDelta}, " +
|
||||
$"Impedance: {Impedance}, Field Drive Time: {FieldDriveTime}, Is Low Flow: {IsInLowFlow}, Is Empty Pipe: {IsInEmptyPipe}, " +
|
||||
$"Fast HPFC: {FastHPFC}, Field Polarity: {FieldPolarity}, Impedance Polarity: {ImpedancePolarity}, " +
|
||||
$"Calc Flow mL/s: {CalcFlowmLps:F2}, Calc Flow GPM: {CalcFlowGPM:F2}, Calc Acc Gal: {CalcAccGal:F2}";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
using System;
|
||||
|
||||
namespace NfcC7_DLL.NfcHandler.Protocols
|
||||
{
|
||||
public class WaterMetrologyDataC7 : WaterMetrologyDataC2
|
||||
{
|
||||
// New fields for C7
|
||||
public int LastFieldmilliGauss { get; set; }
|
||||
public int ImpedanceI { get; set; } // In-phase impedance
|
||||
public int ImpedanceQ { get; set; } // Out-of-phase impedance
|
||||
public int NoiseMetric { get; set; }
|
||||
public short LearningLockout { get; set; }
|
||||
public short ReverseBuffer { get; set; }
|
||||
public int ConditionedAdc { get; set; }
|
||||
public uint Totalalizer { get; set; }
|
||||
|
||||
//public bool IsInLowFlow { get; set; }
|
||||
//public bool IsInEmptyPipe { get; set; }
|
||||
//public bool FastHPFC { get; set; }
|
||||
//public bool FieldPolarity { get; set; }
|
||||
//public bool ImpedancePolarity { get; set; }
|
||||
public bool MagTamperState { get; set; }
|
||||
public bool IsLearningActive { get; set; }
|
||||
public bool AdcShiftsUpdated { get; set; }
|
||||
|
||||
|
||||
public static WaterMetrologyDataC7 Parse(string base64Data, DateTime dt, string dutinfo)
|
||||
{
|
||||
byte[] data = Convert.FromBase64String(base64Data);
|
||||
return Parse(data, dt, dutinfo);
|
||||
}
|
||||
|
||||
public static WaterMetrologyDataC7 Parse(byte[] data, DateTime dt, string dutinfo)
|
||||
{
|
||||
|
||||
// You may want to check for the minimum length required for C7
|
||||
if (data.Length < 48) /* minimum required length for C7 */
|
||||
{
|
||||
throw new ArgumentException("Invalid data length for WaterMetrologyData C7.");
|
||||
}
|
||||
|
||||
var result = new WaterMetrologyDataC7();
|
||||
|
||||
// Parse base C2 fields
|
||||
var c2 = WaterMetrologyDataC2.Parse(data, dt, dutinfo);
|
||||
|
||||
//Copy base fields
|
||||
result.DutInfo = c2.DutInfo;
|
||||
result.Dt = c2.Dt;
|
||||
result.AdcSample = c2.AdcSample;
|
||||
result.LastField = c2.LastField;
|
||||
result.FlowRate = c2.FlowRate;
|
||||
result.Accumulator = c2.Accumulator;
|
||||
result.FlipPeriod = c2.FlipPeriod;
|
||||
result.VinfStart = c2.VinfStart;
|
||||
result.VinfEnd = c2.VinfEnd;
|
||||
result.ElectrodeDelta = c2.ElectrodeDelta;
|
||||
result.Impedance = c2.Impedance;
|
||||
result.FieldDriveTime = c2.FieldDriveTime;
|
||||
|
||||
|
||||
result.IsInLowFlow = c2.IsInLowFlow;
|
||||
result.IsInEmptyPipe = c2.IsInEmptyPipe;
|
||||
result.FieldPolarity = c2.FieldPolarity;
|
||||
result.ImpedancePolarity = c2.ImpedancePolarity;
|
||||
|
||||
|
||||
// Parse new C7 fields (replace ENUM_OptPack0xC7.FIELD_MILLI_GAUSS etc. with actual offsets)
|
||||
byte flags = data[23];
|
||||
result.MagTamperState = (flags & 0x60) != 0; // bits 5 and 6 represent MagTamperState
|
||||
result.IsLearningActive = (flags & 0x80) != 0; // bit 7 represents IsLearningActive
|
||||
|
||||
byte flagTwo = data[24];
|
||||
|
||||
result.AdcShiftsUpdated = (flagTwo & 0x01) != 0; // bit 0 represents AdcShiftsUpdated
|
||||
|
||||
result.LastFieldmilliGauss = BitConverter.ToInt32(data, 25);
|
||||
result.ImpedanceI = BitConverter.ToInt32(data, 29); // in phase
|
||||
result.ImpedanceQ = BitConverter.ToInt32(data, 33); // out of phase
|
||||
result.NoiseMetric = BitConverter.ToInt32(data, 37); //
|
||||
result.LearningLockout = BitConverter.ToInt16(data, 41);
|
||||
result.ReverseBuffer = BitConverter.ToInt16(data, 43);
|
||||
result.ConditionedAdc = BitConverter.ToInt32(data, 45);
|
||||
result.Totalalizer = BitConverter.ToUInt32(data, 49);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"C7: LastFieldmilliGauss={LastFieldmilliGauss}, ImpedanceI={ImpedanceI}, ImpedanceQ={ImpedanceQ}, NoiseMetric={NoiseMetric}, LearningLockout={LearningLockout}, ReverseBuffer={ReverseBuffer}, ConditionedAdc={ConditionedAdc}, Totalalizer={Totalalizer}, MagTamperState={MagTamperState}, IsLearningActive={IsLearningActive}, AdcShiftsUpdated={AdcShiftsUpdated}" + base.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
# Protocol Description
|
||||
@@ -0,0 +1,341 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace NfcC7_DLL.NfcHandler.Utils
|
||||
{
|
||||
public class CliRunner
|
||||
{
|
||||
//static readonly Logger log = LogManager.GetLogger(typeof(CliRunner));
|
||||
//private readonly ILog log;
|
||||
private List<Task> taskPool = new List<Task>();
|
||||
private long startTime;
|
||||
|
||||
public List<Task> TaskPool { get { return taskPool; } }
|
||||
public void AddTask(Task task) { taskPool.Add(task); }
|
||||
public void WaitAll() { Task.WaitAll(taskPool.ToArray()); }
|
||||
|
||||
/// <summary>
|
||||
/// continue with WhenAny() to commpare results if time out is reached
|
||||
/// </summary>
|
||||
/// <param name="timeout"></param>
|
||||
/// <returns></returns>
|
||||
public Task AddTimeOut(int timeout)
|
||||
{
|
||||
Task timeOut = Task.Delay(timeout);
|
||||
taskPool.Add(timeOut);
|
||||
return timeOut;
|
||||
}
|
||||
/// <summary>
|
||||
/// mainly used for time out additional task to compare results
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
|
||||
|
||||
[Obsolete("Use async/await instead - WaitAnyFinished()")]
|
||||
public async Task<Task> WhenAny() { return await Task.WhenAny(taskPool.ToArray()); }
|
||||
|
||||
public Task WaitAnyFinished(Task task, Task timeOut)
|
||||
{
|
||||
Task.WhenAny(task, timeOut);
|
||||
while (true)
|
||||
{
|
||||
if (task.IsCompleted) break;
|
||||
if (task.IsFaulted) break;
|
||||
if (task.IsCanceled) break;
|
||||
|
||||
if(timeOut.IsCompleted) break;
|
||||
if(timeOut.IsFaulted) break;
|
||||
if(timeOut.IsCanceled) break;
|
||||
|
||||
Thread.Sleep(100);
|
||||
}
|
||||
|
||||
var waitAny = Task.WaitAny(task, timeOut);
|
||||
return waitAny == 0 ? task : timeOut;
|
||||
}
|
||||
|
||||
public static async Task<T> WithTimeout<T>(Task<T> task, TimeSpan timeout, CancellationTokenSource externalCts = null)
|
||||
{
|
||||
var localCts = externalCts == null ? externalCts : new CancellationTokenSource();
|
||||
var timeoutCts = new CancellationTokenSource(timeout);
|
||||
var linked = CancellationTokenSource.CreateLinkedTokenSource(localCts.Token, timeoutCts.Token);
|
||||
|
||||
var completion = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
|
||||
// Observe the task
|
||||
_ = task.ContinueWith(_ => completion.TrySetResult(true), TaskScheduler.Default);
|
||||
|
||||
// Observe the timeout
|
||||
_ = Task.Delay(Timeout.InfiniteTimeSpan, timeoutCts.Token)
|
||||
.ContinueWith(_ => completion.TrySetResult(true), TaskScheduler.Default);
|
||||
|
||||
await completion.Task.ConfigureAwait(false);
|
||||
|
||||
if (timeoutCts.IsCancellationRequested == false && task.IsCompleted) // task finished first
|
||||
return await task.ConfigureAwait(false);
|
||||
|
||||
// timeout won → cancel & throw TimeoutException
|
||||
localCts.Cancel(); // triggers your SendAsync to kill process
|
||||
throw new TimeoutException();
|
||||
}
|
||||
|
||||
public Task<string> AddSendAsync(SerialPortData data, SerialPortData.EMeterArg eMeterArg, CancellationToken ct = default)
|
||||
{
|
||||
var task = SendAsync(data.SerialPortCmdClientPath, data.DefaultArgSettingsRead(eMeterArg), ct);
|
||||
taskPool.Add(task); // List<Task> is okay because Task<string> : Task
|
||||
return task;
|
||||
}
|
||||
|
||||
public Task WaitAnyFinished()
|
||||
{
|
||||
int xTask = Task.WaitAny(taskPool.ToArray());
|
||||
return taskPool[xTask];
|
||||
}
|
||||
|
||||
public void Clear() { taskPool.Clear(); }
|
||||
public void CancelAll() { Task.WhenAll(taskPool).ContinueWith(t => { }); }
|
||||
|
||||
|
||||
public void StartAll()
|
||||
{
|
||||
taskPool.ForEach(t => t.Start());
|
||||
}
|
||||
|
||||
public bool AreTasksDone()
|
||||
{
|
||||
return taskPool.All(task => task.IsCompleted);
|
||||
}
|
||||
|
||||
public long StartTime
|
||||
{
|
||||
get => startTime;
|
||||
}
|
||||
|
||||
public bool TimeOutReceived(long timeout)
|
||||
{
|
||||
return (DateTime.Now.Ticks - startTime) > timeout;
|
||||
}
|
||||
|
||||
public CliRunner(bool isCliLogging)
|
||||
{
|
||||
startTime = DateTime.Now.Ticks;
|
||||
|
||||
if (isCliLogging)
|
||||
{
|
||||
try
|
||||
{
|
||||
/*log = new ScopedLoggerFactory().CreateLogger<CliRunner>(
|
||||
@"C:\TBF\Logs\CliRunner.txt",
|
||||
10, // maxFileSizeMB
|
||||
7, // maxBackups
|
||||
log4net.Core.Level.Debug,
|
||||
true, // zipRolledFiles
|
||||
true, // singleZipPerDay
|
||||
TimeSpan.FromMinutes(2) // zipScanInterval
|
||||
);*/
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Fallback to console or handle gracefully
|
||||
Console.WriteLine($"Failed to initialize logger: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="fileName"></param>
|
||||
/// <param name="args"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public Task AddSendAsync(SerialPortData data, SerialPortData.EMeterArg eMeterArg)
|
||||
{
|
||||
var task = SendAsync(data.SerialPortCmdClientPath, data.DefaultArgSettingsRead(eMeterArg));
|
||||
taskPool.Add(task);
|
||||
return task;
|
||||
}
|
||||
|
||||
public Task AddSendAsync(SerialPortData data, SerialPortData.EMeterArg eMeterArg, string arg)
|
||||
{
|
||||
var task = SendAsync(data.SerialPortCmdClientPath, data.DefaultArgSettingsWrite(eMeterArg, arg));
|
||||
taskPool.Add(task);
|
||||
return task;
|
||||
}
|
||||
|
||||
public void AddSendAsync(string fileName, string args)
|
||||
{
|
||||
var task = SendAsync(fileName, args);
|
||||
taskPool.Add(task);
|
||||
}
|
||||
|
||||
|
||||
public async Task<string> SendAsync(string fileName, string args, CancellationToken ct = default)
|
||||
{
|
||||
var psi = new ProcessStartInfo
|
||||
{
|
||||
FileName = fileName,
|
||||
Arguments = args,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true
|
||||
};
|
||||
|
||||
var process = new Process { StartInfo = psi, EnableRaisingEvents = true };
|
||||
try
|
||||
{
|
||||
process.Start();
|
||||
|
||||
Task<string> stdOutTask = process.StandardOutput.ReadToEndAsync();
|
||||
Task<string> stdErrTask = process.StandardError.ReadToEndAsync();
|
||||
|
||||
try
|
||||
{
|
||||
await Task.WhenAll(stdOutTask, stdErrTask, process.WaitForExitAsync(ct));
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
if (!process.HasExited)
|
||||
{
|
||||
process.Kill();
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
string allOutput = (stdOutTask.Result ?? "") + (stdErrTask.Result ?? "");
|
||||
//log?.Debug(allOutput);
|
||||
return allOutput;
|
||||
}
|
||||
finally
|
||||
{
|
||||
process?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public Task<T> AddRunAndCaptureJsonAsync<T>(SerialPortData data, SerialPortData.EMeterArg eMeterArg) where T : new()
|
||||
{
|
||||
var task = RunAndCaptureJsonAsync<T>(data.SerialPortCmdClientPath, data.DefaultArgSettingsRead(eMeterArg));
|
||||
taskPool.Add(task);
|
||||
return task;
|
||||
}
|
||||
|
||||
public async Task<T> RunAndCaptureJsonAsync<T>(string fileName, string args, CancellationToken ct = default) where T : new()
|
||||
{
|
||||
var psi = new ProcessStartInfo
|
||||
{
|
||||
FileName = fileName,
|
||||
Arguments = args,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true
|
||||
};
|
||||
|
||||
var process = new Process { StartInfo = psi, EnableRaisingEvents = true };
|
||||
try
|
||||
{
|
||||
process.Start();
|
||||
|
||||
var stdoutTask = process.StandardOutput.ReadToEndAsync();
|
||||
var stderrTask = process.StandardError.ReadToEndAsync();
|
||||
|
||||
await Task.WhenAll(stdoutTask, stderrTask, process.WaitForExitAsync(ct));
|
||||
|
||||
string allOutput = (stdoutTask.Result ?? "") + (stderrTask.Result ?? "");
|
||||
//log?.Debug(allOutput);
|
||||
|
||||
string json = ExtractJson(allOutput);
|
||||
if (TryJsonStringDeserialize(json, out T result)) return result;
|
||||
return default;
|
||||
}
|
||||
finally
|
||||
{
|
||||
process?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryJsonStringDeserialize<T>(string json, out T runAndCaptureJsonAsync) where T : new()
|
||||
{
|
||||
if (json != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
runAndCaptureJsonAsync = JsonConvert.DeserializeObject<T>(json);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// log.Debug(ex.Message);
|
||||
runAndCaptureJsonAsync = TryConvert<T>(json);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
runAndCaptureJsonAsync = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private static T TryConvert<T>(string json) where T : new()
|
||||
{
|
||||
|
||||
T obj = new T();
|
||||
|
||||
try
|
||||
{
|
||||
JObject jObject = JObject.Parse(json);
|
||||
|
||||
foreach (PropertyInfo prop in typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance))
|
||||
{
|
||||
if (!prop.CanWrite) continue;
|
||||
|
||||
JToken token;
|
||||
if (jObject.TryGetValue(prop.Name, StringComparison.OrdinalIgnoreCase, out token))
|
||||
{
|
||||
try
|
||||
{
|
||||
object value = token.ToObject(prop.PropertyType);
|
||||
prop.SetValue(obj, value);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// leave default if conversion fails
|
||||
}
|
||||
}
|
||||
// else → keep default value
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"TryConvert failed: {ex.Message}");
|
||||
}
|
||||
|
||||
return obj;
|
||||
|
||||
}
|
||||
|
||||
public string ExtractJson(string text)
|
||||
{
|
||||
int start = text.IndexOf('{');
|
||||
int end = text.LastIndexOf('}');
|
||||
|
||||
if (start >= 0 && end > start)
|
||||
{
|
||||
return text.Substring(start, end - start + 1);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NfcC7_DLL.NfcHandler.Utils
|
||||
{
|
||||
public static class ProcessExtensions
|
||||
{
|
||||
public static Task<object> WaitForExitAsync(this Process process, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (process == null) throw new ArgumentNullException(nameof(process));
|
||||
if (process.HasExited) return Task.FromResult<object>(null);
|
||||
|
||||
var tcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
|
||||
EventHandler handler = null;
|
||||
handler = (s, e) =>
|
||||
{
|
||||
try { tcs.TrySetResult(null); }
|
||||
finally { process.Exited -= handler; }
|
||||
};
|
||||
|
||||
process.EnableRaisingEvents = true;
|
||||
process.Exited += handler;
|
||||
|
||||
if (cancellationToken.CanBeCanceled)
|
||||
{
|
||||
cancellationToken.Register(() =>
|
||||
{
|
||||
tcs.TrySetCanceled(cancellationToken);
|
||||
process.Exited -= handler;
|
||||
});
|
||||
}
|
||||
|
||||
return tcs.Task;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO.Ports;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
//*****************************************************************************
|
||||
// Copyright 2020 Sensus GmbH Ludwigshafen. All rights reserved.
|
||||
// Author: Venkat, Rajeshwar
|
||||
//*****************************************************************************
|
||||
|
||||
namespace NfcC7_DLL.NfcHandler.Utils
|
||||
{
|
||||
public class SERIAL_Driver
|
||||
{
|
||||
public string ErrorMessage { get; private set; }
|
||||
public Collection<byte> SerialPortReadBuffer = new Collection<byte>();
|
||||
private SerialPort _serialPort;
|
||||
|
||||
private List<byte[]> _binMessages = new List<byte[]>();
|
||||
private bool _isReading;
|
||||
private Parity Parity { get; set; }
|
||||
private StopBits StopBits { get; set; }
|
||||
|
||||
public SERIAL_Driver()
|
||||
{
|
||||
_serialPort = new SerialPort();
|
||||
}
|
||||
|
||||
public bool OpenConnection(string comPort, int baudrate, int dataBits, Parity parity, StopBits stopbits, int readTimeout=1000, int writeTimeout = 1000)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
if ((_serialPort != null) && (_serialPort.IsOpen))
|
||||
{
|
||||
_serialPort.DataReceived -= DataReceivedHandler;
|
||||
_serialPort.Close();
|
||||
_serialPort.Dispose();
|
||||
_serialPort = null;
|
||||
}
|
||||
try
|
||||
{
|
||||
ErrorMessage = "";
|
||||
//_serialPort = new SerialPort(comPort, 57600, Parity.None, 8, StopBits.Two);
|
||||
_serialPort = new SerialPort(comPort, baudrate, parity, dataBits, stopbits);
|
||||
_serialPort.ReadTimeout = readTimeout;
|
||||
_serialPort.WriteTimeout = writeTimeout;
|
||||
_serialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
|
||||
_serialPort.Open();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ErrorMessage = String.Format("COM error: Open failed {0}.{1}", comPort, ex.Message);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_serialPort.IsOpen)
|
||||
{
|
||||
ErrorMessage = String.Format("COM error: Can't Open {0}.", comPort);
|
||||
return false;
|
||||
}
|
||||
}//End Lock
|
||||
return true;
|
||||
}
|
||||
public bool SendMessage(byte[] sendDataBytes, int length, int readTimeout = 1000, int writeTimeout=1000)
|
||||
{
|
||||
if (!isOpen()) return false;
|
||||
if (sendDataBytes.Length == 0) return true; // nothing to send - no error
|
||||
try
|
||||
{
|
||||
PrepareReading(); //clear read buffer etc.
|
||||
_serialPort.WriteTimeout = writeTimeout;
|
||||
_serialPort.ReadTimeout = readTimeout;
|
||||
_serialPort.Write(sendDataBytes, 0, length);
|
||||
_isReading = true;
|
||||
Thread.Sleep(100);
|
||||
var stopWatch = Stopwatch.StartNew(); //start stop watch for data recevie timeout
|
||||
while (_isReading) //wait until reading finishes or timeout occur
|
||||
{
|
||||
if (stopWatch.ElapsedMilliseconds > readTimeout)
|
||||
{
|
||||
stopWatch.Stop();
|
||||
ErrorMessage = "COM error: Receive timeout";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ErrorMessage = String.Format("COM error: Transmit timeout {0}.{1}", _serialPort.PortName, ex.Message);
|
||||
return false; // Exception in send function
|
||||
}
|
||||
return true;
|
||||
}
|
||||
private void PrepareReading()
|
||||
{
|
||||
_serialPort.DiscardInBuffer();
|
||||
if(_binMessages != null) _binMessages.Clear();
|
||||
_isReading = true;
|
||||
}
|
||||
public byte[] GetRawData()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_binMessages.Count > 0)
|
||||
return _binMessages[0].ToArray();
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
catch(Exception)
|
||||
{
|
||||
byte[] err = { 0xFF };
|
||||
return err;
|
||||
}
|
||||
}
|
||||
private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
|
||||
{
|
||||
if (!_serialPort.IsOpen) return;
|
||||
lock (this)
|
||||
{
|
||||
Thread.Sleep(100);
|
||||
if (!_serialPort.IsOpen) return;
|
||||
SerialPortReadBuffer = new Collection<byte>();
|
||||
while (_serialPort.BytesToRead > 0)
|
||||
{
|
||||
SerialPortReadBuffer.Add((byte)_serialPort.ReadByte());
|
||||
}
|
||||
|
||||
_binMessages.Add(SerialPortReadBuffer.ToArray());
|
||||
_isReading = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void CloseConnection()
|
||||
{
|
||||
if ((_serialPort != null) && (_serialPort.IsOpen))
|
||||
{
|
||||
_serialPort.DataReceived -= DataReceivedHandler;
|
||||
_serialPort.Close();
|
||||
_serialPort.Dispose();
|
||||
_serialPort = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
if (isOpen())
|
||||
{
|
||||
_serialPort.Close();
|
||||
}
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
if (_serialPort != null)
|
||||
{
|
||||
_serialPort.Dispose();
|
||||
}
|
||||
}
|
||||
public bool isOpen()
|
||||
{
|
||||
if(_serialPort != null)
|
||||
return _serialPort.IsOpen;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace NfcC7_DLL.NfcHandler.Utils
|
||||
{
|
||||
public class SerialPortData
|
||||
{
|
||||
private Boolean? _cliExists;
|
||||
public bool CliExists { get {
|
||||
if (_cliExists == null || !_cliExists.HasValue)
|
||||
{
|
||||
_cliExists = File.Exists(SerialPortCmdClientPath);
|
||||
}
|
||||
return _cliExists.Value;
|
||||
} }
|
||||
public string SerialPortCmdClientPath {
|
||||
get {
|
||||
#if DEBUG
|
||||
return Path.Combine("C:\\","TBF","Cli", CmdClientName);
|
||||
#else
|
||||
return Path.Combine("..","Cli", CmdClientName);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
public string CmdClientName { get; set; } = "HalCli.exe";
|
||||
public string PortName { get; set; }
|
||||
public int MeterType { get; set; }
|
||||
public string MeterTypeStr { get; set; }
|
||||
|
||||
public enum EMeterArg {
|
||||
Calibration = 0,
|
||||
AllParams = 2,
|
||||
DeviceId = 3,
|
||||
Optohead = 4,
|
||||
}
|
||||
EMeterArg _eMeterArg = EMeterArg.AllParams;
|
||||
|
||||
public string DefaultArgSettingsRead(EMeterArg eMeterArg)
|
||||
{
|
||||
string meterTypeInsert = !string.IsNullOrEmpty(MeterTypeStr) ? MeterTypeStr : MeterType.ToString();
|
||||
switch (eMeterArg)
|
||||
{
|
||||
case EMeterArg.AllParams:
|
||||
return $"-p {PortName} -m {meterTypeInsert} --operation readall";
|
||||
case EMeterArg.DeviceId:
|
||||
return $"-p {PortName} -m {meterTypeInsert} --operation read --parameter DeviceId";
|
||||
case EMeterArg.Optohead:
|
||||
return $"-p {PortName} -m {meterTypeInsert} --operation read --parameter \"OpticalDataMode\"";
|
||||
default:
|
||||
throw new Exception("Not implemented correct command!");
|
||||
}
|
||||
}
|
||||
|
||||
public string DefaultArgSettingsWrite(EMeterArg eMeterArg, string arg)
|
||||
{
|
||||
string meterTypeInsert = !string.IsNullOrEmpty(MeterTypeStr) ? MeterTypeStr : MeterType.ToString();
|
||||
switch (eMeterArg)
|
||||
{
|
||||
case EMeterArg.Calibration:
|
||||
return $"-p {PortName} -m {meterTypeInsert} --operation write --parameter Calibration --value {arg}";
|
||||
case EMeterArg.Optohead:
|
||||
return $"-p {PortName} -m {meterTypeInsert} --operation write --parameter \"OpticalDataMode\" --value {arg}";
|
||||
default:
|
||||
throw new Exception("Not implemented correct command!");
|
||||
}
|
||||
}
|
||||
|
||||
public SerialPortData(
|
||||
string portName,
|
||||
string cmdClientName,
|
||||
int meterType)
|
||||
{
|
||||
PortName = portName;
|
||||
CmdClientName = cmdClientName;
|
||||
MeterType = meterType;
|
||||
}
|
||||
|
||||
public SerialPortData(
|
||||
string portName,
|
||||
string cmdClientName,
|
||||
string meterType)
|
||||
{
|
||||
PortName = portName;
|
||||
CmdClientName = cmdClientName;
|
||||
MeterTypeStr = meterType;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
//*****************************************************************************
|
||||
@@ -9,7 +7,7 @@ using System.Text;
|
||||
// Author: Venkat, Rajeshwar
|
||||
//*****************************************************************************
|
||||
|
||||
namespace Sensus.Poseidon.NfcHandler
|
||||
namespace NfcC7_DLL.NfcHandler.Utils
|
||||
{
|
||||
public static class Tools
|
||||
{
|
||||
+6
-1
@@ -11,6 +11,7 @@ using NHibernate.Cfg;
|
||||
using NHibernate.Tool.hbm2ddl;
|
||||
using Common;
|
||||
using Results.Entities;
|
||||
using Results.Entities.helpers;
|
||||
|
||||
namespace Results
|
||||
{
|
||||
@@ -107,7 +108,11 @@ namespace Results
|
||||
throw new Exception("Connection string was not specified");
|
||||
}
|
||||
|
||||
if (SessionFactory == null) SessionFactory = CreateSessionFactory();
|
||||
if (SessionFactory == null)
|
||||
{
|
||||
DatabaseMigrationHelper.EnsureSchema(dbType, connectionString);
|
||||
SessionFactory = CreateSessionFactory();
|
||||
}
|
||||
|
||||
return SessionFactory.OpenSession();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
using System;
|
||||
using Common;
|
||||
using log4net;
|
||||
using MySql.Data.MySqlClient;
|
||||
|
||||
namespace Results.Entities.helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Applies explicit, backwards-compatible results DB migrations before the
|
||||
/// first NHibernate session factory is created.
|
||||
/// </summary>
|
||||
public static class DatabaseMigrationHelper
|
||||
{
|
||||
private static readonly ILog log = LogManager.GetLogger(typeof(DatabaseMigrationHelper));
|
||||
|
||||
public static void EnsureSchema(DBType dbType, string connectionString)
|
||||
{
|
||||
switch (dbType)
|
||||
{
|
||||
case DBType.MySql:
|
||||
EnsureMySqlSchema(connectionString);
|
||||
break;
|
||||
case DBType.SQLite:
|
||||
EnsureSQLiteSchema(connectionString);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void EnsureMySqlSchema(string connectionString)
|
||||
{
|
||||
using (var conn = new MySqlConnection(connectionString))
|
||||
{
|
||||
conn.Open();
|
||||
|
||||
// Added by newer MeterTestRslt mapping; older customer DBs do
|
||||
// not contain it and otherwise reject the entire batch insert.
|
||||
EnsureColumnMySql(conn, "MeterTestRslt", "PulsesPerKilogram", "DOUBLE NOT NULL DEFAULT 0");
|
||||
EnsureColumnMySql(conn, "MeterTestRslt", "FlipMode", "INT NULL");
|
||||
EnsureColumnMySql(conn, "MeterTestRslt", "ExtraDataPath", "VARCHAR(255) NULL");
|
||||
EnsureMeterTestResultExtraColumnsMySql(conn);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EnsureMeterTestResultExtraColumnsMySql(MySqlConnection conn)
|
||||
{
|
||||
for (int index = 1; index <= 9; index++)
|
||||
{
|
||||
EnsureColumnMySql(conn, "MeterTestRslt", "X" + index, "FLOAT NOT NULL DEFAULT 0");
|
||||
}
|
||||
}
|
||||
|
||||
private static void EnsureColumnMySql(
|
||||
MySqlConnection conn,
|
||||
string tableName,
|
||||
string columnName,
|
||||
string columnDefinition)
|
||||
{
|
||||
using (var transaction = conn.BeginTransaction())
|
||||
{
|
||||
try
|
||||
{
|
||||
bool exists;
|
||||
using (var cmd = conn.CreateCommand())
|
||||
{
|
||||
cmd.Transaction = transaction;
|
||||
cmd.CommandText = @"
|
||||
SELECT COUNT(*)
|
||||
FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE TABLE_SCHEMA = DATABASE()
|
||||
AND TABLE_NAME = @tableName
|
||||
AND COLUMN_NAME = @columnName";
|
||||
cmd.Parameters.AddWithValue("@tableName", tableName);
|
||||
cmd.Parameters.AddWithValue("@columnName", columnName);
|
||||
exists = Convert.ToInt32(cmd.ExecuteScalar()) > 0;
|
||||
}
|
||||
|
||||
if (!exists)
|
||||
{
|
||||
using (var alter = conn.CreateCommand())
|
||||
{
|
||||
alter.Transaction = transaction;
|
||||
alter.CommandText = "ALTER TABLE `" + tableName + "` ADD COLUMN `" +
|
||||
columnName + "` " + columnDefinition;
|
||||
alter.ExecuteNonQuery();
|
||||
log.WarnFormat("Results DB migration: added {0}.{1} ({2}).",
|
||||
tableName, columnName, columnDefinition);
|
||||
}
|
||||
}
|
||||
|
||||
transaction.Commit();
|
||||
}
|
||||
catch
|
||||
{
|
||||
transaction.Rollback();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void EnsureSQLiteSchema(string databaseFile)
|
||||
{
|
||||
using (var conn = new System.Data.SQLite.SQLiteConnection("Data Source=" + databaseFile))
|
||||
{
|
||||
conn.Open();
|
||||
|
||||
EnsureColumnSQLite(conn, "MeterTestRslt", "PulsesPerKilogram", "REAL NOT NULL DEFAULT 0");
|
||||
EnsureColumnSQLite(conn, "MeterTestRslt", "FlipMode", "INTEGER NULL");
|
||||
EnsureColumnSQLite(conn, "MeterTestRslt", "ExtraDataPath", "TEXT NULL");
|
||||
EnsureMeterTestResultExtraColumnsSQLite(conn);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EnsureMeterTestResultExtraColumnsSQLite(System.Data.SQLite.SQLiteConnection conn)
|
||||
{
|
||||
for (int index = 1; index <= 9; index++)
|
||||
{
|
||||
EnsureColumnSQLite(conn, "MeterTestRslt", "X" + index, "REAL NOT NULL DEFAULT 0");
|
||||
}
|
||||
}
|
||||
|
||||
private static void EnsureColumnSQLite(
|
||||
System.Data.SQLite.SQLiteConnection conn,
|
||||
string tableName,
|
||||
string columnName,
|
||||
string columnDefinition)
|
||||
{
|
||||
bool exists = false;
|
||||
using (var cmd = conn.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = "PRAGMA table_info(" + tableName + ")";
|
||||
using (var reader = cmd.ExecuteReader())
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
if (string.Equals(reader["name"].ToString(), columnName,
|
||||
StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
exists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!exists)
|
||||
{
|
||||
using (var alter = conn.CreateCommand())
|
||||
{
|
||||
alter.CommandText = "ALTER TABLE " + tableName + " ADD COLUMN " +
|
||||
columnName + " " + columnDefinition;
|
||||
alter.ExecuteNonQuery();
|
||||
log.WarnFormat("Results DB migration: added {0}.{1} ({2}).",
|
||||
tableName, columnName, columnDefinition);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>TRACE;DEBUG;IPERL;HEAT_METERS;</DefineConstants>
|
||||
<DefineConstants>TRACE;DEBUG;IPERL;</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
@@ -29,7 +29,7 @@
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;IPERL;HEAT_METERS;</DefineConstants>
|
||||
<DefineConstants>TRACE;IPERL;</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
@@ -53,6 +53,9 @@
|
||||
<Reference Include="NHibernate">
|
||||
<HintPath>..\packages\NHibernate.4.0.4.4000\lib\net40\NHibernate.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Data.SQLite, Version=2.0.3.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Data.SQLite.2.0.3\lib\net471\System.Data.SQLite.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Drawing" />
|
||||
@@ -69,6 +72,7 @@
|
||||
<Compile Include="DBase.cs" />
|
||||
<Compile Include="Entities\Batch.cs" />
|
||||
<Compile Include="Entities\Components.cs" />
|
||||
<Compile Include="Entities\helpers\DatabaseMigrationHelper.cs" />
|
||||
<Compile Include="Entities\MeterTestRslt.cs" />
|
||||
<Compile Include="Entities\PurchaseBox.cs" />
|
||||
<Compile Include="Entities\PurchaseOrder.cs" />
|
||||
@@ -265,4 +269,4 @@
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>TRACE;DEBUG;LANG_PL;HEAT_METERS;</DefineConstants>
|
||||
<DefineConstants>TRACE;DEBUG;LANG_PL;</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
@@ -25,7 +25,7 @@
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;HEAT_METERS;</DefineConstants>
|
||||
<DefineConstants>TRACE;</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -106,13 +106,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LabelPrinting", "LabelPrint
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TBFTests", "TBFTests\TBFTests.csproj", "{77EB589F-C670-4489-AAD6-2A3C02061FD1}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AppDiagnostic", "AppDiagnostic\AppDiagnostic.csproj", "{FA9ABAD1-7184-4295-ADE8-D44F2E3DE6B2}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{8F942729-F454-4C99-BA6C-746962065AE3} = {8F942729-F454-4C99-BA6C-746962065AE3}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharedComponents", "SharedComponents\SharedComponents.csproj", "{8F942729-F454-4C99-BA6C-746962065AE3}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sensus.iPerl.RfidCom", "..\iPerlHead\Sensus.iPerl.RfidCom\Sensus.iPerl.RfidCom.csproj", "{A3E14180-7F00-42E5-94A9-8DB62EAD6EE8}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sensus.iPerl.TestConsole", "..\iPerlHead\Sensus.iPerl.TestConsole\Sensus.iPerl.TestConsole.csproj", "{5025ED8B-A94F-4E58-8BE0-68481B061609}"
|
||||
@@ -481,30 +474,6 @@ Global
|
||||
{77EB589F-C670-4489-AAD6-2A3C02061FD1}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{77EB589F-C670-4489-AAD6-2A3C02061FD1}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{77EB589F-C670-4489-AAD6-2A3C02061FD1}.Release|x86.Build.0 = Release|Any CPU
|
||||
{FA9ABAD1-7184-4295-ADE8-D44F2E3DE6B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FA9ABAD1-7184-4295-ADE8-D44F2E3DE6B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FA9ABAD1-7184-4295-ADE8-D44F2E3DE6B2}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{FA9ABAD1-7184-4295-ADE8-D44F2E3DE6B2}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{FA9ABAD1-7184-4295-ADE8-D44F2E3DE6B2}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{FA9ABAD1-7184-4295-ADE8-D44F2E3DE6B2}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{FA9ABAD1-7184-4295-ADE8-D44F2E3DE6B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FA9ABAD1-7184-4295-ADE8-D44F2E3DE6B2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{FA9ABAD1-7184-4295-ADE8-D44F2E3DE6B2}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{FA9ABAD1-7184-4295-ADE8-D44F2E3DE6B2}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{FA9ABAD1-7184-4295-ADE8-D44F2E3DE6B2}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{FA9ABAD1-7184-4295-ADE8-D44F2E3DE6B2}.Release|x86.Build.0 = Release|Any CPU
|
||||
{8F942729-F454-4C99-BA6C-746962065AE3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8F942729-F454-4C99-BA6C-746962065AE3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8F942729-F454-4C99-BA6C-746962065AE3}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{8F942729-F454-4C99-BA6C-746962065AE3}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{8F942729-F454-4C99-BA6C-746962065AE3}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{8F942729-F454-4C99-BA6C-746962065AE3}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{8F942729-F454-4C99-BA6C-746962065AE3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8F942729-F454-4C99-BA6C-746962065AE3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8F942729-F454-4C99-BA6C-746962065AE3}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{8F942729-F454-4C99-BA6C-746962065AE3}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{8F942729-F454-4C99-BA6C-746962065AE3}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{8F942729-F454-4C99-BA6C-746962065AE3}.Release|x86.Build.0 = Release|Any CPU
|
||||
{A3E14180-7F00-42E5-94A9-8DB62EAD6EE8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A3E14180-7F00-42E5-94A9-8DB62EAD6EE8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A3E14180-7F00-42E5-94A9-8DB62EAD6EE8}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
|
||||
@@ -19,6 +19,9 @@ using System.Runtime.InteropServices;
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
//Visibility to TBFTests internal classes
|
||||
[assembly: InternalsVisibleTo("TBFTests")]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("2c13538e-15ee-48b2-af0f-2c95afb67186")]
|
||||
|
||||
@@ -29,5 +32,5 @@ using System.Runtime.InteropServices;
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("3.9.2149.0")]
|
||||
[assembly: AssemblyFileVersion("3.9.2149.0")]
|
||||
[assembly: AssemblyVersion("3.9.2206.0")]
|
||||
[assembly: AssemblyFileVersion("3.9.2206.0")]
|
||||
|
||||
@@ -3,3 +3,13 @@
|
||||
| Version | Target Environment | Title | Description |
|
||||
|------------|--------------------------------------------------------------|-----------------------------------------------------|------------------------------------|
|
||||
| 3.9.2149.0 | HeatMeters, Heat meter sensors, Procedure Dilog, Tab Process | Excanged columns value 'Sensor' and 'Heat meter sensor' | Fix in code ProcedureDlg, row 1851 |
|
||||
| 3.9.2149.1 | General release | Version iteration | Assembly and file version increment. |
|
||||
| 3.9.2149.2 | Poseidon register reader | Poseidon pulse and timing handling | Added reference-pulse reading in `Run()` and improved Poseidon timing/task tracking. |
|
||||
| 3.9.2149.4 | Mass collection / Poseidon start-stop | Mass collection update | Refactored standing-start mass collection, extended Poseidon start/end data-entry configuration and improved dialog/task handling. |
|
||||
| 3.9.2200.1 | Test infrastructure | TBF test assembly access | Added `InternalsVisibleTo` support for `TBFTests`. |
|
||||
| 3.9.2201.1 | Poseidon CLI | Poseidon CLI configuration | Added macro descriptions, refined serial-port/CLI argument configuration and extended CLI test coverage. |
|
||||
| 3.9.2202.1 | Poseidon CLI | CLI release iteration | Assembly and file version increment for the Poseidon CLI workstream. |
|
||||
| 3.9.2203.1 | Poseidon CLI / smart-meter sequence | CLI test and configuration update | Updated CLI executable test setup, serial-port default responses and smart-meter component-name handling. |
|
||||
| 3.9.2204.1 | Morrisville / Poseidon CLI | Morrisville CLI diagnostics | Restored lost 2204 versioning, added detailed CLI command/response logging and used a fixed CLI directory for deployment. |
|
||||
| 3.9.2205.1 | Morrisville / Poseidon CLI / Results DB | Poseidon read diagnostics and results DB migration | Improved Poseidon CLI execution and diagnostics (fixed CLI working directory, exit code/stdout/stderr capture, JSON/NFC/reading validation and culture-independent decimal parsing). Added reader-cycle and fake-CLI test coverage. Prevented a device/CLI error while changing the legacy optical-head mode from crashing the UI. Results DB now creates missing `MeterTestRslt` compatibility columns (`FlipMode`, `ExtraDataPath`, `X1`-`X9`) automatically for MySQL and SQLite before results are saved. |
|
||||
| 3.9.2206.0 | Morrisville / Poseidon CLI / Results DB | Poseidon start/end rearm and simulation isolation | Fixed the Poseidon start/end read cycle so a completed START reader is armed again once for END, preventing reused START values or skipped END CLI calls. Added trace logging for CLI response, dialog prefill and confirmed dialog values. In `Simulate` mode, `PoseidonCmdStartStop` now always runs the fixed `C:\TBF\Cli\cmdSleepTest.exe` instead of the configured physical Hat CLI. Added regression tests for customer CLI JSON responses, decimal comma/dot and non-zero readings, start/end dialog transfer, full/reduced reader cycles and simulation CLI selection. Extended results-schema migration with `MeterTestRslt.PulsesPerKilogram`. |
|
||||
|
||||
@@ -17,8 +17,7 @@ using TBF.Boxes;
|
||||
using TBF.Rig.GenericDevices;
|
||||
using TBF.Rig.Sequences;
|
||||
using TBF.UiBridge;
|
||||
using AppDiagnostic;
|
||||
using SharedComponents;
|
||||
|
||||
|
||||
namespace TBF.Rig.ControlBoard.Uni
|
||||
{
|
||||
|
||||
@@ -8,10 +8,9 @@ using System.Windows.Forms;
|
||||
using log4net;
|
||||
using Common;
|
||||
using TBF.Rig.Sequences;
|
||||
using TBF.Rig.Output.DB.SensusOracle;
|
||||
using TBF.Resources;
|
||||
using System.Drawing;
|
||||
using NHibernate;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
{
|
||||
@@ -220,6 +219,25 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
orderComboBox.Text = orderComboBox.Items[0].ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public void AutoClickOkAfterDelay(int delayMs = 10000)
|
||||
{
|
||||
_ = AutoClickInternal(okButton, delayMs);
|
||||
}
|
||||
|
||||
private async Task AutoClickInternal(Button clickButton, int delayMs)
|
||||
{
|
||||
await Task.Delay(delayMs);
|
||||
|
||||
if (clickButton.IsHandleCreated && clickButton.Enabled && clickButton.Visible)
|
||||
{
|
||||
// Invoke on UI thread
|
||||
if (clickButton.InvokeRequired)
|
||||
clickButton.BeginInvoke(new Action(() => clickButton.PerformClick()));
|
||||
else
|
||||
clickButton.PerformClick();
|
||||
}
|
||||
}
|
||||
|
||||
private void okButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
@@ -61,6 +61,15 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
|
||||
CurrentOp currentOp;
|
||||
|
||||
public enum ReadDataOp
|
||||
{
|
||||
None,
|
||||
Start,
|
||||
Busy,
|
||||
Done,
|
||||
}
|
||||
ReadDataOp readDataOp;
|
||||
|
||||
|
||||
public EntryForm() { }
|
||||
|
||||
@@ -112,6 +121,7 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
|| currentOp == CurrentOp.SendStartDataStream)
|
||||
) throw new Exception("Sequence error");
|
||||
currentOp = CurrentOp.ReadDatastream_StartStates;
|
||||
readDataOp = ReadDataOp.None;
|
||||
//TODO BUMI apply show data in dialog if config required
|
||||
//entryFormCfg.Direction = Direction.S640;
|
||||
//currentOp = CurrentOp.EnterTestStartStates;
|
||||
@@ -122,10 +132,10 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
if (reader != null && reader is PoseidonReader)
|
||||
{
|
||||
PoseidonReader poseidonReader = (reader as PoseidonReader);
|
||||
if (!string.IsNullOrEmpty(poseidonReader.SerialNr)
|
||||
&& waterMeters.Count > iterator)
|
||||
if (waterMeters.Count > iterator)
|
||||
{
|
||||
waterMeters[iterator].SerialNr = poseidonReader.SerialNr;
|
||||
if(!string.IsNullOrEmpty(poseidonReader.SerialNr))
|
||||
waterMeters[iterator].SerialNr = poseidonReader.SerialNr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,8 +145,17 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
}
|
||||
|
||||
/// <returns>null (not implemented)</returns>
|
||||
public IOperation ShowAdvancedTestStartFormOp(IRegReader[] regReaders, IList<Results.Entities.WaterMeter> waterMeters, bool isCondOp) { return null; }
|
||||
public IOperation ShowTestCollectFormOp(IRegReader[] regReaders, double volumeRef, double errLimLo, double errLimHi) { return null; }
|
||||
public IOperation ShowAdvancedTestStartFormOp(IRegReader[] regReaders,
|
||||
IList<Results.Entities.WaterMeter> waterMeters, bool isCondOp)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public IOperation ShowTestCollectFormOp(IRegReader[] regReaders, double volumeRef, double errLimLo,
|
||||
double errLimHi)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <returns>Reference to the operation</returns>
|
||||
public IOperation ShowTestEndFormOp(IRegReader[] regReaders, double refVolume, double errLimLo, double errLimHi)
|
||||
@@ -155,16 +174,17 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
///
|
||||
void OpenBeginningDlg(EntryForm myRef)
|
||||
{
|
||||
if (!ShowForm)
|
||||
if (ShowForm == 0)
|
||||
return;
|
||||
myRef.modelessDlg = new CycleBeginningForm(TBF.Data.WMsCount, myRef.entryFormCfg,
|
||||
ProcessData.SelectedProcedure.OrderInfo != null ? ProcessData.SelectedProcedure.OrderInfo.POName : string.Empty);
|
||||
(myRef.modelessDlg as CycleBeginningForm)?.AutoClickOkAfterDelay();
|
||||
modelessDlg.Show();
|
||||
}
|
||||
///
|
||||
void OpenTestStartStatesDlg(EntryForm myRef)
|
||||
{
|
||||
if (!ShowForm)
|
||||
if (ShowForm == 0)
|
||||
return;
|
||||
myRef.modelessDlg = new TestStartEndForm(myRef.waterMeters.Count, myRef.regReaders, disabled);
|
||||
modelessDlg.Show();
|
||||
@@ -172,7 +192,7 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
///
|
||||
void OpenTestEndStatesDlg(EntryForm myRef)
|
||||
{
|
||||
if (!ShowForm)
|
||||
if (ShowForm == 0)
|
||||
return;
|
||||
myRef.modelessDlg = new TestStartEndForm(TBF.Data.WMsCount, myRef.regReaders, wmStartStateStr, disabled, refVolume, errLimLo, errLimHi);
|
||||
modelessDlg.Show();
|
||||
@@ -181,15 +201,19 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
/// <summary>Start this operation</summary>
|
||||
public void Start()
|
||||
{
|
||||
if (!ShowForm)
|
||||
readDataOp = ReadDataOp.None;
|
||||
readAndSetDataToMeters = false;
|
||||
filedDataToMeters = false;
|
||||
|
||||
if (ShowForm == 0)
|
||||
return ;
|
||||
|
||||
resultSaved = false;
|
||||
switch (currentOp)
|
||||
{
|
||||
case CurrentOp.SendStartDataStream:
|
||||
ReadAndSetDataToMeters();
|
||||
if (ProcessData.SelectedProcedure.OrderInfo == null || entryFormCfg.Direction != Direction.S640)
|
||||
//ReadAndSetDataToMeters();
|
||||
if (ProcessData.SelectedProcedure.OrderInfo == null)
|
||||
{
|
||||
Program.MainWnd.Invoke(new EntryFormDlgt(OpenBeginningDlg), this);
|
||||
}
|
||||
@@ -209,28 +233,87 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
}
|
||||
}
|
||||
|
||||
private bool readAndSetDataToMeters = false;
|
||||
private bool filedDataToMeters = false;
|
||||
|
||||
/// <summary>Run this operation</summary>
|
||||
/// <returns>Event.ResultsPrinted</returns>
|
||||
public Event Run()
|
||||
{
|
||||
ReadAndSetDataToMeters();
|
||||
if (!readAndSetDataToMeters) // run until not finished
|
||||
readAndSetDataToMeters = ReadAndSetDataToMeters();
|
||||
|
||||
if (!ShowForm)
|
||||
return Event.ModelessFormClosed;
|
||||
|
||||
if (ProcessData.SelectedProcedure.OrderInfo != null && entryFormCfg.Direction == Direction.S640)
|
||||
{
|
||||
for (int i = 0; i < waterMeters.Count; i++)
|
||||
{
|
||||
if (waterMeters[i] != null)
|
||||
waterMeters[i].PurchaseOrder = ProcessData.SelectedProcedure.OrderInfo.POName;
|
||||
}
|
||||
return Event.ModelessFormClosed;
|
||||
}
|
||||
if (ShowForm == 0)
|
||||
if(readAndSetDataToMeters)
|
||||
return Event.ModelessFormClosed;
|
||||
else
|
||||
{
|
||||
return Event.ModelessFormIsOpen;
|
||||
}
|
||||
|
||||
if ((modelessDlg is IHasCompleted) && !(modelessDlg as IHasCompleted).Completed)
|
||||
if (readAndSetDataToMeters && !filedDataToMeters)
|
||||
{
|
||||
return Event.ModelessFormIsOpen;
|
||||
if (regReaders != null)
|
||||
{
|
||||
//add data into dialog
|
||||
int item = 0;
|
||||
TestStartEndForm dlg = (modelessDlg as TestStartEndForm);
|
||||
foreach (var iRegReader in regReaders)
|
||||
{
|
||||
if (iRegReader is PoseidonReader poseidonReader)
|
||||
{
|
||||
if (dlg != null)
|
||||
{
|
||||
if (currentOp == CurrentOp.ReadDatastream_StartStates)
|
||||
{
|
||||
dlg.WMStartState[item] = poseidonReader.BeginWMState;
|
||||
dlg.WMStartStateStr[item] = poseidonReader.BeginWMState.ToString();
|
||||
log.InfoFormat("Poseidon dialog prefill: phase=Start, WM{0}, reader={1}, value={2}",
|
||||
item + 1, poseidonReader.Name, dlg.WMStartState[item]);
|
||||
}
|
||||
|
||||
if (currentOp == CurrentOp.ReadDatastream_EndStates)
|
||||
{
|
||||
dlg.WMEndState[item] = poseidonReader.EndWMState;
|
||||
log.InfoFormat("Poseidon dialog prefill: phase=End, WM{0}, reader={1}, value={2}",
|
||||
item + 1, poseidonReader.Name, dlg.WMEndState[item]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
item++;
|
||||
}
|
||||
|
||||
if (dlg != null)
|
||||
{
|
||||
if (dlg.InvokeRequired)
|
||||
{
|
||||
dlg.BeginInvoke(new Action(() =>
|
||||
{
|
||||
dlg.UpdateValues(currentOp == CurrentOp.ReadDatastream_StartStates, true);
|
||||
if (entryFormCfg.ShowDialogType == ShowDialogType.ContinueAutomatically)
|
||||
{
|
||||
dlg.AutoClickOkAfterDelay();
|
||||
}
|
||||
}));
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
dlg.UpdateValues(currentOp == CurrentOp.ReadDatastream_StartStates, true);
|
||||
if (entryFormCfg.ShowDialogType == ShowDialogType.ContinueAutomatically)
|
||||
{
|
||||
dlg.AutoClickOkAfterDelay();
|
||||
}
|
||||
}
|
||||
}
|
||||
filedDataToMeters = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ((modelessDlg is IHasCompleted) && !(modelessDlg as IHasCompleted).Completed)
|
||||
{
|
||||
return Event.ModelessFormIsOpen; //ModelessFormClosed ??
|
||||
}
|
||||
|
||||
if (!resultSaved) /// This is to save the result only once
|
||||
@@ -249,31 +332,10 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (modelessDlg is TestStartEndForm && currentOp == CurrentOp.ReadDatastream_StartStates)
|
||||
else if (modelessDlg is TestStartEndForm)
|
||||
{
|
||||
/// Fixed start test - start
|
||||
TestStartEndForm dlg = (modelessDlg as TestStartEndForm);
|
||||
if (dlg != null)
|
||||
{
|
||||
for (int i = 0; i < dlg.WaterMetersCount; i++)
|
||||
{
|
||||
wmStartState[i] = dlg.WMStartState[i];
|
||||
wmStartStateStr[i] = dlg.WMStartStateStr[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (modelessDlg is TestStartEndForm && currentOp == CurrentOp.ReadDatastream_EndStates)
|
||||
{
|
||||
/// Fixed start test - end
|
||||
TestStartEndForm dlg = (modelessDlg as TestStartEndForm);
|
||||
if (dlg != null)
|
||||
{
|
||||
for (int i = 0; i < dlg.WaterMetersCount; i++)
|
||||
{
|
||||
wmEndState[i] = dlg.WMEndState[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
StoreAcceptedDialogValues((TestStartEndForm)modelessDlg);
|
||||
}
|
||||
resultSaved = true;
|
||||
modelessDlg = null;
|
||||
}
|
||||
@@ -281,6 +343,36 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
return Event.ModelessFormClosed; /// Form closed
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies values confirmed by the Poseidon start/end dialog into the
|
||||
/// data-entry state used later by the result calculation.
|
||||
/// </summary>
|
||||
private void StoreAcceptedDialogValues(TestStartEndForm dlg)
|
||||
{
|
||||
if (dlg == null)
|
||||
return;
|
||||
|
||||
if (currentOp == CurrentOp.ReadDatastream_StartStates)
|
||||
{
|
||||
for (int i = 0; i < dlg.WaterMetersCount; i++)
|
||||
{
|
||||
wmStartState[i] = dlg.WMStartState[i];
|
||||
wmStartStateStr[i] = dlg.WMStartStateStr[i];
|
||||
log.InfoFormat("Poseidon dialog accepted: phase=Start, WM{0}, text='{1}', value={2}",
|
||||
i + 1, wmStartStateStr[i], wmStartState[i]);
|
||||
}
|
||||
}
|
||||
else if (currentOp == CurrentOp.ReadDatastream_EndStates)
|
||||
{
|
||||
for (int i = 0; i < dlg.WaterMetersCount; i++)
|
||||
{
|
||||
wmEndState[i] = dlg.WMEndState[i];
|
||||
log.InfoFormat("Poseidon dialog accepted: phase=End, WM{0}, value={1}",
|
||||
i + 1, wmEndState[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Stop this operation</summary>
|
||||
public void Stop()
|
||||
{
|
||||
@@ -290,11 +382,13 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
modelessDlg = null;
|
||||
}
|
||||
currentOp = CurrentOp.None;
|
||||
readAndSetDataToMeters = false;
|
||||
filedDataToMeters = false;
|
||||
}
|
||||
|
||||
public bool ShowForm
|
||||
public int ShowForm
|
||||
{
|
||||
get { return entryFormCfg == null ? false : entryFormCfg.ShowDialog; }
|
||||
get { return entryFormCfg == null ? ShowDialogType.Hide.GetHashCode() : entryFormCfg.ShowDialogType.GetHashCode(); }
|
||||
set {} // only for read - svia dilalog
|
||||
}
|
||||
|
||||
@@ -303,13 +397,15 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
get { return entryFormCfg == null ? false : entryFormCfg.SaveCommunication;}
|
||||
}
|
||||
|
||||
//private long GetMaxtime()
|
||||
|
||||
public bool ReadAndSetDataToMeters()
|
||||
{
|
||||
bool bOperationSuccess = false;
|
||||
if (currentOp == CurrentOp.SendStartDataStream)
|
||||
{
|
||||
bool finishedReading = regReaders == null; // we can work only with register readers
|
||||
while (!finishedReading)
|
||||
while (!finishedReading) //TODO BUMI lock - fuck ?
|
||||
{
|
||||
bool bAllReadersFinished = true;
|
||||
foreach (var iRegReader in regReaders )
|
||||
@@ -326,6 +422,7 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
}
|
||||
/// Send start data stream
|
||||
poseidonReader.Run();
|
||||
readDataOp = ReadDataOp.Start;
|
||||
if (!(poseidonReader.CurrentOp == PoseidonReader.CurrentPoseidonOp.Done
|
||||
|| poseidonReader.CurrentOp == PoseidonReader.CurrentPoseidonOp.Error))
|
||||
{
|
||||
@@ -337,10 +434,11 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
if (bAllReadersFinished)
|
||||
{
|
||||
finishedReading = true;
|
||||
readDataOp = ReadDataOp.Done;
|
||||
}
|
||||
else
|
||||
{
|
||||
System.Threading.Thread.Sleep(100);
|
||||
System.Threading.Thread.Sleep(10);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -350,40 +448,50 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
|| (currentOp == CurrentOp.ReadDatastream_EndStates))
|
||||
{
|
||||
bool finishedReading = regReaders == null; // we can work only with register readers
|
||||
while (!finishedReading)
|
||||
List<IPoseidonReadOperation> poseidonReaders = new List<IPoseidonReadOperation>();
|
||||
if (regReaders != null)
|
||||
{
|
||||
bool bAllReadersFinished = true;
|
||||
foreach (var iRegReader in regReaders )
|
||||
foreach (var iRegReader in regReaders)
|
||||
{
|
||||
if (iRegReader is PoseidonReader)
|
||||
PoseidonReader poseidonReader = iRegReader as PoseidonReader;
|
||||
if (poseidonReader != null)
|
||||
{
|
||||
PoseidonReader poseidonReader = (iRegReader as PoseidonReader);
|
||||
if(poseidonReader == null)
|
||||
continue;
|
||||
poseidonReader.SetCliLogging(CliLogging);
|
||||
if (!(poseidonReader.CurrentOp == PoseidonReader.CurrentPoseidonOp.ReadDatastream_Done
|
||||
|| poseidonReader.CurrentOp == PoseidonReader.CurrentPoseidonOp.ReadDatastream_Running))
|
||||
{
|
||||
poseidonReader.SetCurrentOp((currentOp == CurrentOp.ReadDatastream_StartStates)?
|
||||
PoseidonReader.CurrentPoseidonOp.ReadDataStream_Start :
|
||||
PoseidonReader.CurrentPoseidonOp.ReadDataStream_End);
|
||||
}
|
||||
/// Send start data stream
|
||||
poseidonReader.Run();
|
||||
if (!(poseidonReader.CurrentOp == PoseidonReader.CurrentPoseidonOp.Done
|
||||
|| poseidonReader.CurrentOp == PoseidonReader.CurrentPoseidonOp.Error))
|
||||
{
|
||||
bAllReadersFinished = false;
|
||||
}
|
||||
poseidonReaders.Add(new PoseidonReaderOperation(poseidonReader));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var phaseRunner = new PoseidonReadPhaseRunner(
|
||||
currentOp == CurrentOp.ReadDatastream_StartStates);
|
||||
while (!finishedReading) //TODO BUMI lock - fuck ?
|
||||
{
|
||||
foreach (IPoseidonReadOperation poseidonReader in poseidonReaders)
|
||||
{
|
||||
if (poseidonReader.IsNotStarted || poseidonReader.IsFinished)
|
||||
log.DebugFormat("Poseidon read: arming {0} for {1}, previous state finished={2}",
|
||||
currentOp, poseidonReader.Name, poseidonReader.IsFinished);
|
||||
}
|
||||
|
||||
bool bAllReadersFinished = phaseRunner.RunIteration(poseidonReaders);
|
||||
foreach (IPoseidonReadOperation poseidonReader in poseidonReaders)
|
||||
{
|
||||
if (poseidonReader.IsFinished)
|
||||
{
|
||||
if (poseidonReader.HasError)
|
||||
log.ErrorFormat("Poseidon read: {0} completed with Error during {1}", poseidonReader.Name, currentOp);
|
||||
else
|
||||
log.DebugFormat("Poseidon read: {0} completed during {1}", poseidonReader.Name, currentOp);
|
||||
}
|
||||
}
|
||||
if (bAllReadersFinished)
|
||||
{
|
||||
log.DebugFormat("Poseidon read: all readers finished for {0}", currentOp);
|
||||
finishedReading = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
System.Threading.Thread.Sleep(100);
|
||||
System.Threading.Thread.Sleep(10);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
///
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Serialization;
|
||||
using Common;
|
||||
using Config.Entities;
|
||||
@@ -52,6 +53,15 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
#endif
|
||||
Count,
|
||||
}
|
||||
|
||||
public enum ShowDialogType
|
||||
{
|
||||
[Description("Do not Show")] Hide,
|
||||
[Description("Continue Automatically")] ContinueAutomatically,
|
||||
[Description("Continue Manually")] ContinueManually,
|
||||
Count,
|
||||
|
||||
}
|
||||
|
||||
public class EntryFormCfg : ComponentCfgBase, IComponentCfg, IParamsProvider
|
||||
{
|
||||
@@ -69,6 +79,7 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
public Direction Direction;
|
||||
public Orders Orders;
|
||||
public bool ShowDialog;
|
||||
public ShowDialogType ShowDialogType;
|
||||
public bool SaveCommunication;
|
||||
|
||||
/// Private parameterless constructor invoked by all other (public) constructors
|
||||
@@ -89,7 +100,7 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
{
|
||||
Direction = Direction.Forward_RL;
|
||||
Orders = Orders.Arbitrary;
|
||||
ShowDialog = false;
|
||||
ShowDialogType = ShowDialogType.Hide;
|
||||
SaveCommunication = false;
|
||||
}
|
||||
|
||||
@@ -115,8 +126,9 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
for (Orders o = 0; o < Orders.Count; o++) list.Add(o.ToDescription());
|
||||
return list;
|
||||
case 2:
|
||||
list.Add("True");
|
||||
list.Add("False");
|
||||
list.Add(ShowDialogType.Hide.ToDescription());
|
||||
list.Add(ShowDialogType.ContinueAutomatically.ToDescription());
|
||||
list.Add(ShowDialogType.ContinueManually.ToDescription());
|
||||
return list;
|
||||
case 3:
|
||||
list.Add("True");
|
||||
@@ -126,6 +138,19 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool TryFromInt<TEnum>(int value, out TEnum result)
|
||||
where TEnum : struct, Enum
|
||||
{
|
||||
if (Enum.IsDefined(typeof(TEnum), value))
|
||||
{
|
||||
result = (TEnum)(object)value;
|
||||
return true;
|
||||
}
|
||||
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public string ToString(int i)
|
||||
@@ -134,10 +159,10 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
{
|
||||
case 0: return Direction.ToDescription();
|
||||
case 1: return Orders.ToDescription();
|
||||
case 2: return ShowDialog.ToString();
|
||||
case 2: return ShowDialogType.ToDescription();
|
||||
case 3: return SaveCommunication.ToString();
|
||||
default:
|
||||
return string.Format("Name={0}, Direction={1}, Orders={2}, ShowDialog={3}, StoreCommunication={4}", Name, Direction, Orders, ShowDialog, SaveCommunication);
|
||||
return string.Format("Name={0}, Direction={1}, Orders={2}, ShowDialog={3}, StoreCommunication={4}", Name, Direction, Orders, ShowDialogType, SaveCommunication);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,11 +189,14 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
break;
|
||||
case 2:
|
||||
{
|
||||
bool lastSetting = ShowDialog;
|
||||
if (str == "True") ShowDialog = true;
|
||||
else ShowDialog = false;
|
||||
if (lastSetting != ShowDialog)
|
||||
return CfgUpdateFlags.RestartRqrd;
|
||||
ShowDialogType lastSetting = ShowDialogType;
|
||||
for (ShowDialogType s = 0; s < ShowDialogType.Count; s++)
|
||||
if (s.ToDescription() == str)
|
||||
{
|
||||
ShowDialogType = s;
|
||||
if (lastSetting != ShowDialogType)
|
||||
return CfgUpdateFlags.RestartRqrd;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
@@ -196,6 +224,11 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
if (ParamValues(i).Contains(str)) return true;
|
||||
break;
|
||||
case 2:
|
||||
bool exists = Enum.GetValues(typeof(ShowDialogType))
|
||||
.Cast<ShowDialogType>()
|
||||
.Any(d => d.ToDescription() == str);
|
||||
if (exists) return true;
|
||||
break;
|
||||
case 3:
|
||||
if (str == "True" || str == "False") return true;
|
||||
break;
|
||||
@@ -212,7 +245,7 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
{
|
||||
prms.Direction = this.Direction;
|
||||
prms.Orders = this.Orders;
|
||||
prms.ShowDialog = this.ShowDialog;
|
||||
prms.ShowDialogType = this.ShowDialogType;
|
||||
prms.SaveCommunication = this.SaveCommunication;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
///
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using log4net;
|
||||
using TBF.Rig.GenericDevices;
|
||||
@@ -99,9 +100,12 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
this.disabled = disabled;
|
||||
|
||||
ShuffleTextBoxes();
|
||||
ResizeDlgToFitEnabledControls();
|
||||
|
||||
WMStartState = new double[waterMetersCount];
|
||||
WMStartStateStr = new string[waterMetersCount];
|
||||
|
||||
SetUiBusy(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -130,8 +134,44 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
this.warningLimHi = 2 * errLimHi;
|
||||
|
||||
ShuffleTextBoxes();
|
||||
ResizeDlgToFitEnabledControls();
|
||||
|
||||
|
||||
WMEndState = new double[waterMetersCount];
|
||||
|
||||
SetUiBusy(true);
|
||||
}
|
||||
|
||||
private void SetUiBusy(bool busy, long deltaTime = -1)
|
||||
{
|
||||
log.DebugFormat("Poseidon UI: SetUiBusy busy={0}, deltaTime={1}, enabledTextBoxes={2}",
|
||||
busy, deltaTime, enabledTextBoxes.Count);
|
||||
|
||||
// show wait cursor for form and children
|
||||
this.UseWaitCursor = busy;
|
||||
|
||||
// block editing textboxes
|
||||
for (int i = 0; i < enabledTextBoxes.Count; i++)
|
||||
{
|
||||
enabledTextBoxes[i].Enabled = !busy;
|
||||
}
|
||||
|
||||
// disable buttons while busy
|
||||
if (okButton != null) okButton.Enabled = !busy;
|
||||
|
||||
|
||||
// show/hide "loading..." label
|
||||
if (loadingLabel != null)
|
||||
{
|
||||
loadingLabel.Visible = busy;
|
||||
loadingLabel.Text = "Loading...";
|
||||
if (deltaTime > 0)
|
||||
{
|
||||
//show delta time in label
|
||||
loadingLabel.Visible = true;
|
||||
loadingLabel.Text = string.Format("Get: {0} s", deltaTime/1000.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -159,6 +199,43 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
TextBoxesCount = TBF.Data.WMsCount;
|
||||
}
|
||||
}
|
||||
|
||||
void ResizeDlgToFitEnabledControls()
|
||||
{
|
||||
int xMax = 0;
|
||||
int yMax = 0;
|
||||
GetMaxDimensions(startTextBoxes,WaterMetersCount,ref xMax, ref yMax);
|
||||
GetMaxDimensions(endTextBoxes,WaterMetersCount, ref xMax, ref yMax);
|
||||
|
||||
int shapeGap = 50;
|
||||
okButton.Left = xMax + shapeGap;
|
||||
xMax = okButton.Left + okButton.Width;
|
||||
|
||||
Width = xMax + shapeGap;
|
||||
Height = yMax + shapeGap;
|
||||
}
|
||||
|
||||
private void GetMaxDimensions(TextBox[] textBoxes, int waterMetersCount, ref int xMax, ref int yMax)
|
||||
{
|
||||
for (int i = 0; i < waterMetersCount; i++)
|
||||
{
|
||||
if (textBoxes[i].Left + textBoxes[i].Width > xMax)
|
||||
xMax = textBoxes[i].Left + textBoxes[i].Width;
|
||||
if (textBoxes[i].Top + textBoxes[i].Height > yMax)
|
||||
yMax = textBoxes[i].Top + textBoxes[i].Height;
|
||||
}
|
||||
}
|
||||
|
||||
// private void GetMaxDimensions(TextBox[] textBoxes, ref int xMax, ref int yMax)
|
||||
// {
|
||||
// for (int i = 0; i < textBoxes.Length; i++)
|
||||
// {
|
||||
// if(!textBoxes[i].Visible)
|
||||
// continue;
|
||||
// if (textBoxes[i].Left + textBoxes[i].Width > xMax) xMax = textBoxes[i].Left + textBoxes[i].Width;
|
||||
// if (textBoxes[i].Top + textBoxes[i].Height > yMax) yMax = textBoxes[i].Top + textBoxes[i].Height;
|
||||
// }
|
||||
// }
|
||||
|
||||
private void CycleEndForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
@@ -211,6 +288,49 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateValues(bool stratValue = true, bool enableEdit = false, long deltaTime = -1)
|
||||
{
|
||||
// Ensure we are on the UI thread
|
||||
if (InvokeRequired)
|
||||
{
|
||||
log.DebugFormat("Poseidon UI: queue UpdateValues startValue={0}, enableEdit={1}, deltaTime={2}",
|
||||
stratValue, enableEdit, deltaTime);
|
||||
BeginInvoke(new Action(() => UpdateValues(stratValue, enableEdit)));
|
||||
return;
|
||||
}
|
||||
|
||||
log.DebugFormat("Poseidon UI: UpdateValues on UI thread startValue={0}, enableEdit={1}, deltaTime={2}",
|
||||
stratValue, enableEdit, deltaTime);
|
||||
|
||||
for (int i = 0; i < TextBoxesCount; i++)
|
||||
{
|
||||
if (stratValue)
|
||||
{
|
||||
if (WMStartStateStr != null && i < WMStartStateStr.Length)
|
||||
{
|
||||
startTextBoxes[i].Text = WMStartStateStr[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// small bugfix: check WMEndState, not WMStartStateStr
|
||||
if ((WMEndState != null && i < WMEndState.Length) &&
|
||||
(WMStartStateStr != null && i < WMStartStateStr.Length && WMStartStateStr[i] != ""))
|
||||
{
|
||||
endTextBoxes[i].Text = WMEndState[i].ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (enableEdit)
|
||||
{
|
||||
SetUiBusy(false, deltaTime);
|
||||
log.Debug("Poseidon UI: values applied and dialog released from Loading...");
|
||||
}
|
||||
// if you also need to enable/disable editing, do it here,
|
||||
// it's now safely on the UI thread.
|
||||
}
|
||||
|
||||
void Localize()
|
||||
{
|
||||
Text = Strings.Water_Meter_States;
|
||||
@@ -234,6 +354,8 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
if (endTextBoxes[i].Visible && endTextBoxes[i].Enabled)
|
||||
{
|
||||
WMEndState[i] = Utils.ParseUDouble(endTextBoxes[i].Text);
|
||||
log.InfoFormat("Poseidon dialog OK: phase=End, WM{0}, enteredText='{1}', parsedValue={2}",
|
||||
i + 1, endTextBoxes[i].Text, WMEndState[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -245,6 +367,8 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
{
|
||||
WMStartStateStr[i] = startTextBoxes[i].Text;
|
||||
WMStartState[i] = Utils.ParseUDouble(startTextBoxes[i].Text);
|
||||
log.InfoFormat("Poseidon dialog OK: phase=Start, WM{0}, enteredText='{1}', parsedValue={2}",
|
||||
i + 1, startTextBoxes[i].Text, WMStartState[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -258,6 +382,26 @@ namespace TBF.Rig.DataEntry.PoseidonCmd
|
||||
completed = true;
|
||||
Close();
|
||||
}
|
||||
|
||||
public void AutoClickOkAfterDelay(int delayMs = 10000)
|
||||
{
|
||||
_ = AutoClickInternal(okButton, delayMs);
|
||||
}
|
||||
|
||||
private async Task AutoClickInternal(Button okButton, int delayMs)
|
||||
{
|
||||
await Task.Delay(delayMs);
|
||||
|
||||
if (okButton.IsHandleCreated && okButton.Enabled && okButton.Visible)
|
||||
{
|
||||
// Invoke on UI thread
|
||||
if (okButton.InvokeRequired)
|
||||
okButton.BeginInvoke(new Action(() => okButton.PerformClick()));
|
||||
else
|
||||
okButton.PerformClick();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#region Forced close handling
|
||||
|
||||
|
||||
+610
-397
File diff suppressed because it is too large
Load Diff
@@ -21,6 +21,7 @@ namespace TBF.Rig.DataEntry.StandartCameraPurchaseOrder
|
||||
public partial class CycleBeginningForm : Form, GenericDevices.IHasCompleted
|
||||
{
|
||||
private static readonly ILog log = LogManager.GetLogger(typeof(CycleBeginningForm));
|
||||
private static readonly ILog log_selected = LogManager.GetLogger("PurchaseOrderHistory");
|
||||
|
||||
/// <summary> Number of water meters </summary>
|
||||
public readonly int WaterMetersCount;
|
||||
@@ -264,6 +265,11 @@ namespace TBF.Rig.DataEntry.StandartCameraPurchaseOrder
|
||||
Disabled[i] = !checkBoxes[i].Checked;
|
||||
}
|
||||
|
||||
//TODO create logger to log selected items and their order and Order number
|
||||
string snTextArrString = SNText != null ? string.Join(", ", SNText) : string.Empty;
|
||||
log_selected.DebugFormat("Purchase DLG - Selected Order: {0}, Last selected Box: {1}, All items: {2}",
|
||||
orderComboBox.Text, purchaseBoxComboBox.Text,snTextArrString);
|
||||
|
||||
completed = true;
|
||||
Close();
|
||||
}
|
||||
@@ -718,6 +724,17 @@ namespace TBF.Rig.DataEntry.StandartCameraPurchaseOrder
|
||||
.SelectMany(pBox => pBox.PurchaseWaterMeterDataList)
|
||||
.Select(pWM => pWM.SerialNo);
|
||||
|
||||
try
|
||||
{
|
||||
string[] iEnumerable = serialNumbers as string[] ?? serialNumbers.ToArray();
|
||||
log_selected.Debug(
|
||||
$"Selected order: {choosenOrder} box: {choosenBox} possible serial numbers (form DB): {string.Join(", ", iEnumerable)}");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log_selected.Error("Error loading serial numbers: " + e);
|
||||
}
|
||||
|
||||
//enable behaviour type
|
||||
bool addOnEndOnly = false;
|
||||
|
||||
@@ -726,6 +743,7 @@ namespace TBF.Rig.DataEntry.StandartCameraPurchaseOrder
|
||||
|
||||
if (countOfFreeBoxes < serialNumbers.Count())
|
||||
{
|
||||
log_selected.Debug(">" + serialNumbers.Count() + " Serial Numbers in box as we have free positions!");
|
||||
MessageBox.Show(this, "We have more Serial Numbers in box as we have free positions!", "Warning",
|
||||
MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||
return;
|
||||
@@ -753,6 +771,7 @@ namespace TBF.Rig.DataEntry.StandartCameraPurchaseOrder
|
||||
if (lastComboBoxSerialNo >= 0 || lastComboBoxSerialNo < enabledComboBoxes.Count)
|
||||
{
|
||||
comboBoxes[lastComboBoxSerialNo].Text = serialNumber;
|
||||
log_selected.Debug($"Added serial no: {serialNumber} to pos: {lastComboBoxSerialNo}");
|
||||
lastComboBoxSerialNo++;
|
||||
}
|
||||
}
|
||||
@@ -762,6 +781,7 @@ namespace TBF.Rig.DataEntry.StandartCameraPurchaseOrder
|
||||
if (iNextFreeNumber >= 0 || iNextFreeNumber < enabledComboBoxes.Count)
|
||||
{
|
||||
comboBoxes[iNextFreeNumber].Text = serialNumber;
|
||||
log_selected.Debug($"Added serial no: {serialNumber} to pos: {iNextFreeNumber}");
|
||||
lastComboBoxSerialNo = iNextFreeNumber;
|
||||
}
|
||||
}
|
||||
@@ -774,6 +794,7 @@ namespace TBF.Rig.DataEntry.StandartCameraPurchaseOrder
|
||||
|
||||
if (!noImplementedSerialNumbers.IsEmpty())
|
||||
{
|
||||
log_selected.Debug("No implemented serial numbers: " + noImplementedSerialNumbers);
|
||||
MessageBox.Show(this,
|
||||
string.Format("The following serial numbers were not implemented: {0}", noImplementedSerialNumbers),
|
||||
"Serial Numbers repeating!", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
///
|
||||
/// Copyright (c) 2013-2018 Sensus Slovensko a.s.
|
||||
///
|
||||
|
||||
using Common;
|
||||
using Config.Entities;
|
||||
|
||||
namespace TBF.Rig.Generic
|
||||
{
|
||||
public interface ITestParams
|
||||
public interface ITestParams : IParamsProvider
|
||||
{
|
||||
|
||||
public string Activity { get; set; } /// Communication activity
|
||||
public bool SimultWithPrevious { get; set; }
|
||||
public bool SimultWithNext { get; set; }
|
||||
|
||||
void UpdateFromDbEntity(ComponentTest dbEntity);
|
||||
void FromDbEntity(string componentName, Test test);
|
||||
ComponentTest ToDbEntity(string componentName, Test test);
|
||||
|
||||
@@ -2,7 +2,10 @@ namespace TBF.Rig.GenericDevices
|
||||
{
|
||||
public interface IHasFromUNIDisablePossibility
|
||||
{
|
||||
bool ShowForm { get; set; }
|
||||
/// <summary>
|
||||
/// 0 - disabled, > 1 - enabled but can have variable uses how form is shown
|
||||
/// </summary>
|
||||
int ShowForm { get; set; }
|
||||
|
||||
bool ReadAndSetDataToMeters();
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
/// Copyright (c) 2013-2022 Sensus Slovensko a.s.
|
||||
///
|
||||
using System.Collections.Generic;
|
||||
using TBF.Rig.Generic;
|
||||
using TBF.Rig.GenericDevices;
|
||||
|
||||
namespace TBF.Rig
|
||||
@@ -25,7 +26,8 @@ namespace TBF.Rig
|
||||
{
|
||||
for (int i = 0; i < Sequences.ProcessData.WMsCount; i++)
|
||||
{
|
||||
RegisterReaders[i] = TbfComponents.FindComponent(entity.GetSensor(i), components) as IRegReader;
|
||||
IComponent findComponent = TbfComponents.FindComponent(entity.GetSensor(i), components);
|
||||
RegisterReaders[i] = findComponent as IRegReader;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-7
@@ -1,12 +1,10 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2021 Sensus Metering Systems
|
||||
///
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.iPerlReaderUNI.comminication
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.CommonRR
|
||||
{
|
||||
public enum MessageID
|
||||
{
|
||||
@@ -107,7 +105,7 @@ namespace TBF.Rig.RegisterReaders.iPerlReaderUNI.comminication
|
||||
|
||||
public enum CommunicationInterface
|
||||
{
|
||||
RFID,
|
||||
NFC
|
||||
[Description("RFID")] RFID,
|
||||
[Description("NFC")] NFC
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace TBF.Rig.RegisterReaders.CommonRR
|
||||
{
|
||||
public interface IArg
|
||||
{
|
||||
int Value { get; }
|
||||
string Name { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using System.IO.Ports;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.CommonRR.IPerl
|
||||
{
|
||||
public interface ICombiHeadParams
|
||||
{
|
||||
///
|
||||
/// NFC S4.5 Combihead params
|
||||
///
|
||||
public int MciTimeoutMs { get; set; }
|
||||
public int BaudRate { get; set; }
|
||||
public int DataBits { get; set; }
|
||||
public Parity ParityBit { get; set; }
|
||||
public StopBits StopBits { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace TBF.Rig.RegisterReaders.CommonRR.IPerl
|
||||
{
|
||||
public interface ICommunicationTimeOuts
|
||||
{
|
||||
/// Communication timeout in ms (500 .. 5000)
|
||||
public int DelayBetweenRetries { get; set; } /// Delay between communication retries in ms (0 .. 5000)
|
||||
public int MaxCommRetries { get; set; } /// Max. number of retries (1 .. 10)
|
||||
public int WaitTimeAfterFailure { get; set; } /// Wait time after communication failure in ms
|
||||
public int PassThroughWaitTime { get; set; } /// Pass Through wait time for radio parameters in ms
|
||||
public int NrThreads { get; set; } /// Numbwr of parallel threads (1, 2 or 4)
|
||||
public int CommTimeout { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.CommonRR.IPerl
|
||||
{
|
||||
public interface ISerialPortData
|
||||
{
|
||||
|
||||
public Boolean? CliExists { get;}
|
||||
public string CmdClientName { get; set; }
|
||||
public string PortName { get; set; }
|
||||
public int MeterType { get; set; }
|
||||
public string SerialPortCmdClientPath { get; }
|
||||
public IArg MeterArg { get; }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO.Ports;
|
||||
using Config.Entities;
|
||||
using TBF.Rig.Generic;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.CommonRR.IPerl
|
||||
{
|
||||
public interface ITestMethodCfg : IComponentCfg, ICommunicationTimeOuts, ICombiHeadParams, IWebService
|
||||
{
|
||||
|
||||
public abstract IComponentCfgCtrl GetControl(IList<Component> cmpntEntities);
|
||||
public abstract string ToString(int i);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace TBF.Rig.RegisterReaders.CommonRR.IPerl
|
||||
{
|
||||
public interface IWebService
|
||||
{
|
||||
public bool UseWebService { get; set; }
|
||||
public string BaseUrl { get; set; }
|
||||
public string RelativeUrl { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using System.IO.Ports;
|
||||
using System.Xml.Serialization;
|
||||
using TBF.Rig.Generic;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.CommonRR.IPerl
|
||||
{
|
||||
public interface IiPerlTestMethodCfg : ITestMethodCfg
|
||||
{
|
||||
///
|
||||
/// Serialized parameters
|
||||
///
|
||||
|
||||
|
||||
|
||||
public int IperlCheckErrorsToStop { get; set; }
|
||||
|
||||
|
||||
|
||||
public int DfltQ2c_15_rl { get; set; }
|
||||
public int DfltQ2c_15_lr { get; set; }
|
||||
public int DfltQ2c_20_rl { get; set; }
|
||||
public int DfltQ2c_20_lr { get; set; }
|
||||
public int DfltQ2c_25_63_rl { get; set; }
|
||||
public int DfltQ2c_25_63_lr { get; set; }
|
||||
public int DfltQ2c_25_10_rl { get; set; }
|
||||
public int DfltQ2c_25_10_lr { get; set; }
|
||||
public int DfltQ2c_32_rl { get; set; }
|
||||
public int DfltQ2c_32_lr { get; set; }
|
||||
public int DfltQ2c_40_rl { get; set; }
|
||||
public int DfltQ2c_40_lr { get; set; }
|
||||
|
||||
public bool UseWebService { get; set; }
|
||||
public string BaseUrl { get; set; }
|
||||
public string RelativeUrl { get; set; }
|
||||
|
||||
/// <summary> Test parameters </summary>
|
||||
/// Remember to Ignore in XmlSerializer !!
|
||||
[XmlIgnore]
|
||||
public ITestParams TestParams { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Sensus.iPerl.RfidCom.Structures;
|
||||
using TBF.Rig.RegisterReaders.CommonRR;
|
||||
using TBF.Rig.RegisterReaders.CommonRR.IPerl;
|
||||
|
||||
namespace NfcC7_DLL.NfcHanler.Utils
|
||||
{
|
||||
public class SerialPortData : ISerialPortData
|
||||
{
|
||||
private Boolean? _cliExists;
|
||||
public bool? CliExists
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_cliExists == null || !_cliExists.HasValue)
|
||||
{
|
||||
_cliExists = File.Exists(SerialPortCmdClientPath);
|
||||
}
|
||||
|
||||
return _cliExists.Value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public string SerialPortCmdClientPath {
|
||||
get {
|
||||
#if DEBUG
|
||||
return Path.Combine("C:","TBF","Cli", CmdClientName);
|
||||
#else
|
||||
return Path.Combine("..","Cli", CmdClientName);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
public string CmdClientName { get; set; } = "HalCli.exe";
|
||||
public string PortName { get; set; }
|
||||
public int MeterType { get; set; }
|
||||
|
||||
public class EMeterArg : IArg{
|
||||
public int Value { get; }
|
||||
public string Name { get; }
|
||||
|
||||
private EMeterArg(int value, string name)
|
||||
{
|
||||
Value = value;
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public static readonly EMeterArg Calibration = new EMeterArg(0, "Calibration");
|
||||
public static readonly EMeterArg AllParams = new EMeterArg(2, "AllParams");
|
||||
public static readonly EMeterArg DeviceId = new EMeterArg(3, "DeviceId");
|
||||
public static readonly EMeterArg OptoHead = new EMeterArg(4, "OptoHead");
|
||||
|
||||
}
|
||||
|
||||
public IArg MeterArg { get{return _eMeterArg;} }
|
||||
|
||||
EMeterArg _eMeterArg = EMeterArg.AllParams;
|
||||
|
||||
private static readonly Dictionary<EMeterArg, string> _commandsRead = new Dictionary<EMeterArg, string>
|
||||
{
|
||||
{ EMeterArg.AllParams, "-p {0} -m {1} --operation readall" },
|
||||
{ EMeterArg.DeviceId, "-p {0} -m {1} --operation read --parameter DeviceId" },
|
||||
{ EMeterArg.OptoHead, "-p {0} -m {1} --operation read --parameter \"OpticalDataMode\"" }
|
||||
};
|
||||
|
||||
public string DefaultArgSettingsRead(IArg eMeterArg)
|
||||
{
|
||||
EMeterArg meterArg = eMeterArg as EMeterArg;
|
||||
if (meterArg != null && _commandsRead.TryGetValue(meterArg, out var cmd))
|
||||
return string.Format(cmd, PortName, MeterType);
|
||||
|
||||
throw new Exception("Not implemented correct command!");
|
||||
}
|
||||
|
||||
private static readonly Dictionary<EMeterArg, string> _commandsWrite = new Dictionary<EMeterArg, string>
|
||||
{
|
||||
{ EMeterArg.Calibration, "-p {0} -m {1} --operation write --parameter Calibration --value {2}" },
|
||||
{ EMeterArg.OptoHead, "-p {0} -m {1} --operation write --parameter \"OpticalDataMode\" --value {arg}" },
|
||||
|
||||
};
|
||||
|
||||
public string DefaultArgSettingsWrite(IArg eMeterArg, string arg)
|
||||
{
|
||||
EMeterArg meterArg = eMeterArg as EMeterArg;
|
||||
if (meterArg != null && _commandsRead.TryGetValue(meterArg, out var cmd))
|
||||
return string.Format(cmd, PortName, MeterType);
|
||||
|
||||
throw new Exception("Not implemented correct command!");
|
||||
}
|
||||
|
||||
public SerialPortData(
|
||||
string portName,
|
||||
string cmdClientName,
|
||||
int meterType)
|
||||
{
|
||||
PortName = portName;
|
||||
CmdClientName = cmdClientName;
|
||||
MeterType = meterType;
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -1,10 +1,11 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2020 Sensus Metering Systems
|
||||
///
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.iPerlReaderUNI.comminication
|
||||
namespace TBF.Rig.RegisterReaders.CommonRR.IPerl.communication
|
||||
{
|
||||
public class CalibrationStruct
|
||||
{
|
||||
+2
-1
@@ -1,10 +1,11 @@
|
||||
///
|
||||
/// Copyright (c) 2018-2020 Sensus Slovensko a.s.
|
||||
///
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.iPerlReaderUNI.comminication
|
||||
namespace TBF.Rig.RegisterReaders.CommonRR.IPerl.communication
|
||||
{
|
||||
public class CalibrationStructV4
|
||||
{
|
||||
@@ -0,0 +1,43 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2019 Sensus Metering Systems
|
||||
/// Author: Milan Hanajík
|
||||
///
|
||||
|
||||
using System;
|
||||
using TBF.Rig.RegisterReaders.iPerlReaderUNI;
|
||||
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication;
|
||||
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.common;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.CommonRR.IPerl.communication
|
||||
{
|
||||
public class CommCompletedEventArgs : EventArgs
|
||||
{
|
||||
public int ThreadId;
|
||||
public int WMNr0; /// 0-based water meter position
|
||||
public ISmartReader Ihead;
|
||||
public Results.Entities.WaterMeter Wm;
|
||||
public string CommMessage;
|
||||
public CommErr CommErr;
|
||||
|
||||
public CommCompletedEventArgs(int threadId, int wmNr0, ISmartReader ihead, Results.Entities.WaterMeter wm, string commMessage, CommErr commErr)
|
||||
{
|
||||
this.ThreadId = threadId;
|
||||
this.WMNr0 = wmNr0;
|
||||
this.Ihead = ihead;
|
||||
this.Wm = wm;
|
||||
this.CommMessage = commMessage;
|
||||
this.CommErr = commErr;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("Thread={0} WMNr0={1} IHead={2} WM={3} CommMsg={4} CommErr={5}",
|
||||
ThreadId,
|
||||
WMNr0,
|
||||
(Ihead != null) ? Ihead.Name : "null",
|
||||
Wm.WMPosition,
|
||||
(CommMessage != null) ? CommMessage : "null",
|
||||
CommErr);
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -1,10 +1,11 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2020 Sensus Metering Systems
|
||||
///
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.iPerlReaderUNI.comminication
|
||||
namespace TBF.Rig.RegisterReaders.CommonRR.IPerl.communication
|
||||
{
|
||||
public class ConfigStruct
|
||||
{
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace TBF.Rig.RegisterReaders.CommonRR.IPerl.communication
|
||||
{
|
||||
public class IPerlCommunicationsTimeOut : ICommunicationTimeOuts
|
||||
{
|
||||
public int DelayBetweenRetries { get; set; }
|
||||
public int MaxCommRetries { get; set; }
|
||||
public int WaitTimeAfterFailure { get; set; }
|
||||
public int PassThroughWaitTime { get; set; }
|
||||
public int NrThreads { get; set; }
|
||||
public int CommTimeout { get; set; }
|
||||
}
|
||||
}
|
||||
+10
-9
@@ -1,19 +1,20 @@
|
||||
using log4net;
|
||||
using Sensus.iPerl.NfcHandler;
|
||||
using Sensus.iPerl.RfidCom.Exceptions;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using log4net;
|
||||
using Sensus.iPerl.NfcHandler;
|
||||
using Sensus.iPerl.RfidCom.Exceptions;
|
||||
using TBF.Rig.RegisterReaders.iPerlReaderUNI;
|
||||
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.common;
|
||||
using static Sensus.iPerl.NfcHandler.MCI_Protocol;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.iPerlReaderUNI.comminication
|
||||
namespace TBF.Rig.RegisterReaders.CommonRR.IPerl.communication
|
||||
{
|
||||
internal class NfcServices
|
||||
{
|
||||
protected static readonly ILog rfidDataLogger = LogManager.GetLogger("RfidData");
|
||||
internal static int ReadRequest(TestMethodCfg cfg, IPerlReader iperlHead, MCI_Protocol.StructName structName, int offset, int length, out byte[] buffer)
|
||||
internal static int ReadRequest(ITestMethodCfg cfg, ISmartReader iperlHead, MCI_Protocol.StructName structName, int offset, int length, out byte[] buffer)
|
||||
{
|
||||
for (int i = 0; i < cfg.MaxCommRetries; i++)
|
||||
{
|
||||
@@ -58,7 +59,7 @@ namespace TBF.Rig.RegisterReaders.iPerlReaderUNI.comminication
|
||||
return 3;
|
||||
}
|
||||
|
||||
internal static int WriteRequest(TestMethodCfg cfg, IPerlReader iperlHead, MCI_Protocol.StructName structName, int offset, int length, byte[] buffer)
|
||||
internal static int WriteRequest(ITestMethodCfg cfg, ISmartReader iperlHead, MCI_Protocol.StructName structName, int offset, int length, byte[] buffer)
|
||||
{
|
||||
NfcDataHandler _nfcDataHandler = new NfcDataHandler();
|
||||
MessageEventHandlers(_nfcDataHandler);
|
||||
@@ -84,7 +85,7 @@ namespace TBF.Rig.RegisterReaders.iPerlReaderUNI.comminication
|
||||
}
|
||||
}
|
||||
|
||||
private static void OpenConnection(NfcDataHandler nfcDataHandler, TestMethodCfg cfg, IPerlReader iperlHead)
|
||||
private static void OpenConnection(NfcDataHandler nfcDataHandler, ITestMethodCfg cfg, ISmartReader iperlHead)
|
||||
{
|
||||
string comPort = $"COM{iperlHead.RfidComPortNr}";
|
||||
int retryCount = 0 ;
|
||||
@@ -128,7 +129,7 @@ namespace TBF.Rig.RegisterReaders.iPerlReaderUNI.comminication
|
||||
nfcDataHandler.Close();
|
||||
}
|
||||
|
||||
private static byte[] MciRead(NfcDataHandler nfcDataHandler, TestMethodCfg cfg, StructName structName, ushort offset, int length)
|
||||
private static byte[] MciRead(NfcDataHandler nfcDataHandler, ITestMethodCfg cfg, StructName structName, ushort offset, int length)
|
||||
{
|
||||
bool isReadValues = false;
|
||||
int retryCount = 0;
|
||||
@@ -175,7 +176,7 @@ namespace TBF.Rig.RegisterReaders.iPerlReaderUNI.comminication
|
||||
return new byte[length];
|
||||
}
|
||||
|
||||
private static void MciWrite(NfcDataHandler nfcDataHandler, TestMethodCfg cfg, MCI_Protocol.StructName structName, ushort offset, int length, byte[] payload)
|
||||
private static void MciWrite(NfcDataHandler nfcDataHandler, ITestMethodCfg cfg, MCI_Protocol.StructName structName, ushort offset, int length, byte[] payload)
|
||||
{
|
||||
int retryCount = 0;
|
||||
Write:
|
||||
+3
-5
@@ -1,12 +1,10 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2017 Sensus Metering Systems
|
||||
///
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.iPerlReaderUNI.comminication
|
||||
using System;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.CommonRR.IPerl.communication
|
||||
{
|
||||
public class OptoReceivedEventArgs : EventArgs
|
||||
{
|
||||
+10
-10
@@ -1,22 +1,22 @@
|
||||
using Sensus.iPerl.RfidCom.Exceptions;
|
||||
using Sensus.iPerl.RfidCom.Helper;
|
||||
using Sensus.iPerl.RfidCom;
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using log4net;
|
||||
using TBF.Rig.Uni.SharedDialogs.iPerlCommunication;
|
||||
using static TBF.Rig.Uni.SharedDialogs.iPerlCommunication.iPerlCommunicationForm;
|
||||
using Sensus.iPerl.RfidCom;
|
||||
using Sensus.iPerl.RfidCom.Exceptions;
|
||||
using Sensus.iPerl.RfidCom.Helper;
|
||||
using TBF.Rig.RegisterReaders.iPerlReaderUNI;
|
||||
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication;
|
||||
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.common;
|
||||
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.iPerlReaderUNI.comminication
|
||||
namespace TBF.Rig.RegisterReaders.CommonRR.IPerl.communication
|
||||
{
|
||||
internal class RfidServices
|
||||
{
|
||||
protected static readonly ILog rfidDataLogger = LogManager.GetLogger("RfidData");
|
||||
private static readonly ILog log = LogManager.GetLogger(typeof(iPerlCommunicationForm));
|
||||
private static readonly ILog log = LogManager.GetLogger(typeof(SmartCommunicationForm));
|
||||
|
||||
internal static int ReadRequest(TestMethodCfg cfg, IPerlReader iperlHead, MessageID messageID, int offset, int length, out byte[] buffer)
|
||||
internal static int ReadRequest(ITestMethodCfg cfg, ISmartReader iperlHead, MessageID messageID, int offset, int length, out byte[] buffer)
|
||||
{
|
||||
for (int i = 0; i < cfg.MaxCommRetries; i++)
|
||||
{
|
||||
@@ -83,7 +83,7 @@ namespace TBF.Rig.RegisterReaders.iPerlReaderUNI.comminication
|
||||
return 3;
|
||||
}
|
||||
|
||||
internal static int WriteRequest(TestMethodCfg cfg, IPerlReader iperlHead, MessageID messageID, int offset, int length, byte[] buffer)
|
||||
internal static int WriteRequest(ITestMethodCfg cfg, ISmartReader iperlHead, MessageID messageID, int offset, int length, byte[] buffer)
|
||||
{
|
||||
RfidLogic writer = new RfidLogic($"COM{iperlHead.RfidComPortNr}");
|
||||
string payload = RfidHelper.ConvertByteArrayToHexString(buffer);
|
||||
+8
-5
@@ -1,13 +1,16 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using TBF.Rig.RegisterReaders.iPerlReaderUNI;
|
||||
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication;
|
||||
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.common;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.iPerlReaderUNI.comminication
|
||||
namespace TBF.Rig.RegisterReaders.CommonRR.IPerl.communication
|
||||
{
|
||||
internal class SimulationServices
|
||||
{
|
||||
const int Q2CorrFactorsAddr = Uni.SharedDialogs.iPerlCommunication.iPerlCommunicationConstants.Q2CorrFactorsAddr;
|
||||
const int Q2CorrFactorsAddr = iPerlCommunicationConstants.Q2CorrFactorsAddr;
|
||||
|
||||
internal static int ReadRequest(IPerlReader iperlHead, MessageID messageID, int offset, int length, out byte[] buffer)
|
||||
internal static int ReadRequest(ISmartReader iperlHead, MessageID messageID, int offset, int length, out byte[] buffer)
|
||||
{
|
||||
byte[] configurationBuffer = new byte[ConfigStruct.Length] { 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
byte[] calibrationBuffer = new byte[CalibrationStructV4.Length] { 3, 0, 150, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 0, 0, 150, 10 };
|
||||
@@ -34,13 +37,13 @@ namespace TBF.Rig.RegisterReaders.iPerlReaderUNI.comminication
|
||||
return iperlHead.Name.Equals("iPerl13") ? 2 : 0; /// Simulates an error on position 13
|
||||
}
|
||||
|
||||
internal static int WriteRequest(TestMethodCfg cfg, IPerlReader iperlHead, MessageID messageID, int offset,
|
||||
internal static int WriteRequest(ITestMethodCfg cfg, ISmartReader iperlHead, MessageID messageID, int offset,
|
||||
int length, byte[] buffer)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static Array GetPCB(IPerlReader iperlHead)
|
||||
private static Array GetPCB(ISmartReader iperlHead)
|
||||
{
|
||||
string pcbStr = iperlHead.RfidComPortNr.ToString().PadRight(10,'0') + iperlHead.Position.ToString("D2");
|
||||
long decVal = Convert.ToInt64(pcbStr);
|
||||
@@ -0,0 +1,24 @@
|
||||
using System.Collections.Generic;
|
||||
using TBF.Rig.Generic;
|
||||
using TBF.Rig.RegisterReaders.IPerlReader.implementations;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.IPerlReader
|
||||
{
|
||||
public class Factory: IComponentFactory
|
||||
{
|
||||
public string ClassName { get { return this.GetType().Namespace.Substring(8); } }
|
||||
|
||||
public override string ToString() { return ClassName; }
|
||||
|
||||
public IComponent DummyComponent() { return new SmartReader(); }
|
||||
|
||||
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components) { return new SmartReader(cfg); }
|
||||
|
||||
public IComponentCfg DefaultConfig() { return new iPerlReaderUNI.IPerlCfg(this); }
|
||||
|
||||
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
|
||||
{
|
||||
return ComponentCfgBase.CreateFromDbEntity(iPerlReaderUNI.IPerlCfg.Serializer, component, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Serialization;
|
||||
using Common;
|
||||
using Config.Entities;
|
||||
using TBF.Rig.Generic;
|
||||
using TBF.Rig.RegisterReaders.CommonRR;
|
||||
using TBF.Rig.RegisterReaders.iPerlReaderUNI;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.IPerlReader
|
||||
{
|
||||
public class IPerlCfg : ComponentCfgBase, Generic.IComponentCfg
|
||||
{
|
||||
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(IPerlCfg) })[0];
|
||||
public override XmlSerializer GetSerializer() { return Serializer; }
|
||||
public IComponentCfgCtrl GetControl(IList<Component> cmpntEntities)
|
||||
{
|
||||
return new IPerlUniCfgCtrl();
|
||||
}
|
||||
|
||||
|
||||
|
||||
///
|
||||
/// Serialized parameters
|
||||
///
|
||||
public bool UseTcpIP;
|
||||
public string OptoIPAddress;
|
||||
public ushort OptoTcpipPortNr;
|
||||
public int HeadCommunicationComPortNr;
|
||||
public int OptoComPortNr;
|
||||
public int RfidComPortNr; /// 0 = use MuxBoardNr
|
||||
public int MuxBoardNr; /// 0 = use RfidComPort(Nr), otherwise mux. board nr. 1 .. 4
|
||||
public int Group; /// Number written to QuidoRS to connct the watermeter to RfidComPort, 1 .. 10
|
||||
public CommunicationInterface CommunicationInterface; /// Communication Interface: RFID or NFC
|
||||
|
||||
/// <summary> Procedure parameters </summary>
|
||||
[XmlIgnore]
|
||||
public ProcParams ProcParams;
|
||||
public override IParamsProvider GetRuntimeProcParamsProvider() { return ProcParams; }
|
||||
public override IParamsProvider CreateProcParamsProvider() { return new ProcParams(true); }
|
||||
|
||||
[XmlIgnore]
|
||||
public MeterType MeterType { get { return (ProcParams != null) ? ProcParams.MeterType : MeterType.AutoDetect; } }
|
||||
|
||||
|
||||
|
||||
/// Private parameterless constructor invoked by all other (public) constructors
|
||||
IPerlCfg()
|
||||
{
|
||||
Name = "iPerl";
|
||||
ParentName = string.Empty;
|
||||
OptoComPortNr = 10;
|
||||
RfidComPortNr = 0; /// = use mux. board
|
||||
MuxBoardNr = 1;
|
||||
ProcParams = CreateProcParamsProvider() as ProcParams;
|
||||
CommunicationInterface = CommunicationInterface.RFID;
|
||||
HeadCommunicationComPortNr = 0;
|
||||
}
|
||||
|
||||
public IPerlCfg(IComponentFactory factory)
|
||||
: this()
|
||||
{
|
||||
this.Factory = factory;
|
||||
}
|
||||
|
||||
public string ToString(int i)
|
||||
{
|
||||
return $"{Name} Group1 (mux#)={MuxBoardNr}, Group2={Group}, Opto=Com{OptoComPortNr}, {CommunicationInterface}=Com{RfidComPortNr}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2017 Sensus Metering Systems
|
||||
///
|
||||
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Windows.Forms;
|
||||
using Common;
|
||||
using TBF.Resources;
|
||||
using TBF.Rig.Generic;
|
||||
using TBF.Rig.RegisterReaders.CommonRR;
|
||||
using TBF.Rig.RegisterReaders.iPerlReaderUNI;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.IPerlReader
|
||||
{
|
||||
public partial class IPerlUniCfgCtrl : UserControl, IComponentCfgCtrl
|
||||
{
|
||||
public bool ShowMore { get { return false; } }
|
||||
|
||||
iPerlReaderUNI.IPerlCfg config;
|
||||
public IComponentCfg Config
|
||||
{
|
||||
get { return config as IComponentCfg; }
|
||||
set
|
||||
{
|
||||
config = value as iPerlReaderUNI.IPerlCfg;
|
||||
Redraw();
|
||||
}
|
||||
}
|
||||
|
||||
public IPerlUniCfgCtrl()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void WaterMeterCfgCtrl_Load(object sender, EventArgs e)
|
||||
{
|
||||
nameLabel.Text = Strings.Name;
|
||||
classNameLabel.Text = config.Factory.ClassName;
|
||||
Redraw();
|
||||
}
|
||||
|
||||
public void Closing()
|
||||
{
|
||||
}
|
||||
|
||||
void Redraw()
|
||||
{
|
||||
if (config == null) return; /// Control was not loaded, settings were not changed
|
||||
nameTextBox.Text = config.Name;
|
||||
radioButton1.Checked = config.UseTcpIP;
|
||||
radioButton2.Checked = !config.UseTcpIP;
|
||||
ipAddressTextBox.Text = (config.OptoIPAddress != null) ? config.OptoIPAddress : "0.0.0.0";
|
||||
tcpipPortTextBox.Text = config.OptoTcpipPortNr.ToString();
|
||||
headPortNrTextBox.Text = config.HeadCommunicationComPortNr.ToString();
|
||||
optoSerialPortTextBox.Text = config.OptoComPortNr.ToString();
|
||||
rfidPortNrTextBox.Text = config.RfidComPortNr.ToString();
|
||||
muxBoardNrTextBox.Text = config.MuxBoardNr.ToString();
|
||||
groupTextBox.Text = config.Group.ToString();
|
||||
comboBoxCommunicationInterface.SelectedItem = config.CommunicationInterface.ToString();
|
||||
tabPage2.Controls.Add(new IperlUniHeadTestCtrl(config));
|
||||
}
|
||||
|
||||
public void Unlock()
|
||||
{
|
||||
nameTextBox.Enabled = true;
|
||||
radioButton1.Enabled = true;
|
||||
radioButton2.Enabled = true;
|
||||
ipAddressTextBox.Enabled = true;
|
||||
tcpipPortTextBox.Enabled = true;
|
||||
optoSerialPortTextBox.Enabled = true;
|
||||
rfidPortNrTextBox.Enabled = true;
|
||||
headPortNrTextBox.Enabled = true;
|
||||
muxBoardNrTextBox.Enabled = true;
|
||||
groupTextBox.Enabled = true;
|
||||
comboBoxCommunicationInterface.Enabled = true;
|
||||
}
|
||||
|
||||
public CfgUpdateFlags VerifyCfg(ref string message)
|
||||
{
|
||||
CfgUpdateFlags flags = CfgUpdateFlags.None;
|
||||
|
||||
int dummy;
|
||||
if (radioButton1.Checked)
|
||||
{
|
||||
IPAddress dummyIPAddress;
|
||||
if (!IPAddress.TryParse(ipAddressTextBox.Text, out dummyIPAddress))
|
||||
{
|
||||
flags |= CfgUpdateFlags.Error;
|
||||
message += Environment.NewLine + "'IP address' is not valid";
|
||||
}
|
||||
|
||||
ushort sdummy;
|
||||
if (!ushort.TryParse(tcpipPortTextBox.Text, out sdummy))
|
||||
{
|
||||
flags |= CfgUpdateFlags.Error;
|
||||
message += Environment.NewLine + "'TCP/IP port nr.' is not valid";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!int.TryParse(optoSerialPortTextBox.Text, out dummy) || dummy < 1 || dummy > 999)
|
||||
{
|
||||
flags |= CfgUpdateFlags.Error;
|
||||
message += Environment.NewLine + "'Opto serial port nr.' is not valid";
|
||||
}
|
||||
}
|
||||
|
||||
if (!int.TryParse(rfidPortNrTextBox.Text, out dummy) || dummy < 0 || dummy > 999)
|
||||
{
|
||||
flags |= CfgUpdateFlags.Error;
|
||||
message += Environment.NewLine + "'RFID serial port nr.' is not valid";
|
||||
}
|
||||
|
||||
if (!int.TryParse(headPortNrTextBox.Text, out dummy) || dummy < 0 || dummy > 999)
|
||||
{
|
||||
flags |= CfgUpdateFlags.Error;
|
||||
message += Environment.NewLine + "'Head communication serial port nr.' is not valid";
|
||||
}
|
||||
|
||||
if (!int.TryParse(muxBoardNrTextBox.Text, out dummy) || dummy < 1 || dummy > 4)
|
||||
{
|
||||
flags |= CfgUpdateFlags.Error;
|
||||
message += Environment.NewLine + string.Format(Strings.Invalid_0, muxBoardNrLabel.Text);
|
||||
}
|
||||
|
||||
if (!int.TryParse(groupTextBox.Text, out dummy) || dummy < 1 || dummy > 10)
|
||||
{
|
||||
flags |= CfgUpdateFlags.Error;
|
||||
message += Environment.NewLine + string.Format(Strings.Invalid_0, groupLabel.Text);
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
public CfgUpdateFlags UpdateCfg()
|
||||
{
|
||||
CfgUpdateFlags flags = CfgUpdateFlags.RestartRqrd;
|
||||
|
||||
if (config == null) return CfgUpdateFlags.Error; /// Control was not loaded, settings were not changed
|
||||
|
||||
config.Name = nameTextBox.Text;
|
||||
|
||||
if (radioButton1.Checked)
|
||||
{
|
||||
config.UseTcpIP = true;
|
||||
config.OptoIPAddress = ipAddressTextBox.Text;
|
||||
config.OptoTcpipPortNr = ushort.Parse(tcpipPortTextBox.Text);
|
||||
}
|
||||
else
|
||||
{
|
||||
config.UseTcpIP = false;
|
||||
config.OptoComPortNr = int.Parse(optoSerialPortTextBox.Text);
|
||||
}
|
||||
|
||||
config.RfidComPortNr = int.Parse(rfidPortNrTextBox.Text);
|
||||
config.MuxBoardNr = int.Parse(muxBoardNrTextBox.Text);
|
||||
config.Group = int.Parse(groupTextBox.Text);
|
||||
config.CommunicationInterface = (CommunicationInterface)comboBoxCommunicationInterface.SelectedIndex;
|
||||
config.HeadCommunicationComPortNr = int.Parse(headPortNrTextBox.Text);
|
||||
|
||||
return flags;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,441 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2017 Sensus Metering Systems
|
||||
///
|
||||
namespace TBF.Rig.RegisterReaders.IPerlReader
|
||||
{
|
||||
partial class IPerlUniCfgCtrl
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.tabControl1 = new System.Windows.Forms.TabControl();
|
||||
this.tabPage1 = new System.Windows.Forms.TabPage();
|
||||
this.label4 = new System.Windows.Forms.Label();
|
||||
this.label3 = new System.Windows.Forms.Label();
|
||||
this.groupBox1 = new System.Windows.Forms.GroupBox();
|
||||
this.comboBoxCommunicationInterface = new System.Windows.Forms.ComboBox();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.rfidPortNrTextBox = new System.Windows.Forms.TextBox();
|
||||
this.rfidSerialPortNrLabel = new System.Windows.Forms.Label();
|
||||
this.optoDataGroupBox = new System.Windows.Forms.GroupBox();
|
||||
this.tcpipPortLabel = new System.Windows.Forms.Label();
|
||||
this.tcpipPortTextBox = new System.Windows.Forms.TextBox();
|
||||
this.ipAddressLabel = new System.Windows.Forms.Label();
|
||||
this.ipAddressTextBox = new System.Windows.Forms.TextBox();
|
||||
this.radioButton1 = new System.Windows.Forms.RadioButton();
|
||||
this.radioButton2 = new System.Windows.Forms.RadioButton();
|
||||
this.optoSerialPortLabel = new System.Windows.Forms.Label();
|
||||
this.optoSerialPortTextBox = new System.Windows.Forms.TextBox();
|
||||
this.groupTextBox = new System.Windows.Forms.TextBox();
|
||||
this.groupLabel = new System.Windows.Forms.Label();
|
||||
this.muxBoardNrTextBox = new System.Windows.Forms.TextBox();
|
||||
this.muxBoardNrLabel = new System.Windows.Forms.Label();
|
||||
this.nameTextBox = new System.Windows.Forms.TextBox();
|
||||
this.nameLabel = new System.Windows.Forms.Label();
|
||||
this.classNameLabel = new System.Windows.Forms.Label();
|
||||
this.tabPage2 = new System.Windows.Forms.TabPage();
|
||||
this.groupBox2 = new System.Windows.Forms.GroupBox();
|
||||
this.label2 = new System.Windows.Forms.Label();
|
||||
this.headPortNrTextBox = new System.Windows.Forms.TextBox();
|
||||
this.tabControl1.SuspendLayout();
|
||||
this.tabPage1.SuspendLayout();
|
||||
this.groupBox1.SuspendLayout();
|
||||
this.optoDataGroupBox.SuspendLayout();
|
||||
this.groupBox2.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// tabControl1
|
||||
//
|
||||
this.tabControl1.Controls.Add(this.tabPage1);
|
||||
this.tabControl1.Controls.Add(this.tabPage2);
|
||||
this.tabControl1.Location = new System.Drawing.Point(3, 3);
|
||||
this.tabControl1.Name = "tabControl1";
|
||||
this.tabControl1.SelectedIndex = 0;
|
||||
this.tabControl1.Size = new System.Drawing.Size(611, 432);
|
||||
this.tabControl1.TabIndex = 0;
|
||||
//
|
||||
// tabPage1
|
||||
//
|
||||
this.tabPage1.Controls.Add(this.groupBox2);
|
||||
this.tabPage1.Controls.Add(this.label4);
|
||||
this.tabPage1.Controls.Add(this.label3);
|
||||
this.tabPage1.Controls.Add(this.groupBox1);
|
||||
this.tabPage1.Controls.Add(this.optoDataGroupBox);
|
||||
this.tabPage1.Controls.Add(this.groupTextBox);
|
||||
this.tabPage1.Controls.Add(this.groupLabel);
|
||||
this.tabPage1.Controls.Add(this.muxBoardNrTextBox);
|
||||
this.tabPage1.Controls.Add(this.muxBoardNrLabel);
|
||||
this.tabPage1.Controls.Add(this.nameTextBox);
|
||||
this.tabPage1.Controls.Add(this.nameLabel);
|
||||
this.tabPage1.Controls.Add(this.classNameLabel);
|
||||
this.tabPage1.Location = new System.Drawing.Point(4, 25);
|
||||
this.tabPage1.Name = "tabPage1";
|
||||
this.tabPage1.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.tabPage1.Size = new System.Drawing.Size(603, 403);
|
||||
this.tabPage1.TabIndex = 0;
|
||||
this.tabPage1.Text = "Config";
|
||||
this.tabPage1.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// label4
|
||||
//
|
||||
this.label4.AutoSize = true;
|
||||
this.label4.Location = new System.Drawing.Point(208, 101);
|
||||
this.label4.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.label4.Name = "label4";
|
||||
this.label4.Size = new System.Drawing.Size(40, 16);
|
||||
this.label4.TabIndex = 25;
|
||||
this.label4.Text = "1 .. 10";
|
||||
//
|
||||
// label3
|
||||
//
|
||||
this.label3.AutoSize = true;
|
||||
this.label3.Location = new System.Drawing.Point(208, 72);
|
||||
this.label3.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.label3.Name = "label3";
|
||||
this.label3.Size = new System.Drawing.Size(33, 16);
|
||||
this.label3.TabIndex = 24;
|
||||
this.label3.Text = "1 .. 4";
|
||||
//
|
||||
// groupBox1
|
||||
//
|
||||
this.groupBox1.Controls.Add(this.comboBoxCommunicationInterface);
|
||||
this.groupBox1.Controls.Add(this.label1);
|
||||
this.groupBox1.Controls.Add(this.rfidPortNrTextBox);
|
||||
this.groupBox1.Controls.Add(this.rfidSerialPortNrLabel);
|
||||
this.groupBox1.Location = new System.Drawing.Point(10, 259);
|
||||
this.groupBox1.Margin = new System.Windows.Forms.Padding(4);
|
||||
this.groupBox1.Name = "groupBox1";
|
||||
this.groupBox1.Padding = new System.Windows.Forms.Padding(4);
|
||||
this.groupBox1.Size = new System.Drawing.Size(552, 68);
|
||||
this.groupBox1.TabIndex = 23;
|
||||
this.groupBox1.TabStop = false;
|
||||
this.groupBox1.Text = "RFID / NFC communication (in case mux. board is not used)";
|
||||
//
|
||||
// comboBoxCommunicationInterface
|
||||
//
|
||||
this.comboBoxCommunicationInterface.Enabled = false;
|
||||
this.comboBoxCommunicationInterface.FormattingEnabled = true;
|
||||
this.comboBoxCommunicationInterface.Items.AddRange(new object[] {
|
||||
"RFID",
|
||||
"NFC"});
|
||||
this.comboBoxCommunicationInterface.Location = new System.Drawing.Point(201, 27);
|
||||
this.comboBoxCommunicationInterface.Name = "comboBoxCommunicationInterface";
|
||||
this.comboBoxCommunicationInterface.Size = new System.Drawing.Size(71, 24);
|
||||
this.comboBoxCommunicationInterface.TabIndex = 9;
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Location = new System.Drawing.Point(41, 30);
|
||||
this.label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(153, 16);
|
||||
this.label1.TabIndex = 8;
|
||||
this.label1.Text = "Communication Interface";
|
||||
//
|
||||
// rfidPortNrTextBox
|
||||
//
|
||||
this.rfidPortNrTextBox.Enabled = false;
|
||||
this.rfidPortNrTextBox.Location = new System.Drawing.Point(439, 26);
|
||||
this.rfidPortNrTextBox.Margin = new System.Windows.Forms.Padding(4);
|
||||
this.rfidPortNrTextBox.Name = "rfidPortNrTextBox";
|
||||
this.rfidPortNrTextBox.Size = new System.Drawing.Size(44, 22);
|
||||
this.rfidPortNrTextBox.TabIndex = 7;
|
||||
//
|
||||
// rfidSerialPortNrLabel
|
||||
//
|
||||
this.rfidSerialPortNrLabel.AutoSize = true;
|
||||
this.rfidSerialPortNrLabel.Location = new System.Drawing.Point(321, 30);
|
||||
this.rfidSerialPortNrLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.rfidSerialPortNrLabel.Name = "rfidSerialPortNrLabel";
|
||||
this.rfidSerialPortNrLabel.Size = new System.Drawing.Size(88, 16);
|
||||
this.rfidSerialPortNrLabel.TabIndex = 6;
|
||||
this.rfidSerialPortNrLabel.Text = "Serial port nr.:";
|
||||
//
|
||||
// optoDataGroupBox
|
||||
//
|
||||
this.optoDataGroupBox.Controls.Add(this.tcpipPortLabel);
|
||||
this.optoDataGroupBox.Controls.Add(this.tcpipPortTextBox);
|
||||
this.optoDataGroupBox.Controls.Add(this.ipAddressLabel);
|
||||
this.optoDataGroupBox.Controls.Add(this.ipAddressTextBox);
|
||||
this.optoDataGroupBox.Controls.Add(this.radioButton1);
|
||||
this.optoDataGroupBox.Controls.Add(this.radioButton2);
|
||||
this.optoDataGroupBox.Controls.Add(this.optoSerialPortLabel);
|
||||
this.optoDataGroupBox.Controls.Add(this.optoSerialPortTextBox);
|
||||
this.optoDataGroupBox.Location = new System.Drawing.Point(10, 131);
|
||||
this.optoDataGroupBox.Margin = new System.Windows.Forms.Padding(4);
|
||||
this.optoDataGroupBox.Name = "optoDataGroupBox";
|
||||
this.optoDataGroupBox.Padding = new System.Windows.Forms.Padding(4);
|
||||
this.optoDataGroupBox.Size = new System.Drawing.Size(552, 119);
|
||||
this.optoDataGroupBox.TabIndex = 18;
|
||||
this.optoDataGroupBox.TabStop = false;
|
||||
this.optoDataGroupBox.Text = "Opto-data";
|
||||
//
|
||||
// tcpipPortLabel
|
||||
//
|
||||
this.tcpipPortLabel.AutoSize = true;
|
||||
this.tcpipPortLabel.Location = new System.Drawing.Point(41, 87);
|
||||
this.tcpipPortLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.tcpipPortLabel.Name = "tcpipPortLabel";
|
||||
this.tcpipPortLabel.Size = new System.Drawing.Size(54, 16);
|
||||
this.tcpipPortLabel.TabIndex = 4;
|
||||
this.tcpipPortLabel.Text = "Port nr..:";
|
||||
//
|
||||
// tcpipPortTextBox
|
||||
//
|
||||
this.tcpipPortTextBox.Enabled = false;
|
||||
this.tcpipPortTextBox.Location = new System.Drawing.Point(143, 84);
|
||||
this.tcpipPortTextBox.Margin = new System.Windows.Forms.Padding(4);
|
||||
this.tcpipPortTextBox.Name = "tcpipPortTextBox";
|
||||
this.tcpipPortTextBox.Size = new System.Drawing.Size(51, 22);
|
||||
this.tcpipPortTextBox.TabIndex = 5;
|
||||
//
|
||||
// ipAddressLabel
|
||||
//
|
||||
this.ipAddressLabel.AutoSize = true;
|
||||
this.ipAddressLabel.Location = new System.Drawing.Point(41, 59);
|
||||
this.ipAddressLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.ipAddressLabel.Name = "ipAddressLabel";
|
||||
this.ipAddressLabel.Size = new System.Drawing.Size(78, 16);
|
||||
this.ipAddressLabel.TabIndex = 2;
|
||||
this.ipAddressLabel.Text = "IP address.:";
|
||||
//
|
||||
// ipAddressTextBox
|
||||
//
|
||||
this.ipAddressTextBox.Enabled = false;
|
||||
this.ipAddressTextBox.Location = new System.Drawing.Point(143, 55);
|
||||
this.ipAddressTextBox.Margin = new System.Windows.Forms.Padding(4);
|
||||
this.ipAddressTextBox.Name = "ipAddressTextBox";
|
||||
this.ipAddressTextBox.Size = new System.Drawing.Size(129, 22);
|
||||
this.ipAddressTextBox.TabIndex = 3;
|
||||
//
|
||||
// radioButton1
|
||||
//
|
||||
this.radioButton1.AutoSize = true;
|
||||
this.radioButton1.Checked = true;
|
||||
this.radioButton1.Enabled = false;
|
||||
this.radioButton1.Location = new System.Drawing.Point(29, 23);
|
||||
this.radioButton1.Margin = new System.Windows.Forms.Padding(4);
|
||||
this.radioButton1.Name = "radioButton1";
|
||||
this.radioButton1.Size = new System.Drawing.Size(99, 20);
|
||||
this.radioButton1.TabIndex = 0;
|
||||
this.radioButton1.TabStop = true;
|
||||
this.radioButton1.Text = "Use TCP/IP";
|
||||
this.radioButton1.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// radioButton2
|
||||
//
|
||||
this.radioButton2.AutoSize = true;
|
||||
this.radioButton2.Enabled = false;
|
||||
this.radioButton2.Location = new System.Drawing.Point(312, 23);
|
||||
this.radioButton2.Margin = new System.Windows.Forms.Padding(4);
|
||||
this.radioButton2.Name = "radioButton2";
|
||||
this.radioButton2.Size = new System.Drawing.Size(115, 20);
|
||||
this.radioButton2.TabIndex = 1;
|
||||
this.radioButton2.Text = "Use serial port";
|
||||
this.radioButton2.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// optoSerialPortLabel
|
||||
//
|
||||
this.optoSerialPortLabel.AutoSize = true;
|
||||
this.optoSerialPortLabel.Location = new System.Drawing.Point(321, 55);
|
||||
this.optoSerialPortLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.optoSerialPortLabel.Name = "optoSerialPortLabel";
|
||||
this.optoSerialPortLabel.Size = new System.Drawing.Size(88, 16);
|
||||
this.optoSerialPortLabel.TabIndex = 6;
|
||||
this.optoSerialPortLabel.Text = "Serial port nr.:";
|
||||
//
|
||||
// optoSerialPortTextBox
|
||||
//
|
||||
this.optoSerialPortTextBox.Enabled = false;
|
||||
this.optoSerialPortTextBox.Location = new System.Drawing.Point(439, 52);
|
||||
this.optoSerialPortTextBox.Margin = new System.Windows.Forms.Padding(4);
|
||||
this.optoSerialPortTextBox.Name = "optoSerialPortTextBox";
|
||||
this.optoSerialPortTextBox.Size = new System.Drawing.Size(44, 22);
|
||||
this.optoSerialPortTextBox.TabIndex = 7;
|
||||
//
|
||||
// groupTextBox
|
||||
//
|
||||
this.groupTextBox.Enabled = false;
|
||||
this.groupTextBox.Location = new System.Drawing.Point(153, 97);
|
||||
this.groupTextBox.Margin = new System.Windows.Forms.Padding(4);
|
||||
this.groupTextBox.Name = "groupTextBox";
|
||||
this.groupTextBox.Size = new System.Drawing.Size(44, 22);
|
||||
this.groupTextBox.TabIndex = 22;
|
||||
//
|
||||
// groupLabel
|
||||
//
|
||||
this.groupLabel.AutoSize = true;
|
||||
this.groupLabel.Location = new System.Drawing.Point(6, 101);
|
||||
this.groupLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.groupLabel.Name = "groupLabel";
|
||||
this.groupLabel.Size = new System.Drawing.Size(54, 16);
|
||||
this.groupLabel.TabIndex = 21;
|
||||
this.groupLabel.Text = "Group 2";
|
||||
//
|
||||
// muxBoardNrTextBox
|
||||
//
|
||||
this.muxBoardNrTextBox.Enabled = false;
|
||||
this.muxBoardNrTextBox.Location = new System.Drawing.Point(153, 69);
|
||||
this.muxBoardNrTextBox.Margin = new System.Windows.Forms.Padding(4);
|
||||
this.muxBoardNrTextBox.Name = "muxBoardNrTextBox";
|
||||
this.muxBoardNrTextBox.Size = new System.Drawing.Size(44, 22);
|
||||
this.muxBoardNrTextBox.TabIndex = 20;
|
||||
//
|
||||
// muxBoardNrLabel
|
||||
//
|
||||
this.muxBoardNrLabel.AutoSize = true;
|
||||
this.muxBoardNrLabel.Location = new System.Drawing.Point(6, 72);
|
||||
this.muxBoardNrLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.muxBoardNrLabel.Name = "muxBoardNrLabel";
|
||||
this.muxBoardNrLabel.Size = new System.Drawing.Size(131, 16);
|
||||
this.muxBoardNrLabel.TabIndex = 19;
|
||||
this.muxBoardNrLabel.Text = "Group 1 (mux. board)";
|
||||
//
|
||||
// nameTextBox
|
||||
//
|
||||
this.nameTextBox.Enabled = false;
|
||||
this.nameTextBox.Location = new System.Drawing.Point(153, 40);
|
||||
this.nameTextBox.Margin = new System.Windows.Forms.Padding(4);
|
||||
this.nameTextBox.Name = "nameTextBox";
|
||||
this.nameTextBox.Size = new System.Drawing.Size(160, 22);
|
||||
this.nameTextBox.TabIndex = 17;
|
||||
//
|
||||
// nameLabel
|
||||
//
|
||||
this.nameLabel.AutoSize = true;
|
||||
this.nameLabel.Location = new System.Drawing.Point(6, 44);
|
||||
this.nameLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.nameLabel.Name = "nameLabel";
|
||||
this.nameLabel.Size = new System.Drawing.Size(44, 16);
|
||||
this.nameLabel.TabIndex = 16;
|
||||
this.nameLabel.Text = "Name";
|
||||
//
|
||||
// classNameLabel
|
||||
//
|
||||
this.classNameLabel.AutoSize = true;
|
||||
this.classNameLabel.Location = new System.Drawing.Point(149, 11);
|
||||
this.classNameLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.classNameLabel.Name = "classNameLabel";
|
||||
this.classNameLabel.Size = new System.Drawing.Size(78, 16);
|
||||
this.classNameLabel.TabIndex = 15;
|
||||
this.classNameLabel.Text = "ClassName";
|
||||
//
|
||||
// tabPage2
|
||||
//
|
||||
this.tabPage2.Location = new System.Drawing.Point(4, 25);
|
||||
this.tabPage2.Name = "tabPage2";
|
||||
this.tabPage2.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.tabPage2.Size = new System.Drawing.Size(603, 403);
|
||||
this.tabPage2.TabIndex = 1;
|
||||
this.tabPage2.Text = "Test";
|
||||
this.tabPage2.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// groupBox2
|
||||
//
|
||||
this.groupBox2.Controls.Add(this.headPortNrTextBox);
|
||||
this.groupBox2.Controls.Add(this.label2);
|
||||
this.groupBox2.Location = new System.Drawing.Point(10, 335);
|
||||
this.groupBox2.Name = "groupBox2";
|
||||
this.groupBox2.Size = new System.Drawing.Size(552, 50);
|
||||
this.groupBox2.TabIndex = 26;
|
||||
this.groupBox2.TabStop = false;
|
||||
this.groupBox2.Text = "Head Communication";
|
||||
//
|
||||
// label2
|
||||
//
|
||||
this.label2.AutoSize = true;
|
||||
this.label2.Location = new System.Drawing.Point(321, 18);
|
||||
this.label2.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.label2.Name = "label2";
|
||||
this.label2.Size = new System.Drawing.Size(88, 16);
|
||||
this.label2.TabIndex = 7;
|
||||
this.label2.Text = "Serial port nr.:";
|
||||
//
|
||||
// headPortNrTextBox
|
||||
//
|
||||
this.headPortNrTextBox.Enabled = false;
|
||||
this.headPortNrTextBox.Location = new System.Drawing.Point(439, 15);
|
||||
this.headPortNrTextBox.Margin = new System.Windows.Forms.Padding(4);
|
||||
this.headPortNrTextBox.Name = "headPortNrTextBox";
|
||||
this.headPortNrTextBox.Size = new System.Drawing.Size(44, 22);
|
||||
this.headPortNrTextBox.TabIndex = 8;
|
||||
//
|
||||
// IperlHeadCfgCtrl
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.Controls.Add(this.tabControl1);
|
||||
this.Margin = new System.Windows.Forms.Padding(4);
|
||||
this.Name = "IPerlUniCfgCtrl";
|
||||
this.Size = new System.Drawing.Size(617, 438);
|
||||
this.Load += new System.EventHandler(this.WaterMeterCfgCtrl_Load);
|
||||
this.tabControl1.ResumeLayout(false);
|
||||
this.tabPage1.ResumeLayout(false);
|
||||
this.tabPage1.PerformLayout();
|
||||
this.groupBox1.ResumeLayout(false);
|
||||
this.groupBox1.PerformLayout();
|
||||
this.optoDataGroupBox.ResumeLayout(false);
|
||||
this.optoDataGroupBox.PerformLayout();
|
||||
this.groupBox2.ResumeLayout(false);
|
||||
this.groupBox2.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.TabControl tabControl1;
|
||||
private System.Windows.Forms.TabPage tabPage1;
|
||||
private System.Windows.Forms.Label label4;
|
||||
private System.Windows.Forms.Label label3;
|
||||
private System.Windows.Forms.GroupBox groupBox1;
|
||||
private System.Windows.Forms.ComboBox comboBoxCommunicationInterface;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.TextBox rfidPortNrTextBox;
|
||||
private System.Windows.Forms.Label rfidSerialPortNrLabel;
|
||||
private System.Windows.Forms.GroupBox optoDataGroupBox;
|
||||
private System.Windows.Forms.Label tcpipPortLabel;
|
||||
private System.Windows.Forms.TextBox tcpipPortTextBox;
|
||||
private System.Windows.Forms.Label ipAddressLabel;
|
||||
private System.Windows.Forms.TextBox ipAddressTextBox;
|
||||
private System.Windows.Forms.RadioButton radioButton1;
|
||||
private System.Windows.Forms.RadioButton radioButton2;
|
||||
private System.Windows.Forms.Label optoSerialPortLabel;
|
||||
private System.Windows.Forms.TextBox optoSerialPortTextBox;
|
||||
private System.Windows.Forms.TextBox groupTextBox;
|
||||
private System.Windows.Forms.Label groupLabel;
|
||||
private System.Windows.Forms.TextBox muxBoardNrTextBox;
|
||||
private System.Windows.Forms.Label muxBoardNrLabel;
|
||||
private System.Windows.Forms.TextBox nameTextBox;
|
||||
private System.Windows.Forms.Label nameLabel;
|
||||
private System.Windows.Forms.Label classNameLabel;
|
||||
private System.Windows.Forms.TabPage tabPage2;
|
||||
private System.Windows.Forms.GroupBox groupBox2;
|
||||
private System.Windows.Forms.TextBox headPortNrTextBox;
|
||||
private System.Windows.Forms.Label label2;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
namespace TBF.Rig.RegisterReaders.IPerlReader
|
||||
{
|
||||
partial class IperlUniHeadTestCtrl
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.optoTestGroupBox = new System.Windows.Forms.GroupBox();
|
||||
this.optoListBox = new System.Windows.Forms.ListBox();
|
||||
this.rfidOutputListBox = new System.Windows.Forms.ListBox();
|
||||
this.RfidTestGroupBox = new System.Windows.Forms.GroupBox();
|
||||
this.label2 = new System.Windows.Forms.Label();
|
||||
this.rfidCommandComboBox = new System.Windows.Forms.ComboBox();
|
||||
this.commandTestButton = new System.Windows.Forms.Button();
|
||||
this.optoTestGroupBox.SuspendLayout();
|
||||
this.RfidTestGroupBox.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// optoTestGroupBox
|
||||
//
|
||||
this.optoTestGroupBox.Controls.Add(this.optoListBox);
|
||||
this.optoTestGroupBox.Location = new System.Drawing.Point(5, 4);
|
||||
this.optoTestGroupBox.Name = "optoTestGroupBox";
|
||||
this.optoTestGroupBox.Size = new System.Drawing.Size(591, 161);
|
||||
this.optoTestGroupBox.TabIndex = 2;
|
||||
this.optoTestGroupBox.TabStop = false;
|
||||
this.optoTestGroupBox.Text = "Opto-data";
|
||||
//
|
||||
// optoListBox
|
||||
//
|
||||
this.optoListBox.FormattingEnabled = true;
|
||||
this.optoListBox.ItemHeight = 16;
|
||||
this.optoListBox.Location = new System.Drawing.Point(7, 22);
|
||||
this.optoListBox.Name = "optoListBox";
|
||||
this.optoListBox.Size = new System.Drawing.Size(573, 132);
|
||||
this.optoListBox.TabIndex = 0;
|
||||
//
|
||||
// rfidOutputListBox
|
||||
//
|
||||
this.rfidOutputListBox.FormattingEnabled = true;
|
||||
this.rfidOutputListBox.ItemHeight = 16;
|
||||
this.rfidOutputListBox.Location = new System.Drawing.Point(5, 54);
|
||||
this.rfidOutputListBox.Name = "rfidOutputListBox";
|
||||
this.rfidOutputListBox.SelectionMode = System.Windows.Forms.SelectionMode.None;
|
||||
this.rfidOutputListBox.Size = new System.Drawing.Size(575, 164);
|
||||
this.rfidOutputListBox.TabIndex = 3;
|
||||
//
|
||||
// RfidTestGroupBox
|
||||
//
|
||||
this.RfidTestGroupBox.Controls.Add(this.rfidOutputListBox);
|
||||
this.RfidTestGroupBox.Controls.Add(this.label2);
|
||||
this.RfidTestGroupBox.Controls.Add(this.rfidCommandComboBox);
|
||||
this.RfidTestGroupBox.Controls.Add(this.commandTestButton);
|
||||
this.RfidTestGroupBox.Location = new System.Drawing.Point(5, 171);
|
||||
this.RfidTestGroupBox.Name = "RfidTestGroupBox";
|
||||
this.RfidTestGroupBox.Size = new System.Drawing.Size(591, 224);
|
||||
this.RfidTestGroupBox.TabIndex = 3;
|
||||
this.RfidTestGroupBox.TabStop = false;
|
||||
this.RfidTestGroupBox.Text = "RFID / NFC data";
|
||||
//
|
||||
// label2
|
||||
//
|
||||
this.label2.AutoSize = true;
|
||||
this.label2.Location = new System.Drawing.Point(2, 25);
|
||||
this.label2.Name = "label2";
|
||||
this.label2.Size = new System.Drawing.Size(69, 16);
|
||||
this.label2.TabIndex = 2;
|
||||
this.label2.Text = "Command";
|
||||
//
|
||||
// rfidCommandComboBox
|
||||
//
|
||||
this.rfidCommandComboBox.FormattingEnabled = true;
|
||||
this.rfidCommandComboBox.Location = new System.Drawing.Point(86, 19);
|
||||
this.rfidCommandComboBox.Name = "rfidCommandComboBox";
|
||||
this.rfidCommandComboBox.Size = new System.Drawing.Size(341, 24);
|
||||
this.rfidCommandComboBox.TabIndex = 1;
|
||||
//
|
||||
// commandTestButton
|
||||
//
|
||||
this.commandTestButton.Location = new System.Drawing.Point(449, 19);
|
||||
this.commandTestButton.Name = "commandTestButton";
|
||||
this.commandTestButton.Size = new System.Drawing.Size(126, 24);
|
||||
this.commandTestButton.TabIndex = 0;
|
||||
this.commandTestButton.Text = "Send command";
|
||||
this.commandTestButton.UseVisualStyleBackColor = true;
|
||||
this.commandTestButton.MouseClick += new System.Windows.Forms.MouseEventHandler(this.CommandTestButtonClick);
|
||||
//
|
||||
// IperlHeadTestCtrl
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.Controls.Add(this.optoTestGroupBox);
|
||||
this.Controls.Add(this.RfidTestGroupBox);
|
||||
this.Name = "IperlUniHeadTestCtrl";
|
||||
this.Size = new System.Drawing.Size(611, 432);
|
||||
this.Load += new System.EventHandler(this.UserControl_Load);
|
||||
this.optoTestGroupBox.ResumeLayout(false);
|
||||
this.RfidTestGroupBox.ResumeLayout(false);
|
||||
this.RfidTestGroupBox.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.GroupBox optoTestGroupBox;
|
||||
private System.Windows.Forms.ListBox rfidOutputListBox;
|
||||
private System.Windows.Forms.GroupBox RfidTestGroupBox;
|
||||
private System.Windows.Forms.Label label2;
|
||||
private System.Windows.Forms.ComboBox rfidCommandComboBox;
|
||||
private System.Windows.Forms.Button commandTestButton;
|
||||
private System.Windows.Forms.ListBox optoListBox;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using TBF.Rig.RegisterReaders.CommonRR.IPerl.communication;
|
||||
using TBF.Rig.RegisterReaders.iPerlReaderUNI;
|
||||
using TBF.Rig.RegisterReaders.iPerlReaderUNI.common;
|
||||
using TBF.Rig.RegisterReaders.PoseidonReader.implementations;
|
||||
using TBF.Rig.Sequences;
|
||||
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.IPerlReader
|
||||
{
|
||||
public partial class IperlUniHeadTestCtrl : UserControl
|
||||
{
|
||||
private IUniHeadTestCtrl _ctrl;
|
||||
private IUniHeadTestCtrl Ctrl { get => _ctrl; }
|
||||
|
||||
|
||||
|
||||
|
||||
public IperlUniHeadTestCtrl(iPerlReaderUNI.IPerlCfg config)
|
||||
{
|
||||
this._ctrl = new PoseidonImplHeadTestCtrl();
|
||||
Ctrl.config = config;
|
||||
InitializeComponent();
|
||||
if (config == null) return;
|
||||
|
||||
SmartCommunicationForm.TestMethodCfg = new TestMethodCfg(null); // default values for iPerlCommunication
|
||||
|
||||
foreach(var head in ProcessData.SmartHeadsUni)
|
||||
{
|
||||
if (head != null && head.Name == config.Name) { Ctrl.ISmartReader = head; }
|
||||
}
|
||||
|
||||
rfidCommandComboBox.DisplayMember = "Name";
|
||||
rfidCommandComboBox.ValueMember = "Value";
|
||||
var items = Ctrl.GetComboOperationsPairs();
|
||||
/*
|
||||
// CTRL+ALT+double click - hidden poweruser menu
|
||||
if (((Keyboard.ModifierKeys & Keys.Control) == Keys.Control) && ((Keyboard.ModifierKeys & Keys.Alt) == Keys.Alt) && Users.CurrentUser.AuthorizedAs == AuthorizedAs.PowerUser)
|
||||
{
|
||||
Array.Resize(ref items, items.Length + 1);
|
||||
items[items.Length - 1] = new { Name = "Kluc", Value = "Kluc" };
|
||||
}
|
||||
*/
|
||||
rfidCommandComboBox.DataSource = items.Select(i => i.Name).ToArray();
|
||||
|
||||
Ctrl.Initialize();
|
||||
|
||||
Ctrl.OptoReceivedHandler += (EventHandler<OptoReceivedEventArgs>)((sndr, args) =>
|
||||
{
|
||||
if (this.InvokeRequired)
|
||||
this.Invoke((Delegate)new EventHandler<OptoReceivedEventArgs>(this.OnOptoReceived2), sndr, (object)args);
|
||||
else
|
||||
this.OnOptoReceived2(sndr, args);
|
||||
});
|
||||
}
|
||||
|
||||
public void OnOptoReceived2(object sender, OptoReceivedEventArgs args)
|
||||
{
|
||||
optoListBox.Items.Insert(0,args.Data);
|
||||
}
|
||||
|
||||
private void CommandTestButtonClick(object sender, MouseEventArgs e)
|
||||
{
|
||||
Ctrl.CommandTestButtonClick(sender, e, new Arguments()
|
||||
{
|
||||
ISmartReader = Ctrl.ISmartReader,
|
||||
OptoListBox = optoListBox,
|
||||
RfidCommandComboBox = rfidCommandComboBox,
|
||||
RfidOutputListBox = rfidOutputListBox
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void UserControl_Load(object sender, EventArgs e)
|
||||
{
|
||||
this.ParentForm.FormClosing += new FormClosingEventHandler(ParentForm_FormClosing);
|
||||
}
|
||||
|
||||
void ParentForm_FormClosing(object sender, FormClosingEventArgs e)
|
||||
{
|
||||
//OnHandleDestroyed(new EventArgs());
|
||||
Ctrl.Destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Web.UI.WebControls;
|
||||
using System.Windows.Forms;
|
||||
using TBF.Rig.Generic;
|
||||
using TBF.Rig.RegisterReaders.CommonRR.IPerl.communication;
|
||||
using TBF.Rig.RegisterReaders.iPerlReaderUNI.common;
|
||||
using TBF.Rig.RegisterReaders.iPerlReaderUNI.test;
|
||||
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.common;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.IPerlReader.implementations
|
||||
{
|
||||
public class IPerlImplHeadTestCtrl : IUniHeadTestCtrl
|
||||
{
|
||||
Thread optoThread;
|
||||
public ISmartReader ISmartReader { get; set; }
|
||||
public bool stopWorkerThread { get; set; }
|
||||
public event EventHandler<OptoReceivedEventArgs> OptoReceivedHandler;
|
||||
|
||||
public IComponentCfg
|
||||
|
||||
|
||||
config { get; set; }
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
stopWorkerThread = false;
|
||||
}
|
||||
|
||||
public void Destroy()
|
||||
{
|
||||
stopWorkerThread = true;
|
||||
if (optoThread != null)
|
||||
{
|
||||
optoThread.Abort();
|
||||
}
|
||||
}
|
||||
|
||||
private const string ReadPCBCmd = "ReadPCB";
|
||||
private const string SetTestModeCmd = "SetTestMode";
|
||||
private const string SetActiveModeCmd = "SetActiveMode";
|
||||
private const string ReadOptoDataCmd = "ReadOptoData";
|
||||
private const string StopReadOptoDataCmd = "StopReadOptoData";
|
||||
private const string ResetNfcHeadCmd = "ResetNfcHead";
|
||||
private const string SetNfcHeadCmd = "SetNfcHead";
|
||||
private const string SetRfidHeadCmd = "SetRfidHead";
|
||||
private const string EmptyCmd = "";
|
||||
|
||||
private static readonly Dictionary<string, string> ItemsForIperlOperations = new Dictionary<string, string>
|
||||
{
|
||||
{"Read PCB", ReadPCBCmd},
|
||||
{"Set Test Mode", SetTestModeCmd},
|
||||
{"Set Active Mode", SetActiveModeCmd},
|
||||
#if DEBUG
|
||||
{"Start Read Opto Data", ReadOptoDataCmd},
|
||||
{"Stop Read Opto Data", StopReadOptoDataCmd},
|
||||
#endif
|
||||
{" ", EmptyCmd},
|
||||
{"Reset NFC Head", ResetNfcHeadCmd},
|
||||
{"Set NFC Head Interface", SetNfcHeadCmd},
|
||||
{"Set RFID Head interface", SetRfidHeadCmd}
|
||||
};
|
||||
|
||||
public (string Name, string Value)[] GetComboOperationsPairs()
|
||||
{
|
||||
return ItemsForIperlOperations.Select(kvp => (kvp.Key, kvp.Value)).ToArray();
|
||||
}
|
||||
|
||||
public void CommandTestButtonClick(object sender, MouseEventArgs e, Arguments a)
|
||||
{
|
||||
a.RfidOutputListBox.Items.Clear();
|
||||
|
||||
using (Tools.LogChecker logChecker = new Tools.LogChecker("RfidData", log4net.Core.Level.Debug))
|
||||
{
|
||||
ListItem rfidListItem = new ListItem();
|
||||
rfidListItem.Attributes.Add("style", "font-weight:bold");
|
||||
switch (a.RfidCommandComboBox.SelectedValue)
|
||||
{
|
||||
case ReadPCBCmd:
|
||||
rfidListItem.Text = $"PCB: {OpticalHeadTest.ReadRequest_PCB(a.ISmartReader)}";
|
||||
break;
|
||||
case SetTestModeCmd:
|
||||
rfidListItem.Text = OpticalHeadTest.SetTestMode(a.ISmartReader);
|
||||
a.OptoListBox.Items.Clear();
|
||||
stopWorkerThread = false;
|
||||
optoThread = new Thread(OptoWorker);
|
||||
if (!optoThread.IsAlive)
|
||||
{
|
||||
a.ISmartReader.StartDataStreamProcessing(); // open opto port
|
||||
optoThread.Start();
|
||||
}
|
||||
break;
|
||||
case SetActiveModeCmd:
|
||||
rfidListItem.Text = OpticalHeadTest.SetActiveMode(a.ISmartReader);
|
||||
stopWorkerThread = true;
|
||||
a.ISmartReader.StopDataStreamProcessing(); // close opto port
|
||||
break;
|
||||
case ResetNfcHeadCmd:
|
||||
a.ISmartReader.ResetNfcInterface();
|
||||
break;
|
||||
case SetNfcHeadCmd:
|
||||
a.ISmartReader.SetNfcInterface();
|
||||
break;
|
||||
case SetRfidHeadCmd:
|
||||
a.ISmartReader.SetRfidInterface();
|
||||
break;
|
||||
case ReadOptoDataCmd:
|
||||
a.OptoListBox.Items.Clear();
|
||||
stopWorkerThread = false;
|
||||
optoThread = new Thread(OptoWorker);
|
||||
if (optoThread.IsAlive)
|
||||
{
|
||||
stopWorkerThread = true;
|
||||
a.ISmartReader.StopDataStreamProcessing(); // close opto port
|
||||
}
|
||||
if (!optoThread.IsAlive)
|
||||
{
|
||||
a.ISmartReader.StartDataStreamProcessing(); // open opto port
|
||||
optoThread.Start();
|
||||
}
|
||||
break;
|
||||
case StopReadOptoDataCmd:
|
||||
stopWorkerThread = true;
|
||||
a.ISmartReader.StopDataStreamProcessing(); // close opto port
|
||||
break;
|
||||
}
|
||||
a.RfidOutputListBox.Items.Add(rfidListItem);
|
||||
a.RfidOutputListBox.Items.AddRange(logChecker.Messages.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
private void OptoWorker()
|
||||
{
|
||||
while (!this.stopWorkerThread)
|
||||
{
|
||||
Thread.Sleep(250);
|
||||
if (this.stopWorkerThread)
|
||||
break;
|
||||
|
||||
try
|
||||
{
|
||||
string buffer = ISmartReader.ReadOptoData();
|
||||
if (string.IsNullOrEmpty(buffer))
|
||||
{
|
||||
this.OnOptoReceived((object)this, new OptoReceivedEventArgs("."));
|
||||
}
|
||||
else
|
||||
OnOptoReceived((object)this, new OptoReceivedEventArgs(buffer));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.OnOptoReceived((object)this, new OptoReceivedEventArgs(ex.Message));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnOptoReceived(object sender, OptoReceivedEventArgs args)
|
||||
{
|
||||
if (this.OptoReceivedHandler == null)
|
||||
return;
|
||||
try
|
||||
{
|
||||
this.OptoReceivedHandler(sender, args);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,224 +1,474 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using log4net;
|
||||
using log4net.Config;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using SharedDatabase;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
{
|
||||
public class CliRunner
|
||||
{
|
||||
//static readonly ILog log = LogManager.GetLogger(typeof(CliRunner));
|
||||
private readonly ILog log;
|
||||
private List<Task> taskPool = new List<Task>();
|
||||
private long startTime;
|
||||
|
||||
public List<Task> TaskPool { get { return taskPool; } }
|
||||
public void AddTask(Task task) { taskPool.Add(task); }
|
||||
public void WaitAll() { Task.WaitAll(taskPool.ToArray()); }
|
||||
public void Clear() { taskPool.Clear(); }
|
||||
public void CancelAll() { Task.WhenAll(taskPool).ContinueWith(t => { }); }
|
||||
private readonly List<CliTaskInfo> taskPool = new List<CliTaskInfo>();
|
||||
private long startTimeMs;
|
||||
private long incommingTimeMs;
|
||||
|
||||
public void StartAll()
|
||||
public List<CliTaskInfo> TaskPool
|
||||
{
|
||||
taskPool.ForEach(t => t.Start());
|
||||
}
|
||||
|
||||
public bool AreTasksDone()
|
||||
{
|
||||
return taskPool.All(task => task.IsCompleted);
|
||||
get { return taskPool; }
|
||||
}
|
||||
|
||||
public long StartTime
|
||||
{
|
||||
get => startTime;
|
||||
get { return startTimeMs; }
|
||||
}
|
||||
|
||||
public bool TimeOutReceived(long timeout)
|
||||
public long IncommingTime
|
||||
{
|
||||
return (DateTime.Now.Ticks - startTime) > timeout;
|
||||
get { return incommingTimeMs; }
|
||||
}
|
||||
|
||||
|
||||
public CliRunner(bool isCliLogging)
|
||||
{
|
||||
startTime = DateTime.Now.Ticks;
|
||||
ResetStartTime();
|
||||
|
||||
if (isCliLogging)
|
||||
{
|
||||
log = new ScopedLoggerFactory().CreateLogger<CliRunner>(
|
||||
@"C:\TBF\Logs\CliRunner.txt",
|
||||
10, // maxFileSizeMB
|
||||
7, // maxBackups
|
||||
log4net.Core.Level.Debug,
|
||||
true, // zipRolledFiles
|
||||
true, // singleZipPerDay
|
||||
TimeSpan.FromMinutes(2) // zipScanInterval
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="fileName"></param>
|
||||
/// <param name="args"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public void AddSendAsync(SerialPortData data, SerialPortData.EMeterArg eMeterArg)
|
||||
{
|
||||
var task = SendAsync(data.SerialPortCmdClientPath, data.DefaultArgSettings(eMeterArg));
|
||||
taskPool.Add(task);
|
||||
}
|
||||
|
||||
public void AddSendAsync(string fileName, string args)
|
||||
{
|
||||
var task = SendAsync(fileName, args);
|
||||
taskPool.Add(task);
|
||||
}
|
||||
|
||||
|
||||
public async Task<string> SendAsync(string fileName, string args)
|
||||
{
|
||||
var psi = new ProcessStartInfo
|
||||
{
|
||||
FileName = fileName,
|
||||
Arguments = args,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true
|
||||
};
|
||||
|
||||
var process = new Process { StartInfo = psi };
|
||||
var sb = new StringBuilder();
|
||||
|
||||
process.OutputDataReceived += (sender, e) =>
|
||||
{
|
||||
if (e.Data != null)
|
||||
sb.AppendLine(e.Data);
|
||||
};
|
||||
|
||||
process.Start();
|
||||
process.BeginOutputReadLine();
|
||||
|
||||
process.WaitForExit();
|
||||
|
||||
// Now all outputs are available
|
||||
string allOutput = sb.ToString();
|
||||
log?.Debug(allOutput);
|
||||
|
||||
return allOutput;
|
||||
}
|
||||
|
||||
public void AddRunAndCaptureJsonAsync<T>(SerialPortData data, SerialPortData.EMeterArg eMeterArg) where T : new()
|
||||
{
|
||||
var task = RunAndCaptureJsonAsync<T>(data.SerialPortCmdClientPath, data.DefaultArgSettings(eMeterArg));
|
||||
taskPool.Add(task);
|
||||
}
|
||||
|
||||
public async Task<T> RunAndCaptureJsonAsync<T>(string fileName, string args) where T : new()
|
||||
{
|
||||
var psi = new ProcessStartInfo
|
||||
{
|
||||
FileName = fileName,
|
||||
Arguments = args,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true
|
||||
};
|
||||
|
||||
var process = new Process { StartInfo = psi };
|
||||
var sb = new StringBuilder();
|
||||
|
||||
process.OutputDataReceived += (sender, e) =>
|
||||
{
|
||||
if (e.Data != null)
|
||||
sb.AppendLine(e.Data);
|
||||
};
|
||||
|
||||
process.Start();
|
||||
process.BeginOutputReadLine();
|
||||
|
||||
process.WaitForExit();
|
||||
|
||||
// Now sb contains all output text
|
||||
string allOutput = sb.ToString();
|
||||
log?.Debug(allOutput);
|
||||
|
||||
// Extract JSON part
|
||||
string json = ExtractJson(allOutput);
|
||||
|
||||
if (TryJsonStringDeserialize(json, out T runAndCaptureJsonAsync)) return runAndCaptureJsonAsync;
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
public bool TryJsonStringDeserialize<T>(string json, out T runAndCaptureJsonAsync) where T : new()
|
||||
{
|
||||
if (json != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
runAndCaptureJsonAsync = JsonConvert.DeserializeObject<T>(json);
|
||||
return true;
|
||||
log = new ScopedLoggerFactory().CreateLogger<CliRunner>(
|
||||
@"C:\TBF\Logs\CliRunner.txt",
|
||||
10,
|
||||
7,
|
||||
log4net.Core.Level.Debug,
|
||||
true,
|
||||
true,
|
||||
TimeSpan.FromMinutes(2)
|
||||
);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.Debug(ex.Message);
|
||||
runAndCaptureJsonAsync = TryConvert<T>(json);
|
||||
return true;
|
||||
Console.WriteLine($"Failed to initialize logger: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
runAndCaptureJsonAsync = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private static T TryConvert<T>(string json) where T : new()
|
||||
public void ResetStartTime()
|
||||
{
|
||||
|
||||
T obj = new T();
|
||||
startTimeMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
foreach (var item in taskPool)
|
||||
{
|
||||
try
|
||||
{
|
||||
item?.Cts?.Dispose();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
JObject jObject = JObject.Parse(json);
|
||||
|
||||
foreach (PropertyInfo prop in typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance))
|
||||
if (item?.Process != null)
|
||||
{
|
||||
if (!prop.CanWrite) continue;
|
||||
item.Process.Dispose();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
JToken token;
|
||||
if (jObject.TryGetValue(prop.Name, StringComparison.OrdinalIgnoreCase, out token))
|
||||
{
|
||||
try
|
||||
{
|
||||
object value = token.ToObject(prop.PropertyType);
|
||||
prop.SetValue(obj, value);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// leave default if conversion fails
|
||||
}
|
||||
}
|
||||
// else → keep default value
|
||||
taskPool.Clear();
|
||||
}
|
||||
|
||||
public void WaitAll()
|
||||
{
|
||||
var tasks = taskPool
|
||||
.Where(t => t != null && t.Task != null)
|
||||
.Select(t => t.Task)
|
||||
.ToArray();
|
||||
|
||||
if (tasks.Length == 0)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
Task.WaitAll(tasks);
|
||||
}
|
||||
catch (AggregateException)
|
||||
{
|
||||
RefreshTaskStates();
|
||||
}
|
||||
}
|
||||
|
||||
public bool AreTasksDone()
|
||||
{
|
||||
RefreshTaskStates();
|
||||
return taskPool.Count > 0 && taskPool.All(t => t.State != CliTaskState.Running);
|
||||
}
|
||||
|
||||
public bool TimeOutReceived(long timeoutMs)
|
||||
{
|
||||
long nowMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||
return (nowMs - startTimeMs) > timeoutMs;
|
||||
}
|
||||
|
||||
public void RefreshTaskStates()
|
||||
{
|
||||
foreach (var item in taskPool)
|
||||
{
|
||||
if (item == null || item.Task == null)
|
||||
continue;
|
||||
|
||||
if (item.State == CliTaskState.TimedOut)
|
||||
continue;
|
||||
|
||||
if (!item.Task.IsCompleted)
|
||||
{
|
||||
item.State = CliTaskState.Running;
|
||||
}
|
||||
else if (item.Task.IsCanceled)
|
||||
{
|
||||
item.State = CliTaskState.Canceled;
|
||||
}
|
||||
else if (item.Task.IsFaulted)
|
||||
{
|
||||
item.State = CliTaskState.Faulted;
|
||||
}
|
||||
else
|
||||
{
|
||||
item.State = CliTaskState.Completed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void CancelUndoneTasksAsTimedOut()
|
||||
{
|
||||
foreach (var item in taskPool)
|
||||
{
|
||||
if (item == null || item.Task == null)
|
||||
continue;
|
||||
|
||||
if (item.Task.IsCompleted)
|
||||
{
|
||||
if (item.Task.IsCanceled)
|
||||
item.State = CliTaskState.Canceled;
|
||||
else if (item.Task.IsFaulted)
|
||||
item.State = CliTaskState.Faulted;
|
||||
else
|
||||
item.State = CliTaskState.Completed;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
item.State = CliTaskState.TimedOut;
|
||||
|
||||
try
|
||||
{
|
||||
item.Cts?.Cancel();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log?.Warn("Cancel token failed", ex);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (item.Process != null && !item.Process.HasExited)
|
||||
{
|
||||
item.Process.Kill();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"TryConvert failed: {ex.Message}");
|
||||
log?.Warn("Kill process failed", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void AddSendAsync(SerialPortData data, SerialPortData.EMeterArg eMeterArg)
|
||||
{
|
||||
AddSendAsync(data.SerialPortCmdClientPath, data.DefaultArgSettings(eMeterArg));
|
||||
}
|
||||
|
||||
public void AddSendAsync(string fileName, string args)
|
||||
{
|
||||
ResetStartTime();
|
||||
|
||||
var cts = new CancellationTokenSource();
|
||||
var info = new CliTaskInfo
|
||||
{
|
||||
Cts = cts,
|
||||
Name = "SendAsync"
|
||||
};
|
||||
|
||||
var task = SendAsync(fileName, args, info, cts.Token);
|
||||
info.Task = task;
|
||||
taskPool.Add(info);
|
||||
}
|
||||
|
||||
public async Task<string> SendAsync(string fileName, string args, CliTaskInfo info, CancellationToken ct = default)
|
||||
{
|
||||
var psi = new ProcessStartInfo
|
||||
{
|
||||
FileName = fileName,
|
||||
Arguments = args,
|
||||
WorkingDirectory = System.IO.Path.GetDirectoryName(System.IO.Path.GetFullPath(fileName)),
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true
|
||||
};
|
||||
|
||||
using (var process = new Process { StartInfo = psi, EnableRaisingEvents = true })
|
||||
{
|
||||
info.Process = process;
|
||||
|
||||
try
|
||||
{
|
||||
process.Start();
|
||||
|
||||
Task<string> stdOutTask = process.StandardOutput.ReadToEndAsync();
|
||||
Task<string> stdErrTask = process.StandardError.ReadToEndAsync();
|
||||
|
||||
try
|
||||
{
|
||||
await Task.WhenAll(stdOutTask, stdErrTask, process.WaitForExitAsync(ct));
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
if (info.State != CliTaskState.TimedOut)
|
||||
info.State = CliTaskState.Canceled;
|
||||
|
||||
if (!process.HasExited)
|
||||
{
|
||||
process.Kill();
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
incommingTimeMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||
|
||||
info.ExitCode = process.ExitCode;
|
||||
info.StandardOutput = stdOutTask.Result ?? "";
|
||||
info.StandardError = stdErrTask.Result ?? "";
|
||||
string allOutput = info.StandardOutput + info.StandardError;
|
||||
log?.Debug(allOutput);
|
||||
|
||||
if (info.ExitCode != 0)
|
||||
{
|
||||
info.FailureReason = $"CLI exited with exit code {info.ExitCode}.";
|
||||
log?.Error($"{info.Name}: {info.FailureReason} stderr='{info.StandardError}'");
|
||||
}
|
||||
|
||||
info.State = CliTaskState.Completed;
|
||||
return allOutput;
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
info.State = CliTaskState.Faulted;
|
||||
log?.Error("SendAsync failed", ex);
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
info.Process = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void AddRunAndCaptureJsonAsync<T>(SerialPortData data, SerialPortData.EMeterArg eMeterArg) where T : new()
|
||||
{
|
||||
AddRunAndCaptureJsonAsync<T>(
|
||||
data.SerialPortCmdClientPath,
|
||||
data.DefaultArgSettings(eMeterArg));
|
||||
}
|
||||
|
||||
public void AddRunAndCaptureJsonAsync<T>(string fileName, string args) where T : new()
|
||||
{
|
||||
// Tests deliberately create CliRunner without a logger. Starting a CLI task
|
||||
// must not depend on diagnostics being configured.
|
||||
log?.Debug($"CLI: {fileName}");
|
||||
log?.Debug($"ARGS: {args}");
|
||||
|
||||
ResetStartTime();
|
||||
|
||||
var cts = new CancellationTokenSource();
|
||||
var info = new CliTaskInfo
|
||||
{
|
||||
Cts = cts,
|
||||
Name = $"RunAndCaptureJsonAsync<{typeof(T).Name}>"
|
||||
};
|
||||
|
||||
var task = RunAndCaptureJsonAsync<T>(fileName, args, info, cts.Token);
|
||||
|
||||
info.Task = task;
|
||||
taskPool.Add(info);
|
||||
}
|
||||
|
||||
public async Task<T> RunAndCaptureJsonAsync<T>(string fileName, string args, CliTaskInfo info, CancellationToken ct = default) where T : new()
|
||||
{
|
||||
var psi = new ProcessStartInfo
|
||||
{
|
||||
FileName = fileName,
|
||||
Arguments = args,
|
||||
WorkingDirectory = System.IO.Path.GetDirectoryName(System.IO.Path.GetFullPath(fileName)),
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true
|
||||
};
|
||||
|
||||
using (var process = new Process { StartInfo = psi, EnableRaisingEvents = true })
|
||||
{
|
||||
info.Process = process;
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
log?.Debug($"FileName = '{psi.FileName}'");
|
||||
log?.Debug($"Arguments = '{psi.Arguments}'");
|
||||
log?.Debug($"WorkingDirectory = '{psi.WorkingDirectory}'");
|
||||
log?.Debug($"Exists = {System.IO.File.Exists(psi.FileName)}");
|
||||
|
||||
process.Start();
|
||||
|
||||
var stdoutTask = process.StandardOutput.ReadToEndAsync();
|
||||
var stderrTask = process.StandardError.ReadToEndAsync();
|
||||
|
||||
try
|
||||
{
|
||||
await Task.WhenAll(stdoutTask, stderrTask, process.WaitForExitAsync(ct));
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
if (info.State != CliTaskState.TimedOut)
|
||||
info.State = CliTaskState.Canceled;
|
||||
|
||||
if (!process.HasExited)
|
||||
{
|
||||
process.Kill();
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
incommingTimeMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||
|
||||
info.ExitCode = process.ExitCode;
|
||||
info.StandardOutput = stdoutTask.Result ?? "";
|
||||
info.StandardError = stderrTask.Result ?? "";
|
||||
string allOutput = info.StandardOutput + info.StandardError;
|
||||
log?.Debug(allOutput);
|
||||
|
||||
if (info.ExitCode != 0)
|
||||
{
|
||||
info.FailureReason = $"CLI exited with exit code {info.ExitCode}.";
|
||||
log?.Error($"{info.Name}: {info.FailureReason} stderr='{info.StandardError}'");
|
||||
info.State = CliTaskState.Completed;
|
||||
return default(T);
|
||||
}
|
||||
|
||||
string json = ExtractJson(allOutput);
|
||||
T result;
|
||||
if (TryJsonStringDeserialize(json, out result))
|
||||
{
|
||||
info.State = CliTaskState.Completed;
|
||||
return result;
|
||||
}
|
||||
|
||||
info.FailureReason = "CLI completed without a valid JSON response.";
|
||||
log?.Error($"{info.Name}: {info.FailureReason} stdout='{info.StandardOutput}' stderr='{info.StandardError}'");
|
||||
info.State = CliTaskState.Completed;
|
||||
return default(T);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
info.State = CliTaskState.Faulted;
|
||||
log?.Error("RunAndCaptureJsonAsync failed", ex);
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
info.Process = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryJsonStringDeserialize<T>(string json, out T value) where T : new()
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(json))
|
||||
{
|
||||
try
|
||||
{
|
||||
value = JsonConvert.DeserializeObject<T>(json);
|
||||
return value != null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log?.Debug(ex.Message);
|
||||
return TryConvert(json, out value);
|
||||
}
|
||||
}
|
||||
|
||||
value = default(T);
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool TryConvert<T>(string json, out T value) where T : new()
|
||||
{
|
||||
T obj = new T();
|
||||
|
||||
try
|
||||
{
|
||||
JObject jObject = JObject.Parse(json);
|
||||
|
||||
foreach (PropertyInfo prop in typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance))
|
||||
{
|
||||
if (!prop.CanWrite)
|
||||
continue;
|
||||
|
||||
JToken token;
|
||||
if (jObject.TryGetValue(prop.Name, StringComparison.OrdinalIgnoreCase, out token))
|
||||
{
|
||||
try
|
||||
{
|
||||
object propertyValue = token.ToObject(prop.PropertyType);
|
||||
prop.SetValue(obj, propertyValue);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return obj;
|
||||
|
||||
value = obj;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"TryConvert failed: {ex.Message}");
|
||||
value = default(T);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public string ExtractJson(string text)
|
||||
@@ -233,6 +483,20 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
internal void AddTaskForTest(Task task, string name = "TestTask", CancellationTokenSource cts = null)
|
||||
{
|
||||
taskPool.Add(new CliTaskInfo
|
||||
{
|
||||
Task = task,
|
||||
Cts = cts,
|
||||
Name = name,
|
||||
State = task.IsCompleted
|
||||
? (task.IsCanceled ? CliTaskState.Canceled :
|
||||
task.IsFaulted ? CliTaskState.Faulted :
|
||||
CliTaskState.Completed)
|
||||
: CliTaskState.Running
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
{
|
||||
public class CliTaskInfo
|
||||
{
|
||||
public Task Task { get; set; }
|
||||
public CancellationTokenSource Cts { get; set; }
|
||||
public Process Process { get; set; }
|
||||
public CliTaskState State { get; set; } = CliTaskState.Running;
|
||||
public string Name { get; set; }
|
||||
public int? ExitCode { get; set; }
|
||||
public string StandardOutput { get; set; }
|
||||
public string StandardError { get; set; }
|
||||
public string FailureReason { get; set; }
|
||||
|
||||
public bool UseResult
|
||||
{
|
||||
get
|
||||
{
|
||||
return State == CliTaskState.Completed
|
||||
&& Task != null
|
||||
&& Task.Status == TaskStatus.RanToCompletion;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
{
|
||||
public enum CliTaskState
|
||||
{
|
||||
Running,
|
||||
Completed,
|
||||
TimedOut,
|
||||
Canceled,
|
||||
Faulted
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Reflection;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
{
|
||||
public static class GetDescription
|
||||
{
|
||||
public static string ToDescription(this Enum en)
|
||||
{
|
||||
Type type = en.GetType();
|
||||
MemberInfo[] memInfo = type.GetMember(en.ToString());
|
||||
|
||||
if (memInfo != null && memInfo.Length > 0)
|
||||
{
|
||||
object[] attrs = memInfo[0].GetCustomAttributes(
|
||||
typeof(DescriptionAttribute),
|
||||
false);
|
||||
|
||||
if (attrs != null && attrs.Length > 0)
|
||||
return ((DescriptionAttribute)attrs[0]).Description;
|
||||
}
|
||||
|
||||
return en.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,53 @@
|
||||
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
{
|
||||
public class JsonDataFromPoseidon
|
||||
{
|
||||
public bool? NfcTagDetected { get; set; }
|
||||
public int? ProductType { get; set; }
|
||||
public string ProductTypeVersion { get; set; }
|
||||
public bool NfcTagDetected { get; set; }
|
||||
public bool ReadingComplete { get; set; }
|
||||
|
||||
public string DeviceId { get; set; }
|
||||
public string ProductType { get; set; }
|
||||
public string ProductTypeVersion { get; set; }
|
||||
public string CliVersion { get; set; }
|
||||
|
||||
public string Reading { get; set; }
|
||||
public string Reading_Totalizer { get; set; }
|
||||
public string Reading_Digits { get; set; }
|
||||
public string Reading_Shift { get; set; }
|
||||
public string Reading_Resolution { get; set; }
|
||||
|
||||
public object Reading_Totalizer { get; set; }
|
||||
public object Reading_FlowRate { get; set; }
|
||||
public object Reading_FlowDirection { get; set; }
|
||||
public object Reading_Digits { get; set; }
|
||||
public object Reading_Shift { get; set; }
|
||||
public object Reading_Resolution { get; set; }
|
||||
public string Reading_Units { get; set; }
|
||||
public string Reading_FlowDirection { get; set; }
|
||||
public string Reading_FlowRate { get; set; }
|
||||
|
||||
public string MeterState { get; set; }
|
||||
public string CalibrationFactor { get; set; }
|
||||
public bool? ReadingComplete { get; set; }
|
||||
public string OpticalDataMode { get; set; }
|
||||
|
||||
public string BuildInformation { get; set; }
|
||||
public string ManufactureDate { get; set; }
|
||||
public string MeterSize { get; set; }
|
||||
public string FactoryId { get; set; }
|
||||
public string CustomerText { get; set; }
|
||||
|
||||
public string TestTotalizer { get; set; }
|
||||
public string FlowUnits { get; set; }
|
||||
public string ReadingUnits { get; set; }
|
||||
|
||||
public string SpreadSpectrumParameters { get; set; }
|
||||
|
||||
public string SpreadSpect_DisableSpreadSpectrum { get; set; }
|
||||
public string SpreadSpect_AlwaysUseFullRateBags { get; set; }
|
||||
public string SpreadSpect_PowerUp { get; set; }
|
||||
public string SpreadSpect_HighNoise { get; set; }
|
||||
public string SpreadSpect_EmptyPipe { get; set; }
|
||||
public string SpreadSpect_BadAdc { get; set; }
|
||||
public string SpreadSpect_InitLearningCompleteCount { get; set; }
|
||||
public string SpreadSpect_MinOffsetLearningSampleCount { get; set; }
|
||||
public string SpreadSpect_AdcShiftUpdateInterval { get; set; }
|
||||
public string SpreadSpect_MaxPreviousAdcAge { get; set; }
|
||||
public string SpreadSpect_AdcOffsetLearningGuard { get; set; }
|
||||
public string SpreadSpect_DisplacementCorrectionCount { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -3,10 +3,12 @@
|
||||
///
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO.Ports;
|
||||
using System.ComponentModel;
|
||||
using System.Xml.Serialization;
|
||||
using Common;
|
||||
using TBF.Rig.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Common;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
{
|
||||
@@ -22,7 +24,22 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
///
|
||||
public int ComPortNr;
|
||||
public string CliFileName;
|
||||
public int MeterType;
|
||||
|
||||
[XmlIgnore]
|
||||
public SerialPortData.MeterProduct MeterType = SerialPortData.MeterProduct.Poseidon;
|
||||
|
||||
[XmlElement("MeterProduct")]
|
||||
public string MeterProductXml
|
||||
{
|
||||
get { return SerialPortData.MeterToString(MeterType); }
|
||||
set { MeterType = SerialPortData.StringToMeter(value); }
|
||||
}
|
||||
|
||||
public SerialPortData.HatType HatType = SerialPortData.HatType.Mth;
|
||||
public int TimeOut = 30;
|
||||
public string MainMacro = SerialPortData.MacroTypes.readall.ToDescription();
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary> Procedure parameters </summary>
|
||||
@@ -31,14 +48,68 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
public override IParamsProvider GetRuntimeProcParamsProvider() { return ProcParams; }
|
||||
public override IParamsProvider CreateProcParamsProvider() { return new PoseidonProcParams(true); }
|
||||
|
||||
public static bool TryParseMeter(
|
||||
string description,
|
||||
out SerialPortData.MeterProduct meter)
|
||||
{
|
||||
var found = Enum.GetValues(typeof(SerialPortData.MeterProduct))
|
||||
.Cast<SerialPortData.MeterProduct>()
|
||||
.FirstOrDefault(e =>
|
||||
string.Equals(
|
||||
e.GetType()
|
||||
.GetField(e.ToString())
|
||||
.GetCustomAttribute<DescriptionAttribute>()
|
||||
?.Description,
|
||||
description,
|
||||
StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (!Equals(found, default(SerialPortData.MeterProduct)) ||
|
||||
string.Equals(description, "Poseidon", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
meter = found;
|
||||
return true;
|
||||
}
|
||||
|
||||
meter = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool TryParseMacro(
|
||||
string description,
|
||||
out string macro)
|
||||
{
|
||||
var found = Enum.GetValues(typeof(SerialPortData.MacroTypes))
|
||||
.Cast<SerialPortData.MacroTypes>()
|
||||
.FirstOrDefault(e =>
|
||||
string.Equals(
|
||||
e.GetType()
|
||||
.GetField(e.ToString())
|
||||
.GetCustomAttribute<DescriptionAttribute>()
|
||||
?.Description,
|
||||
description,
|
||||
StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (!Equals(found, default(SerialPortData.MacroTypes)) ||
|
||||
string.Equals(description, "readall", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
macro = found.ToDescription();
|
||||
return true;
|
||||
}
|
||||
|
||||
macro = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
string[] paramNames = new string[]
|
||||
{
|
||||
"Serial port number", /// 0
|
||||
"CLI program name", /// 1
|
||||
"Meter Type", /// 2
|
||||
"Hat Type", /// 3
|
||||
"TimeOut [s]", /// 4
|
||||
"Main Macro" /// 5
|
||||
};
|
||||
|
||||
public string ParamName(int i) { return paramNames[i]; }
|
||||
public int ParamsCount() { return paramNames.Length; }
|
||||
|
||||
@@ -51,8 +122,27 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
case 1:
|
||||
return new string[] { "HatCLI.exe"};
|
||||
case 2:
|
||||
return new string[] { "74" };
|
||||
|
||||
return new string[] {
|
||||
SerialPortData.MeterProduct.Poseidon.ToDescription() ,
|
||||
SerialPortData.MeterProduct.Ally.ToDescription(),
|
||||
SerialPortData.MeterProduct.IperlPlus.ToDescription(),
|
||||
SerialPortData.MeterProduct.IperlLegacy.ToDescription()
|
||||
};
|
||||
case 3:
|
||||
return new string[]
|
||||
{
|
||||
SerialPortData.HatType.Mth.ToDescription(),
|
||||
SerialPortData.HatType.Harry.ToDescription()
|
||||
};
|
||||
case 4:
|
||||
return new string[] { "30", "60", "90"};
|
||||
case 5:
|
||||
string macro0 = SerialPortData.MacroTypes.readall.ToDescription();
|
||||
string macro1 = SerialPortData.MacroTypes.macro1.ToDescription();
|
||||
string macro2 = SerialPortData.MacroTypes.macro2.ToDescription();
|
||||
string macro3 = SerialPortData.MacroTypes.macro3.ToDescription();
|
||||
|
||||
return new string[] { macro0, macro1, macro2, macro3 };
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
@@ -60,12 +150,15 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
|
||||
public IComponentCfgCtrl GetControl(IList<Config.Entities.Component> cmpntEntities) { return new Configs.ParamsProvider.ComponentCfgCtrl(this, null); }
|
||||
|
||||
|
||||
|
||||
public void InitializeAll()
|
||||
{
|
||||
ComPortNr = 3;
|
||||
CliFileName = "HatCLI.exe";
|
||||
MeterType = 74;
|
||||
CliFileName = "HatCLI.exe";
|
||||
MeterType = SerialPortData.MeterProduct.Poseidon;
|
||||
HatType = SerialPortData.HatType.Mth;
|
||||
TimeOut = 30;
|
||||
MainMacro = SerialPortData.MacroTypes.readall.ToDescription();
|
||||
}
|
||||
|
||||
public bool ValidateParam(int i, string strValue, out string message)
|
||||
@@ -83,8 +176,17 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
if(System.Text.RegularExpressions.Regex.IsMatch(strValue, @"^[a-zA-Z0-9_-]+\.exe$")) return true; //validate exe file name
|
||||
break;
|
||||
case 2:
|
||||
if (TryParseMeter(strValue, out var meter)) return true;
|
||||
break;
|
||||
case 3:
|
||||
if (TryParseHatType(strValue, out var hatType)) return true;
|
||||
break;
|
||||
case 4:
|
||||
if (int.TryParse(strValue, out idummy) && idummy > 0) return true;
|
||||
break;
|
||||
case 5:
|
||||
if (TryParseMacro(strValue, out string macroType)) return true;
|
||||
break;
|
||||
default:
|
||||
message = "Invalid index";
|
||||
return false;
|
||||
@@ -100,11 +202,38 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
{
|
||||
case 0: ComPortNr = int.Parse(str); return CfgUpdateFlags.RestartRqrd;
|
||||
case 1: CliFileName = str; return CfgUpdateFlags.RestartRqrd;
|
||||
case 2: MeterType = int.Parse(str); return CfgUpdateFlags.RestartRqrd;
|
||||
case 2: TryParseMeter(str, out MeterType); return CfgUpdateFlags.RestartRqrd;
|
||||
case 3: TryParseHatType(str, out HatType); return CfgUpdateFlags.RestartRqrd;
|
||||
case 4: TimeOut = int.Parse(str); return CfgUpdateFlags.RestartRqrd;
|
||||
case 5: MainMacro = str; return CfgUpdateFlags.RestartRqrd;
|
||||
default: return CfgUpdateFlags.None;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool TryParseHatType(string description, out SerialPortData.HatType hatType)
|
||||
{
|
||||
var found = Enum.GetValues(typeof(SerialPortData.HatType))
|
||||
.Cast<SerialPortData.HatType>()
|
||||
.FirstOrDefault(e =>
|
||||
string.Equals(
|
||||
e.GetType()
|
||||
.GetField(e.ToString())
|
||||
.GetCustomAttribute<DescriptionAttribute>()
|
||||
?.Description,
|
||||
description,
|
||||
StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (!Equals(found, default(SerialPortData.HatType)) ||
|
||||
string.Equals(description, "Mth", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
hatType = found;
|
||||
return true;
|
||||
}
|
||||
|
||||
hatType = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool UpdateEmbeddedDbEntity()
|
||||
{
|
||||
return true; /// =OK, do nothing
|
||||
@@ -139,9 +268,12 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
case 0: return ComPortNr.ToString();
|
||||
case 1: return CliFileName;
|
||||
case 2: return MeterType.ToString();
|
||||
case 3: return HatType.ToString();
|
||||
case 4: return TimeOut.ToString();
|
||||
case 5: return MainMacro;
|
||||
default:
|
||||
return string.Format("{0}: Com{1}, CliName =`{2}`, MeterType = {3}",
|
||||
Name, ComPortNr, CliFileName, MeterType);
|
||||
return string.Format("{0}: Com{1}, CliName =`{2}`, MeterType = {3}, HatType = {4}, TimeOut = {5}",
|
||||
Name, ComPortNr, CliFileName, MeterType, HatType, TimeOut);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,6 +282,9 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
prms.ComPortNr = this.ComPortNr;
|
||||
prms.CliFileName = this.CliFileName;
|
||||
prms.MeterType = this.MeterType;
|
||||
prms.HatType = this.HatType;
|
||||
prms.TimeOut = this.TimeOut;
|
||||
prms.MainMacro = this.MainMacro;
|
||||
prms.ProcParams = this.ProcParams;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using TBF.Rig;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
{
|
||||
/// <summary>
|
||||
/// A single polling step for the Poseidon start/end read dialog.
|
||||
///
|
||||
/// A reader is armed only from None. In particular, a terminal reader
|
||||
/// must not be armed again: doing so starts a new CLI process on every
|
||||
/// polling iteration and leaves the dialog in Loading.
|
||||
/// </summary>
|
||||
public interface IPoseidonReadOperation
|
||||
{
|
||||
string Name { get; }
|
||||
bool IsNotStarted { get; }
|
||||
bool IsFinished { get; }
|
||||
bool HasError { get; }
|
||||
void Start(bool readStart);
|
||||
Event Run();
|
||||
}
|
||||
|
||||
public sealed class PoseidonReaderOperation : IPoseidonReadOperation
|
||||
{
|
||||
private readonly PoseidonReader reader;
|
||||
|
||||
public PoseidonReaderOperation(PoseidonReader reader)
|
||||
{
|
||||
if (reader == null) throw new ArgumentNullException(nameof(reader));
|
||||
this.reader = reader;
|
||||
}
|
||||
|
||||
public string Name { get { return reader.Name; } }
|
||||
public bool IsNotStarted { get { return reader.CurrentOp == PoseidonReader.CurrentPoseidonOp.None; } }
|
||||
public bool IsFinished
|
||||
{
|
||||
get
|
||||
{
|
||||
return reader.CurrentOp == PoseidonReader.CurrentPoseidonOp.Done ||
|
||||
reader.CurrentOp == PoseidonReader.CurrentPoseidonOp.Error;
|
||||
}
|
||||
}
|
||||
public bool HasError { get { return reader.CurrentOp == PoseidonReader.CurrentPoseidonOp.Error; } }
|
||||
public void Start(bool readStart)
|
||||
{
|
||||
reader.SetCurrentOp(readStart
|
||||
? PoseidonReader.CurrentPoseidonOp.ReadDataStream_Start
|
||||
: PoseidonReader.CurrentPoseidonOp.ReadDataStream_End);
|
||||
}
|
||||
public Event Run() { return reader.Run(); }
|
||||
}
|
||||
|
||||
public static class PoseidonReadCycle
|
||||
{
|
||||
public static bool RunIteration(IEnumerable<IPoseidonReadOperation> readers, bool readStart)
|
||||
{
|
||||
if (readers == null)
|
||||
return true;
|
||||
|
||||
bool allReadersFinished = true;
|
||||
foreach (IPoseidonReadOperation reader in readers)
|
||||
{
|
||||
if (reader == null)
|
||||
continue;
|
||||
|
||||
// None means that this dialog operation has not been started yet.
|
||||
// Done/Error are terminal and deliberately remain terminal.
|
||||
if (reader.IsNotStarted)
|
||||
reader.Start(readStart);
|
||||
|
||||
reader.Run();
|
||||
|
||||
if (!reader.IsFinished)
|
||||
allReadersFinished = false;
|
||||
}
|
||||
|
||||
return allReadersFinished;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Owns one logical dialog phase. A new phase must arm a reader even when
|
||||
/// the preceding phase left it in Done/Error; within this phase it is armed
|
||||
/// only once.
|
||||
/// </summary>
|
||||
public sealed class PoseidonReadPhaseRunner
|
||||
{
|
||||
private readonly bool readStart;
|
||||
private readonly HashSet<IPoseidonReadOperation> startedReaders =
|
||||
new HashSet<IPoseidonReadOperation>();
|
||||
|
||||
public PoseidonReadPhaseRunner(bool readStart)
|
||||
{
|
||||
this.readStart = readStart;
|
||||
}
|
||||
|
||||
public bool RunIteration(IEnumerable<IPoseidonReadOperation> readers)
|
||||
{
|
||||
if (readers == null)
|
||||
return true;
|
||||
|
||||
bool allReadersFinished = true;
|
||||
foreach (IPoseidonReadOperation reader in readers)
|
||||
{
|
||||
if (reader == null)
|
||||
continue;
|
||||
|
||||
if (startedReaders.Add(reader))
|
||||
reader.Start(readStart);
|
||||
|
||||
reader.Run();
|
||||
if (!reader.IsFinished)
|
||||
allReadersFinished = false;
|
||||
}
|
||||
|
||||
return allReadersFinished;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
///
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.IO.Ports;
|
||||
using System.Text.RegularExpressions;
|
||||
@@ -17,12 +18,16 @@ using TBF.Rig.Generic;
|
||||
using TBF.Rig.GenericDevices;
|
||||
using TBF.Rig.RegisterReaders.SerialStream;
|
||||
using TBF.Rig.RegisterReaders.StandingStartStop;
|
||||
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.common;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
{
|
||||
public class PoseidonReader : ComponentBase, IDevice, IRegReaderDatastream, ISessionDataMngmnt, IOperation
|
||||
public class PoseidonReader : ComponentBase, IDevice, IRegReaderDatastream, ISessionDataMngmnt, IOperation, ICommonRegReader
|
||||
{
|
||||
private static readonly ILog log = LogManager.GetLogger(typeof(PoseidonReader));
|
||||
// The simulator must never open the configured physical Hat CLI. The
|
||||
// deterministic test CLI returns a valid Poseidon JSON response instead.
|
||||
internal const string SimulatedCliFileName = "cmdSleepTest.exe";
|
||||
public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); }
|
||||
|
||||
readonly PoseidonCfg registerReaderCfg;
|
||||
@@ -134,10 +139,10 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
public int WMPulses { get { return wmPulses; } }
|
||||
public int WMRefPulses { get { return wmRefPulses; } }
|
||||
public double WMVolume { get { return wmVolume; } }
|
||||
public double BeginWMState { get { return beginWMState; } }
|
||||
public double EndWMState { get { return endWMState; } }
|
||||
public double BeginWMState { get { return beginWMState; } set { beginWMState = value;} }
|
||||
public double EndWMState { get { return endWMState; } set { endWMState = value;} }
|
||||
public double WMTestTime { get { return wmTestTime; } }
|
||||
public string SerialNr { get => wmSerialNr; }
|
||||
public string SerialNr { get => wmSerialNr; set => wmSerialNr = value; }
|
||||
|
||||
|
||||
double beginWMState;
|
||||
@@ -147,6 +152,8 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
int wmRefPulses;
|
||||
double wmTestTime;
|
||||
private string wmSerialNr;
|
||||
|
||||
int timeFromStart; /// [s] Time from test start to determine when the test start sample should be taken
|
||||
|
||||
|
||||
public IOperation ReadDatastreamOp()
|
||||
@@ -277,11 +284,23 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
if ((DebugLevel == DebugMode.Normal)||(DebugLevel == DebugMode.Simulate))
|
||||
{
|
||||
/// Prepare serial port
|
||||
string cliFileName = GetCliFileNameForMode(DebugLevel, registerReaderCfg.CliFileName);
|
||||
serialPort = new SerialPortData(string.Format("COM{0}", registerReaderCfg.ComPortNr),
|
||||
registerReaderCfg.CliFileName,
|
||||
registerReaderCfg.MeterType);
|
||||
cliFileName,
|
||||
registerReaderCfg.MeterType, //registerReaderCfg.MeterType, //MeterProduct.Poseidon
|
||||
registerReaderCfg.HatType,//HatType.Mth
|
||||
registerReaderCfg.TimeOut, //timeoutSeconds
|
||||
registerReaderCfg.MainMacro
|
||||
);
|
||||
|
||||
|
||||
if (DebugLevel == DebugMode.Simulate)
|
||||
{
|
||||
log.WarnFormat(
|
||||
"{0}: simulation mode enabled; overriding configured CLI '{1}' with '{2}'.",
|
||||
Name, registerReaderCfg.CliFileName, serialPort.SerialPortCmdClientPath);
|
||||
}
|
||||
|
||||
//TODO BUMI prepare serial port - for us do nothing
|
||||
//serialPort.Open();
|
||||
//we can check file program if exists
|
||||
@@ -302,6 +321,13 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
}
|
||||
}
|
||||
|
||||
internal static string GetCliFileNameForMode(DebugMode debugMode, string configuredCliFileName)
|
||||
{
|
||||
return debugMode == DebugMode.Simulate
|
||||
? SimulatedCliFileName
|
||||
: configuredCliFileName;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
log.DebugFormat("{0}:Clear()", Name);
|
||||
@@ -314,7 +340,7 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
|
||||
private void ReadPulses()
|
||||
{
|
||||
wmRefPulses = controlBoard.RefPulses;
|
||||
wmRefPulses = controlBoard?.RefPulses ?? 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -326,84 +352,291 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
/// <summary>
|
||||
/// for debug purposes what time will consume answer
|
||||
/// </summary>
|
||||
private long startTimeInMilis, fullTimeInMilis;
|
||||
private static long SafetyTimeOut = 30 * 1000; /// 30 seconds
|
||||
private long startTimeInMilis = -1, fullTimeInMilis = -1;
|
||||
/// 30 seconds
|
||||
private static long SafetyTimeOut = 30 * 1000;
|
||||
private long incommingTime = -1;
|
||||
private bool _lastOpTimedOut;
|
||||
private bool lastCliReadingParsed;
|
||||
private string lastCliReadFailureReason;
|
||||
private bool lastCliReadSucceeded;
|
||||
|
||||
|
||||
|
||||
public long DeltaTime { get{return fullTimeInMilis;}}
|
||||
public long IncommingTime { get{return incommingTime;}}
|
||||
public bool LastCliReadingParsed { get { return lastCliReadingParsed; } }
|
||||
public string LastCliReadFailureReason { get { return lastCliReadFailureReason; } }
|
||||
public bool LastCliReadSucceeded { get { return lastCliReadSucceeded; } }
|
||||
|
||||
/// <summary>Run this operation</summary>
|
||||
/// <returns>eventDone</returns>
|
||||
public Event Run()
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
timeFromStart += StateMachine.Period;
|
||||
ReadPulses();
|
||||
}
|
||||
|
||||
if (_currentOp == CurrentPoseidonOp.SendStartDataStream)
|
||||
{
|
||||
CliRunner.Clear();
|
||||
_lastOpTimedOut = false;
|
||||
CliRunner.AddSendAsync(serialPort, SerialPortData.EMeterArg.AllParams);
|
||||
return Event.Busy;
|
||||
_currentOp = CurrentPoseidonOp.SendStartDataStream_Runing;
|
||||
return Event.Busy;
|
||||
}
|
||||
else if (_currentOp == CurrentPoseidonOp.SendStartDataStream_Runing)
|
||||
{
|
||||
if (CliRunner.AreTasksDone()
|
||||
|| CliRunner.TimeOutReceived(SafetyTimeOut))
|
||||
if (CliRunner.AreTasksDone())
|
||||
{
|
||||
_currentOp = CurrentPoseidonOp.SendStartDataStream_Done;
|
||||
}
|
||||
return Event.Busy;
|
||||
else if (CliRunner.TimeOutReceived(SafetyTimeOut))
|
||||
{
|
||||
_lastOpTimedOut = true;
|
||||
CliRunner.CancelUndoneTasksAsTimedOut();
|
||||
_currentOp = CurrentPoseidonOp.SendStartDataStream_Done;
|
||||
}
|
||||
|
||||
return Event.Busy;
|
||||
}
|
||||
else if (_currentOp == CurrentPoseidonOp.SendStartDataStream_Done)
|
||||
{
|
||||
_currentOp = CurrentPoseidonOp.Done;
|
||||
var firstTaskInfo = CliRunner.TaskPool
|
||||
.FindLast(t => t.Task is Task<string> && t.UseResult);
|
||||
|
||||
if (firstTaskInfo != null)
|
||||
{
|
||||
var task = (Task<string>)firstTaskInfo.Task;
|
||||
string data = task.Result;
|
||||
|
||||
if (!string.IsNullOrEmpty(data))
|
||||
{
|
||||
TryGetDeviceId(data, out wmSerialNr);
|
||||
}
|
||||
}
|
||||
else if (_lastOpTimedOut)
|
||||
{
|
||||
log.Warn(
|
||||
$"PoseidonReader {Name}: SendStartDataStream timed out, no completed result will be used.");
|
||||
}
|
||||
|
||||
CliRunner.Clear();
|
||||
_currentOp = _lastOpTimedOut ? CurrentPoseidonOp.Error : CurrentPoseidonOp.Done;
|
||||
return Event.Done;
|
||||
}
|
||||
else if (_currentOp == CurrentPoseidonOp.ReadDataStream_Start
|
||||
else if (_currentOp == CurrentPoseidonOp.ReadDataStream_Start
|
||||
|| _currentOp == CurrentPoseidonOp.ReadDataStream_End)
|
||||
{
|
||||
startTimeInMilis = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
|
||||
lastCliReadingParsed = false;
|
||||
lastCliReadFailureReason = null;
|
||||
lastCliReadSucceeded = false;
|
||||
startTimeInMilis = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||
incommingTime = -1;
|
||||
_isReadingStart = (_currentOp == CurrentPoseidonOp.ReadDataStream_Start);
|
||||
CliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(serialPort, SerialPortData.EMeterArg.AllParams);
|
||||
|
||||
CliRunner.Clear();
|
||||
_lastOpTimedOut = false;
|
||||
log.DebugFormat("{0}: starting CLI read, direction={1}, path='{2}', args='{3}'",
|
||||
Name,
|
||||
_isReadingStart ? "start" : "end",
|
||||
serialPort == null ? "<not initialized>" : serialPort.SerialPortCmdClientPath,
|
||||
serialPort == null ? "<not initialized>" : serialPort.DefaultArgSettings(SerialPortData.EMeterArg.AllParams));
|
||||
CliRunner.AddRunAndCaptureJsonAsync<JsonDataFromPoseidon>(serialPort,
|
||||
SerialPortData.EMeterArg.AllParams);
|
||||
_currentOp = CurrentPoseidonOp.ReadDatastream_Running;
|
||||
return Event.Busy;
|
||||
}else if (_currentOp == CurrentPoseidonOp.ReadDatastream_Running)
|
||||
}
|
||||
else if (_currentOp == CurrentPoseidonOp.ReadDatastream_Running)
|
||||
{
|
||||
if (CliRunner.AreTasksDone()
|
||||
|| CliRunner.TimeOutReceived(SafetyTimeOut))
|
||||
if (CliRunner.AreTasksDone())
|
||||
{
|
||||
_currentOp = CurrentPoseidonOp.ReadDatastream_Done;
|
||||
incommingTime = CliRunner.IncommingTime;
|
||||
log.DebugFormat("{0}: CLI read task finished, taskCount={1}, incomingTime={2}",
|
||||
Name, CliRunner.TaskPool.Count, incommingTime);
|
||||
}
|
||||
else if (CliRunner.TimeOutReceived(SafetyTimeOut))
|
||||
{
|
||||
_lastOpTimedOut = true;
|
||||
CliRunner.CancelUndoneTasksAsTimedOut();
|
||||
_currentOp = CurrentPoseidonOp.ReadDatastream_Done;
|
||||
incommingTime = CliRunner.IncommingTime;
|
||||
}
|
||||
|
||||
return Event.Busy;
|
||||
}
|
||||
else if (_currentOp == CurrentPoseidonOp.ReadDatastream_Done)
|
||||
{
|
||||
fullTimeInMilis = (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - startTimeInMilis;
|
||||
log.Debug($"PoseidonReader.Run() Name= {Cfg.Name} fullTimeInMilis = {fullTimeInMilis} ");
|
||||
JsonDataFromPoseidon data = null;
|
||||
var first = CliRunner.TaskPool.FindLast(t => t is Task<JsonDataFromPoseidon>);
|
||||
if (first != null && first is Task<JsonDataFromPoseidon>)
|
||||
{
|
||||
data = (first as Task<JsonDataFromPoseidon>).Result;
|
||||
fullTimeInMilis = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() - startTimeInMilis;
|
||||
log.Debug($"PoseidonReader.Run() Name= {Cfg.Name} fullTimeInMilis = {fullTimeInMilis}");
|
||||
|
||||
if (data != null && Double.TryParse(data.Reading, out double Volume))
|
||||
JsonDataFromPoseidon data = null;
|
||||
|
||||
var firstTaskInfo = CliRunner.TaskPool
|
||||
.FindLast(t => t.Task is Task<JsonDataFromPoseidon> && t.UseResult);
|
||||
|
||||
if (firstTaskInfo != null)
|
||||
{
|
||||
var task = (Task<JsonDataFromPoseidon>)firstTaskInfo.Task;
|
||||
data = task.Result;
|
||||
if (data == null)
|
||||
{
|
||||
double VolumeLi = Units.ConvertFrom(Unit.USgal, Volume);
|
||||
//double VolumeM3 = Units.ConvertTo(Unit.m3, VolumeLi);
|
||||
if (_isReadingStart)
|
||||
lastCliReadFailureReason = firstTaskInfo.FailureReason ?? "CLI returned no Poseidon JSON data.";
|
||||
log.ErrorFormat("{0}: Poseidon {1} read failed. reason='{2}', exitCode={3}, stderr='{4}'",
|
||||
Name,
|
||||
_isReadingStart ? "Begin" : "End",
|
||||
lastCliReadFailureReason,
|
||||
firstTaskInfo.ExitCode,
|
||||
firstTaskInfo.StandardError);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var lastTaskInfo = CliRunner.TaskPool.FindLast(t => t.Task is Task<JsonDataFromPoseidon>);
|
||||
lastCliReadFailureReason = lastTaskInfo == null
|
||||
? "No CLI task was created."
|
||||
: lastTaskInfo.FailureReason ?? "CLI task was not usable, state=" + lastTaskInfo.State + ".";
|
||||
if (_lastOpTimedOut)
|
||||
{
|
||||
log.Warn($"PoseidonReader {Name}: ReadDatastream timed out, no completed result available. {lastCliReadFailureReason}");
|
||||
}
|
||||
else
|
||||
{
|
||||
log.Error($"PoseidonReader {Name}: no usable JsonDataFromPoseidon task. {lastCliReadFailureReason}");
|
||||
}
|
||||
}
|
||||
|
||||
if (data != null)
|
||||
{
|
||||
log.DebugFormat("{0}: CLI read result deviceId={1}, reading={2}, readingComplete={3}, nfcTagDetected={4}",
|
||||
Name, data.DeviceId, data.Reading, data.ReadingComplete, data.NfcTagDetected);
|
||||
string validationError;
|
||||
if (!TryValidateCliReadResponse(data, out validationError))
|
||||
{
|
||||
lastCliReadFailureReason = validationError;
|
||||
log.ErrorFormat("{0}: Poseidon {1} read rejected. {2}. Begin={3}, End={4}",
|
||||
Name, _isReadingStart ? "Begin" : "End", validationError, beginWMState, endWMState);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (string.IsNullOrEmpty(wmSerialNr))
|
||||
{
|
||||
try
|
||||
{
|
||||
//volume
|
||||
beginWMState = VolumeLi;
|
||||
wmSerialNr = data.DeviceId ?? wmSerialNr;
|
||||
}
|
||||
else
|
||||
catch (Exception e)
|
||||
{
|
||||
//volume
|
||||
endWMState = VolumeLi;
|
||||
log.Error("Serial Nr - parse error!", e);
|
||||
}
|
||||
}
|
||||
|
||||
double volumeLi;
|
||||
string dialogValueFailureReason;
|
||||
if (TryGetDialogValue(data, out volumeLi, out dialogValueFailureReason))
|
||||
{
|
||||
lastCliReadingParsed = true;
|
||||
lastCliReadSucceeded = true;
|
||||
double volume;
|
||||
TryParseCliReading(data.Reading, out volume);
|
||||
|
||||
if (_isReadingStart)
|
||||
beginWMState = volumeLi;
|
||||
else
|
||||
endWMState = volumeLi;
|
||||
|
||||
log.InfoFormat("{0}: Poseidon {1} value stored. deviceId={2}, rawReading='{3}', gallons={4}, litres={5}, Begin={6}, End={7}",
|
||||
Name, _isReadingStart ? "Begin" : "End", data.DeviceId, data.Reading, volume, volumeLi, beginWMState, endWMState);
|
||||
}
|
||||
else
|
||||
{
|
||||
lastCliReadFailureReason = dialogValueFailureReason;
|
||||
log.ErrorFormat("{0}: cannot parse CLI reading '{1}' using invariant or current culture.",
|
||||
Name, data.Reading);
|
||||
}
|
||||
}
|
||||
}
|
||||
_currentOp = CurrentPoseidonOp.Done;
|
||||
|
||||
CliRunner.Clear();
|
||||
_currentOp = _lastOpTimedOut ? CurrentPoseidonOp.Error : CurrentPoseidonOp.Done;
|
||||
return Event.Done;
|
||||
}
|
||||
|
||||
return Event.None;
|
||||
|
||||
return Event.None;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// CLI values must not depend on the Windows UI culture. Both dot and comma
|
||||
/// are accepted as a decimal separator and normalized before parsing.
|
||||
/// </summary>
|
||||
public static bool TryParseCliReading(string reading, out double value)
|
||||
{
|
||||
value = 0;
|
||||
if (String.IsNullOrWhiteSpace(reading))
|
||||
return false;
|
||||
|
||||
string normalizedReading = reading.Trim().Replace(',', '.');
|
||||
return Double.TryParse(normalizedReading, NumberStyles.Float, CultureInfo.InvariantCulture, out value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a validated CLI response to the value written into the
|
||||
/// start/end dialog. Poseidon reports US gallons; TBF stores litres.
|
||||
/// </summary>
|
||||
public static bool TryGetDialogValue(JsonDataFromPoseidon data, out double valueLitres,
|
||||
out string failureReason)
|
||||
{
|
||||
valueLitres = 0;
|
||||
if (!TryValidateCliReadResponse(data, out failureReason))
|
||||
return false;
|
||||
|
||||
double valueGallons;
|
||||
if (!TryParseCliReading(data.Reading, out valueGallons))
|
||||
{
|
||||
failureReason = "Reading could not be parsed: '" + data.Reading + "'.";
|
||||
return false;
|
||||
}
|
||||
|
||||
valueLitres = Units.ConvertFrom(Unit.USgal, valueGallons);
|
||||
failureReason = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool TryValidateCliReadResponse(JsonDataFromPoseidon data, out string failureReason)
|
||||
{
|
||||
if (data == null)
|
||||
{
|
||||
failureReason = "CLI returned no JSON data.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!data.NfcTagDetected)
|
||||
{
|
||||
failureReason = "NfcTagDetected=false.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!data.ReadingComplete)
|
||||
{
|
||||
failureReason = "ReadingComplete=false.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (String.IsNullOrWhiteSpace(data.Reading))
|
||||
{
|
||||
failureReason = "Reading is empty.";
|
||||
return false;
|
||||
}
|
||||
|
||||
failureReason = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>Stop this operation</summary>
|
||||
public void Stop()
|
||||
{
|
||||
@@ -457,34 +690,38 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
|
||||
public void StartSession()
|
||||
{
|
||||
|
||||
ValidateCliFileExistence(false);
|
||||
if (DebugLevel == DebugMode.Simulate)
|
||||
{
|
||||
wmSerialNr = "777321";
|
||||
}
|
||||
else
|
||||
{
|
||||
//TODO BUMI start session - CMD send data to Poseidon
|
||||
|
||||
CliRunner.AddSendAsync(serialPort, SerialPortData.EMeterArg.DeviceId);
|
||||
CliRunner.WaitAll();
|
||||
foreach (Task task in CliRunner.TaskPool)
|
||||
{
|
||||
if (task is Task<string>)
|
||||
{
|
||||
string result = (task as Task<string>).Result;
|
||||
if (TryGetDeviceId(result, out wmSerialNr))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CliRunner.Clear();
|
||||
}
|
||||
//this is no place to get device id
|
||||
}
|
||||
|
||||
// private void RetrieveDeviceIdFromResponse()
|
||||
// {
|
||||
// if (DebugLevel == DebugMode.Simulate)
|
||||
// {
|
||||
// wmSerialNr = "777321";
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// //TODO BUMI start session - CMD send data to Poseidon
|
||||
//
|
||||
// CliRunner.AddSendAsync(serialPort, SerialPortData.EMeterArg.DeviceId);
|
||||
// CliRunner.WaitAll();
|
||||
// foreach (Task task in CliRunner.TaskPool)
|
||||
// {
|
||||
// if (task is Task<string>)
|
||||
// {
|
||||
// string result = (task as Task<string>).Result;
|
||||
// if (TryGetDeviceId(result, out wmSerialNr))
|
||||
// {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// CliRunner.Clear();
|
||||
// }
|
||||
// }
|
||||
|
||||
private static readonly Regex DeviceIdRegex = new Regex(
|
||||
@"(?im)(?:" +
|
||||
@"^\s*Device\s*Id\s*:\s*([^\r\n]+)\s*$" + // old format
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
{
|
||||
public static class ProcessExtensions
|
||||
{
|
||||
public static Task WaitForExitAsync(this Process process, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (process == null) throw new ArgumentNullException(nameof(process));
|
||||
if (process.HasExited) return Task.CompletedTask;
|
||||
|
||||
var tcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
|
||||
EventHandler handler = null;
|
||||
handler = (s, e) =>
|
||||
{
|
||||
try { tcs.TrySetResult(null); }
|
||||
finally { process.Exited -= handler; }
|
||||
};
|
||||
|
||||
process.EnableRaisingEvents = true;
|
||||
process.Exited += handler;
|
||||
|
||||
if (cancellationToken.CanBeCanceled)
|
||||
{
|
||||
cancellationToken.Register(() =>
|
||||
{
|
||||
tcs.TrySetCanceled(cancellationToken);
|
||||
process.Exited -= handler;
|
||||
});
|
||||
}
|
||||
|
||||
return tcs.Task;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,15 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.ComponentModel;
|
||||
using System.Reflection;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
{
|
||||
public class SerialPortData
|
||||
{
|
||||
public const string CliDirectory = @"C:\TBF\Cli";
|
||||
|
||||
private Boolean? _cliExists;
|
||||
public bool CliExists { get {
|
||||
if (_cliExists == null || !_cliExists.HasValue)
|
||||
@@ -13,35 +18,245 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
}
|
||||
return _cliExists.Value;
|
||||
} }
|
||||
public string SerialPortCmdClientPath {
|
||||
get { return Path.Combine("..","Cli", CmdClientName);}
|
||||
}
|
||||
public string SerialPortCmdClientPath
|
||||
{
|
||||
get
|
||||
{
|
||||
// The configured value is a file name, not an executable path.
|
||||
// Keeping the CLI directory fixed prevents a bench configuration
|
||||
// from starting an unintended executable or failing due to a
|
||||
// relative path/current-directory change.
|
||||
string cliFileName = Path.GetFileName(CmdClientName);
|
||||
if (string.IsNullOrWhiteSpace(cliFileName))
|
||||
cliFileName = "HalCli.exe";
|
||||
|
||||
return Path.Combine(CliDirectory, cliFileName);
|
||||
}
|
||||
}
|
||||
public string CmdClientName { get; set; } = "HalCli.exe";
|
||||
public string PortName { get; set; }
|
||||
public int MeterType { get; set; }
|
||||
// Backward compatibility: old numeric meter type
|
||||
public int? OldMeterType { get; set; }
|
||||
|
||||
public enum EMeterArg {
|
||||
// New v2.0 parameters
|
||||
public HatType Hat { get; set; } = HatType.Mth;
|
||||
public int TimeoutSeconds { get; set; } = 10;
|
||||
public string Macro { get; set; } = "readall";
|
||||
|
||||
[XmlIgnore]
|
||||
public MeterProduct Meter { get; set; } = MeterProduct.Poseidon;
|
||||
|
||||
[XmlElement("MeterProduct")]
|
||||
public string MeterXml
|
||||
{
|
||||
get { return MeterToString(Meter); }
|
||||
set { Meter = StringToMeter(value); }
|
||||
}
|
||||
|
||||
public static string MeterToString(MeterProduct meter)
|
||||
{
|
||||
switch (meter)
|
||||
{
|
||||
case MeterProduct.Poseidon:
|
||||
return "Poseidon"; //Poseidon
|
||||
case MeterProduct.Ally:
|
||||
return "ally";
|
||||
case MeterProduct.IperlPlus:
|
||||
return "iperlplus";
|
||||
case MeterProduct.IperlLegacy:
|
||||
return "iperllegacy";
|
||||
default:
|
||||
return "74";
|
||||
}
|
||||
}
|
||||
|
||||
public static MeterProduct StringToMeter(string value)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
return MeterProduct.Poseidon;
|
||||
|
||||
// old numeric values: 74, 7889, etc.
|
||||
if (int.TryParse(value, out _))
|
||||
return MeterProduct.Poseidon;
|
||||
|
||||
if (string.Equals(value, "cTouchRead", StringComparison.OrdinalIgnoreCase))
|
||||
return MeterProduct.Poseidon;
|
||||
|
||||
if (string.Equals(value, "Poseidon", StringComparison.OrdinalIgnoreCase))
|
||||
return MeterProduct.Poseidon;
|
||||
|
||||
if (string.Equals(value, "ally", StringComparison.OrdinalIgnoreCase))
|
||||
return MeterProduct.Ally;
|
||||
|
||||
if (string.Equals(value, "iperlplus", StringComparison.OrdinalIgnoreCase))
|
||||
return MeterProduct.IperlPlus;
|
||||
|
||||
if (string.Equals(value, "iperllegacy", StringComparison.OrdinalIgnoreCase))
|
||||
return MeterProduct.IperlLegacy;
|
||||
|
||||
return MeterProduct.Poseidon;
|
||||
}
|
||||
|
||||
public static bool TryParseMeter(
|
||||
string description,
|
||||
out SerialPortData.MeterProduct meter)
|
||||
{
|
||||
foreach (SerialPortData.MeterProduct value in
|
||||
Enum.GetValues(typeof(SerialPortData.MeterProduct)))
|
||||
{
|
||||
var attr = value.GetType()
|
||||
.GetField(value.ToString())
|
||||
.GetCustomAttribute<DescriptionAttribute>();
|
||||
|
||||
if (string.Equals(attr?.Description, description, StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(value.ToString(), description, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
meter = value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
meter = SerialPortData.MeterProduct.Poseidon;
|
||||
return false;
|
||||
}
|
||||
|
||||
public enum MacroTypes
|
||||
{
|
||||
[Description("readall")]
|
||||
readall = 0,
|
||||
[Description("readmacro1")]
|
||||
macro1 = 1,
|
||||
[Description("readmacro2")]
|
||||
macro2 = 2,
|
||||
[Description("readmacro3")]
|
||||
macro3 = 3
|
||||
}
|
||||
|
||||
public enum HatType
|
||||
{
|
||||
[Description("Mth")]
|
||||
Mth = 0,
|
||||
[Description("Harry")]
|
||||
Harry = 1
|
||||
}
|
||||
|
||||
public enum MeterProduct
|
||||
{
|
||||
[Description("Poseidon")]
|
||||
[XmlEnum("74")]
|
||||
Poseidon = 74,
|
||||
|
||||
[Description("ally")]
|
||||
[XmlEnum("ally")]
|
||||
Ally = 75,
|
||||
|
||||
[Description("iperlplus")]
|
||||
[XmlEnum("iperlplus")]
|
||||
IperlPlus = 76,
|
||||
|
||||
[Description("iperllegacy")]
|
||||
[XmlEnum("iperllegacy")]
|
||||
IperlLegacy = 77
|
||||
}
|
||||
|
||||
public enum EMeterArg
|
||||
{
|
||||
Calibration = 0,
|
||||
AllParams = 2,
|
||||
DeviceId = 3,
|
||||
}
|
||||
EMeterArg _eMeterArg = EMeterArg.AllParams;
|
||||
|
||||
// New macro operations - just waste
|
||||
ReadMacro1 = 10,
|
||||
ReadMacro2 = 11,
|
||||
ReadMacro3 = 12
|
||||
}
|
||||
|
||||
public string DefaultArgSettings(EMeterArg eMeterArg)
|
||||
public string DefaultArgSettings(EMeterArg eMeterArg)
|
||||
{
|
||||
string commonArgs = BuildCommonArgs();
|
||||
|
||||
switch (eMeterArg)
|
||||
{
|
||||
case EMeterArg.Calibration:
|
||||
return $"-p {PortName} -m {MeterType} --operation write --parameter Calibration --value 1";
|
||||
case EMeterArg.AllParams:
|
||||
return $"-p {PortName} -m {MeterType} --operation readall";
|
||||
return $"{commonArgs} --operation write --parameter Calibration --value 1";
|
||||
|
||||
case EMeterArg.DeviceId:
|
||||
return $"-p {PortName} -m {MeterType} --operation read --parameter DeviceId";
|
||||
return $"{commonArgs} --operation read --parameter DeviceId";
|
||||
|
||||
case EMeterArg.AllParams:
|
||||
case EMeterArg.ReadMacro1:
|
||||
case EMeterArg.ReadMacro2:
|
||||
case EMeterArg.ReadMacro3:
|
||||
return $"{commonArgs} --operation {Macro}";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private string BuildCommonArgs()
|
||||
{
|
||||
return $"-p {PortName} " +
|
||||
$"-m {GetMeterArgument()} " +
|
||||
$"--hat {GetHatArgument()} " +
|
||||
$"--timeout {TimeoutSeconds}";
|
||||
}
|
||||
|
||||
private string GetMeterArgument()
|
||||
{
|
||||
// Old compatibility mode
|
||||
if (OldMeterType.HasValue)
|
||||
return OldMeterType.Value.ToString();
|
||||
|
||||
switch (Meter)
|
||||
{
|
||||
case MeterProduct.Poseidon:
|
||||
return "74"; //return "Poseidon";
|
||||
|
||||
case MeterProduct.Ally:
|
||||
return "ally";
|
||||
|
||||
case MeterProduct.IperlPlus:
|
||||
return "iperlplus";
|
||||
|
||||
case MeterProduct.IperlLegacy:
|
||||
return "iperllegacy";
|
||||
|
||||
default:
|
||||
return "74"; //return "Poseidon";
|
||||
}
|
||||
}
|
||||
|
||||
private string GetHatArgument()
|
||||
{
|
||||
switch (Hat)
|
||||
{
|
||||
case HatType.Harry:
|
||||
return "harry";
|
||||
|
||||
case HatType.Mth:
|
||||
default:
|
||||
return "mth";
|
||||
}
|
||||
}
|
||||
|
||||
// New constructor for v2.0
|
||||
public SerialPortData(
|
||||
string portName,
|
||||
string cmdClientName,
|
||||
MeterProduct meter = MeterProduct.Poseidon,
|
||||
HatType hat = HatType.Mth,
|
||||
int timeoutSeconds = 10,
|
||||
string macro = "readall")
|
||||
{
|
||||
PortName = portName;
|
||||
CmdClientName = cmdClientName;
|
||||
Meter = meter;
|
||||
Hat = hat;
|
||||
TimeoutSeconds = timeoutSeconds;
|
||||
Macro = macro;
|
||||
}
|
||||
|
||||
// Old constructor kept for backward compatibility
|
||||
public SerialPortData(
|
||||
string portName,
|
||||
string cmdClientName,
|
||||
@@ -49,7 +264,9 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
{
|
||||
PortName = portName;
|
||||
CmdClientName = cmdClientName;
|
||||
MeterType = meterType;
|
||||
OldMeterType = meterType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
using System.Collections.Generic;
|
||||
using TBF.Rig.Generic;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.PoseidonReader
|
||||
{
|
||||
public class Factory: IComponentFactory
|
||||
{
|
||||
public string ClassName { get { return this.GetType().Namespace.Substring(8); } }
|
||||
|
||||
public override string ToString() { return ClassName; }
|
||||
|
||||
public IComponent DummyComponent() { return new SmartReader(); }
|
||||
|
||||
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components) { return new SmartReader(cfg); }
|
||||
|
||||
public IComponentCfg DefaultConfig() { return new PoseidonCfg(this); }
|
||||
|
||||
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
|
||||
{
|
||||
return ComponentCfgBase.CreateFromDbEntity(PoseidonCfg.Serializer, component, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
+19
-14
@@ -12,19 +12,20 @@ using Sensus.iPerl.NfcHandler;
|
||||
using TBF.Rig.Generic;
|
||||
using TBF.Rig.GenericDevices;
|
||||
using TBF.Rig.TestMethods.iPerlCommunication.iPerlHead;
|
||||
using CalibrationStruct = TBF.Rig.RegisterReaders.iPerlReaderUNI.comminication.CalibrationStruct;
|
||||
using CalibrationStructV4 = TBF.Rig.RegisterReaders.iPerlReaderUNI.comminication.CalibrationStructV4;
|
||||
using CommunicationInterface = TBF.Rig.RegisterReaders.iPerlReaderUNI.comminication.CommunicationInterface;
|
||||
using ConfigStruct = TBF.Rig.RegisterReaders.iPerlReaderUNI.comminication.ConfigStruct;
|
||||
using MeterType = TBF.Rig.RegisterReaders.iPerlReaderUNI.comminication.MeterType;
|
||||
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.common;
|
||||
using CalibrationStruct = TBF.Rig.RegisterReaders.CommonRR.IPerl.communication.CalibrationStruct;
|
||||
using CalibrationStructV4 = TBF.Rig.RegisterReaders.CommonRR.IPerl.communication.CalibrationStructV4;
|
||||
using CommunicationInterface = TBF.Rig.RegisterReaders.CommonRR.CommunicationInterface;
|
||||
using ConfigStruct = TBF.Rig.RegisterReaders.CommonRR.IPerl.communication.ConfigStruct;
|
||||
using MeterType = TBF.Rig.RegisterReaders.CommonRR.MeterType;
|
||||
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.iPerlReaderUNI
|
||||
namespace TBF.Rig.RegisterReaders.PoseidonReader
|
||||
{
|
||||
/// <summary>
|
||||
/// based on IPerlReader class
|
||||
/// </summary>
|
||||
public class IPerlReader : ComponentBase, IDevice,IRegReaderDatastream, ISessionDataMngmnt, IOperation
|
||||
public class IPerlReader : ComponentBase, IDevice,IRegReaderDatastream, ISessionDataMngmnt, IOperation, IntIPerlReader
|
||||
{
|
||||
private static readonly ILog log = LogManager.GetLogger(typeof(IPerlReader));
|
||||
public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); }
|
||||
@@ -41,8 +42,9 @@ namespace TBF.Rig.RegisterReaders.iPerlReaderUNI
|
||||
public const int StartEndFilterSamplesCount2 = 20; /// StartEndFilterSamplesCount = 2 * StartEndFilterSamplesCount2 + 1
|
||||
public const int FeatureVectorSize = 9;
|
||||
|
||||
readonly IPerlCfg _iPerlCfg;
|
||||
readonly iPerlReaderUNI.IPerlCfg _iPerlCfg;
|
||||
|
||||
|
||||
public int RfidComPortNr { get { return _iPerlCfg.RfidComPortNr; } }
|
||||
public int OptoComPortNr { get { return _iPerlCfg.OptoComPortNr; } }
|
||||
public int MuxBoardNrOrGroup14 { get { return _iPerlCfg.MuxBoardNr; } }
|
||||
@@ -56,6 +58,8 @@ namespace TBF.Rig.RegisterReaders.iPerlReaderUNI
|
||||
public Counting InitFlowDir { get { return (_iPerlCfg != null && _iPerlCfg.ProcParams != null) ? _iPerlCfg.ProcParams.Counting : Counting.Arbitrary; } }
|
||||
|
||||
string simulatedPcbNr = null;
|
||||
public string Name { get; set; }
|
||||
|
||||
/// Properties set by the Begin and the End form
|
||||
public string SerialNr
|
||||
{
|
||||
@@ -75,7 +79,8 @@ namespace TBF.Rig.RegisterReaders.iPerlReaderUNI
|
||||
}
|
||||
|
||||
public bool Disabled;
|
||||
public bool CommFailed;
|
||||
public bool _commFailed;
|
||||
public bool CommFailed { get => _commFailed; set => _commFailed = value; }
|
||||
public int ResultCode;
|
||||
|
||||
|
||||
@@ -235,7 +240,7 @@ namespace TBF.Rig.RegisterReaders.iPerlReaderUNI
|
||||
public IPerlReader(Generic.IComponentCfg cfg)
|
||||
: base(cfg)
|
||||
{
|
||||
_iPerlCfg = cfg as IPerlCfg;
|
||||
_iPerlCfg = cfg as iPerlReaderUNI.IPerlCfg;
|
||||
}
|
||||
|
||||
|
||||
@@ -1373,7 +1378,7 @@ namespace TBF.Rig.RegisterReaders.iPerlReaderUNI
|
||||
if (reader.ReadBoolean()) (LastTestResult2 = new Results.Entities.MeterTestRslt()).ReadBinary(reader, null);
|
||||
}
|
||||
|
||||
internal void ResetNfcInterface(bool? nfc_on = null)
|
||||
public void ResetNfcInterface(bool? nfc_on = null)
|
||||
{
|
||||
if (_iPerlCfg.HeadCommunicationComPortNr == 0) return;
|
||||
|
||||
@@ -1387,17 +1392,17 @@ namespace TBF.Rig.RegisterReaders.iPerlReaderUNI
|
||||
_SERIAL_Driver_Head_Config.Dispose();
|
||||
}
|
||||
|
||||
internal void SetNfcInterface()
|
||||
public void SetNfcInterface()
|
||||
{
|
||||
ResetNfcInterface(true);
|
||||
}
|
||||
|
||||
internal void SetRfidInterface()
|
||||
public void SetRfidInterface()
|
||||
{
|
||||
ResetNfcInterface(false);
|
||||
}
|
||||
|
||||
internal void SetCommunicationInterface(CommunicationInterface commInterface)
|
||||
public void SetCommunicationInterface(CommunicationInterface commInterface)
|
||||
{
|
||||
//using (ISession session = TBF.DB.ConfigDBSessionFactory.OpenSession())
|
||||
// Replace the problematic line with the following code to fix the error:
|
||||
@@ -0,0 +1,71 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Serialization;
|
||||
using Common;
|
||||
using Config.Entities;
|
||||
using TBF.Rig.Generic;
|
||||
using TBF.Rig.RegisterReaders.CommonRR;
|
||||
using TBF.Rig.RegisterReaders.PoseidonReader.communication;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.PoseidonReader
|
||||
{
|
||||
[XmlRoot("PoseidonCfg")]
|
||||
public class PoseidonCfg : ComponentCfgBase, Generic.IComponentCfg
|
||||
{
|
||||
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(PoseidonCfg) })[0];
|
||||
public override XmlSerializer GetSerializer() { return Serializer; }
|
||||
public IComponentCfgCtrl GetControl(IList<Component> cmpntEntities)
|
||||
{
|
||||
return new PoseidonCfgCtrl();
|
||||
}
|
||||
|
||||
public static readonly string[] ValidMeterTypes = { "74", "touch" };
|
||||
|
||||
|
||||
|
||||
///
|
||||
/// Serialized parameters
|
||||
///
|
||||
public int HeadCommunicationComPortNr;
|
||||
public int OptoComPortNr;
|
||||
public int RfidComPortNr; /// 0 = use MuxBoardNr
|
||||
public ECommunicationInterface CommunicationInterface; /// Communication Interface: NFC, touch capl
|
||||
public string CliProgramName;
|
||||
public string CliMeterType;
|
||||
|
||||
|
||||
/// <summary> Procedure parameters </summary>
|
||||
[XmlIgnore]
|
||||
public ProcParams ProcParams;
|
||||
public override IParamsProvider GetRuntimeProcParamsProvider() { return ProcParams; }
|
||||
public override IParamsProvider CreateProcParamsProvider() { return new ProcParams(true); }
|
||||
|
||||
[XmlIgnore]
|
||||
public MeterType MeterType { get { return (ProcParams != null) ? ProcParams.MeterType : MeterType.AutoDetect; } }
|
||||
|
||||
|
||||
|
||||
|
||||
/// Private parameterless constructor invoked by all other (public) constructors
|
||||
PoseidonCfg()
|
||||
{
|
||||
Name = "PoseidonReader";
|
||||
ParentName = string.Empty;
|
||||
OptoComPortNr = 5;
|
||||
RfidComPortNr = 0; /// = use mux. board
|
||||
ProcParams = CreateProcParamsProvider() as ProcParams;
|
||||
CommunicationInterface = ECommunicationInterface.None;
|
||||
HeadCommunicationComPortNr = 0;
|
||||
}
|
||||
|
||||
public PoseidonCfg(IComponentFactory factory)
|
||||
: this()
|
||||
{
|
||||
this.Factory = factory;
|
||||
}
|
||||
|
||||
public string ToString(int i)
|
||||
{
|
||||
return $"{Name} Opto=Com{OptoComPortNr}, {CommunicationInterface}=Com{RfidComPortNr}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,273 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2017 Sensus Metering Systems
|
||||
///
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Ports;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Windows.Forms;
|
||||
using Common;
|
||||
using log4net;
|
||||
using TBF.Resources;
|
||||
using TBF.Rig.Generic;
|
||||
using TBF.Rig.RegisterReaders.CommonRR;
|
||||
using TBF.Rig.RegisterReaders.PoseidonReader.communication;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.PoseidonReader
|
||||
{
|
||||
public partial class PoseidonCfgCtrl : UserControl, IComponentCfgCtrl
|
||||
{
|
||||
private static readonly ILog log = LogManager.GetLogger(typeof(PoseidonCfgCtrl));
|
||||
public bool ShowMore { get { return false; } }
|
||||
|
||||
PoseidonCfg config;
|
||||
public IComponentCfg Config
|
||||
{
|
||||
get { return config as IComponentCfg; }
|
||||
set
|
||||
{
|
||||
config = value as PoseidonCfg;
|
||||
Redraw();
|
||||
}
|
||||
}
|
||||
|
||||
public PoseidonCfgCtrl()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
InitComPortsComboByList(listOfComPoertsComboBox, GetAvailableComPorts());
|
||||
InitComboByList(cliProgramComboBox, GetAvailableCliPrograms());
|
||||
InitComboByList(meterTypeComboBox, PoseidonCfg.ValidMeterTypes.ToList());
|
||||
InitComboByEnum<ECommunicationInterface>(comboBoxCommunicationInterface);
|
||||
}
|
||||
|
||||
private List<string> GetAvailableCliPrograms()
|
||||
{
|
||||
try
|
||||
{
|
||||
string cliDirectory = Path.Combine("c:/","TBF","Cli");
|
||||
List<string> availableCliPrograms =
|
||||
Directory.GetFiles(cliDirectory, "*.exe").Select(Path.GetFileName).ToList();
|
||||
if (availableCliPrograms.Count == 0)
|
||||
{
|
||||
availableCliPrograms.Add("None");
|
||||
labelMissingInfo.Text = $"* Missing CLI programs in {cliDirectory}!";
|
||||
}
|
||||
|
||||
return availableCliPrograms;
|
||||
}catch(Exception ex)
|
||||
{
|
||||
log.Error("Problem with get cli programs list!", ex);
|
||||
return new List<string> { "None" };
|
||||
}
|
||||
}
|
||||
|
||||
private void WaterMeterCfgCtrl_Load(object sender, EventArgs e)
|
||||
{
|
||||
nameLabel.Text = Strings.Name;
|
||||
classNameLabel.Text = config.Factory.ClassName;
|
||||
Redraw();
|
||||
}
|
||||
|
||||
public void Closing()
|
||||
{
|
||||
}
|
||||
|
||||
void Redraw()
|
||||
{
|
||||
if (config == null) return; /// Control was not loaded, settings were not changed
|
||||
nameTextBox.Text = config.Name;
|
||||
//radioButton1.Checked = config.UseTcpIP;
|
||||
//radioButton2.Checked = !config.UseTcpIP;
|
||||
//ipAddressTextBox.Text = (config.OptoIPAddress != null) ? config.OptoIPAddress : "0.0.0.0";
|
||||
//tcpipPortTextBox.Text = config.OptoTcpipPortNr.ToString();
|
||||
headPortNrTextBox.Text = config.HeadCommunicationComPortNr.ToString();
|
||||
optoSerialPortTextBox.Text = config.OptoComPortNr.ToString();
|
||||
rfidPortNrTextBox.Text = config.RfidComPortNr.ToString();
|
||||
//muxBoardNrTextBox.Text = config.MuxBoardNr.ToString();
|
||||
//groupTextBox.Text = config.Group.ToString();
|
||||
cliProgramComboBox.Text = config.CliProgramName;
|
||||
meterTypeComboBox.Text = config.CliMeterType;
|
||||
|
||||
comboBoxCommunicationInterface.Text = config.CommunicationInterface.ToDescription();
|
||||
tabPage2.Controls.Add(new UniHeadTestCtrl(config));
|
||||
}
|
||||
|
||||
public void Unlock()
|
||||
{
|
||||
nameTextBox.Enabled = true;
|
||||
//radioButton1.Enabled = true;
|
||||
//radioButton2.Enabled = true;
|
||||
//ipAddressTextBox.Enabled = true;
|
||||
//tcpipPortTextBox.Enabled = true;
|
||||
optoSerialPortTextBox.Enabled = true;
|
||||
rfidPortNrTextBox.Enabled = true;
|
||||
headPortNrTextBox.Enabled = true;
|
||||
//muxBoardNrTextBox.Enabled = true;
|
||||
//groupTextBox.Enabled = true;
|
||||
comboBoxCommunicationInterface.Enabled = true;
|
||||
cliProgramComboBox.Enabled = true;
|
||||
meterTypeComboBox.Enabled = true;
|
||||
listOfComPoertsComboBox.Enabled = true;
|
||||
button_refreshComPorts.Enabled = true;
|
||||
}
|
||||
|
||||
public CfgUpdateFlags VerifyCfg(ref string message)
|
||||
{
|
||||
CfgUpdateFlags flags = CfgUpdateFlags.None;
|
||||
|
||||
int dummy;
|
||||
|
||||
if (!int.TryParse(optoSerialPortTextBox.Text, out dummy) || dummy < 1 || dummy > 999)
|
||||
{
|
||||
flags |= CfgUpdateFlags.Error;
|
||||
message += Environment.NewLine + "'Opto serial port nr.' is not valid";
|
||||
}
|
||||
|
||||
if (!int.TryParse(rfidPortNrTextBox.Text, out dummy) || dummy < 0 || dummy > 999)
|
||||
{
|
||||
flags |= CfgUpdateFlags.Error;
|
||||
message += Environment.NewLine + "'RFID serial port nr.' is not valid";
|
||||
}
|
||||
|
||||
if (!int.TryParse(headPortNrTextBox.Text, out dummy) || dummy < 0 || dummy > 999)
|
||||
{
|
||||
flags |= CfgUpdateFlags.Error;
|
||||
message += Environment.NewLine + "'Head communication serial port nr.' is not valid";
|
||||
}
|
||||
|
||||
if (!ValidateEnumInput<ECommunicationInterface>(comboBoxCommunicationInterface))
|
||||
{
|
||||
flags |= CfgUpdateFlags.Error;
|
||||
message += Environment.NewLine + "'Not a valid communication interface'";
|
||||
}
|
||||
|
||||
if (!IsValidProgramName(cliProgramComboBox.Text))
|
||||
{
|
||||
flags |= CfgUpdateFlags.Error;
|
||||
message += Environment.NewLine + "'Not a valid CLI program name'";
|
||||
}
|
||||
|
||||
if (!IsValidCliMeterType(meterTypeComboBox.Text))
|
||||
{
|
||||
flags |= CfgUpdateFlags.Error;
|
||||
message += Environment.NewLine + "'Not a valid CLI meter type'";
|
||||
}
|
||||
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
private bool ValidateEnumInput<T>(ComboBox comboBox) where T : Enum
|
||||
{
|
||||
if (comboBox.SelectedItem == null)
|
||||
return false;
|
||||
|
||||
T selectedInterface;
|
||||
|
||||
// Check if SelectedItem is already of type T
|
||||
if (comboBox.SelectedItem is T enumValueT)
|
||||
{
|
||||
selectedInterface = enumValueT;
|
||||
}
|
||||
// Otherwise, try to parse it as a string
|
||||
else
|
||||
{
|
||||
string selectedText = comboBox.Text;
|
||||
foreach (T enumValue in Enum.GetValues(typeof(T)))
|
||||
{
|
||||
if (enumValue.ToDescription() == selectedText)
|
||||
{
|
||||
selectedInterface = enumValue;
|
||||
return !selectedInterface.Equals(Enum.ToObject(typeof(T), 0));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the selected value is not the default (zero) value
|
||||
return !selectedInterface.Equals(Enum.ToObject(typeof(T), 0));
|
||||
}
|
||||
|
||||
|
||||
private bool IsValidCliMeterType(string text)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(text))
|
||||
return false;
|
||||
|
||||
return int.TryParse(text, out _) || PoseidonCfg.ValidMeterTypes.Contains(text);
|
||||
}
|
||||
|
||||
public CfgUpdateFlags UpdateCfg()
|
||||
{
|
||||
CfgUpdateFlags flags = CfgUpdateFlags.RestartRqrd;
|
||||
|
||||
if (config == null) return CfgUpdateFlags.Error; /// Control was not loaded, settings were not changed
|
||||
|
||||
config.Name = nameTextBox.Text;
|
||||
config.OptoComPortNr = int.Parse(optoSerialPortTextBox.Text);
|
||||
config.RfidComPortNr = int.Parse(rfidPortNrTextBox.Text);
|
||||
config.CommunicationInterface = (ECommunicationInterface)(comboBoxCommunicationInterface.SelectedIndex);
|
||||
config.HeadCommunicationComPortNr = int.Parse(headPortNrTextBox.Text);
|
||||
config.CliProgramName = cliProgramComboBox.Text;
|
||||
config.CliMeterType = meterTypeComboBox.Text;
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private string[] GetAvailableComPorts()
|
||||
{
|
||||
string[] ports = SerialPort.GetPortNames();
|
||||
return ports;
|
||||
}
|
||||
|
||||
private void InitComboByList(ComboBox comboBox, List<string> list)
|
||||
{
|
||||
comboBox.Items.Clear();
|
||||
comboBox.Items.Add("..");
|
||||
comboBox.Items.AddRange(list.ToArray());
|
||||
comboBox.SelectedIndex = 0;
|
||||
}
|
||||
|
||||
private void InitComboByEnum<T>(ComboBox comboBox) where T : Enum
|
||||
{
|
||||
comboBox.Items.Clear();
|
||||
comboBox.Items.AddRange(Enum.GetValues(typeof(T)).Cast<T>().Select(x => x.ToDescription()).ToArray());
|
||||
if (comboBox.Text == "")
|
||||
{
|
||||
comboBox.SelectedIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void InitComPortsComboByList(ComboBox comboBox, string[] list)
|
||||
{
|
||||
comboBox.Items.Clear();
|
||||
comboBox.Items.Add("List of ports ..");
|
||||
if( list.Length <= 0)
|
||||
comboBox.Items.Add("None");
|
||||
else
|
||||
{
|
||||
comboBox.Items.AddRange(list);
|
||||
}
|
||||
comboBox.SelectedIndex = 0;
|
||||
}
|
||||
|
||||
private void buttonRefreshComPorts_Click(object sender, EventArgs e)
|
||||
{
|
||||
button_refreshComPorts.Enabled = false;
|
||||
InitComPortsComboByList(listOfComPoertsComboBox, GetAvailableComPorts());
|
||||
button_refreshComPorts.Enabled = true;
|
||||
}
|
||||
|
||||
private bool IsValidProgramName(string programName)
|
||||
{
|
||||
return !string.IsNullOrWhiteSpace(programName)
|
||||
&& Regex.IsMatch(programName, @"^[^\\/:*?""<>|]+\.exe$", RegexOptions.IgnoreCase);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,401 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2017 Sensus Metering Systems
|
||||
///
|
||||
namespace TBF.Rig.RegisterReaders.PoseidonReader
|
||||
{
|
||||
partial class PoseidonCfgCtrl
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.tabControl1 = new System.Windows.Forms.TabControl();
|
||||
this.tabPage1 = new System.Windows.Forms.TabPage();
|
||||
this.groupBox3 = new System.Windows.Forms.GroupBox();
|
||||
this.button_refreshComPorts = new System.Windows.Forms.Button();
|
||||
this.label3 = new System.Windows.Forms.Label();
|
||||
this.listOfComPoertsComboBox = new System.Windows.Forms.ComboBox();
|
||||
this.groupBox2 = new System.Windows.Forms.GroupBox();
|
||||
this.headPortNrTextBox = new System.Windows.Forms.TextBox();
|
||||
this.label2 = new System.Windows.Forms.Label();
|
||||
this.groupBox1 = new System.Windows.Forms.GroupBox();
|
||||
this.labelMissingInfo = new System.Windows.Forms.Label();
|
||||
this.labelMeterType = new System.Windows.Forms.Label();
|
||||
this.meterTypeComboBox = new System.Windows.Forms.ComboBox();
|
||||
this.cliProgramComboBox = new System.Windows.Forms.ComboBox();
|
||||
this.labelCliProgramName = new System.Windows.Forms.Label();
|
||||
this.comboBoxCommunicationInterface = new System.Windows.Forms.ComboBox();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.rfidPortNrTextBox = new System.Windows.Forms.TextBox();
|
||||
this.rfidSerialPortNrLabel = new System.Windows.Forms.Label();
|
||||
this.optoDataGroupBox = new System.Windows.Forms.GroupBox();
|
||||
this.optoSerialPortLabel = new System.Windows.Forms.Label();
|
||||
this.optoSerialPortTextBox = new System.Windows.Forms.TextBox();
|
||||
this.nameTextBox = new System.Windows.Forms.TextBox();
|
||||
this.nameLabel = new System.Windows.Forms.Label();
|
||||
this.classNameLabel = new System.Windows.Forms.Label();
|
||||
this.tabPage2 = new System.Windows.Forms.TabPage();
|
||||
this.tabControl1.SuspendLayout();
|
||||
this.tabPage1.SuspendLayout();
|
||||
this.groupBox3.SuspendLayout();
|
||||
this.groupBox2.SuspendLayout();
|
||||
this.groupBox1.SuspendLayout();
|
||||
this.optoDataGroupBox.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// tabControl1
|
||||
//
|
||||
this.tabControl1.Controls.Add(this.tabPage1);
|
||||
this.tabControl1.Controls.Add(this.tabPage2);
|
||||
this.tabControl1.Location = new System.Drawing.Point(3, 4);
|
||||
this.tabControl1.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
this.tabControl1.Name = "tabControl1";
|
||||
this.tabControl1.SelectedIndex = 0;
|
||||
this.tabControl1.Size = new System.Drawing.Size(687, 540);
|
||||
this.tabControl1.TabIndex = 0;
|
||||
//
|
||||
// tabPage1
|
||||
//
|
||||
this.tabPage1.Controls.Add(this.groupBox3);
|
||||
this.tabPage1.Controls.Add(this.groupBox2);
|
||||
this.tabPage1.Controls.Add(this.groupBox1);
|
||||
this.tabPage1.Controls.Add(this.optoDataGroupBox);
|
||||
this.tabPage1.Controls.Add(this.nameTextBox);
|
||||
this.tabPage1.Controls.Add(this.nameLabel);
|
||||
this.tabPage1.Controls.Add(this.classNameLabel);
|
||||
this.tabPage1.Location = new System.Drawing.Point(4, 29);
|
||||
this.tabPage1.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
this.tabPage1.Name = "tabPage1";
|
||||
this.tabPage1.Padding = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
this.tabPage1.Size = new System.Drawing.Size(679, 507);
|
||||
this.tabPage1.TabIndex = 0;
|
||||
this.tabPage1.Text = "Config";
|
||||
this.tabPage1.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// groupBox3
|
||||
//
|
||||
this.groupBox3.Controls.Add(this.button_refreshComPorts);
|
||||
this.groupBox3.Controls.Add(this.label3);
|
||||
this.groupBox3.Controls.Add(this.listOfComPoertsComboBox);
|
||||
this.groupBox3.Location = new System.Drawing.Point(11, 99);
|
||||
this.groupBox3.Name = "groupBox3";
|
||||
this.groupBox3.Size = new System.Drawing.Size(620, 59);
|
||||
this.groupBox3.TabIndex = 27;
|
||||
this.groupBox3.TabStop = false;
|
||||
this.groupBox3.Text = "Ports Overview ";
|
||||
//
|
||||
// button_refreshComPorts
|
||||
//
|
||||
this.button_refreshComPorts.Enabled = false;
|
||||
this.button_refreshComPorts.Location = new System.Drawing.Point(466, 17);
|
||||
this.button_refreshComPorts.Name = "button_refreshComPorts";
|
||||
this.button_refreshComPorts.Size = new System.Drawing.Size(77, 33);
|
||||
this.button_refreshComPorts.TabIndex = 29;
|
||||
this.button_refreshComPorts.Text = "Refresh";
|
||||
this.button_refreshComPorts.UseVisualStyleBackColor = true;
|
||||
this.button_refreshComPorts.Click += new System.EventHandler(this.buttonRefreshComPorts_Click);
|
||||
//
|
||||
// label3
|
||||
//
|
||||
this.label3.Location = new System.Drawing.Point(46, 23);
|
||||
this.label3.Name = "label3";
|
||||
this.label3.Size = new System.Drawing.Size(149, 26);
|
||||
this.label3.TabIndex = 28;
|
||||
this.label3.Text = "Available ports:";
|
||||
//
|
||||
// listOfComPoertsComboBox
|
||||
//
|
||||
this.listOfComPoertsComboBox.FormattingEnabled = true;
|
||||
this.listOfComPoertsComboBox.Location = new System.Drawing.Point(234, 20);
|
||||
this.listOfComPoertsComboBox.Name = "listOfComPoertsComboBox";
|
||||
this.listOfComPoertsComboBox.Size = new System.Drawing.Size(202, 28);
|
||||
this.listOfComPoertsComboBox.TabIndex = 27;
|
||||
//
|
||||
// groupBox2
|
||||
//
|
||||
this.groupBox2.Controls.Add(this.headPortNrTextBox);
|
||||
this.groupBox2.Controls.Add(this.label2);
|
||||
this.groupBox2.Location = new System.Drawing.Point(11, 425);
|
||||
this.groupBox2.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
this.groupBox2.Name = "groupBox2";
|
||||
this.groupBox2.Padding = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
this.groupBox2.Size = new System.Drawing.Size(621, 62);
|
||||
this.groupBox2.TabIndex = 26;
|
||||
this.groupBox2.TabStop = false;
|
||||
this.groupBox2.Text = "Head Communication";
|
||||
//
|
||||
// headPortNrTextBox
|
||||
//
|
||||
this.headPortNrTextBox.Enabled = false;
|
||||
this.headPortNrTextBox.Location = new System.Drawing.Point(494, 19);
|
||||
this.headPortNrTextBox.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
|
||||
this.headPortNrTextBox.Name = "headPortNrTextBox";
|
||||
this.headPortNrTextBox.Size = new System.Drawing.Size(49, 26);
|
||||
this.headPortNrTextBox.TabIndex = 8;
|
||||
//
|
||||
// label2
|
||||
//
|
||||
this.label2.AutoSize = true;
|
||||
this.label2.Location = new System.Drawing.Point(361, 22);
|
||||
this.label2.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.label2.Name = "label2";
|
||||
this.label2.Size = new System.Drawing.Size(107, 20);
|
||||
this.label2.TabIndex = 7;
|
||||
this.label2.Text = "Serial port nr.:";
|
||||
//
|
||||
// groupBox1
|
||||
//
|
||||
this.groupBox1.Controls.Add(this.labelMissingInfo);
|
||||
this.groupBox1.Controls.Add(this.labelMeterType);
|
||||
this.groupBox1.Controls.Add(this.meterTypeComboBox);
|
||||
this.groupBox1.Controls.Add(this.cliProgramComboBox);
|
||||
this.groupBox1.Controls.Add(this.labelCliProgramName);
|
||||
this.groupBox1.Controls.Add(this.comboBoxCommunicationInterface);
|
||||
this.groupBox1.Controls.Add(this.label1);
|
||||
this.groupBox1.Controls.Add(this.rfidPortNrTextBox);
|
||||
this.groupBox1.Controls.Add(this.rfidSerialPortNrLabel);
|
||||
this.groupBox1.Location = new System.Drawing.Point(11, 249);
|
||||
this.groupBox1.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
|
||||
this.groupBox1.Name = "groupBox1";
|
||||
this.groupBox1.Padding = new System.Windows.Forms.Padding(4, 5, 4, 5);
|
||||
this.groupBox1.Size = new System.Drawing.Size(621, 167);
|
||||
this.groupBox1.TabIndex = 23;
|
||||
this.groupBox1.TabStop = false;
|
||||
this.groupBox1.Text = "RFID / NFC communication (in case mux. board is not used)";
|
||||
//
|
||||
// labelMissingInfo
|
||||
//
|
||||
this.labelMissingInfo.ForeColor = System.Drawing.Color.OrangeRed;
|
||||
this.labelMissingInfo.Location = new System.Drawing.Point(49, 138);
|
||||
this.labelMissingInfo.Name = "labelMissingInfo";
|
||||
this.labelMissingInfo.Size = new System.Drawing.Size(550, 24);
|
||||
this.labelMissingInfo.TabIndex = 14;
|
||||
this.labelMissingInfo.Text = "*";
|
||||
this.labelMissingInfo.Visible = false;
|
||||
//
|
||||
// labelMeterType
|
||||
//
|
||||
this.labelMeterType.Location = new System.Drawing.Point(46, 103);
|
||||
this.labelMeterType.Name = "labelMeterType";
|
||||
this.labelMeterType.Size = new System.Drawing.Size(149, 27);
|
||||
this.labelMeterType.TabIndex = 13;
|
||||
this.labelMeterType.Text = "Meter Type: ";
|
||||
//
|
||||
// meterTypeComboBox
|
||||
//
|
||||
this.meterTypeComboBox.Enabled = false;
|
||||
this.meterTypeComboBox.FormattingEnabled = true;
|
||||
this.meterTypeComboBox.Location = new System.Drawing.Point(234, 103);
|
||||
this.meterTypeComboBox.Name = "meterTypeComboBox";
|
||||
this.meterTypeComboBox.Size = new System.Drawing.Size(127, 28);
|
||||
this.meterTypeComboBox.TabIndex = 12;
|
||||
//
|
||||
// cliProgramComboBox
|
||||
//
|
||||
this.cliProgramComboBox.Enabled = false;
|
||||
this.cliProgramComboBox.FormattingEnabled = true;
|
||||
this.cliProgramComboBox.Location = new System.Drawing.Point(234, 69);
|
||||
this.cliProgramComboBox.Name = "cliProgramComboBox";
|
||||
this.cliProgramComboBox.Size = new System.Drawing.Size(127, 28);
|
||||
this.cliProgramComboBox.TabIndex = 11;
|
||||
//
|
||||
// labelCliProgramName
|
||||
//
|
||||
this.labelCliProgramName.Location = new System.Drawing.Point(46, 71);
|
||||
this.labelCliProgramName.Name = "labelCliProgramName";
|
||||
this.labelCliProgramName.Size = new System.Drawing.Size(146, 22);
|
||||
this.labelCliProgramName.TabIndex = 10;
|
||||
this.labelCliProgramName.Text = "Cli program name: ";
|
||||
//
|
||||
// comboBoxCommunicationInterface
|
||||
//
|
||||
this.comboBoxCommunicationInterface.Enabled = false;
|
||||
this.comboBoxCommunicationInterface.FormattingEnabled = true;
|
||||
this.comboBoxCommunicationInterface.Items.AddRange(new object[] { "Nfc", "Touch" });
|
||||
this.comboBoxCommunicationInterface.Location = new System.Drawing.Point(234, 34);
|
||||
this.comboBoxCommunicationInterface.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
this.comboBoxCommunicationInterface.Name = "comboBoxCommunicationInterface";
|
||||
this.comboBoxCommunicationInterface.Size = new System.Drawing.Size(79, 28);
|
||||
this.comboBoxCommunicationInterface.TabIndex = 9;
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Location = new System.Drawing.Point(46, 38);
|
||||
this.label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(187, 20);
|
||||
this.label1.TabIndex = 8;
|
||||
this.label1.Text = "Communication Interface";
|
||||
//
|
||||
// rfidPortNrTextBox
|
||||
//
|
||||
this.rfidPortNrTextBox.Enabled = false;
|
||||
this.rfidPortNrTextBox.Location = new System.Drawing.Point(494, 32);
|
||||
this.rfidPortNrTextBox.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
|
||||
this.rfidPortNrTextBox.Name = "rfidPortNrTextBox";
|
||||
this.rfidPortNrTextBox.Size = new System.Drawing.Size(49, 26);
|
||||
this.rfidPortNrTextBox.TabIndex = 7;
|
||||
//
|
||||
// rfidSerialPortNrLabel
|
||||
//
|
||||
this.rfidSerialPortNrLabel.AutoSize = true;
|
||||
this.rfidSerialPortNrLabel.Location = new System.Drawing.Point(361, 38);
|
||||
this.rfidSerialPortNrLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.rfidSerialPortNrLabel.Name = "rfidSerialPortNrLabel";
|
||||
this.rfidSerialPortNrLabel.Size = new System.Drawing.Size(107, 20);
|
||||
this.rfidSerialPortNrLabel.TabIndex = 6;
|
||||
this.rfidSerialPortNrLabel.Text = "Serial port nr.:";
|
||||
//
|
||||
// optoDataGroupBox
|
||||
//
|
||||
this.optoDataGroupBox.Controls.Add(this.optoSerialPortLabel);
|
||||
this.optoDataGroupBox.Controls.Add(this.optoSerialPortTextBox);
|
||||
this.optoDataGroupBox.Location = new System.Drawing.Point(11, 170);
|
||||
this.optoDataGroupBox.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
|
||||
this.optoDataGroupBox.Name = "optoDataGroupBox";
|
||||
this.optoDataGroupBox.Padding = new System.Windows.Forms.Padding(4, 5, 4, 5);
|
||||
this.optoDataGroupBox.Size = new System.Drawing.Size(621, 68);
|
||||
this.optoDataGroupBox.TabIndex = 18;
|
||||
this.optoDataGroupBox.TabStop = false;
|
||||
this.optoDataGroupBox.Text = "Opto-data";
|
||||
//
|
||||
// optoSerialPortLabel
|
||||
//
|
||||
this.optoSerialPortLabel.AutoSize = true;
|
||||
this.optoSerialPortLabel.Location = new System.Drawing.Point(361, 26);
|
||||
this.optoSerialPortLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.optoSerialPortLabel.Name = "optoSerialPortLabel";
|
||||
this.optoSerialPortLabel.Size = new System.Drawing.Size(107, 20);
|
||||
this.optoSerialPortLabel.TabIndex = 6;
|
||||
this.optoSerialPortLabel.Text = "Serial port nr.:";
|
||||
//
|
||||
// optoSerialPortTextBox
|
||||
//
|
||||
this.optoSerialPortTextBox.Enabled = false;
|
||||
this.optoSerialPortTextBox.Location = new System.Drawing.Point(494, 22);
|
||||
this.optoSerialPortTextBox.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
|
||||
this.optoSerialPortTextBox.Name = "optoSerialPortTextBox";
|
||||
this.optoSerialPortTextBox.Size = new System.Drawing.Size(49, 26);
|
||||
this.optoSerialPortTextBox.TabIndex = 7;
|
||||
//
|
||||
// nameTextBox
|
||||
//
|
||||
this.nameTextBox.Enabled = false;
|
||||
this.nameTextBox.Location = new System.Drawing.Point(172, 50);
|
||||
this.nameTextBox.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
|
||||
this.nameTextBox.Name = "nameTextBox";
|
||||
this.nameTextBox.Size = new System.Drawing.Size(180, 26);
|
||||
this.nameTextBox.TabIndex = 17;
|
||||
//
|
||||
// nameLabel
|
||||
//
|
||||
this.nameLabel.AutoSize = true;
|
||||
this.nameLabel.Location = new System.Drawing.Point(7, 55);
|
||||
this.nameLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.nameLabel.Name = "nameLabel";
|
||||
this.nameLabel.Size = new System.Drawing.Size(51, 20);
|
||||
this.nameLabel.TabIndex = 16;
|
||||
this.nameLabel.Text = "Name";
|
||||
//
|
||||
// classNameLabel
|
||||
//
|
||||
this.classNameLabel.AutoSize = true;
|
||||
this.classNameLabel.Location = new System.Drawing.Point(168, 14);
|
||||
this.classNameLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.classNameLabel.Name = "classNameLabel";
|
||||
this.classNameLabel.Size = new System.Drawing.Size(90, 20);
|
||||
this.classNameLabel.TabIndex = 15;
|
||||
this.classNameLabel.Text = "ClassName";
|
||||
//
|
||||
// tabPage2
|
||||
//
|
||||
this.tabPage2.Location = new System.Drawing.Point(4, 29);
|
||||
this.tabPage2.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
this.tabPage2.Name = "tabPage2";
|
||||
this.tabPage2.Padding = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
this.tabPage2.Size = new System.Drawing.Size(679, 507);
|
||||
this.tabPage2.TabIndex = 1;
|
||||
this.tabPage2.Text = "Test";
|
||||
this.tabPage2.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// PoseidonCfgCtrl
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 20F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.Controls.Add(this.tabControl1);
|
||||
this.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
|
||||
this.Name = "PoseidonCfgCtrl";
|
||||
this.Size = new System.Drawing.Size(694, 548);
|
||||
this.Load += new System.EventHandler(this.WaterMeterCfgCtrl_Load);
|
||||
this.tabControl1.ResumeLayout(false);
|
||||
this.tabPage1.ResumeLayout(false);
|
||||
this.tabPage1.PerformLayout();
|
||||
this.groupBox3.ResumeLayout(false);
|
||||
this.groupBox2.ResumeLayout(false);
|
||||
this.groupBox2.PerformLayout();
|
||||
this.groupBox1.ResumeLayout(false);
|
||||
this.groupBox1.PerformLayout();
|
||||
this.optoDataGroupBox.ResumeLayout(false);
|
||||
this.optoDataGroupBox.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
}
|
||||
|
||||
private System.Windows.Forms.Label labelMissingInfo;
|
||||
|
||||
private System.Windows.Forms.GroupBox groupBox3;
|
||||
private System.Windows.Forms.Button button_refreshComPorts;
|
||||
|
||||
private System.Windows.Forms.ComboBox listOfComPoertsComboBox;
|
||||
private System.Windows.Forms.Label label3;
|
||||
|
||||
private System.Windows.Forms.ComboBox cliProgramComboBox;
|
||||
private System.Windows.Forms.ComboBox meterTypeComboBox;
|
||||
|
||||
private System.Windows.Forms.Label labelCliProgramName;
|
||||
|
||||
private System.Windows.Forms.Label labelMeterType;
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.TabControl tabControl1;
|
||||
private System.Windows.Forms.TabPage tabPage1;
|
||||
private System.Windows.Forms.GroupBox groupBox1;
|
||||
private System.Windows.Forms.ComboBox comboBoxCommunicationInterface;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.TextBox rfidPortNrTextBox;
|
||||
private System.Windows.Forms.Label rfidSerialPortNrLabel;
|
||||
private System.Windows.Forms.GroupBox optoDataGroupBox;
|
||||
private System.Windows.Forms.Label optoSerialPortLabel;
|
||||
private System.Windows.Forms.TextBox optoSerialPortTextBox;
|
||||
private System.Windows.Forms.TextBox nameTextBox;
|
||||
private System.Windows.Forms.Label nameLabel;
|
||||
private System.Windows.Forms.Label classNameLabel;
|
||||
private System.Windows.Forms.TabPage tabPage2;
|
||||
private System.Windows.Forms.GroupBox groupBox2;
|
||||
private System.Windows.Forms.TextBox headPortNrTextBox;
|
||||
private System.Windows.Forms.Label label2;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
@@ -0,0 +1,137 @@
|
||||
namespace TBF.Rig.RegisterReaders.PoseidonReader
|
||||
{
|
||||
partial class PoseidonHeadTestCtrl
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.optoTestGroupBox = new System.Windows.Forms.GroupBox();
|
||||
this.optoListBox = new System.Windows.Forms.ListBox();
|
||||
this.rfidOutputListBox = new System.Windows.Forms.ListBox();
|
||||
this.RfidTestGroupBox = new System.Windows.Forms.GroupBox();
|
||||
this.label2 = new System.Windows.Forms.Label();
|
||||
this.rfidCommandComboBox = new System.Windows.Forms.ComboBox();
|
||||
this.commandTestButton = new System.Windows.Forms.Button();
|
||||
this.optoTestGroupBox.SuspendLayout();
|
||||
this.RfidTestGroupBox.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// optoTestGroupBox
|
||||
//
|
||||
this.optoTestGroupBox.Controls.Add(this.optoListBox);
|
||||
this.optoTestGroupBox.Location = new System.Drawing.Point(5, 4);
|
||||
this.optoTestGroupBox.Name = "optoTestGroupBox";
|
||||
this.optoTestGroupBox.Size = new System.Drawing.Size(591, 161);
|
||||
this.optoTestGroupBox.TabIndex = 2;
|
||||
this.optoTestGroupBox.TabStop = false;
|
||||
this.optoTestGroupBox.Text = "Opto-data";
|
||||
//
|
||||
// optoListBox
|
||||
//
|
||||
this.optoListBox.FormattingEnabled = true;
|
||||
this.optoListBox.ItemHeight = 16;
|
||||
this.optoListBox.Location = new System.Drawing.Point(7, 22);
|
||||
this.optoListBox.Name = "optoListBox";
|
||||
this.optoListBox.Size = new System.Drawing.Size(573, 132);
|
||||
this.optoListBox.TabIndex = 0;
|
||||
//
|
||||
// rfidOutputListBox
|
||||
//
|
||||
this.rfidOutputListBox.FormattingEnabled = true;
|
||||
this.rfidOutputListBox.ItemHeight = 16;
|
||||
this.rfidOutputListBox.Location = new System.Drawing.Point(5, 54);
|
||||
this.rfidOutputListBox.Name = "rfidOutputListBox";
|
||||
this.rfidOutputListBox.SelectionMode = System.Windows.Forms.SelectionMode.None;
|
||||
this.rfidOutputListBox.Size = new System.Drawing.Size(575, 164);
|
||||
this.rfidOutputListBox.TabIndex = 3;
|
||||
//
|
||||
// RfidTestGroupBox
|
||||
//
|
||||
this.RfidTestGroupBox.Controls.Add(this.rfidOutputListBox);
|
||||
this.RfidTestGroupBox.Controls.Add(this.label2);
|
||||
this.RfidTestGroupBox.Controls.Add(this.rfidCommandComboBox);
|
||||
this.RfidTestGroupBox.Controls.Add(this.commandTestButton);
|
||||
this.RfidTestGroupBox.Location = new System.Drawing.Point(5, 171);
|
||||
this.RfidTestGroupBox.Name = "RfidTestGroupBox";
|
||||
this.RfidTestGroupBox.Size = new System.Drawing.Size(591, 224);
|
||||
this.RfidTestGroupBox.TabIndex = 3;
|
||||
this.RfidTestGroupBox.TabStop = false;
|
||||
this.RfidTestGroupBox.Text = "RFID / NFC data";
|
||||
//
|
||||
// label2
|
||||
//
|
||||
this.label2.AutoSize = true;
|
||||
this.label2.Location = new System.Drawing.Point(2, 25);
|
||||
this.label2.Name = "label2";
|
||||
this.label2.Size = new System.Drawing.Size(69, 16);
|
||||
this.label2.TabIndex = 2;
|
||||
this.label2.Text = "Command";
|
||||
//
|
||||
// rfidCommandComboBox
|
||||
//
|
||||
this.rfidCommandComboBox.FormattingEnabled = true;
|
||||
this.rfidCommandComboBox.Location = new System.Drawing.Point(86, 19);
|
||||
this.rfidCommandComboBox.Name = "rfidCommandComboBox";
|
||||
this.rfidCommandComboBox.Size = new System.Drawing.Size(341, 24);
|
||||
this.rfidCommandComboBox.TabIndex = 1;
|
||||
//
|
||||
// commandTestButton
|
||||
//
|
||||
this.commandTestButton.Location = new System.Drawing.Point(449, 19);
|
||||
this.commandTestButton.Name = "commandTestButton";
|
||||
this.commandTestButton.Size = new System.Drawing.Size(126, 24);
|
||||
this.commandTestButton.TabIndex = 0;
|
||||
this.commandTestButton.Text = "Send command";
|
||||
this.commandTestButton.UseVisualStyleBackColor = true;
|
||||
this.commandTestButton.MouseClick += new System.Windows.Forms.MouseEventHandler(this.CommandTestButtonClick);
|
||||
//
|
||||
// IperlHeadTestCtrl
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.Controls.Add(this.optoTestGroupBox);
|
||||
this.Controls.Add(this.RfidTestGroupBox);
|
||||
this.Name = "PoseidonHeadTestCtrl";
|
||||
this.Size = new System.Drawing.Size(611, 432);
|
||||
this.Load += new System.EventHandler(this.UserControl_Load);
|
||||
this.optoTestGroupBox.ResumeLayout(false);
|
||||
this.RfidTestGroupBox.ResumeLayout(false);
|
||||
this.RfidTestGroupBox.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.GroupBox optoTestGroupBox;
|
||||
private System.Windows.Forms.ListBox rfidOutputListBox;
|
||||
private System.Windows.Forms.GroupBox RfidTestGroupBox;
|
||||
private System.Windows.Forms.Label label2;
|
||||
private System.Windows.Forms.ComboBox rfidCommandComboBox;
|
||||
private System.Windows.Forms.Button commandTestButton;
|
||||
private System.Windows.Forms.ListBox optoListBox;
|
||||
}
|
||||
}
|
||||
+29
-28
@@ -2,22 +2,23 @@ using System;
|
||||
using System.Threading;
|
||||
using System.Web.UI.WebControls;
|
||||
using System.Windows.Forms;
|
||||
using TBF.Rig.RegisterReaders.iPerlReaderUNI.comminication;
|
||||
using TBF.Rig.RegisterReaders.CommonRR.IPerl.communication;
|
||||
using TBF.Rig.RegisterReaders.iPerlReaderUNI.test;
|
||||
using TBF.Rig.Sequences;
|
||||
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.common;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.iPerlReaderUNI
|
||||
namespace TBF.Rig.RegisterReaders.PoseidonReader
|
||||
{
|
||||
public partial class IperlHeadTestCtrl : UserControl
|
||||
public partial class PoseidonHeadTestCtrl : UserControl
|
||||
{
|
||||
IPerlCfg config;
|
||||
IPerlReader _iPerlReader;
|
||||
PoseidonCfg config;
|
||||
ISmartReader _iSmartReader;
|
||||
Thread optoThread;
|
||||
|
||||
private bool stopWorkerThread;
|
||||
public event EventHandler<OptoReceivedEventArgs> OptoReceivedHandler;
|
||||
|
||||
public IperlHeadTestCtrl(IPerlCfg config)
|
||||
public PoseidonHeadTestCtrl(PoseidonCfg config)
|
||||
{
|
||||
this.config = config;
|
||||
InitializeComponent();
|
||||
@@ -26,9 +27,9 @@ namespace TBF.Rig.RegisterReaders.iPerlReaderUNI
|
||||
//TODO fix possibility set test method in config
|
||||
//iPerlCommunicationForm.cfg = new TestMethodCfg(null); // default values for iPerlCommunication
|
||||
|
||||
foreach(var head in ProcessData.IperlHeadsUni)
|
||||
foreach(var head in ProcessData.SmartHeadsUni)
|
||||
{
|
||||
if (head != null && head.Name == config.Name) { _iPerlReader = head; }
|
||||
if (head != null && head.Name == config.Name) { _iSmartReader = head; }
|
||||
}
|
||||
|
||||
rfidCommandComboBox.DisplayMember = "Name";
|
||||
@@ -84,32 +85,32 @@ namespace TBF.Rig.RegisterReaders.iPerlReaderUNI
|
||||
switch (rfidCommandComboBox.SelectedValue)
|
||||
{
|
||||
case "ReadPCB":
|
||||
rfidListItem.Text = $"PCB: {OpticalHeadTest.ReadRequest_PCB(_iPerlReader)}";
|
||||
// rfidListItem.Text = $"PCB: {OpticalHeadTest.ReadRequest_PCB(_iPerlReader)}";
|
||||
break;
|
||||
case "SetTestMode":
|
||||
rfidListItem.Text = OpticalHeadTest.SetTestMode(_iPerlReader);
|
||||
optoListBox.Items.Clear();
|
||||
stopWorkerThread = false;
|
||||
optoThread = new Thread(OptoWorker);
|
||||
if (!optoThread.IsAlive)
|
||||
{
|
||||
_iPerlReader.StartDataStreamProcessing(); // open opto port
|
||||
optoThread.Start();
|
||||
}
|
||||
// rfidListItem.Text = OpticalHeadTest.SetTestMode(_iPerlReader);
|
||||
// optoListBox.Items.Clear();
|
||||
// stopWorkerThread = false;
|
||||
// optoThread = new Thread(OptoWorker);
|
||||
// if (!optoThread.IsAlive)
|
||||
// {
|
||||
// _iPerlReader.StartDataStreamProcessing(); // open opto port
|
||||
// optoThread.Start();
|
||||
// }
|
||||
break;
|
||||
case "SetActiveMode":
|
||||
rfidListItem.Text = OpticalHeadTest.SetActiveMode(_iPerlReader);
|
||||
stopWorkerThread = true;
|
||||
_iPerlReader.StopDataStreamProcessing(); // close opto port
|
||||
// rfidListItem.Text = OpticalHeadTest.SetActiveMode(_iPerlReader);
|
||||
// stopWorkerThread = true;
|
||||
// _iPerlReader.StopDataStreamProcessing(); // close opto port
|
||||
break;
|
||||
case "ResetNfcHead":
|
||||
_iPerlReader.ResetNfcInterface();
|
||||
_iSmartReader.ResetNfcInterface();
|
||||
break;
|
||||
case "SetNfcHead":
|
||||
_iPerlReader.SetNfcInterface();
|
||||
_iSmartReader.SetNfcInterface();
|
||||
break;
|
||||
case "SetRfidHead":
|
||||
_iPerlReader.SetRfidInterface();
|
||||
_iSmartReader.SetRfidInterface();
|
||||
break;
|
||||
case "ReadOptoData":
|
||||
optoListBox.Items.Clear();
|
||||
@@ -118,17 +119,17 @@ namespace TBF.Rig.RegisterReaders.iPerlReaderUNI
|
||||
if (optoThread.IsAlive)
|
||||
{
|
||||
stopWorkerThread = true;
|
||||
_iPerlReader.StopDataStreamProcessing(); // close opto port
|
||||
_iSmartReader.StopDataStreamProcessing(); // close opto port
|
||||
}
|
||||
if (!optoThread.IsAlive)
|
||||
{
|
||||
_iPerlReader.StartDataStreamProcessing(); // open opto port
|
||||
_iSmartReader.StartDataStreamProcessing(); // open opto port
|
||||
optoThread.Start();
|
||||
}
|
||||
break;
|
||||
case "StopReadOptoData":
|
||||
stopWorkerThread = true;
|
||||
_iPerlReader.StopDataStreamProcessing(); // close opto port
|
||||
_iSmartReader.StopDataStreamProcessing(); // close opto port
|
||||
break;
|
||||
}
|
||||
rfidOutputListBox.Items.Add(rfidListItem);
|
||||
@@ -146,7 +147,7 @@ namespace TBF.Rig.RegisterReaders.iPerlReaderUNI
|
||||
|
||||
try
|
||||
{
|
||||
string buffer = _iPerlReader.ReadOptoData();
|
||||
string buffer = _iSmartReader.ReadOptoData();
|
||||
if (string.IsNullOrEmpty(buffer))
|
||||
{
|
||||
this.OnOptoReceived((object)this, new OptoReceivedEventArgs("."));
|
||||
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
@@ -0,0 +1,184 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Xml.Serialization;
|
||||
using Common;
|
||||
using Config.Entities;
|
||||
using TBF.Rig.Generic;
|
||||
using TBF.Rig.RegisterReaders.CommonRR;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.PoseidonReader
|
||||
{
|
||||
public class ProcParams : ProcedureParamsBase, IParamsProvider, IProcedureParams
|
||||
{
|
||||
|
||||
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(ProcParams) })[0];
|
||||
public override XmlSerializer GetSerializer() { return Serializer; }
|
||||
|
||||
public int WMType_ID;
|
||||
public MeterType MeterType;
|
||||
public float CalibTarget; /// Target error after calibration in [%]
|
||||
public int FactorLimitLo; /// Lower limit for the calibration factor
|
||||
public int FactorLimitHi; /// Upper limit for the calibration factor
|
||||
public Counting Counting; /// Initial iPerl counting (Artbitrary, Positive or Negative)
|
||||
|
||||
|
||||
public override void InitializeAll()
|
||||
{
|
||||
MeterType = MeterType.AutoDetect;
|
||||
CalibTarget = 0;
|
||||
FactorLimitLo = 1000;
|
||||
FactorLimitHi = 8000;
|
||||
Counting = Counting.Arbitrary;
|
||||
}
|
||||
|
||||
string[] paramNames = new string[]
|
||||
{
|
||||
"iPerl type",
|
||||
"Calib. target [%]",
|
||||
"Calib. factor Lo",
|
||||
"Calib. factor Hi",
|
||||
"Counting",
|
||||
};
|
||||
public override string ParamName(int i) { return paramNames[i]; }
|
||||
public override int ParamsCount() { return paramNames.Length; }
|
||||
|
||||
public override ICollection<string> ParamValues(int i)
|
||||
{
|
||||
if (i == 0)
|
||||
{
|
||||
var retVal = new List<string>();
|
||||
for (MeterType mt = 0; mt < MeterType.Count; mt++) retVal.Add(mt.ToString());
|
||||
return retVal;
|
||||
}
|
||||
else if (i == 5)
|
||||
{
|
||||
var retVal = new List<string>();
|
||||
for (Counting c = 0; c < Counting.Count; c++) retVal.Add(c.ToString());
|
||||
return retVal;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public override string ToString(int i)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0: return MeterType.ToString();
|
||||
case 1: return CalibTarget.ToString();
|
||||
case 2: return FactorLimitLo.ToString();
|
||||
case 3: return FactorLimitHi.ToString();
|
||||
case 4: return Counting.ToString();
|
||||
default: return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//implement IParamsProvider
|
||||
public bool ValidateParam(int i, string strValue, out string message)
|
||||
{
|
||||
message = string.Empty;
|
||||
|
||||
int iDummy;
|
||||
float fDummy;
|
||||
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
for (MeterType mt = 0; mt < MeterType.Count; mt++) if (mt.ToString().Equals(strValue)) return true;
|
||||
break;
|
||||
case 1:
|
||||
if (Utils.TryParseSFloat(strValue, out fDummy) && fDummy >= -10.0f && fDummy <= 10.0f) return true;
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
if (int.TryParse(strValue, out iDummy) && iDummy >= 1000 && iDummy <= 8000) return true;
|
||||
break;
|
||||
case 4:
|
||||
for (Counting c = 0; c < Counting.Count; c++) if (c.ToString().Equals(strValue)) return true;
|
||||
break;
|
||||
default:
|
||||
message = "Invalid index";
|
||||
return false;
|
||||
}
|
||||
|
||||
message = ParamName(i) + " is invalid";
|
||||
return false;
|
||||
}
|
||||
|
||||
public CfgUpdateFlags UpdateParam(int i, string strValue)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
for (MeterType mt = 0; mt < MeterType.Count; mt++)
|
||||
{
|
||||
if (mt.ToString().Equals(strValue)) { MeterType = mt; return CfgUpdateFlags.None; }
|
||||
}
|
||||
break;
|
||||
case 1: CalibTarget = Utils.ParseSFloat(strValue); return CfgUpdateFlags.None;
|
||||
case 2: FactorLimitLo = int.Parse(strValue); return CfgUpdateFlags.None;
|
||||
case 3: FactorLimitHi = int.Parse(strValue); return CfgUpdateFlags.None;
|
||||
case 4:
|
||||
for (Counting c = 0; c < Counting.Count; c++)
|
||||
{
|
||||
if (c.ToString().Equals(strValue)) { Counting = c; return CfgUpdateFlags.None; }
|
||||
}
|
||||
break;
|
||||
default: return CfgUpdateFlags.None;
|
||||
}
|
||||
|
||||
return CfgUpdateFlags.None;
|
||||
}
|
||||
|
||||
void CopyContentTo(ProcParams prms)
|
||||
{
|
||||
prms.MeterType = this.MeterType;
|
||||
prms.CalibTarget = this.CalibTarget;
|
||||
prms.FactorLimitLo = this.FactorLimitLo;
|
||||
prms.FactorLimitHi = this.FactorLimitHi;
|
||||
prms.Counting = this.Counting;
|
||||
}
|
||||
|
||||
public IParamsProvider Clone()
|
||||
{
|
||||
ProcParams pars = new ProcParams();
|
||||
CopyContentTo(pars);
|
||||
return pars;
|
||||
}
|
||||
|
||||
public override void UpdateFromDbEntity(ComponentProcedure dbEntity)
|
||||
{
|
||||
if (dbEntity == null) return;
|
||||
try
|
||||
{
|
||||
ProcParams tmp = Serializer.Deserialize(new StringReader(dbEntity.Parameters)) as ProcParams;
|
||||
|
||||
procedureParamsEntity = dbEntity;
|
||||
componentName = dbEntity.CmpntName;
|
||||
procedure = dbEntity.Procedure;
|
||||
|
||||
if (tmp != null) tmp.CopyContentTo(this);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public ProcParams()
|
||||
{
|
||||
}
|
||||
|
||||
public ProcParams(bool initialize)
|
||||
{
|
||||
if (initialize) InitializeAll();
|
||||
}
|
||||
|
||||
public ProcParams(ComponentProcedure procParamsEntity, string componentName, Procedure procedure)
|
||||
{
|
||||
this.procedureParamsEntity = procParamsEntity;
|
||||
this.componentName = componentName;
|
||||
this.procedure = procedure;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
+5
-3
@@ -1,17 +1,19 @@
|
||||
///
|
||||
/// Copyright (c) 2015-2021 Sensus Slovensko a.s.
|
||||
///
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO.Ports;
|
||||
using System.Threading;
|
||||
using System.Xml.Serialization;
|
||||
using Common;
|
||||
using Config.Entities;
|
||||
using TBF.Rig.Generic;
|
||||
using TBF.Rig.TestMethods.SmartTest;
|
||||
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication;
|
||||
|
||||
namespace TBF.Rig.TestMethods.iPerlCommunication
|
||||
namespace TBF.Rig.RegisterReaders.PoseidonReader
|
||||
{
|
||||
public class TestMethodCfg : ComponentCfgBase, Generic.IComponentCfg
|
||||
public class TestMethodCfg : ComponentCfgBase, IComponentCfg
|
||||
{
|
||||
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(TestMethodCfg) })[0];
|
||||
public override XmlSerializer GetSerializer() { return Serializer; }
|
||||
@@ -0,0 +1,137 @@
|
||||
namespace TBF.Rig.RegisterReaders.PoseidonReader
|
||||
{
|
||||
partial class UniHeadTestCtrl
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.optoTestGroupBox = new System.Windows.Forms.GroupBox();
|
||||
this.optoListBox = new System.Windows.Forms.ListBox();
|
||||
this.rfidOutputListBox = new System.Windows.Forms.ListBox();
|
||||
this.RfidTestGroupBox = new System.Windows.Forms.GroupBox();
|
||||
this.label2 = new System.Windows.Forms.Label();
|
||||
this.rfidCommandComboBox = new System.Windows.Forms.ComboBox();
|
||||
this.commandTestButton = new System.Windows.Forms.Button();
|
||||
this.optoTestGroupBox.SuspendLayout();
|
||||
this.RfidTestGroupBox.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// optoTestGroupBox
|
||||
//
|
||||
this.optoTestGroupBox.Controls.Add(this.optoListBox);
|
||||
this.optoTestGroupBox.Location = new System.Drawing.Point(5, 4);
|
||||
this.optoTestGroupBox.Name = "optoTestGroupBox";
|
||||
this.optoTestGroupBox.Size = new System.Drawing.Size(591, 161);
|
||||
this.optoTestGroupBox.TabIndex = 2;
|
||||
this.optoTestGroupBox.TabStop = false;
|
||||
this.optoTestGroupBox.Text = "Opto-data";
|
||||
//
|
||||
// optoListBox
|
||||
//
|
||||
this.optoListBox.FormattingEnabled = true;
|
||||
this.optoListBox.ItemHeight = 16;
|
||||
this.optoListBox.Location = new System.Drawing.Point(7, 22);
|
||||
this.optoListBox.Name = "optoListBox";
|
||||
this.optoListBox.Size = new System.Drawing.Size(573, 132);
|
||||
this.optoListBox.TabIndex = 0;
|
||||
//
|
||||
// rfidOutputListBox
|
||||
//
|
||||
this.rfidOutputListBox.FormattingEnabled = true;
|
||||
this.rfidOutputListBox.ItemHeight = 16;
|
||||
this.rfidOutputListBox.Location = new System.Drawing.Point(5, 54);
|
||||
this.rfidOutputListBox.Name = "rfidOutputListBox";
|
||||
this.rfidOutputListBox.SelectionMode = System.Windows.Forms.SelectionMode.None;
|
||||
this.rfidOutputListBox.Size = new System.Drawing.Size(575, 164);
|
||||
this.rfidOutputListBox.TabIndex = 3;
|
||||
//
|
||||
// RfidTestGroupBox
|
||||
//
|
||||
this.RfidTestGroupBox.Controls.Add(this.rfidOutputListBox);
|
||||
this.RfidTestGroupBox.Controls.Add(this.label2);
|
||||
this.RfidTestGroupBox.Controls.Add(this.rfidCommandComboBox);
|
||||
this.RfidTestGroupBox.Controls.Add(this.commandTestButton);
|
||||
this.RfidTestGroupBox.Location = new System.Drawing.Point(5, 171);
|
||||
this.RfidTestGroupBox.Name = "RfidTestGroupBox";
|
||||
this.RfidTestGroupBox.Size = new System.Drawing.Size(591, 224);
|
||||
this.RfidTestGroupBox.TabIndex = 3;
|
||||
this.RfidTestGroupBox.TabStop = false;
|
||||
this.RfidTestGroupBox.Text = "RFID / NFC data";
|
||||
//
|
||||
// label2
|
||||
//
|
||||
this.label2.AutoSize = true;
|
||||
this.label2.Location = new System.Drawing.Point(2, 25);
|
||||
this.label2.Name = "label2";
|
||||
this.label2.Size = new System.Drawing.Size(69, 16);
|
||||
this.label2.TabIndex = 2;
|
||||
this.label2.Text = "Command";
|
||||
//
|
||||
// rfidCommandComboBox
|
||||
//
|
||||
this.rfidCommandComboBox.FormattingEnabled = true;
|
||||
this.rfidCommandComboBox.Location = new System.Drawing.Point(86, 19);
|
||||
this.rfidCommandComboBox.Name = "rfidCommandComboBox";
|
||||
this.rfidCommandComboBox.Size = new System.Drawing.Size(341, 24);
|
||||
this.rfidCommandComboBox.TabIndex = 1;
|
||||
//
|
||||
// commandTestButton
|
||||
//
|
||||
this.commandTestButton.Location = new System.Drawing.Point(449, 19);
|
||||
this.commandTestButton.Name = "commandTestButton";
|
||||
this.commandTestButton.Size = new System.Drawing.Size(126, 24);
|
||||
this.commandTestButton.TabIndex = 0;
|
||||
this.commandTestButton.Text = "Send command";
|
||||
this.commandTestButton.UseVisualStyleBackColor = true;
|
||||
this.commandTestButton.MouseClick += new System.Windows.Forms.MouseEventHandler(this.CommandTestButtonClick);
|
||||
//
|
||||
// IperlHeadTestCtrl
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.Controls.Add(this.optoTestGroupBox);
|
||||
this.Controls.Add(this.RfidTestGroupBox);
|
||||
this.Name = "UniHeadTestCtrl";
|
||||
this.Size = new System.Drawing.Size(611, 432);
|
||||
this.Load += new System.EventHandler(this.UserControl_Load);
|
||||
this.optoTestGroupBox.ResumeLayout(false);
|
||||
this.RfidTestGroupBox.ResumeLayout(false);
|
||||
this.RfidTestGroupBox.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.GroupBox optoTestGroupBox;
|
||||
private System.Windows.Forms.ListBox rfidOutputListBox;
|
||||
private System.Windows.Forms.GroupBox RfidTestGroupBox;
|
||||
private System.Windows.Forms.Label label2;
|
||||
private System.Windows.Forms.ComboBox rfidCommandComboBox;
|
||||
private System.Windows.Forms.Button commandTestButton;
|
||||
private System.Windows.Forms.ListBox optoListBox;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using log4net;
|
||||
using TBF.Rig.RegisterReaders.CommonRR.IPerl.communication;
|
||||
using TBF.Rig.RegisterReaders.iPerlReaderUNI.common;
|
||||
using TBF.Rig.RegisterReaders.PoseidonReader.implementations;
|
||||
using TBF.Rig.Sequences;
|
||||
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.PoseidonReader
|
||||
{
|
||||
public partial class UniHeadTestCtrl : UserControl
|
||||
{
|
||||
private static readonly ILog log = LogManager.GetLogger(typeof(UniHeadTestCtrl));
|
||||
private IUniHeadTestCtrl _ctrl;
|
||||
private IUniHeadTestCtrl Ctrl { get => _ctrl; }
|
||||
|
||||
public UniHeadTestCtrl(Generic.IComponentCfg config)
|
||||
{
|
||||
this._ctrl = new PoseidonImplHeadTestCtrl();
|
||||
Ctrl.config = config;
|
||||
InitializeComponent();
|
||||
if (config == null) return;
|
||||
|
||||
SmartCommunicationForm.TestMethodCfg = new iPerlReaderUNI.TestMethodCfg(null); // default values for iPerlCommunication
|
||||
|
||||
if (ProcessData.SmartHeadsUni != null)
|
||||
{
|
||||
foreach (var head in ProcessData.SmartHeadsUni)
|
||||
{
|
||||
if (head != null && head.Name == config.Name)
|
||||
{
|
||||
Ctrl.ISmartReader = head;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rfidCommandComboBox.DisplayMember = "Name";
|
||||
rfidCommandComboBox.ValueMember = "Value";
|
||||
var items = Ctrl.GetComboOperationsPairs();
|
||||
/*
|
||||
// CTRL+ALT+double click - hidden poweruser menu
|
||||
if (((Keyboard.ModifierKeys & Keys.Control) == Keys.Control) && ((Keyboard.ModifierKeys & Keys.Alt) == Keys.Alt) && Users.CurrentUser.AuthorizedAs == AuthorizedAs.PowerUser)
|
||||
{
|
||||
Array.Resize(ref items, items.Length + 1);
|
||||
items[items.Length - 1] = new { Name = "Kluc", Value = "Kluc" };
|
||||
}
|
||||
*/
|
||||
rfidCommandComboBox.DataSource = items.Select(i => i.Name).ToArray();
|
||||
|
||||
Ctrl.Initialize();
|
||||
|
||||
Ctrl.OptoReceivedHandler += (EventHandler<OptoReceivedEventArgs>)((sndr, args) =>
|
||||
{
|
||||
if (this.InvokeRequired)
|
||||
this.Invoke((Delegate)new EventHandler<OptoReceivedEventArgs>(this.OnOptoReceived2), sndr, (object)args);
|
||||
else
|
||||
this.OnOptoReceived2(sndr, args);
|
||||
});
|
||||
}
|
||||
|
||||
public void OnOptoReceived2(object sender, OptoReceivedEventArgs args)
|
||||
{
|
||||
optoListBox.Items.Insert(0,args.Data);
|
||||
}
|
||||
|
||||
public void CommandTestButtonClick(object sender, MouseEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
commandTestButton.Enabled = false;
|
||||
|
||||
Ctrl.CommandTestButtonClick(sender, e, new Arguments()
|
||||
{
|
||||
ISmartReader = Ctrl.ISmartReader,
|
||||
OptoListBox = optoListBox,
|
||||
RfidCommandComboBox = rfidCommandComboBox,
|
||||
RfidOutputListBox = rfidOutputListBox
|
||||
});
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
// A device/CLI communication failure must not terminate Application.Run.
|
||||
log.Error("Poseidon head test command failed.", exception);
|
||||
rfidOutputListBox.Items.Add("Error: " + exception.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
commandTestButton.Enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void UserControl_Load(object sender, EventArgs e)
|
||||
{
|
||||
this.ParentForm.FormClosing += new FormClosingEventHandler(ParentForm_FormClosing);
|
||||
}
|
||||
|
||||
void ParentForm_FormClosing(object sender, FormClosingEventArgs e)
|
||||
{
|
||||
//OnHandleDestroyed(new EventArgs());
|
||||
Ctrl.Destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
@@ -0,0 +1,22 @@
|
||||
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7
|
||||
{
|
||||
public class JsonDataFromPoseidon
|
||||
{
|
||||
public bool? NfcTagDetected { get; set; }
|
||||
public int? ProductType { get; set; }
|
||||
public string ProductTypeVersion { get; set; }
|
||||
public string DeviceId { get; set; }
|
||||
public string Reading { get; set; }
|
||||
public string Reading_Totalizer { get; set; }
|
||||
public string Reading_Digits { get; set; }
|
||||
public string Reading_Shift { get; set; }
|
||||
public string Reading_Resolution { get; set; }
|
||||
public string Reading_Units { get; set; }
|
||||
public string Reading_FlowDirection { get; set; }
|
||||
public string Reading_FlowRate { get; set; }
|
||||
public string CalibrationFactor { get; set; }
|
||||
public bool? ReadingComplete { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,259 @@
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CliRunner = TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Utils.CliRunner;
|
||||
using OptoHeadStatus = TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Protocols.OptoHeadStatus;
|
||||
using SerialPortData = TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Utils.SerialPortData;
|
||||
using EMeterArg = TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Utils.SerialPortData.EMeterArg;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7
|
||||
{
|
||||
public class NfcHeadService
|
||||
{
|
||||
|
||||
private bool activeHandlerSessioEnabled = false;
|
||||
private CliRunner _cliRunner;
|
||||
|
||||
private SerialPortData serialPort;
|
||||
|
||||
public NfcHeadService(SerialPortData serialPort)
|
||||
{
|
||||
this.serialPort = serialPort;
|
||||
this._cliRunner = null;
|
||||
ValidateCliFileExistence(true);
|
||||
}
|
||||
|
||||
private CliRunner CliRunner
|
||||
{
|
||||
get { return (_cliRunner != null ? _cliRunner : (_cliRunner = new CliRunner(CliLogging))); }
|
||||
}
|
||||
|
||||
private bool CliLogging
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
private static readonly Regex OpticalDataModeRegex = new Regex(
|
||||
@"(?im)(?:" +
|
||||
@"^\s*OpticalDataMode\s*Id\s*:\s*([^\r\n]+)\s*$" + // old format
|
||||
@"|" +
|
||||
@"""OpticalDataMode""\s*:\s*""?(0x[0-9A-Fa-f]+|\d+)""?" + // JSON format (handles hex and decimal)
|
||||
@")",
|
||||
RegexOptions.Compiled);
|
||||
|
||||
public bool TryGetOpticalDataMode(string result, out string s)
|
||||
{
|
||||
s = null;
|
||||
if (string.IsNullOrEmpty(result))
|
||||
return false;
|
||||
|
||||
var m = OpticalDataModeRegex.Match(result);
|
||||
if (!m.Success)
|
||||
return false;
|
||||
|
||||
// one of the groups will be filled
|
||||
s = !string.IsNullOrEmpty(m.Groups[1].Value)
|
||||
? m.Groups[1].Value.Trim()
|
||||
: m.Groups[2].Value.Trim();
|
||||
return true;
|
||||
}
|
||||
|
||||
private static readonly Regex DeviceIdRegex = new Regex(
|
||||
@"(?im)(?:" +
|
||||
@"^\s*Device\s*Id\s*:\s*([^\r\n]+)\s*$" + // old format
|
||||
@"|" +
|
||||
@"""DeviceId""\s*:\s*""?([0-9]+)""?" + // JSON format
|
||||
@")",
|
||||
RegexOptions.Compiled);
|
||||
|
||||
public bool TryGetDeviceId(string result, out string s)
|
||||
{
|
||||
s = null;
|
||||
if (string.IsNullOrEmpty(result))
|
||||
return false;
|
||||
|
||||
var m = DeviceIdRegex.Match(result);
|
||||
if (!m.Success)
|
||||
return false;
|
||||
|
||||
// one of the groups will be filled
|
||||
s = !string.IsNullOrEmpty(m.Groups[1].Value)
|
||||
? m.Groups[1].Value.Trim()
|
||||
: m.Groups[2].Value.Trim();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private void ValidateCliFileExistence(bool showErrorIfMissing)
|
||||
{
|
||||
if (serialPort != null)
|
||||
{
|
||||
if (!serialPort.CliExists)
|
||||
{
|
||||
throw new Exception("CLI file " + serialPort.SerialPortCmdClientPath +
|
||||
" does not exist! Current path: " + Environment.CurrentDirectory);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// ////////////
|
||||
/// </summary>
|
||||
public string GetSerialNr()
|
||||
{
|
||||
if (serialPort == null)
|
||||
throw new Exception("Serial port not initialized");
|
||||
|
||||
|
||||
Task<string> optoheadDeviceIdTask = CliRunner.SendAsync(serialPort.SerialPortCmdClientPath, serialPort.DefaultArgSettingsRead(EMeterArg.DeviceId) );
|
||||
//var timeOut = CliRunner.AddTimeOut(15000);
|
||||
//optoheadDeviceIdTask.GetAwaiter().GetResult();
|
||||
//optoheadDeviceIdTask.Wait();
|
||||
int doneTask = Task.WaitAny(new Task[] { optoheadDeviceIdTask }, TimeSpan.FromMilliseconds(15000));
|
||||
if (doneTask != 0)
|
||||
//if (timeOut == doneTask)
|
||||
{
|
||||
throw new Exception("Timeout");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (optoheadDeviceIdTask is Task<string>)
|
||||
{
|
||||
string serialNr;
|
||||
if (optoheadDeviceIdTask.Status == TaskStatus.Faulted)
|
||||
throw new Exception("Error TaskStatus.Faulted");
|
||||
if (optoheadDeviceIdTask is Task<string> taskStr)
|
||||
{
|
||||
string result = taskStr.Result;
|
||||
if (TryGetDeviceId(result, out serialNr))
|
||||
{
|
||||
return serialNr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public async Task<string> GetSerialNrAsync()
|
||||
{
|
||||
if (serialPort == null)
|
||||
throw new Exception("Serial port not initialized");
|
||||
|
||||
var cts = new CancellationTokenSource(); // we own the token
|
||||
var sendTask = CliRunner.AddSendAsync(serialPort, SerialPortData.EMeterArg.DeviceId, cts.Token);
|
||||
|
||||
string output;
|
||||
try
|
||||
{
|
||||
output = await CliRunner.WithTimeout(sendTask, TimeSpan.FromSeconds(15), cts);
|
||||
}
|
||||
catch (TimeoutException)
|
||||
{
|
||||
throw new Exception("Timeout");
|
||||
}
|
||||
|
||||
if (TryGetDeviceId(output, out var serialNr))
|
||||
return serialNr;
|
||||
|
||||
throw new Exception("Failed to parse DeviceId from output.");
|
||||
}
|
||||
|
||||
public OptoHeadStatus SetTestingMode(OptoHeadStatus status)
|
||||
{
|
||||
if (serialPort == null)
|
||||
throw new Exception("Serial port not initialized");
|
||||
|
||||
|
||||
Task optoheadMode =
|
||||
CliRunner.AddSendAsync(serialPort, SerialPortData.EMeterArg.Optohead, $"0x{((byte)status):X2}");
|
||||
var timeOut = CliRunner.AddTimeOut(5000);
|
||||
var doneTask = CliRunner.WhenAny();
|
||||
if (timeOut == doneTask)
|
||||
{
|
||||
throw new Exception("Timeout");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (optoheadMode is Task<string>)
|
||||
{
|
||||
string strOpticalDataMode;
|
||||
if (optoheadMode.Status == TaskStatus.Faulted)
|
||||
throw new Exception("Error TaskStatus.Faulted");
|
||||
string result = (optoheadMode as Task<string>).Result;
|
||||
if (TryGetOpticalDataMode(result, out strOpticalDataMode))
|
||||
{
|
||||
byte value;
|
||||
|
||||
if (strOpticalDataMode.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
|
||||
value = Convert.ToByte(strOpticalDataMode, 16); // interpret as hex
|
||||
else
|
||||
value = Convert.ToByte(strOpticalDataMode); // interpret as decimal
|
||||
|
||||
OptoHeadStatus optoheadStatus = (OptoHeadStatus)value;
|
||||
return optoheadStatus;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception($"Failed to parse OptoHeadStatus from output. Result: {result}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return OptoHeadStatus.Unknown;
|
||||
}
|
||||
|
||||
public OptoHeadStatus GetTestingMode()
|
||||
{
|
||||
if (serialPort == null)
|
||||
throw new Exception("Serial port not initialized");
|
||||
|
||||
|
||||
Task optoheadMode = CliRunner.AddSendAsync(serialPort, SerialPortData.EMeterArg.Optohead);
|
||||
var timeOut = CliRunner.AddTimeOut(5000);
|
||||
var doneTask = CliRunner.WhenAny();
|
||||
if (timeOut == doneTask)
|
||||
{
|
||||
throw new Exception("Timeout");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (optoheadMode is Task<string>)
|
||||
{
|
||||
string strOpticalDataMode;
|
||||
if (optoheadMode.Status == TaskStatus.Faulted)
|
||||
throw new Exception("Error TaskStatus.Faulted");
|
||||
string result = (optoheadMode as Task<string>).Result;
|
||||
if (TryGetOpticalDataMode(result, out strOpticalDataMode))
|
||||
{
|
||||
byte value;
|
||||
|
||||
if (strOpticalDataMode.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
|
||||
value = Convert.ToByte(strOpticalDataMode, 16); // interpret as hex
|
||||
else
|
||||
value = Convert.ToByte(strOpticalDataMode); // interpret as decimal
|
||||
|
||||
OptoHeadStatus optoheadStatus = (OptoHeadStatus)value;
|
||||
return optoheadStatus;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return OptoHeadStatus.Unknown;
|
||||
}
|
||||
|
||||
private void SendCommand()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private string RawDataAnswer()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,333 @@
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Utils;
|
||||
using CliRunner = TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Utils.CliRunnerOld;
|
||||
using OptoHeadStatus = TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Protocols.OptoHeadStatus;
|
||||
using SerialPortData = TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Utils.SerialPortData;
|
||||
using EMeterArg = TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Utils.SerialPortData.EMeterArg;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7
|
||||
{
|
||||
public class NfcHeadServiceOld
|
||||
{
|
||||
|
||||
private bool activeHandlerSessioEnabled = false;
|
||||
private CliRunner _cliRunner;
|
||||
|
||||
private SerialPortData serialPort;
|
||||
|
||||
public NfcHeadServiceOld(SerialPortData serialPort)
|
||||
{
|
||||
this.serialPort = serialPort;
|
||||
this._cliRunner = null;
|
||||
ValidateCliFileExistence(true);
|
||||
}
|
||||
|
||||
private CliRunner CliRunner
|
||||
{
|
||||
get { return (_cliRunner != null ? _cliRunner : (_cliRunner = new CliRunner(CliLogging))); }
|
||||
}
|
||||
|
||||
private bool CliLogging
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
private static readonly Regex OpticalDataModeRegex = new Regex(
|
||||
@"(?im)(?:" +
|
||||
@"^\s*OpticalDataMode\s*Id\s*:\s*([^\r\n]+)\s*$" + // old format
|
||||
@"|" +
|
||||
@"""OpticalDataMode""\s*:\s*""?(0x[0-9A-Fa-f]+|\d+)""?" + // JSON format (handles hex and decimal)
|
||||
@")",
|
||||
RegexOptions.Compiled);
|
||||
|
||||
public bool TryGetOpticalDataMode(string result, out string s)
|
||||
{
|
||||
s = null;
|
||||
if (string.IsNullOrEmpty(result))
|
||||
return false;
|
||||
|
||||
var m = OpticalDataModeRegex.Match(result);
|
||||
if (!m.Success)
|
||||
return false;
|
||||
|
||||
// one of the groups will be filled
|
||||
s = !string.IsNullOrEmpty(m.Groups[1].Value)
|
||||
? m.Groups[1].Value.Trim()
|
||||
: m.Groups[2].Value.Trim();
|
||||
return true;
|
||||
}
|
||||
|
||||
private static readonly Regex DeviceIdRegex = new Regex(
|
||||
@"(?im)(?:" +
|
||||
@"^\s*Device\s*Id\s*:\s*([^\r\n]+)\s*$" + // old format
|
||||
@"|" +
|
||||
@"""DeviceId""\s*:\s*""?([0-9]+)""?" + // JSON format
|
||||
@")",
|
||||
RegexOptions.Compiled);
|
||||
|
||||
public bool TryGetDeviceId(string result, out string s)
|
||||
{
|
||||
s = null;
|
||||
if (string.IsNullOrEmpty(result))
|
||||
return false;
|
||||
|
||||
var m = DeviceIdRegex.Match(result);
|
||||
if (!m.Success)
|
||||
return false;
|
||||
|
||||
// one of the groups will be filled
|
||||
s = !string.IsNullOrEmpty(m.Groups[1].Value)
|
||||
? m.Groups[1].Value.Trim()
|
||||
: m.Groups[2].Value.Trim();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private void ValidateCliFileExistence(bool showErrorIfMissing)
|
||||
{
|
||||
if (serialPort != null)
|
||||
{
|
||||
if (!serialPort.CliExists)
|
||||
{
|
||||
throw new Exception("CLI file " + serialPort.SerialPortCmdClientPath +
|
||||
" does not exist! Current path: " + Environment.CurrentDirectory);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// ////////////
|
||||
/// </summary>
|
||||
public string GetSerialNr()
|
||||
{
|
||||
if (serialPort == null)
|
||||
throw new Exception("Serial port not initialized");
|
||||
|
||||
|
||||
Task<string> optoheadDeviceIdTask = CliRunner.SendAsync(serialPort.SerialPortCmdClientPath, serialPort.DefaultArgSettingsRead(EMeterArg.DeviceId) );
|
||||
//Task<string> optoheadDeviceIdTask = CliRunner.SendAsync(serialPort.SerialPortCmdClientPath, serialPort.DefaultArgSettingsRead(EMeterArg.DeviceId) );
|
||||
//var timeOut = CliRunner.AddTimeOut(15000);
|
||||
//optoheadDeviceIdTask.GetAwaiter().GetResult();
|
||||
//optoheadDeviceIdTask.Wait();
|
||||
//CliRunner.StartAll();
|
||||
int doneTask = -1;
|
||||
DateTime time = DateTime.Now;
|
||||
while (true)
|
||||
{
|
||||
if (CliRunner.AreTasksDone())
|
||||
{
|
||||
doneTask = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
Thread.Sleep(100);
|
||||
if (DateTime.Now.Subtract(time).TotalMilliseconds > 15000)
|
||||
{
|
||||
doneTask = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//int doneTask = Task.WaitAny(new Task[] { optoheadDeviceIdTask }, TimeSpan.FromMilliseconds(15000));
|
||||
if (doneTask != 0)
|
||||
//if (timeOut == doneTask)
|
||||
{
|
||||
throw new Exception("Timeout");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (optoheadDeviceIdTask is Task<string>)
|
||||
{
|
||||
string serialNr;
|
||||
if (optoheadDeviceIdTask.Status == TaskStatus.Faulted)
|
||||
throw new Exception("Error TaskStatus.Faulted");
|
||||
if (optoheadDeviceIdTask is Task<string> taskStr)
|
||||
{
|
||||
string result = taskStr.Result;
|
||||
if (TryGetDeviceId(result, out serialNr))
|
||||
{
|
||||
return serialNr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public OptoHeadStatus SetTestingMode(OptoHeadStatus status)
|
||||
{
|
||||
if (serialPort == null)
|
||||
throw new Exception("Serial port not initialized");
|
||||
|
||||
|
||||
//Task<string> optoheadMode = CliRunner.AddSendAsyncRead(serialPort, SerialPortData.EMeterArg.Optohead);
|
||||
Task<string> optoheadMode = CliRunner.AddSendAsyncWrite(serialPort, SerialPortData.EMeterArg.Optohead, $"0x{((byte)status):X2}");
|
||||
|
||||
int doneTask = -1;
|
||||
DateTime time = DateTime.Now;
|
||||
while (true)
|
||||
{
|
||||
if (CliRunner.AreTasksDone())
|
||||
{
|
||||
doneTask = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
Thread.Sleep(100);
|
||||
if (DateTime.Now.Subtract(time).TotalMilliseconds > 15000)
|
||||
{
|
||||
doneTask = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (optoheadMode is Task<string>)
|
||||
{
|
||||
string strOpticalDataMode;
|
||||
if (optoheadMode.Status == TaskStatus.Faulted)
|
||||
throw new Exception("Error TaskStatus.Faulted");
|
||||
string result = (optoheadMode as Task<string>).Result;
|
||||
if (TryGetOpticalDataMode(result, out strOpticalDataMode))
|
||||
{
|
||||
byte value;
|
||||
|
||||
if (strOpticalDataMode.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
|
||||
value = Convert.ToByte(strOpticalDataMode, 16); // interpret as hex
|
||||
else
|
||||
value = Convert.ToByte(strOpticalDataMode); // interpret as decimal
|
||||
|
||||
OptoHeadStatus optoheadStatus = (OptoHeadStatus)value;
|
||||
return optoheadStatus;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception($"Failed to parse OptoHeadStatus from output. Result: {result}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return OptoHeadStatus.Unknown;
|
||||
}
|
||||
|
||||
|
||||
// public async Task<string> GetSerialNrAsync()
|
||||
// {
|
||||
// if (serialPort == null)
|
||||
// throw new Exception("Serial port not initialized");
|
||||
//
|
||||
// var cts = new CancellationTokenSource(); // we own the token
|
||||
// var sendTask = CliRunner.AddSendAsync(serialPort, SerialPortData.EMeterArg.DeviceId, cts.Token);
|
||||
//
|
||||
// string output;
|
||||
// try
|
||||
// {
|
||||
// output = await CliRunner.WithTimeout(sendTask, TimeSpan.FromSeconds(15), cts);
|
||||
// }
|
||||
// catch (TimeoutException)
|
||||
// {
|
||||
// throw new Exception("Timeout");
|
||||
// }
|
||||
//
|
||||
// if (TryGetDeviceId(output, out var serialNr))
|
||||
// return serialNr;
|
||||
//
|
||||
// throw new Exception("Failed to parse DeviceId from output.");
|
||||
// }
|
||||
|
||||
// public OptoHeadStatus SetTestingMode(OptoHeadStatus status)
|
||||
// {
|
||||
// if (serialPort == null)
|
||||
// throw new Exception("Serial port not initialized");
|
||||
//
|
||||
//
|
||||
// Task optoheadMode =
|
||||
// CliRunner.AddSendAsync(serialPort, SerialPortData.EMeterArg.Optohead, $"0x{((byte)status):X2}");
|
||||
// var timeOut = CliRunner.AddTimeOut(5000);
|
||||
// var doneTask = CliRunner.WhenAny();
|
||||
// if (timeOut == doneTask)
|
||||
// {
|
||||
// throw new Exception("Timeout");
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// if (optoheadMode is Task<string>)
|
||||
// {
|
||||
// string strOpticalDataMode;
|
||||
// if (optoheadMode.Status == TaskStatus.Faulted)
|
||||
// throw new Exception("Error TaskStatus.Faulted");
|
||||
// string result = (optoheadMode as Task<string>).Result;
|
||||
// if (TryGetOpticalDataMode(result, out strOpticalDataMode))
|
||||
// {
|
||||
// byte value;
|
||||
//
|
||||
// if (strOpticalDataMode.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
|
||||
// value = Convert.ToByte(strOpticalDataMode, 16); // interpret as hex
|
||||
// else
|
||||
// value = Convert.ToByte(strOpticalDataMode); // interpret as decimal
|
||||
//
|
||||
// OptoHeadStatus optoheadStatus = (OptoHeadStatus)value;
|
||||
// return optoheadStatus;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return OptoHeadStatus.Unknown;
|
||||
// }
|
||||
//
|
||||
// public OptoHeadStatus GetTestingMode()
|
||||
// {
|
||||
// if (serialPort == null)
|
||||
// throw new Exception("Serial port not initialized");
|
||||
//
|
||||
//
|
||||
// Task optoheadMode = CliRunner.AddSendAsync(serialPort, SerialPortData.EMeterArg.Optohead);
|
||||
// var timeOut = CliRunner.AddTimeOut(5000);
|
||||
// var doneTask = CliRunner.WhenAny();
|
||||
// if (timeOut == doneTask)
|
||||
// {
|
||||
// throw new Exception("Timeout");
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// if (optoheadMode is Task<string>)
|
||||
// {
|
||||
// string strOpticalDataMode;
|
||||
// if (optoheadMode.Status == TaskStatus.Faulted)
|
||||
// throw new Exception("Error TaskStatus.Faulted");
|
||||
// string result = (optoheadMode as Task<string>).Result;
|
||||
// if (TryGetOpticalDataMode(result, out strOpticalDataMode))
|
||||
// {
|
||||
// byte value;
|
||||
//
|
||||
// if (strOpticalDataMode.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
|
||||
// value = Convert.ToByte(strOpticalDataMode, 16); // interpret as hex
|
||||
// else
|
||||
// value = Convert.ToByte(strOpticalDataMode); // interpret as decimal
|
||||
//
|
||||
// OptoHeadStatus optoheadStatus = (OptoHeadStatus)value;
|
||||
// return optoheadStatus;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return OptoHeadStatus.Unknown;
|
||||
// }
|
||||
//
|
||||
// private void SendCommand()
|
||||
// {
|
||||
//
|
||||
// }
|
||||
//
|
||||
// private string RawDataAnswer()
|
||||
// {
|
||||
// return "";
|
||||
// }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
using System;
|
||||
using System.IO.Ports;
|
||||
using System.Threading.Tasks;
|
||||
using SERIAL_Driver = TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Utils.SERIAL_Driver;
|
||||
using WaterMetrologyData = TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Protocols.WaterMetrologyData;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7
|
||||
{
|
||||
public class OptoHeadService
|
||||
{
|
||||
|
||||
public class Con
|
||||
{
|
||||
public string com = "COM5";
|
||||
public int baudrate = 38400;
|
||||
public int dataBits = 8;
|
||||
public Parity parity = Parity.None;
|
||||
public StopBits stopbits = StopBits.Two;
|
||||
public int readTimeout = 5000;
|
||||
public int writeTimeout = 1000;
|
||||
|
||||
public Con(string com, int baudrate, int dataBits, Parity parity, StopBits stopbits, int readTimeout,
|
||||
int writeTimeout) : this(com)
|
||||
{
|
||||
this.baudrate = baudrate;
|
||||
this.dataBits = dataBits;
|
||||
this.parity = parity;
|
||||
this.stopbits = stopbits;
|
||||
this.readTimeout = readTimeout;
|
||||
this.writeTimeout = writeTimeout;
|
||||
}
|
||||
|
||||
public Con(string com)
|
||||
{
|
||||
this.com = com;
|
||||
}
|
||||
}
|
||||
|
||||
private Con Connection { get; set; }
|
||||
private SERIAL_Driver driver;
|
||||
/// <summary>
|
||||
/// Filed After Run() is called.
|
||||
/// </summary>
|
||||
public WaterMetrologyData WaterMetrologyData { get; private set; }
|
||||
|
||||
public OptoHeadService(Con con)
|
||||
{
|
||||
Connection = con;
|
||||
driver = new SERIAL_Driver();
|
||||
OnOptoReceivedHandler = null;
|
||||
}
|
||||
|
||||
public bool CreateSerialConnection()
|
||||
{
|
||||
OnOptoReceivedHandler = null;
|
||||
bool isopen = false;
|
||||
Con con = Connection;
|
||||
|
||||
byte[] message = {0x00};
|
||||
byte[] bytesReceived;
|
||||
|
||||
if (!driver.isOpen())
|
||||
{
|
||||
|
||||
isopen = driver.OpenConnection(
|
||||
con.com,
|
||||
con.baudrate,
|
||||
con.dataBits,
|
||||
con.parity,
|
||||
con.stopbits,
|
||||
con.readTimeout,
|
||||
con.writeTimeout);
|
||||
}
|
||||
|
||||
return isopen;
|
||||
}
|
||||
|
||||
public void CloseSerialConnection()
|
||||
{
|
||||
dissableRunLoop = true;
|
||||
OnOptoReceivedHandler = null;
|
||||
driver.Close();
|
||||
OnOptoReceivedHandler = null;
|
||||
}
|
||||
|
||||
private EventHandler<CommonRR.IPerl.communication.OptoReceivedEventArgs> OnOptoReceivedHandler;
|
||||
|
||||
public void RunLoop(EventHandler<CommonRR.IPerl.communication.OptoReceivedEventArgs> onOptoReceivedHandler)
|
||||
{
|
||||
OnOptoReceivedHandler = onOptoReceivedHandler;
|
||||
Task.Run(() => Run());
|
||||
}
|
||||
|
||||
public void RunLoop()
|
||||
{
|
||||
Task.Run(() => Run());
|
||||
}
|
||||
|
||||
private bool dissableRunLoop = false;
|
||||
/// <summary>
|
||||
/// Run the service. Catch one communication to WaterMetrologyData field.
|
||||
/// </summary>
|
||||
public void Run()
|
||||
{
|
||||
while (!dissableRunLoop)
|
||||
{
|
||||
WaterMetrologyData = ParseData(RunReading());
|
||||
if (OnOptoReceivedHandler != null && WaterMetrologyData != null)
|
||||
{
|
||||
OnOptoReceivedHandler.Invoke(this, new CommonRR.IPerl.communication.OptoReceivedEventArgs(WaterMetrologyData.ToString()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
byte[] RunReading()
|
||||
{
|
||||
if (driver.isOpen())
|
||||
{
|
||||
driver.SendMessage(new byte[] {0x00}, 1);
|
||||
return driver.GetRawData();
|
||||
}
|
||||
else
|
||||
{
|
||||
dissableRunLoop = true;
|
||||
}
|
||||
|
||||
return new byte[] {0xFF};
|
||||
}
|
||||
|
||||
public WaterMetrologyData ParseData(byte[] data)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (data == null || data.Length == 0)
|
||||
return null;
|
||||
return WaterMetrologyData.Parse(data, DateTime.Now, "");
|
||||
}catch(Exception e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Protocols
|
||||
{
|
||||
public enum OptoHeadStatus : byte
|
||||
{
|
||||
Unknown = 0xFF,
|
||||
OptoHeadDisabled = 0x00,
|
||||
OptoHeadC2 = 0xC2,
|
||||
OptoHeadC7 = 0xC7,
|
||||
}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
using System;
|
||||
using NfcC7_DLL.NfcHandler.Protocols;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Protocols
|
||||
{
|
||||
public class WaterMetrologyData
|
||||
{
|
||||
private TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Protocols.OptoHeadStatus _optoHeadStatus;
|
||||
private WaterMetrologyDataC7 c7Data;
|
||||
private WaterMetrologyDataC2 c2Data;
|
||||
|
||||
public WaterMetrologyDataC7 C7Data { get => c7Data; }
|
||||
public WaterMetrologyDataC2 C2Data { get => c2Data; }
|
||||
public TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Protocols.OptoHeadStatus OptoHeadStatus { get => _optoHeadStatus; }
|
||||
|
||||
public static WaterMetrologyData Parse(byte[] data, DateTime dt, string dutinfo)
|
||||
{
|
||||
if (data.Length < 24)
|
||||
{
|
||||
throw new ArgumentException("Invalid data length for WaterMetrologyData C2.");
|
||||
}
|
||||
WaterMetrologyData waterMetrologyData = new WaterMetrologyData();
|
||||
waterMetrologyData._optoHeadStatus = TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Protocols.OptoHeadStatus.Unknown;
|
||||
// Probably C2
|
||||
if(data.Length > 24 && data.Length < 48)
|
||||
{
|
||||
waterMetrologyData.c2Data = WaterMetrologyDataC2.Parse(data, dt, dutinfo);
|
||||
waterMetrologyData._optoHeadStatus = TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Protocols.OptoHeadStatus.OptoHeadC2;
|
||||
}
|
||||
// Probably C7
|
||||
else if(data.Length >= 48)
|
||||
{
|
||||
waterMetrologyData.c7Data = WaterMetrologyDataC7.Parse(data, dt, dutinfo);
|
||||
waterMetrologyData._optoHeadStatus = TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Protocols.OptoHeadStatus.OptoHeadC7;
|
||||
}
|
||||
|
||||
return waterMetrologyData;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Status: {_optoHeadStatus}, C7Data: {c7Data}, C2Data: {c2Data}";
|
||||
}
|
||||
}
|
||||
}
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
using System;
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7.Protocols
|
||||
{
|
||||
public class WaterMetrologyDataC2
|
||||
{
|
||||
public string DutInfo { get; set; }
|
||||
public DateTime Dt { get; set; }
|
||||
public int AdcSample { get; set; }
|
||||
public short LastField { get; set; }
|
||||
public short FlowRate { get; set; }
|
||||
public uint Accumulator { get; set; }
|
||||
public ushort FlipPeriod { get; set; }
|
||||
public ushort VinfStart { get; set; }
|
||||
public ushort VinfEnd { get; set; }
|
||||
public short ElectrodeDelta { get; set; }
|
||||
public ushort Impedance { get; set; }
|
||||
public byte FieldDriveTime { get; set; }
|
||||
public bool IsInLowFlow { get; set; }
|
||||
public bool IsInEmptyPipe { get; set; }
|
||||
public bool FastHPFC { get; set; }
|
||||
public bool FieldPolarity { get; set; }
|
||||
public bool ImpedancePolarity { get; set; }
|
||||
|
||||
public double CalcFlowmLps
|
||||
{
|
||||
get { return FlowRate / 4.0; } // FlowRate is in 1/4 mL/s
|
||||
}
|
||||
public double CalcFlowGPM
|
||||
{
|
||||
get { return CalcFlowmLps * 0.015850323141489; } // mL/s to gal/min conversion
|
||||
}
|
||||
public double CalcAccGal
|
||||
{
|
||||
get { return (Accumulator / 4.0) * 0.000264172; } // Accumulator is in 1/4 mL, convert to gallons
|
||||
}
|
||||
|
||||
public static WaterMetrologyDataC2 Parse(string base64Data, DateTime dt, string dutinfo)
|
||||
{
|
||||
byte[] data = Convert.FromBase64String(base64Data);
|
||||
return Parse(data, dt, dutinfo);
|
||||
}
|
||||
|
||||
public static WaterMetrologyDataC2 Parse(byte[] data, DateTime dt, string dutinfo)
|
||||
{
|
||||
if (data.Length < 24)
|
||||
{
|
||||
throw new ArgumentException("Invalid data length for WaterMetrologyData C2.");
|
||||
}
|
||||
|
||||
|
||||
WaterMetrologyDataC2 result = new WaterMetrologyDataC2();
|
||||
|
||||
result.DutInfo = dutinfo;
|
||||
result.Dt = dt;
|
||||
result.AdcSample = BitConverter.ToInt32(data, 0);
|
||||
result.LastField = BitConverter.ToInt16(data, 4);
|
||||
result.FlowRate = BitConverter.ToInt16(data, 6);
|
||||
result.Accumulator = BitConverter.ToUInt32(data, 8);
|
||||
result.FlipPeriod = BitConverter.ToUInt16(data, 12);
|
||||
result.VinfStart = BitConverter.ToUInt16(data, 14);
|
||||
result.VinfEnd = BitConverter.ToUInt16(data, 16);
|
||||
result.ElectrodeDelta = BitConverter.ToInt16(data, 18);
|
||||
result.Impedance = BitConverter.ToUInt16(data, 20);
|
||||
result.FieldDriveTime = data[22];
|
||||
|
||||
byte flags = data[23];
|
||||
result.IsInLowFlow = (flags & 0x01) != 0;
|
||||
result.IsInEmptyPipe = (flags & 0x02) != 0;
|
||||
result.FastHPFC = (flags & 0x04) != 0; // Fast High Pass Filter Constant in bit 2
|
||||
result.FieldPolarity = (flags & 0x08) != 0; // Field Polarity in bit 3
|
||||
result.ImpedancePolarity = (flags & 0x10) != 0; // Impedance Polarity in bit 4
|
||||
return result;
|
||||
}
|
||||
|
||||
//public override string ToString()
|
||||
//{
|
||||
// return $"ADC Sample: {AdcSample}, Last Field: {LastField}, Flow Rate: {FlowRate}, Accumulator: {Accumulator}, " +
|
||||
// $"Flip Period Ticks: {FlipPeriodTicks}, Vinf Start: {VinfStart}, Vinf End: {VinfEnd}, Electrode Delta: {ElectrodeDelta}, " +
|
||||
// $"Impedance: {Impedance}, Field Drive Time: {FieldDriveTime}, Is Low Flow: {IsInLowFlow}, Is Empty Pipe: {IsInEmptyPipe}, " +
|
||||
// $"Fast High Pass Filter: {FastHighPassFilterConstant}, Field Polarity: {FieldPolarity}, Impedance Polarity: {ImpedancePolarity}";
|
||||
//}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"DutInfo: {DutInfo}, Dt: {Dt}, ADC Sample: {AdcSample}, Last Field: {LastField}, Flow Rate: {FlowRate}, Accumulator: {Accumulator}, " +
|
||||
$"Flip Period: {FlipPeriod}, Vinf Start: {VinfStart}, Vinf End: {VinfEnd}, Electrode Delta: {ElectrodeDelta}, " +
|
||||
$"Impedance: {Impedance}, Field Drive Time: {FieldDriveTime}, Is Low Flow: {IsInLowFlow}, Is Empty Pipe: {IsInEmptyPipe}, " +
|
||||
$"Fast HPFC: {FastHPFC}, Field Polarity: {FieldPolarity}, Impedance Polarity: {ImpedancePolarity}, " +
|
||||
$"Calc Flow mL/s: {CalcFlowmLps:F2}, Calc Flow GPM: {CalcFlowGPM:F2}, Calc Acc Gal: {CalcAccGal:F2}";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user