Compare commits

..
Author SHA1 Message Date
michal cf41a26a0a Add LocalWebRequest helper class for managing Genesis web requests:
- Introduce methods for HTTP POST, GET, DELETE operations with JSON, binary, and custom headers support.
- Add response handling for status codes, exceptions, content retrieval, and asynchronous operations.
- Include string and object extension methods for HTTP requests.
- Provide initial implementation for uploading binary data and error handling stubbed for future enhancement.
2026-03-26 07:30:54 +01:00
michal 2e4741b929 Add Genesis RegisterReaders namespace, resource handling, constants, and application definitions:
- Add new classes and enums (`ApplicationDefinition`, `MeterApplications`, `FileApplications`, `ProgrammingParameters`, etc.) for Genesis application management and definition handling.
- Introduce resource localization with `Resources.Designer.cs`.
- Implement constants for error states, alarms, LED modes, and metrology definitions.
- Add `ServiceUrlsBackUp_New` for managing Genesis-related service endpoints.
2026-03-26 07:20:28 +01:00
129 changed files with 41992 additions and 12231 deletions
+2 -5
View File
@@ -19,9 +19,6 @@ using System.Runtime.InteropServices;
// COM, set the ComVisible attribute to true on that type. // COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)] [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 // The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("2c13538e-15ee-48b2-af0f-2c95afb67186")] [assembly: Guid("2c13538e-15ee-48b2-af0f-2c95afb67186")]
@@ -32,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number // Build Number
// Revision // Revision
// //
[assembly: AssemblyVersion("3.9.3058.1")] [assembly: AssemblyVersion("3.9.3013.1")]
[assembly: AssemblyFileVersion("3.9.3058.1")] [assembly: AssemblyFileVersion("3.9.3013.1")]
+1 -9
View File
@@ -1,6 +1,7 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <auto-generated> // <auto-generated>
// This code was generated by a tool. // This code was generated by a tool.
// Runtime Version:4.0.30319.42000
// //
// Changes to this file may cause incorrect behavior and will be lost if // Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated. // the code is regenerated.
@@ -6269,15 +6270,6 @@ namespace TBF.Resources {
} }
} }
/// <summary>
/// Looks up a localized string similar to Test in calculation.
/// </summary>
internal static string Test_in_calculation {
get {
return ResourceManager.GetString("Test_in_calculation", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Test in progress. /// Looks up a localized string similar to Test in progress.
/// </summary> /// </summary>
File diff suppressed because it is too large Load Diff
-3
View File
@@ -1764,7 +1764,4 @@
<data name="Units" xml:space="preserve"> <data name="Units" xml:space="preserve">
<value /> <value />
</data> </data>
<data name="Test_in_calculation" xml:space="preserve">
<value>Probíhá výpočet</value>
</data>
</root> </root>
-3
View File
@@ -2482,7 +2482,4 @@
<data name="Units" xml:space="preserve"> <data name="Units" xml:space="preserve">
<value>Units</value> <value>Units</value>
</data> </data>
<data name="Test_in_calculation" xml:space="preserve">
<value>Test in calculation</value>
</data>
</root> </root>
-3
View File
@@ -259,7 +259,4 @@
<data name="Units" xml:space="preserve"> <data name="Units" xml:space="preserve">
<value /> <value />
</data> </data>
<data name="Test_in_calculation" xml:space="preserve">
<value>Prebieha výpočet</value>
</data>
</root> </root>
-2
View File
@@ -111,7 +111,6 @@ namespace TBF.Rig.BuiltIn.PumpTandem
public void TurnOff() public void TurnOff()
{ {
log.DebugFormat("{0}.TurnOff()", Name);
if ((pumpFm1 != null) && (pumpFm2 != null)) if ((pumpFm1 != null) && (pumpFm2 != null))
{ {
pumpFm1.TurnOff(); pumpFm1.TurnOff();
@@ -121,7 +120,6 @@ namespace TBF.Rig.BuiltIn.PumpTandem
{ {
// TODO // TODO
} }
log.DebugFormat("DONE {0}.TurnOff()", Name);
} }
@@ -175,8 +175,8 @@ namespace TBF.Rig.ControlBoard.Uni
double reqFlowLo = (0.7 * qFrom) + (0.3 * reqFlowAve); /// Move the lower limit 15% of the range up double reqFlowLo = (0.7 * qFrom) + (0.3 * reqFlowAve); /// Move the lower limit 15% of the range up
double reqFlowHi = (0.7 * qTo) + (0.3 * reqFlowAve); /// Move the upper limit 15% of the range down double reqFlowHi = (0.7 * qTo) + (0.3 * reqFlowAve); /// Move the upper limit 15% of the range down
/// ///
uniCB.SetFlow(false, regV.Idx1, flowMeter.NominalFreq * reqFlowLo / flowMeter.NominalFlow, uniCB.SetFlow(false, regV.Idx1, 2000.0 * reqFlowLo / flowMeter.NominalFlow,
flowMeter.NominalFreq * reqFlowHi / flowMeter.NominalFlow); 2000.0 * reqFlowHi / flowMeter.NominalFlow);
if (readDivTransition) if (readDivTransition)
{ {
/// Schedule reading diverter transition data /// Schedule reading diverter transition data
+4 -65
View File
@@ -803,60 +803,12 @@ namespace TBF.Rig.ControlBoard.Uni
/// </summary> /// </summary>
public void SetFlow(bool isFromUI, int regVId, double freqLo, double freqHi, int regulationMinStep = 0) public void SetFlow(bool isFromUI, int regVId, double freqLo, double freqHi, int regulationMinStep = 0)
{ {
LiveLogDiag.Log1("----------------------------------------"); if (IsUIBlocked && isFromUI) return;
LiveLogDiag.Log1(
"SetFlow() >> ENTER isFromUI={0} regVId={1} freqLo={2} freqHi={3} regulationMinStep={4} IsUIBlocked={5}",
isFromUI, regVId, freqLo, freqHi, regulationMinStep, IsUIBlocked);
if (IsUIBlocked && isFromUI) actionQueue.Enqueue(Action.SetFlow(isFromUI, regVId, freqLo, freqHi, Convert.ToInt32(Math.Round(Devices.PidCoef)), 200, regulationMinStep));
{ log.InfoFormat("Enqueue( SetFlow(rv={0}, fLo={1}, fHi={2}, pid={3}) )", regVId, freqLo, freqHi, Convert.ToInt32(Math.Round(Devices.PidCoef)));
LiveLogDiag.Log1(
"SetFlow() >> EXIT (UI BLOCKED) isFromUI={0}",
isFromUI);
return;
}
int pid = Convert.ToInt32(Math.Round(Devices.PidCoef)); foreach (var a in actionQueue) log.DebugFormat(" {0}", a);
int fixedParam = 200;
LiveLogDiag.Log1(
"SetFlow() >> PREPARE pid={0} fixedParam={1} regulationMinStep={2}",
pid, fixedParam, regulationMinStep);
var action = Action.SetFlow(
isFromUI,
regVId,
freqLo,
freqHi,
pid,
fixedParam,
regulationMinStep);
LiveLogDiag.Log1(
"SetFlow() >> ACTION CREATED: rv={0} fLo={1} fHi={2} pid={3} p6={4} minStep={5}",
regVId, freqLo, freqHi, pid, fixedParam, regulationMinStep);
actionQueue.Enqueue(action);
LiveLogDiag.Log1(
"SetFlow() >> ENQUEUED actionQueue.Count={0}",
actionQueue.Count);
log.InfoFormat(
"Enqueue( SetFlow(rv={0}, fLo={1}, fHi={2}, pid={3}) )",
regVId, freqLo, freqHi, pid);
int i = 0;
foreach (var a in actionQueue)
{
LiveLogDiag.Log1(
"SetFlow() >> QUEUE[{0}] = {1}",
i++, a);
log.DebugFormat(" {0}", a);
}
LiveLogDiag.Log1("SetFlow() >> EXIT");
LiveLogDiag.Log1("----------------------------------------");
} }
public void StartTest(bool isFromUI, int flowMId, int divId, int divThreshold, public void StartTest(bool isFromUI, int flowMId, int divId, int divThreshold,
@@ -1029,18 +981,5 @@ namespace TBF.Rig.ControlBoard.Uni
{ {
/// TODO /// TODO
} }
/// <summary>
/// Logging
/// For activation use compilation condition: LIVELOGDIAG_FlowMeter_cs
/// </summary>
static class LiveLogDiag
{
[Conditional("LIVELOGDIAG_UniCB_cs")]
public static void Log1(string format, params object[] args)
{
LiveLogCache.Instance.AddLog("UniCB.cs LOG>> " + string.Format(format, args));
}
}
} }
} }
-2
View File
@@ -332,8 +332,6 @@ namespace TBF.Rig.Danfoss.VLT2800
Telegram.UpdateTelegramChecksum(msg); Telegram.UpdateTelegramChecksum(msg);
} }
SendData(msg); SendData(msg);
log.DebugFormat("DONE {0}.TurnOff()", Name);
} }
-2
View File
@@ -264,8 +264,6 @@ namespace TBF.Rig.Modbus.PumpFM.DanfossVLT
modbus.SendMessage(msg, Name); modbus.SendMessage(msg, Name);
} }
log.DebugFormat("DONE {0}.TurnOff()", Name);
} }
-2
View File
@@ -416,8 +416,6 @@ namespace TBF.Rig.Modbus.PumpFM.Grundfoss
// --- DIAGNOSTIKA --- // --- DIAGNOSTIKA ---
LiveLogDiag.Log1("GF TurnOff msg = " + BitConverter.ToString(msg)); LiveLogDiag.Log1("GF TurnOff msg = " + BitConverter.ToString(msg));
} }
log.DebugFormat("DONE {0}.TurnOff()", Name);
} }
/// <summary> /// <summary>
@@ -17,6 +17,8 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader
return new GenesisCfgCtrl(); return new GenesisCfgCtrl();
} }
/// ///
/// Serialized parameters /// Serialized parameters
/// ///
@@ -29,9 +31,7 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader
public int MuxBoardNr; /// 0 = use RfidComPort(Nr), otherwise mux. board nr. 1 .. 4 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 int Group; /// Number written to QuidoRS to connct the watermeter to RfidComPort, 1 .. 10
public CommunicationInterface CommunicationInterface; /// Communication Interface: RFID or NFC public CommunicationInterface CommunicationInterface; /// Communication Interface: RFID or NFC
public bool EnableShowChanels; ///
public int IBeginDataFlush;
/// <summary> Procedure parameters </summary> /// <summary> Procedure parameters </summary>
@@ -56,8 +56,6 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader
ProcParams = CreateProcParamsProvider() as ProcParams; ProcParams = CreateProcParamsProvider() as ProcParams;
CommunicationInterface = CommunicationInterface.RFID; CommunicationInterface = CommunicationInterface.RFID;
HeadCommunicationComPortNr = 0; HeadCommunicationComPortNr = 0;
EnableShowChanels = false;
IBeginDataFlush = 2000;
} }
public GenesisCfg(IComponentFactory factory) public GenesisCfg(IComponentFactory factory)
@@ -69,7 +67,7 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader
public string ToString(int i) public string ToString(int i)
{ {
return $"{Name} Group1 (mux#)={MuxBoardNr}, Group2={Group}, Opto=Com{OptoComPortNr}, {CommunicationInterface}=Com{RfidComPortNr}, EnableShowChanels={EnableShowChanels}, IBeginDataFlush={IBeginDataFlush}"; return $"{Name} Group1 (mux#)={MuxBoardNr}, Group2={Group}, Opto=Com{OptoComPortNr}, {CommunicationInterface}=Com{RfidComPortNr}";
} }
} }
} }
@@ -58,9 +58,6 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader
muxBoardNrTextBox.Text = config.MuxBoardNr.ToString(); muxBoardNrTextBox.Text = config.MuxBoardNr.ToString();
groupTextBox.Text = config.Group.ToString(); groupTextBox.Text = config.Group.ToString();
comboBoxCommunicationInterface.SelectedItem = config.CommunicationInterface.ToString(); comboBoxCommunicationInterface.SelectedItem = config.CommunicationInterface.ToString();
tBBeginDataFlush.Text = config.IBeginDataFlush.ToString();
checkBox_EnableShowChanels.Checked = config.EnableShowChanels;
tabPage2.Controls.Add(new GenesisHeadTestCtrl(config)); tabPage2.Controls.Add(new GenesisHeadTestCtrl(config));
} }
@@ -77,8 +74,6 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader
muxBoardNrTextBox.Enabled = true; muxBoardNrTextBox.Enabled = true;
groupTextBox.Enabled = true; groupTextBox.Enabled = true;
comboBoxCommunicationInterface.Enabled = true; comboBoxCommunicationInterface.Enabled = true;
tBBeginDataFlush.Enabled = true;
checkBox_EnableShowChanels.Enabled = true;
} }
public CfgUpdateFlags VerifyCfg(ref string message) public CfgUpdateFlags VerifyCfg(ref string message)
@@ -135,12 +130,6 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader
message += Environment.NewLine + string.Format(Strings.Invalid_0, groupLabel.Text); message += Environment.NewLine + string.Format(Strings.Invalid_0, groupLabel.Text);
} }
if (!int.TryParse(tBBeginDataFlush.Text, out dummy) || dummy < 0 || dummy > 10000)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + string.Format(Strings.Invalid_0, tBBeginDataFlush.Text);
}
return flags; return flags;
} }
@@ -169,8 +158,6 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader
config.Group = int.Parse(groupTextBox.Text); config.Group = int.Parse(groupTextBox.Text);
config.CommunicationInterface = (CommunicationInterface)comboBoxCommunicationInterface.SelectedIndex; config.CommunicationInterface = (CommunicationInterface)comboBoxCommunicationInterface.SelectedIndex;
config.HeadCommunicationComPortNr = int.Parse(headPortNrTextBox.Text); config.HeadCommunicationComPortNr = int.Parse(headPortNrTextBox.Text);
config.IBeginDataFlush = int.Parse(tBBeginDataFlush.Text);
config.EnableShowChanels = checkBox_EnableShowChanels.Checked;
return flags; return flags;
} }
@@ -31,427 +31,382 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader
/// </summary> /// </summary>
private void InitializeComponent() private void InitializeComponent()
{ {
this.tabControl1 = new System.Windows.Forms.TabControl(); this.tabControl1 = new System.Windows.Forms.TabControl();
this.tabPage1 = new System.Windows.Forms.TabPage(); this.tabPage1 = new System.Windows.Forms.TabPage();
this.groupBox2 = new System.Windows.Forms.GroupBox(); this.label4 = new System.Windows.Forms.Label();
this.headPortNrTextBox = new System.Windows.Forms.TextBox(); this.label3 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label(); this.groupBox1 = new System.Windows.Forms.GroupBox();
this.label4 = new System.Windows.Forms.Label(); this.comboBoxCommunicationInterface = new System.Windows.Forms.ComboBox();
this.label3 = new System.Windows.Forms.Label(); this.label1 = new System.Windows.Forms.Label();
this.groupBox1 = new System.Windows.Forms.GroupBox(); this.rfidPortNrTextBox = new System.Windows.Forms.TextBox();
this.comboBoxCommunicationInterface = new System.Windows.Forms.ComboBox(); this.rfidSerialPortNrLabel = new System.Windows.Forms.Label();
this.label1 = new System.Windows.Forms.Label(); this.optoDataGroupBox = new System.Windows.Forms.GroupBox();
this.rfidPortNrTextBox = new System.Windows.Forms.TextBox(); this.tcpipPortLabel = new System.Windows.Forms.Label();
this.rfidSerialPortNrLabel = new System.Windows.Forms.Label(); this.tcpipPortTextBox = new System.Windows.Forms.TextBox();
this.optoDataGroupBox = new System.Windows.Forms.GroupBox(); this.ipAddressLabel = new System.Windows.Forms.Label();
this.checkBox_EnableShowChanels = new System.Windows.Forms.CheckBox(); this.ipAddressTextBox = new System.Windows.Forms.TextBox();
this.tBBeginDataFlush = new System.Windows.Forms.TextBox(); this.radioButton1 = new System.Windows.Forms.RadioButton();
this.labelFlush = new System.Windows.Forms.Label(); this.radioButton2 = new System.Windows.Forms.RadioButton();
this.tcpipPortLabel = new System.Windows.Forms.Label(); this.optoSerialPortLabel = new System.Windows.Forms.Label();
this.tcpipPortTextBox = new System.Windows.Forms.TextBox(); this.optoSerialPortTextBox = new System.Windows.Forms.TextBox();
this.ipAddressLabel = new System.Windows.Forms.Label(); this.groupTextBox = new System.Windows.Forms.TextBox();
this.ipAddressTextBox = new System.Windows.Forms.TextBox(); this.groupLabel = new System.Windows.Forms.Label();
this.radioButton1 = new System.Windows.Forms.RadioButton(); this.muxBoardNrTextBox = new System.Windows.Forms.TextBox();
this.radioButton2 = new System.Windows.Forms.RadioButton(); this.muxBoardNrLabel = new System.Windows.Forms.Label();
this.optoSerialPortLabel = new System.Windows.Forms.Label(); this.nameTextBox = new System.Windows.Forms.TextBox();
this.optoSerialPortTextBox = new System.Windows.Forms.TextBox(); this.nameLabel = new System.Windows.Forms.Label();
this.groupTextBox = new System.Windows.Forms.TextBox(); this.classNameLabel = new System.Windows.Forms.Label();
this.groupLabel = new System.Windows.Forms.Label(); this.tabPage2 = new System.Windows.Forms.TabPage();
this.muxBoardNrTextBox = new System.Windows.Forms.TextBox(); this.groupBox2 = new System.Windows.Forms.GroupBox();
this.muxBoardNrLabel = new System.Windows.Forms.Label(); this.label2 = new System.Windows.Forms.Label();
this.nameTextBox = new System.Windows.Forms.TextBox(); this.headPortNrTextBox = new System.Windows.Forms.TextBox();
this.nameLabel = new System.Windows.Forms.Label(); this.tabControl1.SuspendLayout();
this.classNameLabel = new System.Windows.Forms.Label(); this.tabPage1.SuspendLayout();
this.tabPage2 = new System.Windows.Forms.TabPage(); this.groupBox1.SuspendLayout();
this.tabControl1.SuspendLayout(); this.optoDataGroupBox.SuspendLayout();
this.tabPage1.SuspendLayout(); this.groupBox2.SuspendLayout();
this.groupBox2.SuspendLayout(); this.SuspendLayout();
this.groupBox1.SuspendLayout(); //
this.optoDataGroupBox.SuspendLayout(); // tabControl1
this.SuspendLayout(); //
// this.tabControl1.Controls.Add(this.tabPage1);
// tabControl1 this.tabControl1.Controls.Add(this.tabPage2);
// this.tabControl1.Location = new System.Drawing.Point(3, 3);
this.tabControl1.Controls.Add(this.tabPage1); this.tabControl1.Name = "tabControl1";
this.tabControl1.Controls.Add(this.tabPage2); this.tabControl1.SelectedIndex = 0;
this.tabControl1.Location = new System.Drawing.Point(3, 4); this.tabControl1.Size = new System.Drawing.Size(611, 432);
this.tabControl1.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); this.tabControl1.TabIndex = 0;
this.tabControl1.Name = "tabControl1"; //
this.tabControl1.SelectedIndex = 0; // tabPage1
this.tabControl1.Size = new System.Drawing.Size(687, 540); //
this.tabControl1.TabIndex = 0; this.tabPage1.Controls.Add(this.groupBox2);
// this.tabPage1.Controls.Add(this.label4);
// tabPage1 this.tabPage1.Controls.Add(this.label3);
// this.tabPage1.Controls.Add(this.groupBox1);
this.tabPage1.Controls.Add(this.groupBox2); this.tabPage1.Controls.Add(this.optoDataGroupBox);
this.tabPage1.Controls.Add(this.label4); this.tabPage1.Controls.Add(this.groupTextBox);
this.tabPage1.Controls.Add(this.label3); this.tabPage1.Controls.Add(this.groupLabel);
this.tabPage1.Controls.Add(this.groupBox1); this.tabPage1.Controls.Add(this.muxBoardNrTextBox);
this.tabPage1.Controls.Add(this.optoDataGroupBox); this.tabPage1.Controls.Add(this.muxBoardNrLabel);
this.tabPage1.Controls.Add(this.groupTextBox); this.tabPage1.Controls.Add(this.nameTextBox);
this.tabPage1.Controls.Add(this.groupLabel); this.tabPage1.Controls.Add(this.nameLabel);
this.tabPage1.Controls.Add(this.muxBoardNrTextBox); this.tabPage1.Controls.Add(this.classNameLabel);
this.tabPage1.Controls.Add(this.muxBoardNrLabel); this.tabPage1.Location = new System.Drawing.Point(4, 25);
this.tabPage1.Controls.Add(this.nameTextBox); this.tabPage1.Name = "tabPage1";
this.tabPage1.Controls.Add(this.nameLabel); this.tabPage1.Padding = new System.Windows.Forms.Padding(3);
this.tabPage1.Controls.Add(this.classNameLabel); this.tabPage1.Size = new System.Drawing.Size(603, 403);
this.tabPage1.Location = new System.Drawing.Point(4, 29); this.tabPage1.TabIndex = 0;
this.tabPage1.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); this.tabPage1.Text = "Config";
this.tabPage1.Name = "tabPage1"; this.tabPage1.UseVisualStyleBackColor = true;
this.tabPage1.Padding = new System.Windows.Forms.Padding(3, 4, 3, 4); //
this.tabPage1.Size = new System.Drawing.Size(679, 507); // label4
this.tabPage1.TabIndex = 0; //
this.tabPage1.Text = "Config"; this.label4.AutoSize = true;
this.tabPage1.UseVisualStyleBackColor = true; this.label4.Location = new System.Drawing.Point(208, 101);
// this.label4.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
// groupBox2 this.label4.Name = "label4";
// this.label4.Size = new System.Drawing.Size(40, 16);
this.groupBox2.Controls.Add(this.headPortNrTextBox); this.label4.TabIndex = 25;
this.groupBox2.Controls.Add(this.label2); this.label4.Text = "1 .. 10";
this.groupBox2.Location = new System.Drawing.Point(11, 450); //
this.groupBox2.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); // label3
this.groupBox2.Name = "groupBox2"; //
this.groupBox2.Padding = new System.Windows.Forms.Padding(3, 4, 3, 4); this.label3.AutoSize = true;
this.groupBox2.Size = new System.Drawing.Size(621, 52); this.label3.Location = new System.Drawing.Point(208, 72);
this.groupBox2.TabIndex = 26; this.label3.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.groupBox2.TabStop = false; this.label3.Name = "label3";
this.groupBox2.Text = "Head Communication"; this.label3.Size = new System.Drawing.Size(33, 16);
// this.label3.TabIndex = 24;
// headPortNrTextBox this.label3.Text = "1 .. 4";
// //
this.headPortNrTextBox.Enabled = false; // groupBox1
this.headPortNrTextBox.Location = new System.Drawing.Point(494, 19); //
this.headPortNrTextBox.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); this.groupBox1.Controls.Add(this.comboBoxCommunicationInterface);
this.headPortNrTextBox.Name = "headPortNrTextBox"; this.groupBox1.Controls.Add(this.label1);
this.headPortNrTextBox.Size = new System.Drawing.Size(49, 26); this.groupBox1.Controls.Add(this.rfidPortNrTextBox);
this.headPortNrTextBox.TabIndex = 8; this.groupBox1.Controls.Add(this.rfidSerialPortNrLabel);
// this.groupBox1.Location = new System.Drawing.Point(10, 259);
// label2 this.groupBox1.Margin = new System.Windows.Forms.Padding(4);
// this.groupBox1.Name = "groupBox1";
this.label2.AutoSize = true; this.groupBox1.Padding = new System.Windows.Forms.Padding(4);
this.label2.Location = new System.Drawing.Point(361, 22); this.groupBox1.Size = new System.Drawing.Size(552, 68);
this.label2.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.groupBox1.TabIndex = 23;
this.label2.Name = "label2"; this.groupBox1.TabStop = false;
this.label2.Size = new System.Drawing.Size(107, 20); this.groupBox1.Text = "RFID / NFC communication (in case mux. board is not used)";
this.label2.TabIndex = 7; //
this.label2.Text = "Serial port nr.:"; // comboBoxCommunicationInterface
// //
// label4 this.comboBoxCommunicationInterface.Enabled = false;
// this.comboBoxCommunicationInterface.FormattingEnabled = true;
this.label4.AutoSize = true; this.comboBoxCommunicationInterface.Items.AddRange(new object[] {
this.label4.Location = new System.Drawing.Point(234, 126); "RFID",
this.label4.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); "NFC"});
this.label4.Name = "label4"; this.comboBoxCommunicationInterface.Location = new System.Drawing.Point(201, 27);
this.label4.Size = new System.Drawing.Size(52, 20); this.comboBoxCommunicationInterface.Name = "comboBoxCommunicationInterface";
this.label4.TabIndex = 25; this.comboBoxCommunicationInterface.Size = new System.Drawing.Size(71, 24);
this.label4.Text = "1 .. 10"; this.comboBoxCommunicationInterface.TabIndex = 9;
// //
// label3 // label1
// //
this.label3.AutoSize = true; this.label1.AutoSize = true;
this.label3.Location = new System.Drawing.Point(234, 90); this.label1.Location = new System.Drawing.Point(41, 30);
this.label3.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.label3.Name = "label3"; this.label1.Name = "label1";
this.label3.Size = new System.Drawing.Size(43, 20); this.label1.Size = new System.Drawing.Size(153, 16);
this.label3.TabIndex = 24; this.label1.TabIndex = 8;
this.label3.Text = "1 .. 4"; this.label1.Text = "Communication Interface";
// //
// groupBox1 // rfidPortNrTextBox
// //
this.groupBox1.Controls.Add(this.comboBoxCommunicationInterface); this.rfidPortNrTextBox.Enabled = false;
this.groupBox1.Controls.Add(this.label1); this.rfidPortNrTextBox.Location = new System.Drawing.Point(439, 26);
this.groupBox1.Controls.Add(this.rfidPortNrTextBox); this.rfidPortNrTextBox.Margin = new System.Windows.Forms.Padding(4);
this.groupBox1.Controls.Add(this.rfidSerialPortNrLabel); this.rfidPortNrTextBox.Name = "rfidPortNrTextBox";
this.groupBox1.Location = new System.Drawing.Point(11, 363); this.rfidPortNrTextBox.Size = new System.Drawing.Size(44, 22);
this.groupBox1.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); this.rfidPortNrTextBox.TabIndex = 7;
this.groupBox1.Name = "groupBox1"; //
this.groupBox1.Padding = new System.Windows.Forms.Padding(4, 5, 4, 5); // rfidSerialPortNrLabel
this.groupBox1.Size = new System.Drawing.Size(621, 85); //
this.groupBox1.TabIndex = 23; this.rfidSerialPortNrLabel.AutoSize = true;
this.groupBox1.TabStop = false; this.rfidSerialPortNrLabel.Location = new System.Drawing.Point(321, 30);
this.groupBox1.Text = "RFID / NFC communication (in case mux. board is not used)"; this.rfidSerialPortNrLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
// this.rfidSerialPortNrLabel.Name = "rfidSerialPortNrLabel";
// comboBoxCommunicationInterface this.rfidSerialPortNrLabel.Size = new System.Drawing.Size(88, 16);
// this.rfidSerialPortNrLabel.TabIndex = 6;
this.comboBoxCommunicationInterface.Enabled = false; this.rfidSerialPortNrLabel.Text = "Serial port nr.:";
this.comboBoxCommunicationInterface.FormattingEnabled = true; //
this.comboBoxCommunicationInterface.Items.AddRange(new object[] { "RFID", "NFC" }); // optoDataGroupBox
this.comboBoxCommunicationInterface.Location = new System.Drawing.Point(226, 34); //
this.comboBoxCommunicationInterface.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); this.optoDataGroupBox.Controls.Add(this.tcpipPortLabel);
this.comboBoxCommunicationInterface.Name = "comboBoxCommunicationInterface"; this.optoDataGroupBox.Controls.Add(this.tcpipPortTextBox);
this.comboBoxCommunicationInterface.Size = new System.Drawing.Size(79, 28); this.optoDataGroupBox.Controls.Add(this.ipAddressLabel);
this.comboBoxCommunicationInterface.TabIndex = 9; this.optoDataGroupBox.Controls.Add(this.ipAddressTextBox);
// this.optoDataGroupBox.Controls.Add(this.radioButton1);
// label1 this.optoDataGroupBox.Controls.Add(this.radioButton2);
// this.optoDataGroupBox.Controls.Add(this.optoSerialPortLabel);
this.label1.AutoSize = true; this.optoDataGroupBox.Controls.Add(this.optoSerialPortTextBox);
this.label1.Location = new System.Drawing.Point(46, 38); this.optoDataGroupBox.Location = new System.Drawing.Point(10, 131);
this.label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.optoDataGroupBox.Margin = new System.Windows.Forms.Padding(4);
this.label1.Name = "label1"; this.optoDataGroupBox.Name = "optoDataGroupBox";
this.label1.Size = new System.Drawing.Size(187, 20); this.optoDataGroupBox.Padding = new System.Windows.Forms.Padding(4);
this.label1.TabIndex = 8; this.optoDataGroupBox.Size = new System.Drawing.Size(552, 119);
this.label1.Text = "Communication Interface"; this.optoDataGroupBox.TabIndex = 18;
// this.optoDataGroupBox.TabStop = false;
// rfidPortNrTextBox this.optoDataGroupBox.Text = "Opto-data";
// //
this.rfidPortNrTextBox.Enabled = false; // tcpipPortLabel
this.rfidPortNrTextBox.Location = new System.Drawing.Point(494, 32); //
this.rfidPortNrTextBox.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); this.tcpipPortLabel.AutoSize = true;
this.rfidPortNrTextBox.Name = "rfidPortNrTextBox"; this.tcpipPortLabel.Location = new System.Drawing.Point(41, 87);
this.rfidPortNrTextBox.Size = new System.Drawing.Size(49, 26); this.tcpipPortLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.rfidPortNrTextBox.TabIndex = 7; this.tcpipPortLabel.Name = "tcpipPortLabel";
// this.tcpipPortLabel.Size = new System.Drawing.Size(54, 16);
// rfidSerialPortNrLabel this.tcpipPortLabel.TabIndex = 4;
// this.tcpipPortLabel.Text = "Port nr..:";
this.rfidSerialPortNrLabel.AutoSize = true; //
this.rfidSerialPortNrLabel.Location = new System.Drawing.Point(361, 38); // tcpipPortTextBox
this.rfidSerialPortNrLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); //
this.rfidSerialPortNrLabel.Name = "rfidSerialPortNrLabel"; this.tcpipPortTextBox.Enabled = false;
this.rfidSerialPortNrLabel.Size = new System.Drawing.Size(107, 20); this.tcpipPortTextBox.Location = new System.Drawing.Point(143, 84);
this.rfidSerialPortNrLabel.TabIndex = 6; this.tcpipPortTextBox.Margin = new System.Windows.Forms.Padding(4);
this.rfidSerialPortNrLabel.Text = "Serial port nr.:"; this.tcpipPortTextBox.Name = "tcpipPortTextBox";
// this.tcpipPortTextBox.Size = new System.Drawing.Size(51, 22);
// optoDataGroupBox this.tcpipPortTextBox.TabIndex = 5;
// //
this.optoDataGroupBox.Controls.Add(this.checkBox_EnableShowChanels); // ipAddressLabel
this.optoDataGroupBox.Controls.Add(this.tBBeginDataFlush); //
this.optoDataGroupBox.Controls.Add(this.labelFlush); this.ipAddressLabel.AutoSize = true;
this.optoDataGroupBox.Controls.Add(this.tcpipPortLabel); this.ipAddressLabel.Location = new System.Drawing.Point(41, 59);
this.optoDataGroupBox.Controls.Add(this.tcpipPortTextBox); this.ipAddressLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.optoDataGroupBox.Controls.Add(this.ipAddressLabel); this.ipAddressLabel.Name = "ipAddressLabel";
this.optoDataGroupBox.Controls.Add(this.ipAddressTextBox); this.ipAddressLabel.Size = new System.Drawing.Size(78, 16);
this.optoDataGroupBox.Controls.Add(this.radioButton1); this.ipAddressLabel.TabIndex = 2;
this.optoDataGroupBox.Controls.Add(this.radioButton2); this.ipAddressLabel.Text = "IP address.:";
this.optoDataGroupBox.Controls.Add(this.optoSerialPortLabel); //
this.optoDataGroupBox.Controls.Add(this.optoSerialPortTextBox); // ipAddressTextBox
this.optoDataGroupBox.Location = new System.Drawing.Point(11, 164); //
this.optoDataGroupBox.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); this.ipAddressTextBox.Enabled = false;
this.optoDataGroupBox.Name = "optoDataGroupBox"; this.ipAddressTextBox.Location = new System.Drawing.Point(143, 55);
this.optoDataGroupBox.Padding = new System.Windows.Forms.Padding(4, 5, 4, 5); this.ipAddressTextBox.Margin = new System.Windows.Forms.Padding(4);
this.optoDataGroupBox.Size = new System.Drawing.Size(621, 189); this.ipAddressTextBox.Name = "ipAddressTextBox";
this.optoDataGroupBox.TabIndex = 18; this.ipAddressTextBox.Size = new System.Drawing.Size(129, 22);
this.optoDataGroupBox.TabStop = false; this.ipAddressTextBox.TabIndex = 3;
this.optoDataGroupBox.Text = "Opto-data"; //
// // radioButton1
// checkBox_EnableShowChanels //
// this.radioButton1.AutoSize = true;
this.checkBox_EnableShowChanels.Checked = true; this.radioButton1.Checked = true;
this.checkBox_EnableShowChanels.CheckState = System.Windows.Forms.CheckState.Checked; this.radioButton1.Enabled = false;
this.checkBox_EnableShowChanels.Enabled = false; this.radioButton1.Location = new System.Drawing.Point(29, 23);
this.checkBox_EnableShowChanels.Location = new System.Drawing.Point(351, 147); this.radioButton1.Margin = new System.Windows.Forms.Padding(4);
this.checkBox_EnableShowChanels.Name = "checkBox_EnableShowChanels"; this.radioButton1.Name = "radioButton1";
this.checkBox_EnableShowChanels.Size = new System.Drawing.Size(238, 24); this.radioButton1.Size = new System.Drawing.Size(99, 20);
this.checkBox_EnableShowChanels.TabIndex = 10; this.radioButton1.TabIndex = 0;
this.checkBox_EnableShowChanels.Text = "Enable Show Channels"; this.radioButton1.TabStop = true;
this.checkBox_EnableShowChanels.UseVisualStyleBackColor = true; this.radioButton1.Text = "Use TCP/IP";
// this.radioButton1.UseVisualStyleBackColor = true;
// tBBeginDataFlush //
// // radioButton2
this.tBBeginDataFlush.Enabled = false; //
this.tBBeginDataFlush.Location = new System.Drawing.Point(474, 105); this.radioButton2.AutoSize = true;
this.tBBeginDataFlush.MaxLength = 8; this.radioButton2.Enabled = false;
this.tBBeginDataFlush.Name = "tBBeginDataFlush"; this.radioButton2.Location = new System.Drawing.Point(312, 23);
this.tBBeginDataFlush.Size = new System.Drawing.Size(69, 26); this.radioButton2.Margin = new System.Windows.Forms.Padding(4);
this.tBBeginDataFlush.TabIndex = 9; this.radioButton2.Name = "radioButton2";
this.tBBeginDataFlush.Text = "2000"; this.radioButton2.Size = new System.Drawing.Size(115, 20);
this.tBBeginDataFlush.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; this.radioButton2.TabIndex = 1;
// this.radioButton2.Text = "Use serial port";
// labelFlush this.radioButton2.UseVisualStyleBackColor = true;
// //
this.labelFlush.Location = new System.Drawing.Point(328, 109); // optoSerialPortLabel
this.labelFlush.Name = "labelFlush"; //
this.labelFlush.Size = new System.Drawing.Size(140, 22); this.optoSerialPortLabel.AutoSize = true;
this.labelFlush.TabIndex = 8; this.optoSerialPortLabel.Location = new System.Drawing.Point(321, 55);
this.labelFlush.Text = "Begin Data Flush:"; this.optoSerialPortLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
// this.optoSerialPortLabel.Name = "optoSerialPortLabel";
// tcpipPortLabel this.optoSerialPortLabel.Size = new System.Drawing.Size(88, 16);
// this.optoSerialPortLabel.TabIndex = 6;
this.tcpipPortLabel.AutoSize = true; this.optoSerialPortLabel.Text = "Serial port nr.:";
this.tcpipPortLabel.Location = new System.Drawing.Point(46, 109); //
this.tcpipPortLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); // optoSerialPortTextBox
this.tcpipPortLabel.Name = "tcpipPortLabel"; //
this.tcpipPortLabel.Size = new System.Drawing.Size(68, 20); this.optoSerialPortTextBox.Enabled = false;
this.tcpipPortLabel.TabIndex = 4; this.optoSerialPortTextBox.Location = new System.Drawing.Point(439, 52);
this.tcpipPortLabel.Text = "Port nr..:"; this.optoSerialPortTextBox.Margin = new System.Windows.Forms.Padding(4);
// this.optoSerialPortTextBox.Name = "optoSerialPortTextBox";
// tcpipPortTextBox this.optoSerialPortTextBox.Size = new System.Drawing.Size(44, 22);
// this.optoSerialPortTextBox.TabIndex = 7;
this.tcpipPortTextBox.Enabled = false; //
this.tcpipPortTextBox.Location = new System.Drawing.Point(161, 105); // groupTextBox
this.tcpipPortTextBox.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); //
this.tcpipPortTextBox.Name = "tcpipPortTextBox"; this.groupTextBox.Enabled = false;
this.tcpipPortTextBox.Size = new System.Drawing.Size(57, 26); this.groupTextBox.Location = new System.Drawing.Point(153, 97);
this.tcpipPortTextBox.TabIndex = 5; this.groupTextBox.Margin = new System.Windows.Forms.Padding(4);
// this.groupTextBox.Name = "groupTextBox";
// ipAddressLabel this.groupTextBox.Size = new System.Drawing.Size(44, 22);
// this.groupTextBox.TabIndex = 22;
this.ipAddressLabel.AutoSize = true; //
this.ipAddressLabel.Location = new System.Drawing.Point(46, 74); // groupLabel
this.ipAddressLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); //
this.ipAddressLabel.Name = "ipAddressLabel"; this.groupLabel.AutoSize = true;
this.ipAddressLabel.Size = new System.Drawing.Size(93, 20); this.groupLabel.Location = new System.Drawing.Point(6, 101);
this.ipAddressLabel.TabIndex = 2; this.groupLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.ipAddressLabel.Text = "IP address.:"; this.groupLabel.Name = "groupLabel";
// this.groupLabel.Size = new System.Drawing.Size(54, 16);
// ipAddressTextBox this.groupLabel.TabIndex = 21;
// this.groupLabel.Text = "Group 2";
this.ipAddressTextBox.Enabled = false; //
this.ipAddressTextBox.Location = new System.Drawing.Point(161, 69); // muxBoardNrTextBox
this.ipAddressTextBox.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); //
this.ipAddressTextBox.Name = "ipAddressTextBox"; this.muxBoardNrTextBox.Enabled = false;
this.ipAddressTextBox.Size = new System.Drawing.Size(145, 26); this.muxBoardNrTextBox.Location = new System.Drawing.Point(153, 69);
this.ipAddressTextBox.TabIndex = 3; this.muxBoardNrTextBox.Margin = new System.Windows.Forms.Padding(4);
// this.muxBoardNrTextBox.Name = "muxBoardNrTextBox";
// radioButton1 this.muxBoardNrTextBox.Size = new System.Drawing.Size(44, 22);
// this.muxBoardNrTextBox.TabIndex = 20;
this.radioButton1.AutoSize = true; //
this.radioButton1.Checked = true; // muxBoardNrLabel
this.radioButton1.Enabled = false; //
this.radioButton1.Location = new System.Drawing.Point(33, 29); this.muxBoardNrLabel.AutoSize = true;
this.radioButton1.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); this.muxBoardNrLabel.Location = new System.Drawing.Point(6, 72);
this.radioButton1.Name = "radioButton1"; this.muxBoardNrLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.radioButton1.Size = new System.Drawing.Size(109, 24); this.muxBoardNrLabel.Name = "muxBoardNrLabel";
this.radioButton1.TabIndex = 0; this.muxBoardNrLabel.Size = new System.Drawing.Size(131, 16);
this.radioButton1.TabStop = true; this.muxBoardNrLabel.TabIndex = 19;
this.radioButton1.Text = "Use TCP/IP"; this.muxBoardNrLabel.Text = "Group 1 (mux. board)";
this.radioButton1.UseVisualStyleBackColor = true; //
// // nameTextBox
// radioButton2 //
// this.nameTextBox.Enabled = false;
this.radioButton2.AutoSize = true; this.nameTextBox.Location = new System.Drawing.Point(153, 40);
this.radioButton2.Enabled = false; this.nameTextBox.Margin = new System.Windows.Forms.Padding(4);
this.radioButton2.Location = new System.Drawing.Point(351, 29); this.nameTextBox.Name = "nameTextBox";
this.radioButton2.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); this.nameTextBox.Size = new System.Drawing.Size(160, 22);
this.radioButton2.Name = "radioButton2"; this.nameTextBox.TabIndex = 17;
this.radioButton2.Size = new System.Drawing.Size(129, 24); //
this.radioButton2.TabIndex = 1; // nameLabel
this.radioButton2.Text = "Use serial port"; //
this.radioButton2.UseVisualStyleBackColor = true; this.nameLabel.AutoSize = true;
// this.nameLabel.Location = new System.Drawing.Point(6, 44);
// optoSerialPortLabel this.nameLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
// this.nameLabel.Name = "nameLabel";
this.optoSerialPortLabel.AutoSize = true; this.nameLabel.Size = new System.Drawing.Size(44, 16);
this.optoSerialPortLabel.Location = new System.Drawing.Point(361, 69); this.nameLabel.TabIndex = 16;
this.optoSerialPortLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.nameLabel.Text = "Name";
this.optoSerialPortLabel.Name = "optoSerialPortLabel"; //
this.optoSerialPortLabel.Size = new System.Drawing.Size(107, 20); // classNameLabel
this.optoSerialPortLabel.TabIndex = 6; //
this.optoSerialPortLabel.Text = "Serial port nr.:"; this.classNameLabel.AutoSize = true;
// this.classNameLabel.Location = new System.Drawing.Point(149, 11);
// optoSerialPortTextBox this.classNameLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
// this.classNameLabel.Name = "classNameLabel";
this.optoSerialPortTextBox.Enabled = false; this.classNameLabel.Size = new System.Drawing.Size(78, 16);
this.optoSerialPortTextBox.Location = new System.Drawing.Point(494, 65); this.classNameLabel.TabIndex = 15;
this.optoSerialPortTextBox.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); this.classNameLabel.Text = "ClassName";
this.optoSerialPortTextBox.Name = "optoSerialPortTextBox"; //
this.optoSerialPortTextBox.Size = new System.Drawing.Size(49, 26); // tabPage2
this.optoSerialPortTextBox.TabIndex = 7; //
// this.tabPage2.Location = new System.Drawing.Point(4, 25);
// groupTextBox this.tabPage2.Name = "tabPage2";
// this.tabPage2.Padding = new System.Windows.Forms.Padding(3);
this.groupTextBox.Enabled = false; this.tabPage2.Size = new System.Drawing.Size(603, 403);
this.groupTextBox.Location = new System.Drawing.Point(172, 121); this.tabPage2.TabIndex = 1;
this.groupTextBox.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); this.tabPage2.Text = "Test";
this.groupTextBox.Name = "groupTextBox"; this.tabPage2.UseVisualStyleBackColor = true;
this.groupTextBox.Size = new System.Drawing.Size(49, 26); //
this.groupTextBox.TabIndex = 22; // groupBox2
// //
// groupLabel this.groupBox2.Controls.Add(this.headPortNrTextBox);
// this.groupBox2.Controls.Add(this.label2);
this.groupLabel.AutoSize = true; this.groupBox2.Location = new System.Drawing.Point(10, 335);
this.groupLabel.Location = new System.Drawing.Point(7, 126); this.groupBox2.Name = "groupBox2";
this.groupLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.groupBox2.Size = new System.Drawing.Size(552, 50);
this.groupLabel.Name = "groupLabel"; this.groupBox2.TabIndex = 26;
this.groupLabel.Size = new System.Drawing.Size(67, 20); this.groupBox2.TabStop = false;
this.groupLabel.TabIndex = 21; this.groupBox2.Text = "Head Communication";
this.groupLabel.Text = "Group 2"; //
// // label2
// muxBoardNrTextBox //
// this.label2.AutoSize = true;
this.muxBoardNrTextBox.Enabled = false; this.label2.Location = new System.Drawing.Point(321, 18);
this.muxBoardNrTextBox.Location = new System.Drawing.Point(172, 86); this.label2.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.muxBoardNrTextBox.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); this.label2.Name = "label2";
this.muxBoardNrTextBox.Name = "muxBoardNrTextBox"; this.label2.Size = new System.Drawing.Size(88, 16);
this.muxBoardNrTextBox.Size = new System.Drawing.Size(49, 26); this.label2.TabIndex = 7;
this.muxBoardNrTextBox.TabIndex = 20; this.label2.Text = "Serial port nr.:";
// //
// muxBoardNrLabel // headPortNrTextBox
// //
this.muxBoardNrLabel.AutoSize = true; this.headPortNrTextBox.Enabled = false;
this.muxBoardNrLabel.Location = new System.Drawing.Point(7, 90); this.headPortNrTextBox.Location = new System.Drawing.Point(439, 15);
this.muxBoardNrLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.headPortNrTextBox.Margin = new System.Windows.Forms.Padding(4);
this.muxBoardNrLabel.Name = "muxBoardNrLabel"; this.headPortNrTextBox.Name = "headPortNrTextBox";
this.muxBoardNrLabel.Size = new System.Drawing.Size(159, 20); this.headPortNrTextBox.Size = new System.Drawing.Size(44, 22);
this.muxBoardNrLabel.TabIndex = 19; this.headPortNrTextBox.TabIndex = 8;
this.muxBoardNrLabel.Text = "Group 1 (mux. board)"; //
// // IperlHeadCfgCtrl
// nameTextBox //
// this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
this.nameTextBox.Enabled = false; this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.nameTextBox.Location = new System.Drawing.Point(172, 50); this.Controls.Add(this.tabControl1);
this.nameTextBox.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); this.Margin = new System.Windows.Forms.Padding(4);
this.nameTextBox.Name = "nameTextBox"; this.Name = "GenesisCfgCtrl";
this.nameTextBox.Size = new System.Drawing.Size(180, 26); this.Size = new System.Drawing.Size(617, 438);
this.nameTextBox.TabIndex = 17; this.Load += new System.EventHandler(this.WaterMeterCfgCtrl_Load);
// this.tabControl1.ResumeLayout(false);
// nameLabel this.tabPage1.ResumeLayout(false);
// this.tabPage1.PerformLayout();
this.nameLabel.AutoSize = true; this.groupBox1.ResumeLayout(false);
this.nameLabel.Location = new System.Drawing.Point(7, 55); this.groupBox1.PerformLayout();
this.nameLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.optoDataGroupBox.ResumeLayout(false);
this.nameLabel.Name = "nameLabel"; this.optoDataGroupBox.PerformLayout();
this.nameLabel.Size = new System.Drawing.Size(51, 20); this.groupBox2.ResumeLayout(false);
this.nameLabel.TabIndex = 16; this.groupBox2.PerformLayout();
this.nameLabel.Text = "Name"; this.ResumeLayout(false);
//
// 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;
//
// GenesisCfgCtrl
//
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 = "GenesisCfgCtrl";
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.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.CheckBox checkBox_EnableShowChanels; #endregion
private System.Windows.Forms.Label labelFlush;
private System.Windows.Forms.TextBox tBBeginDataFlush;
#endregion
private System.Windows.Forms.TabControl tabControl1; private System.Windows.Forms.TabControl tabControl1;
private System.Windows.Forms.TabPage tabPage1; private System.Windows.Forms.TabPage tabPage1;
@@ -6,7 +6,7 @@ using System;
using System.Globalization; using System.Globalization;
using TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.DataPackages.MeasurementRecords; using TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.DataPackages.MeasurementRecords;
using TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.Protocols.StreamingProtocol; using TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.Protocols.StreamingProtocol;
using Xylem.Common.Metrology.Measurements;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.common namespace TBF.Rig.RegisterReaders.GenesisRegReader.common
@@ -25,7 +25,6 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.common
public static readonly int Length = 42; public static readonly int Length = 42;
private static CultureInfo culture; private static CultureInfo culture;
public MeasurementRecord data;
/// ///
/// Strobed value /// Strobed value
@@ -125,7 +124,11 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.common
} }
// -------- TIMESTAMP (seconds) --------
private const double TS_RANGE = StreamingDecoder.CpuTimeOverflowS;
// -------- VOLUME (liters) --------
private const double VOL_RANGE = StreamingDecoder.DefaultAccuDutOverflowVolumeCm * 1000;
/// <summary> /// <summary>
/// update data by CalibrationRecord /// update data by CalibrationRecord
@@ -146,8 +149,7 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.common
if (data == null) if (data == null)
throw new ArgumentNullException(nameof(data)); throw new ArgumentNullException(nameof(data));
this.data = data; UpdateData( data.Channel, data.VolumeCm, data.TimeS, counter, refFlow, ref volumeRawExtLast, ref timestampExtLast);
UpdateData( data.Channel, data.VolumeCm, data.OverflowVolumeCm, data.TimeS, data.OverflowTimeS, counter, refFlow, ref volumeRawExtLast, ref timestampExtLast);
} }
/// <summary> /// <summary>
@@ -168,8 +170,8 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.common
{ {
if (data == null) if (data == null)
throw new ArgumentNullException(nameof(data)); throw new ArgumentNullException(nameof(data));
this.data = data;
UpdateData( data.Channel, data.VolumeCm, data.OverflowVolumeCm, data.TimeS, data.OverflowTimeS, counter, refFlow, ref volumeRawExtLast, ref timestampExtLast); UpdateData( data.Channel, data.VolumeCm, data.TimeS, counter, refFlow, ref volumeRawExtLast, ref timestampExtLast);
} }
/// <summary> /// <summary>
@@ -185,9 +187,7 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.common
private void UpdateData( private void UpdateData(
int channel, int channel,
double volumeCm, double volumeCm,
double OverflowVolumeCm,
double timeS, double timeS,
double OverflowTimeS,
int counter, int counter,
float refFlow, float refFlow,
ref double volumeRawExtLast, ref double volumeRawExtLast,
@@ -200,30 +200,29 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.common
Flags = OptoTelegramFlags.OK; Flags = OptoTelegramFlags.OK;
FlowRaw = 0; FlowRaw = 0;
double nV = NormalizeByOverflow(volumeCm, OverflowVolumeCm); VolumeRaw = volumeCm * 1000.0; // liters
VolumeRaw = nV * 1000.0; // liters
CheckSum = 0; CheckSum = 0;
Impedance = 0; Impedance = 0;
EmfRaw = 0; EmfRaw = 0;
MagneticFieldRaw = 0; MagneticFieldRaw = 0;
double ts = NormalizeByOverflow(timeS, OverflowTimeS); double ts = NormalizeTimestamp(timeS);
Timestamp = ts; Timestamp = ts;
VolumeRawExt = UnwrapVolume(VolumeRaw,OverflowVolumeCm * 1000, ref volumeRawExtLast); VolumeRawExt = UnwrapVolume(VolumeRaw, ref volumeRawExtLast);
TimestampExt = UnwrapTimestamp(ts,OverflowTimeS, ref timestampExtLast); TimestampExt = UnwrapTimestamp(ts, ref timestampExtLast);
} }
private static double NormalizeByOverflow(double value, double overfValue = 0) private static double NormalizeTimestamp(double timeS)
{ {
double nValue = value % overfValue; double ts = timeS % TS_RANGE;
if (nValue < 0) if (ts < 0)
nValue += overfValue; ts += TS_RANGE;
return nValue; return ts;
} }
private static double UnwrapVolume(double currentVolume, double overfValue, ref double volumeRawExtLast) private static double UnwrapVolume(double currentVolume, ref double volumeRawExtLast)
{ {
double result; double result;
@@ -233,25 +232,16 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.common
} }
else else
{ {
double lastMod = volumeRawExtLast % overfValue; result = currentVolume < volumeRawExtLast
if (lastMod < 0) ? currentVolume + VOL_RANGE
lastMod += overfValue; : currentVolume;
double delta = currentVolume - lastMod;
if (delta < -overfValue / 2.0)
delta += overfValue;
else if (delta > overfValue / 2.0)
delta -= overfValue;
result = volumeRawExtLast + delta;
} }
volumeRawExtLast = result; volumeRawExtLast = result;
return result; return result;
} }
private static double UnwrapTimestamp(double currentTimestamp,double overfValue, ref double timestampExtLast) private static double UnwrapTimestamp(double currentTimestamp, ref double timestampExtLast)
{ {
double result; double result;
@@ -261,16 +251,16 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.common
} }
else else
{ {
double lastMod = timestampExtLast % overfValue; double lastMod = timestampExtLast % TS_RANGE;
if (lastMod < 0) if (lastMod < 0)
lastMod += overfValue; lastMod += TS_RANGE;
double delta = currentTimestamp - lastMod; double delta = currentTimestamp - lastMod;
if (delta < -overfValue / 2.0) if (delta < -TS_RANGE / 2.0)
delta += overfValue; delta += TS_RANGE;
else if (delta > overfValue / 2.0) else if (delta > TS_RANGE / 2.0)
delta -= overfValue; delta -= TS_RANGE;
result = timestampExtLast + delta; result = timestampExtLast + delta;
} }
@@ -359,33 +349,5 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.common
Label()); Label());
} }
} }
public void Copy(OptoTelegramRaw optoTelegramRaw)
{
this.Flags = optoTelegramRaw.Flags;
this.DateTime = optoTelegramRaw.DateTime;
this.RefFlow = optoTelegramRaw.RefFlow;
this.Counter = optoTelegramRaw.Counter;
this.EmfRaw = optoTelegramRaw.EmfRaw;
this.MagneticFieldRaw = optoTelegramRaw.MagneticFieldRaw;
this.FlowRaw = optoTelegramRaw.FlowRaw;
this.VolumeRaw = optoTelegramRaw.VolumeRaw;
this.VolumeRawExt = optoTelegramRaw.VolumeRawExt;
this.Impedance = optoTelegramRaw.Impedance;
this.Timestamp = optoTelegramRaw.Timestamp;
this.TimestampExt = optoTelegramRaw.TimestampExt;
this.CheckSum = optoTelegramRaw.CheckSum;
this.iChannel = optoTelegramRaw.iChannel;
}
public string rawDataToString()
{
if (data != null)
{
return string.Format("Channel: {0}, VolumeCm:{1}, OverflowVolumeCm:{2}, TimeS: {3}, OverflowTimeS:{4} ",
data.Channel, data.VolumeCm, data.OverflowVolumeCm, data.TimeS, data.OverflowTimeS);
}
return string.Empty;
}
} }
} }
@@ -0,0 +1,43 @@
using System;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.Applications
{
/// <summary>
/// describe a genesis register.
/// need for read and write
/// all request protocols uses RegisterDefinition
/// </summary>
public class ApplicationDefinition
{
/// <summary>
/// name of the application
/// </summary>
public String AppName;
/// <summary>
/// address of application
/// </summary>
/// <remarks date="2025-Aug-05" author="Thomas Wiedebusch">
/// - AppId from Byte to UInt16 including typecast for Byte[] return. To external, it will be used as Byte
/// as before this change. But being able to parse the configuration.json with OPTICALINTERFACE using the
/// AppId 256, which exceeds the byte range as this isn't a real application, but will be used to identify
/// the interface (configuration.json) version.
/// </remarks>
public UInt16 AppId;
/// <summary>
/// version of the application
/// </summary>
public Int32? AppVersion;
/// <summary>
/// Get application name
/// </summary>
/// <returns></returns>
public String GetIdent()
{
return $"{AppName}";
}
}
}
@@ -0,0 +1,78 @@
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.Applications.Const
{
/// <summary>
/// Genesis meter application state
/// </summary>
public enum MeterAppState
{
/// <summary>
/// This file application is not installed in the meter
/// </summary>
MeterAppNotInstalled,
/// <summary>
/// Meter version is equal to file version - it is up to date
/// </summary>
MeterAppUpToDate,
/// <summary>
/// Installation of application is required
/// </summary>
MeterAppInstallationRequired,
/// <summary>
/// Meter application is different from file application
/// </summary>
MeterAppVersionOutdated,
/// <summary>
/// CRC does not match even if meter and file application version are
/// shown as being identical!
/// </summary>
InvalidCrc,
/// <summary>
/// Meter applications has to be erased
/// </summary>
MeterAppErasureRequired,
/// <summary>
/// Application successfully downloaded to meter
/// </summary>
MeterAppDownloadSucceeded,
/// <summary>
/// Application download to meter suspicious
/// </summary>
MeterAppDownloadSuspicious,
/// <summary>
/// Application successfully erased from meter
/// </summary>
MeterAppSuccessfulErased,
/// <summary>
/// Application successfully updated in meter
/// </summary>
MeterAppSuccessfulUpdated,
/// <summary>
/// Application download to meter failed
/// </summary>
MeterAppDownloadFailed,
/// <summary>
/// Application download to meter active ongoing
/// </summary>
MeterAppDownloadActive,
/// <summary>
/// This file application is invalid
/// </summary>
FileAppInvalid,
/// <summary>
/// State is unknown because package file not loaded
/// </summary>
Unknown,
/// <summary>
/// Meter application detected but not checked
/// </summary>
MeterAppInstalledUnchecked,
/// <summary>
/// Meter application is not required
/// </summary>
MeterAppNotRequired,
/// <summary>
/// Delimiter for list
/// </summary>
MeterAppStateListDelimiter
}
}
@@ -0,0 +1,92 @@
using System;
using System.Linq;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.Applications.Const
{
/// <summary>
/// Concatenation of state and string
/// </summary>
public class MeterAppStateInfo
{
/// <summary>
/// Build state information
/// </summary>
private readonly MeterAppStateText[] _stateInfos;
/// <summary>
/// Ctor
/// </summary>
public MeterAppStateInfo()
{
_stateInfos = new MeterAppStateText[(Int32)MeterAppState.MeterAppStateListDelimiter];
_stateInfos[(Int32)MeterAppState.MeterAppNotInstalled].State = MeterAppState.MeterAppNotInstalled;
_stateInfos[(Int32)MeterAppState.MeterAppNotInstalled].Message = Xylem.Common.Hardware.WaterMeter.Genesis.Applications.Properties.Resources.StrMeterAppNotInstalled;
_stateInfos[(Int32)MeterAppState.MeterAppNotRequired].State = MeterAppState.MeterAppNotRequired;
_stateInfos[(Int32)MeterAppState.MeterAppNotRequired].Message = Xylem.Common.Hardware.WaterMeter.Genesis.Applications.Properties.Resources.StrMeterAppNotRequired;
_stateInfos[(Int32)MeterAppState.MeterAppUpToDate].State = MeterAppState.MeterAppUpToDate;
_stateInfos[(Int32)MeterAppState.MeterAppUpToDate].Message = Xylem.Common.Hardware.WaterMeter.Genesis.Applications.Properties.Resources.StrMeterAppUpToDate;
_stateInfos[(Int32)MeterAppState.MeterAppInstallationRequired].State = MeterAppState.MeterAppInstallationRequired;
_stateInfos[(Int32)MeterAppState.MeterAppInstallationRequired].Message = Xylem.Common.Hardware.WaterMeter.Genesis.Applications.Properties.Resources.StrMeterAppInstallationRequired;
_stateInfos[(Int32)MeterAppState.MeterAppVersionOutdated].State = MeterAppState.MeterAppVersionOutdated;
_stateInfos[(Int32)MeterAppState.MeterAppVersionOutdated].Message = Xylem.Common.Hardware.WaterMeter.Genesis.Applications.Properties.Resources.StrMeterAppVersionOutdated;
_stateInfos[(Int32)MeterAppState.InvalidCrc].State = MeterAppState.InvalidCrc;
_stateInfos[(Int32)MeterAppState.InvalidCrc].Message = Xylem.Common.Hardware.WaterMeter.Genesis.Applications.Properties.Resources.StrInvalidCrc;
_stateInfos[(Int32)MeterAppState.MeterAppErasureRequired].State = MeterAppState.MeterAppErasureRequired;
_stateInfos[(Int32)MeterAppState.MeterAppErasureRequired].Message = Xylem.Common.Hardware.WaterMeter.Genesis.Applications.Properties.Resources.StrMeterAppErasureRequired;
_stateInfos[(Int32)MeterAppState.MeterAppDownloadSucceeded].State = MeterAppState.MeterAppDownloadSucceeded;
_stateInfos[(Int32)MeterAppState.MeterAppDownloadSucceeded].Message = Xylem.Common.Hardware.WaterMeter.Genesis.Applications.Properties.Resources.StrMeterAppDownloadSucceeded;
_stateInfos[(Int32)MeterAppState.MeterAppDownloadSuspicious].State = MeterAppState.MeterAppDownloadSuspicious;
_stateInfos[(Int32)MeterAppState.MeterAppDownloadSuspicious].Message = Xylem.Common.Hardware.WaterMeter.Genesis.Applications.Properties.Resources.StrMeterAppDownloadSuspicious;
_stateInfos[(Int32)MeterAppState.MeterAppSuccessfulErased].State = MeterAppState.MeterAppSuccessfulErased;
_stateInfos[(Int32)MeterAppState.MeterAppSuccessfulErased].Message = Xylem.Common.Hardware.WaterMeter.Genesis.Applications.Properties.Resources.StrMeterAppSuccessfulErased;
_stateInfos[(Int32)MeterAppState.MeterAppSuccessfulUpdated].State = MeterAppState.MeterAppSuccessfulUpdated;
_stateInfos[(Int32)MeterAppState.MeterAppSuccessfulUpdated].Message = Xylem.Common.Hardware.WaterMeter.Genesis.Applications.Properties.Resources.StrMeterAppSuccessfulUpdated;
_stateInfos[(Int32)MeterAppState.MeterAppDownloadFailed].State = MeterAppState.MeterAppDownloadFailed;
_stateInfos[(Int32)MeterAppState.MeterAppDownloadFailed].Message = Xylem.Common.Hardware.WaterMeter.Genesis.Applications.Properties.Resources.StrMeterAppDownloadFailed;
_stateInfos[(Int32)MeterAppState.MeterAppDownloadActive].State = MeterAppState.MeterAppDownloadActive;
_stateInfos[(Int32)MeterAppState.MeterAppDownloadActive].Message = Xylem.Common.Hardware.WaterMeter.Genesis.Applications.Properties.Resources.StrMeterAppDownloadActive;
_stateInfos[(Int32)MeterAppState.FileAppInvalid].State = MeterAppState.FileAppInvalid;
_stateInfos[(Int32)MeterAppState.FileAppInvalid].Message = Xylem.Common.Hardware.WaterMeter.Genesis.Applications.Properties.Resources.StrFileAppInvalid;
_stateInfos[(Int32)MeterAppState.Unknown].State = MeterAppState.Unknown;
_stateInfos[(Int32)MeterAppState.Unknown].Message = Xylem.Common.Hardware.WaterMeter.Genesis.Applications.Properties.Resources.StrMeterAppStateUnknown;
_stateInfos[(Int32)MeterAppState.MeterAppInstalledUnchecked].State = MeterAppState.MeterAppInstalledUnchecked;
_stateInfos[(Int32)MeterAppState.MeterAppInstalledUnchecked].Message = Xylem.Common.Hardware.WaterMeter.Genesis.Applications.Properties.Resources.StrMeterAppDetected;
}
/// <summary>
/// Get the text of this state
/// </summary>
/// <param name="state">state to search for information text</param>
public String GetTextFromState(MeterAppState state)
{
return (from stateInfo in _stateInfos
where stateInfo.State == state select stateInfo.Message).Last();
}
/// <summary>
/// Get the state of the text
/// </summary>
/// <param name="text">information text to search if state is assigned</param>
public MeterAppState GetStateFromText(String text)
{
return (from stateInfo in _stateInfos
where stateInfo.Message == text select stateInfo.State).Last();
}
}
}
@@ -0,0 +1,19 @@
using System;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.Applications.Const
{
/// <summary>
/// Concatenation between meter application state and text
/// </summary>
public struct MeterAppStateText
{
/// <summary>
/// The state of the firmware update
/// </summary>
public MeterAppState State;
/// <summary>
/// The message text of the meter application state
/// </summary>
public String Message;
}
}
@@ -0,0 +1,83 @@
using System;
using System.Collections.Generic;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.Applications
{
/// <summary>
/// File FW and application information
/// </summary>
public class FileApplications
{
/// <summary>
/// Name of application
/// </summary>
public String AppName;
/// <summary>
/// File name of the file system where the binaries are stored
/// </summary>
public String BinaryFilename;
/// <summary>
/// File name of the meter including the "1\\upg" string and the AppId as hexadecimal 2 digits
/// </summary>
public String MeterFilename;
/// <summary>
/// Ctor file applications
/// </summary>
/// <param name="binaryFilename"></param>
public FileApplications(String binaryFilename)
{
BinaryFilename = binaryFilename;
}
/// <summary>
/// Identification number of application
/// </summary>
public Byte AppId;
/// <summary>
/// Version of application
/// </summary>
public UInt32 Version;
/// <summary>
/// Version string of application because of FLEXNETVERSION
/// does return a different layout, instead of decimals it
/// used hexadecimals. Therefore the version has to be saved as
/// string at time of receiving for the FW-Update comparison
/// </summary>
public String StrVersion;
/// <summary>
/// Check of application for verification
/// </summary>
public UInt16 Crc;
/// <summary>
/// Validation of application
/// </summary>
public Boolean IsValid;
/// <summary>
/// Binary file content
/// </summary>
public List<Byte> BinData = new List<Byte>();
/// <summary>
/// Actual part if file is going to be partitioned
/// </summary>
public Int32 Part = 0;
/// <summary>
/// Number of parts for entire file if partitioned
/// </summary>
public Int32 Parts = 1;
/// <summary>
/// Meter file offset if file is partitioned
/// </summary>
public Int32 MeterFileOffset = 0;
}
}
@@ -0,0 +1,65 @@
using System;
using TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.Applications.Const;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.Applications
{
/// <summary>
/// Meter FW and application information
/// </summary>
public class MeterApplications
{
/// <summary>
/// Name of application
/// </summary>
public String AppName;
/// <summary>
/// Identification number of application
/// </summary>
/// <remarks date="2025-Aug-05" author="Thomas Wiedebusch">
/// - AppId from Byte to UInt16 including typecast for Byte[] return. To external, it will be used as Byte
/// as before this change. But being able to parse the configuration.json with OPTICALINTERFACE using the
/// AppId 256, which exceeds the byte range as this isn't a real application, but will be used to identify
/// the interface (configuration.json) version.
/// </remarks>
public UInt16 AppId;
/// <summary>
/// Version of application
/// </summary>
public UInt32 Version;
/// <summary>
/// Version string of application because of FLEXNETVERSION does return a different layout, instead of decimals
/// it uses hexadecimals. Therefore, the version has to be saved as string at time of receiving for the FW-Update
/// comparison.
/// </summary>
public String StrVersion;
/// <summary>
/// Check of application for verification
/// </summary>
public UInt16 Crc;
/// <summary>
/// Check if application is installed
/// </summary>
public Boolean IsInstalled;
/// <summary>
/// Update this version
/// </summary>
public Boolean Update;
/// <summary>
/// Erase this version
/// </summary>
public Boolean Erase;
/// <summary>
/// Status text
/// </summary>
public MeterAppState Status;
}
}
@@ -0,0 +1,207 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Xylem.Common.Hardware.WaterMeter.Genesis.Applications.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Xylem.Common.Hardware.WaterMeter.Genesis.Applications.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized string similar to INVALID UPDATE FILE.
/// </summary>
public static string StrFileAppInvalid {
get {
return ResourceManager.GetString("StrFileAppInvalid", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to CRC ERROR.
/// </summary>
public static string StrInvalidCrc {
get {
return ResourceManager.GetString("StrInvalidCrc", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Installed.
/// </summary>
public static string StrMeterAppDetected {
get {
return ResourceManager.GetString("StrMeterAppDetected", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to DOWNLOAD....
/// </summary>
public static string StrMeterAppDownloadActive {
get {
return ResourceManager.GetString("StrMeterAppDownloadActive", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Download failed.
/// </summary>
public static string StrMeterAppDownloadFailed {
get {
return ResourceManager.GetString("StrMeterAppDownloadFailed", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Burn - Trigger upgrade required.
/// </summary>
public static string StrMeterAppDownloadSucceeded {
get {
return ResourceManager.GetString("StrMeterAppDownloadSucceeded", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Verification required.
/// </summary>
public static string StrMeterAppDownloadSuspicious {
get {
return ResourceManager.GetString("StrMeterAppDownloadSuspicious", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Erase - Trigger upgrade required.
/// </summary>
public static string StrMeterAppErasureRequired {
get {
return ResourceManager.GetString("StrMeterAppErasureRequired", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Installation required.
/// </summary>
public static string StrMeterAppInstallationRequired {
get {
return ResourceManager.GetString("StrMeterAppInstallationRequired", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Not installed.
/// </summary>
public static string StrMeterAppNotInstalled {
get {
return ResourceManager.GetString("StrMeterAppNotInstalled", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Not required.
/// </summary>
public static string StrMeterAppNotRequired {
get {
return ResourceManager.GetString("StrMeterAppNotRequired", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Installation state unknown.
/// </summary>
public static string StrMeterAppStateUnknown {
get {
return ResourceManager.GetString("StrMeterAppStateUnknown", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Erasure succeeded.
/// </summary>
public static string StrMeterAppSuccessfulErased {
get {
return ResourceManager.GetString("StrMeterAppSuccessfulErased", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Update succeeded.
/// </summary>
public static string StrMeterAppSuccessfulUpdated {
get {
return ResourceManager.GetString("StrMeterAppSuccessfulUpdated", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Okay.
/// </summary>
public static string StrMeterAppUpToDate {
get {
return ResourceManager.GetString("StrMeterAppUpToDate", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Update required.
/// </summary>
public static string StrMeterAppVersionOutdated {
get {
return ResourceManager.GetString("StrMeterAppVersionOutdated", resourceCulture);
}
}
}
}
@@ -0,0 +1,168 @@
<?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>
<data name="StrMeterAppNotInstalled" xml:space="preserve">
<value>Nicht installiert</value>
</data>
<data name="StrMeterAppUpToDate" xml:space="preserve">
<value>Okay</value>
</data>
<data name="StrMeterAppInstallationRequired" xml:space="preserve">
<value>Installation notwendig</value>
</data>
<data name="StrMeterAppVersionOutdated" xml:space="preserve">
<value>Update erforderlich</value>
</data>
<data name="StrInvalidCrc" xml:space="preserve">
<value>Prüfsummenfehler (CRC)</value>
</data>
<data name="StrMeterAppErasureRequired" xml:space="preserve">
<value>Lösche beim Abschlußvorgang</value>
</data>
<data name="StrMeterAppDownloadSucceeded" xml:space="preserve">
<value>Übernehme beim Abschlußvorgang</value>
</data>
<data name="StrMeterAppDownloadSuspicious" xml:space="preserve">
<value>Überprüfung notwendig</value>
</data>
<data name="StrMeterAppSuccessfulErased" xml:space="preserve">
<value>Löschen erforderlich</value>
</data>
<data name="StrMeterAppSuccessfulUpdated" xml:space="preserve">
<value>Aktualisierung war erfolgreich</value>
</data>
<data name="StrMeterAppDownloadFailed" xml:space="preserve">
<value>Dateiübertragung fehlgeschlagen</value>
</data>
<data name="StrMeterAppDownloadActive" xml:space="preserve">
<value>EINSPIELEN...</value>
</data>
<data name="StrFileAppInvalid" xml:space="preserve">
<value>Ungültige Aktualisierungsdatei</value>
</data>
<data name="StrMeterAppDetected" xml:space="preserve">
<value>Installiert</value>
</data>
<data name="StrMeterAppStateUnknown" xml:space="preserve">
<value>Installationszustand unbekannt</value>
</data>
<data name="StrMeterAppNotRequired" xml:space="preserve">
<value>Nicht eforderlich</value>
</data>
</root>
@@ -0,0 +1,168 @@
<?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>
<data name="StrMeterAppNotInstalled" xml:space="preserve">
<value>Not installed</value>
</data>
<data name="StrMeterAppUpToDate" xml:space="preserve">
<value>Okay</value>
</data>
<data name="StrMeterAppInstallationRequired" xml:space="preserve">
<value>Installation required</value>
</data>
<data name="StrMeterAppVersionOutdated" xml:space="preserve">
<value>Update required</value>
</data>
<data name="StrInvalidCrc" xml:space="preserve">
<value>CRC ERROR</value>
</data>
<data name="StrMeterAppErasureRequired" xml:space="preserve">
<value>Erase - Trigger upgrade required</value>
</data>
<data name="StrMeterAppDownloadSucceeded" xml:space="preserve">
<value>Burn - Trigger upgrade required</value>
</data>
<data name="StrMeterAppDownloadSuspicious" xml:space="preserve">
<value>Verification required</value>
</data>
<data name="StrMeterAppSuccessfulErased" xml:space="preserve">
<value>Erasure succeeded</value>
</data>
<data name="StrMeterAppSuccessfulUpdated" xml:space="preserve">
<value>Update succeeded</value>
</data>
<data name="StrMeterAppDownloadFailed" xml:space="preserve">
<value>Download failed</value>
</data>
<data name="StrMeterAppDownloadActive" xml:space="preserve">
<value>DOWNLOAD...</value>
</data>
<data name="StrFileAppInvalid" xml:space="preserve">
<value>INVALID UPDATE FILE</value>
</data>
<data name="StrMeterAppDetected" xml:space="preserve">
<value>Installed</value>
</data>
<data name="StrMeterAppStateUnknown" xml:space="preserve">
<value>Installation state unknown</value>
</data>
<data name="StrMeterAppNotRequired" xml:space="preserve">
<value>Not required</value>
</data>
</root>
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/></startup></configuration>
@@ -0,0 +1,19 @@
using System;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis
{
/// <summary>
/// Constants for inter-program exchange
/// </summary>
public static class Constants
{
/// <summary>
/// Marker for lack of information in strings e.g. for region, size, LutCrc, ...
/// </summary>
public const String StrUnknown = "?";
/// <summary>
/// Marker for wildcard in search operations
/// </summary>
public const String StrWildcard = "*";
}
}
@@ -0,0 +1,107 @@
using System;
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisConfig.Const;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.GenesisCore
{
/// <summary>
/// Calibration content
/// </summary>
public class CalibFactor
{
/// <summary>
/// has been calibrated
/// </summary>
public Boolean IsCalculated;
/// <summary>
/// Channel for calibration
/// </summary>
public Int32 Channel { get; }
/// <summary>
/// Register to store the calibration
/// </summary>
public String RegisterToStoreCalibFactor { get; }
/// <summary>
/// Ctor for calibration factor
/// </summary>
/// <param name="channel"></param>
/// <param name="registerToStoreCalibFactor"></param>
public CalibFactor(Int32 channel, String registerToStoreCalibFactor)
{
Channel = channel;
RegisterToStoreCalibFactor = registerToStoreCalibFactor;
IsCalculated = false;
}
private UInt16 _meterRawCalibFactor = MeterConfig.CalibrationDefault;
/// <summary>
/// set the user readable relative (around 1.0) calibration factor
/// and convert it to the raw calibration factor for the meter
/// </summary>
/// <param name="relativeCalibFactor"></param>
/// <exception cref="Exception"></exception>
public void BuildMeterCalibFactor(Double relativeCalibFactor)
{
try
{
var tmp = Math.Round(relativeCalibFactor * GetMeterRawCalibFactor(), 0);
_meterRawCalibFactor = Convert.ToUInt16(tmp);
}
catch (Exception ex)
{
throw new Exception("Unable to set calibration factor", ex);
}
}
/// <summary>
/// Read the relative (around 1.0) calibration factor calculated from the actual
/// meter calibration factor divided by the default calibration factor
/// </summary>
/// <returns></returns>
public Double GetRelativeCalibFactor()
{
Double calibFactor = GetMeterRawCalibFactor();
var calibDivider = GetMeterRawCalibFactorDefault();
if (0 != calibDivider)
{
calibFactor /= calibDivider;
}
else
{
throw new ApplicationException("Default calibration factor row value is 0");
}
return calibFactor;
}
/// <summary>
/// Genesis internal raw default value (around 15625)
/// </summary>
/// <returns></returns>
public UInt16 GetMeterRawCalibFactorDefault()
{
return MeterConfig.CalibrationDefault;
}
/// <summary>
/// Set the meter raw calibration factor (around 15625)
/// </summary>
/// <param name="meterRawCalibFactor"></param>
public void SetMeterRawCalibFactor(UInt16 meterRawCalibFactor)
{
_meterRawCalibFactor = meterRawCalibFactor;
}
/// <summary>
/// Get the meter raw calibration factor (around 15625)
/// </summary>
/// <returns></returns>
public UInt16 GetMeterRawCalibFactor()
{
return _meterRawCalibFactor;
}
}
}
@@ -0,0 +1,37 @@
using System;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.GenesisCore.Consts
{
/// <summary>
/// Alarm messages
/// </summary>
[Flags]
public enum Alarm
{
// ReSharper disable InconsistentNaming
#pragma warning disable CS1591
REBOOT = 1 << 0, //Bit 0
LOW_BATTERY = 1 << 1, //Bit 1
//Bit 2
//Bit 3
EMPTY_PIPE = 1 << 4, //Bit 4
//Bit 5
REVERSE_FLOW = 1 << 6, //Bit 6
SUSPECT_LEAK = 1 << 7, //Bit 7
BROKEN_PIPE = 1 << 8, //Bit 8
LOW_PRESSURE = 1 << 9, //Bit 9
HIGH_PRESSURE = 1 << 10, //Bit 10
LOW_TEMPERATURE = 1 << 11, //Bit 11
HIGH_TEMPERATURE = 1 << 12, //Bit 12
RADIO_ERROR = 1 << 13, //Bit 13
METROLOGY_PARAMS = 1 << 14, //Bit 14
METROLOGY_MEASURE = 1 << 15, //Bit 15
ALL = 0x7FFFFFFF //enum is defined as Int32
#pragma warning restore CS1591
// ReSharper restore InconsistentNaming
}
}
@@ -0,0 +1,6 @@
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.GenesisCore.Consts
{
class Applications
{
}
}
@@ -0,0 +1,66 @@
using System;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.GenesisCore.Consts
{
/// <summary>
/// Common definition for Meter handling in production and on test benches
/// </summary>
/// <summary>
/// represents any error state a meter can have
/// if hash code is 0 everything is running
/// is Flags, so watch out to check with hasFlag!
/// </summary>
[Flags]
public enum ErrorState
{
/// <summary>
/// everything is good
/// </summary>
None = 0x0000,
/// <summary>
/// problems on initialization
/// </summary>
InitFailed = 0x0001,
/// <summary>
/// problems on Measurement
/// </summary>
MeasurementFailed = 0x0002,
/// <summary>
/// Problem on communication with meter
/// </summary>
ComErrorRequestPort = 0x0004,
/// <summary>
/// Problem on optical output on meter
/// </summary>
ComErrorLed = 0x0008,
/// <summary>
/// if pulse can not readout
/// </summary>
ComErrorPulse = 0x0010,
/// <summary>
/// no (or no good) reference flow available
/// </summary>
ErrorQRef = 0x0020,
/// <summary>
/// Calibration went wrong
/// </summary>
CalibrationFailed = 0x0040,
/// <summary>
/// calibration is out of range. Check documentation from meter to find limitation
/// </summary>
CalibrationOutOfRange = 0x0080,
/// <summary>
/// blue screen like error
/// </summary>
FatalError = 0x0100
}
}
@@ -0,0 +1,38 @@
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.GenesisCore.Consts
{
/// <summary>
/// Streaming modes that supported by genesis meter.
/// Set meter to this Streaming mode means that , the meter pushes mode-specific record to port without any responses
/// </summary>
public enum LedMode
{
/// <summary>
/// Test mode with raw record to log.
/// Should give one <see cref="FlowTestRecord"/>
/// 3 times <see cref="CalibrationRecord"/> and
/// one <see cref="BendDetectionRecord"/>
/// </summary>
FlowTestAndCalibDataAndBendCorrect = 7,
/// <summary>
/// Test mode with raw record to log. Should give one <see cref="FlowTestRecord"/>
/// 3 times <see cref="CalibrationRecord"/> and repeat this till led mode is switch
/// </summary>
FlowTestAndCalibData = 6,
/// <summary>
/// Test mode should give <see cref="FlowTestRecord"/> out
/// </summary>
FlowTestData = 4,
/// <summary>
/// Calibration mode should give <see cref="CalibrationRecord"/> out
/// </summary>
CalibData = 3,
/// <summary>
/// Deactivate streaming
/// </summary>
Off = 0,
/// <summary>
/// not set or an new not supported Streaming mode
/// </summary>
Unknown = -1
}
}
@@ -0,0 +1,20 @@
using System;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.GenesisCore.Consts
{
/// <summary>
/// Update capability check for all necessary settings according to meter.
/// </summary>
public static class MetrologyDefinition
{
/// <summary>
/// It is allowed to upgrade the metrology, causing an upgrade capability check to pass always.
/// </summary>
public const Byte MetrologyUpgradePermitted = 0xFF;
/// <summary>
/// The name of the metrology application.
/// </summary>
public const String MetrologyName = "GENESISFLOW";
}
}
@@ -0,0 +1,86 @@
using System;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.GenesisCore.Consts
{
/// <summary>
/// Power correction constants
/// </summary>
public static class PowCorrConst
{
/// <summary>
/// Threshold for power correction EMEA version
/// </summary>
public const UInt32 EmeaFwThresholdForPowCorr = 0x1300;
/// <summary>
/// Threshold for power correction NA version
/// </summary>
public const UInt32 NaFNaFwThresholdForPowCorr = 0x2006;
/// <summary>
/// Minimum region radio current NA
/// </summary>
public const Double MinNaCurrent_uA = 119;
/// <summary>
/// Minimum region radio current sensus radio RF mode EMEA
/// </summary>
public const Double MinEmeaRadioRfModeCurrent_uA = 136;
/// <summary>
/// Minimum region radio current sensus radio TFX mode EMEA
/// </summary>
public const Double MinEmeaRadioTfxModeCurrent_uA = 155;
/// <summary>
/// Fixed current in production if production values are not logged in DB
/// and dispatched as 0 or null.
/// </summary>
public const Double FixProductionCurrent_uA = 160;
/// <summary>
/// Fixed region radio current NA
/// </summary>
public const Double FixNaCurrent_uA = 132;
/// <summary>
/// Fixed region radio current sensus radio RF mode EMEA
/// </summary>
public const Double PulseReportLengthEstimate_uA = 45.453;
/// <summary>
/// Fixed region radio current sensus radio RF mode EMEA
/// </summary>
public const Double FixEmeaRadioRfModeCurrent_uA = 153;
/// <summary>
/// Fixed region radio current sensus radio TFX mode EMEA
/// </summary>
public const Double FixEmeaRadioTfxModeCurrent_uA = 174;
/// <summary>
/// Pulse report length for pulse mode 1 to 4 even distribution 0
/// </summary>
public const UInt32 PulseReportLengthMode1To4Even0 = 8;
/// <summary>
/// Pulse report length for pulse mode 1 to 4 even distribution 1
/// </summary>
public const UInt32 PulseReportLengthMode1To4Even1 = 10;
/// <summary>
/// Pulse report length for pulse mode 5 to 6 even distribution 0
/// </summary>
public const UInt32 PulseReportLengthMode5To6Even0 = 6;
/// <summary>
/// Pulse report length for pulse mode 5 to 6 even distribution 1
/// </summary>
public const UInt32 PulseReportLengthMode5To6Even1 = 8;
/// <summary>
/// TFX mode mask of sensus radio system state
/// </summary>
public const Byte SensusRadioSystemStateTfXModeMask = 0x20;
}
}
@@ -0,0 +1,359 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text.RegularExpressions;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.Applications;
using TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.Registers;
using TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.Registers.DataTypes;
using TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.Registers.Json;
using Xylem.Common.Hardware.WaterMeter.WaterMeterRegisters;
using IRegister = TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.WaterMeterRegisters.IRegister;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.GenesisCore
{
/// <summary>
/// JSON filer reader for generation of register lists
/// </summary>
public class GenesisConfigurationReader
{
/// <summary>
/// Registers defined in configuration.json file
/// </summary>
public List<IRegister> ConfigRegistersDefinitions { get; }
= new List<IRegister>();
/// <summary>
/// Applications defined in configuration.json file
/// </summary>
public List<ApplicationDefinition> ConfigApplicationDefinitions { get; }
= new List<ApplicationDefinition>();
/// <summary>
/// Information collected during 'configuration.json' read
/// </summary>
public readonly InterfaceInfo InterfaceInfo = new InterfaceInfo();
/// <summary>
/// Ctor
/// </summary>
public GenesisConfigurationReader() { }
/// <summary>
/// Ctor
/// </summary>
/// <param name="configFilePath">the file path for configuration.json as interface description to the meter</param>
public GenesisConfigurationReader(String configFilePath)
{
if (string.IsNullOrEmpty(configFilePath))
{
throw new ApplicationException("JsonFileRegisterReader needs at least one file path");
}
if (!File.Exists(configFilePath))
{
throw new ApplicationException($" {configFilePath} doesn't exists");
}
BuildRegisterList(File.ReadAllText(configFilePath));
}
/// <summary>
/// Convert file content to register list
/// </summary>
/// <param name="configurationJson"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
/// <remarks date="??" author="Stoyan Slatev">
/// - Initial.
/// </remarks>
/// <remarks date="2025-Aug-05" author="Thomas Wiedebusch">
/// - AppId from Byte to UInt16 including typecast for Byte[] return. To external, it will be used as Byte
/// as before this change. But being able to parse the configuration.json with OPTICALINTERFACE using the
/// AppId 256, which exceeds the byte range as this isn't a real application, but will be used to identify
/// the interface (configuration.json) version.
/// </remarks>
/// <remarks date="2025-Aug-07" author="Thomas Wiedebusch">
/// - Extract the max supported versions for EMEA and NA to check the supported FW.
/// </remarks>
/// <remarks date="2025-Sep-30" author="Thomas Wiedebusch">
/// - Supported application list introduced.
/// </remarks>
/// <remarks date="2025-Oct-10" author="Thomas Wiedebusch">
/// - Data size introduced including the new 'ByteArray' type and size to get rid of new defined 'uintxx_t'
/// data types.
/// </remarks>
public void BuildRegisterList(String configurationJson)
{
IDictionary<String, AppSection> sections;
try
{
sections = JsonConvert
.DeserializeObject<IDictionary<String, AppSection>>(configurationJson, SerializerSettings)
?? new Dictionary<String, AppSection>();
}
catch (Exception)
{
sections = new Dictionary<String, AppSection>();
}
foreach (var sectionKVP in sections)
{
var appId = sectionKVP.Value.Id;
var appName = sectionKVP.Key;
var appVersion = sectionKVP.Value.Version.Last;
if (appName.Equals("OPTICALINTERFACE"))
{
var builds = sectionKVP.Value.Builds;
var emeaBuilds = builds["emea"];
var naBuilds = builds["na"];
InterfaceInfo.SupportedFwVersions = new List<String>();
foreach (var build in emeaBuilds)
{
InterfaceInfo.SupportedFwVersions.Add(build.FW);
}
foreach (var build in naBuilds)
{
InterfaceInfo.SupportedFwVersions.Add(build.FW);
}
InterfaceInfo.InterfaceVersion = TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.GenesisCore.GenesisMeter.BuildFwVersionStringFromDec(appVersion);
continue;
}
ConfigApplicationDefinitions.Add(new ApplicationDefinition
{
AppId = appId,
AppName = appName,
AppVersion = appVersion,
});
var section = sectionKVP.Value;
var registers = section.Registers;
if (registers is null)
{
continue;
}
foreach (var registerKVP in registers)
{
var register = registerKVP.Value;
if (register is null)
{
continue;
}
var details = register.Details;
if (details is null)
{
continue;
}
var regId = register.Id;
foreach (var detail in details)
{
var values = detail.Values;
ConfigRegistersDefinitions.Add(new RegisterDefinition
{
AppAddress = appId,
AppName = appName,
DataType = GetType(detail.Type),
DataSize = GetSize(detail.Type),
Default = values?.Default is Int64 d ? d : default(Int64?),
IsAvailable = false,
Maximum = values?.Maximum is Int64 max ? max : default(Int64?),
Minimum = values?.Minimum is Int64 min ? min : default(Int64?),
RegAddressInApp = regId,
// RegisterAddress = new byte[] { appId, regId },
RegisterDetail = detail,
RegisterName = registerKVP.Key,
RestoreCapability = new StaticType(detail.StaticType)
});
}
}
}
}
/// <summary>
/// Settings
/// </summary>
private static readonly JsonSerializerSettings SerializerSettings = new JsonSerializerSettings
{
MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
DateParseHandling = DateParseHandling.None,
Converters =
{
AccessConverter.Singleton,
new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }
},
};
/// <summary>
/// Convert data types from interface 'configuration.json' to CLR type or array
/// </summary>
/// <param name="value"></param>
/// <returns>type</returns>
/// <exception cref="Exception"></exception>
/// <remarks date="??" author="Stoyan Slatev">
/// - Initial.
/// </remarks>
/// <remarks date="2025-Oct-10" author="Thomas Wiedebusch">
/// - Parsed all 'uintxx_t' which are not based on CLR types to byte-array
/// </remarks>
private static Type GetType(String value)
{
// Catch all uintxx_t to split to standard CLR or to array
var lowStrValue = value.ToLower();
if (lowStrValue.Contains("uint") && lowStrValue.Contains("_t"))
{
switch (lowStrValue)
{
case "uint8_t": return typeof(Byte);
case "uint16_t": return typeof(UInt16);
case "uint32_t": return typeof(UInt32);
case "uint64_t": return typeof(UInt64);
default:
return typeof(ByteArray);
}
}
// Catch the signed standard CLR and some special types
switch (lowStrValue)
{
// CLR types
case "bool_t": return typeof(Boolean);
case "int8_t": return typeof(SByte);
case "int16_t": return typeof(Int16);
case "int32_t": return typeof(Int32);
case "int64_t": return typeof(Int64);
case "string": return typeof(String);
// Special types defined in FW interface file 'configuration.json'
case "rpc": return typeof(Rpc);
case "time_t": return typeof(TimeT);
case "status_t": return typeof(StatusT);
case "enum8": return typeof(Enum8);
default:
throw new Exception($"Data type {value} in unknown!");
}
}
/// <summary>
/// Build the data size
/// </summary>
/// <param name="value"></param>
/// <returns>size</returns>
/// <remarks date="2025-Oct-10" author="Thomas Wiedebusch">
/// - Initial: - parsed all 'uintxx_t' which are not based on CLR types to byte-array
/// </remarks>
private static Int32 GetSize(String value)
{
// Catch all uintxx_t to split to standard CLR or to array
var lowStrValue = value.ToLower();
if (lowStrValue.Contains("uint") && lowStrValue.Contains("_t"))
{
switch (lowStrValue)
{
case "uint8_t": return sizeof(Byte);
case "uint16_t": return sizeof(UInt16);
case "uint32_t": return sizeof(UInt32);
case "uint64_t": return sizeof(UInt64);
default:
// Extract the size from the string
var dataSizeStr = Regex.Replace(lowStrValue, "[^0-9]", string.Empty);
if (Int32.TryParse(dataSizeStr, out var dataSize))
return dataSize / 8;
throw new Exception($"Data size {lowStrValue} cannot be converted!");
}
}
// Catch the signed standard CLR and some special types
switch (lowStrValue)
{
// CLR types
case "bool_t": return sizeof(Boolean);
case "int8_t": return sizeof(SByte);
case "int16_t": return sizeof(Int16);
case "int32_t": return sizeof(Int32);
case "int64_t": return sizeof(Int64);
// Take just some value as the string length is unknown
case "string": return 6 * 4;
// Special types defined in FW interface file 'configuration.json'
// Remote procedure call is always a 4 byte value
case "rpc": return sizeof(UInt32);
// Time will be in seconds since 01. Jan 2000 00:00:00 UTC as signed Int32
case "time_t": return sizeof(Int32);
case "status_t": return sizeof(UInt32);
case "enum8": return sizeof(Byte);
default:
throw new Exception($"Data type {value} in unknown!");
}
}
}
/// <summary>
///
/// </summary>
public class AccessConverter : JsonConverter
{
/// <summary>
///
/// </summary>
/// <param name="t"></param>
/// <returns></returns>
public override Boolean CanConvert(Type t) => t == typeof(Access) || t == typeof(Access?);
/// <summary>
///
/// </summary>
/// <param name="reader"></param>
/// <param name="t"></param>
/// <param name="existingValue"></param>
/// <param name="serializer"></param>
/// <returns></returns>
public override Object ReadJson(JsonReader reader, Type t, Object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
{
return null;
}
var value = serializer.Deserialize<String>(reader);
return Enum.TryParse(value, true, out Access access) ? access : default(Access);
}
/// <summary>
///
/// </summary>
/// <param name="writer"></param>
/// <param name="untypedValue"></param>
/// <param name="serializer"></param>
public override void WriteJson(JsonWriter writer, Object untypedValue, JsonSerializer serializer)
{
if (untypedValue is Access access)
{
writer.WriteValue(access.ToString());
}
else
{
throw new Exception("Cannot marshal type Lvl");
}
}
/// <summary>
///
/// </summary>
public static readonly AccessConverter Singleton = new AccessConverter();
}
}
@@ -0,0 +1,214 @@
using System;
using System.Collections.Generic;
using TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.Interfaces.Ports.PortCore.EventArguments;
using TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.Interfaces.Ports.SerialPorts;
using TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.Protocols.StreamingProtocol;
using Xylem.Common.CommonCore.Consts;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.GenesisCore
{
/// <summary>
/// Check the positioning of the streaming LED to validate the quality of the communication line
/// </summary>
public class GenesisMeterStreamingQuality : TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.GenesisCore.GenesisMeter
{
/// <summary>
/// Backup of last quality
/// </summary>
public QualityResult LastQualityResult;
private StreamingDecoder _sd;
/// <summary>
/// Quality check is active
/// </summary>
public Boolean IsRunning;
private DateTimeOffset? _startTime;
private DateTimeOffset? _stopTime;
private List<String> _collectedRecords;
private Int32? _tillDecodedCount;
/// <summary>
/// Kick off the streaming quality check.
/// </summary>
/// <param name="tillDecodedCount"></param>
/// <exception cref="ApplicationException"></exception>
public void StartStreamingQualityCheck(Int32? tillDecodedCount = null)
{
if (IsRunning)
{
return;
}
_tillDecodedCount = tillDecodedCount;
if (_tillDecodedCount.HasValue)
{
_sd = new StreamingDecoder(false);
}
if (StreamingPort == null || !(StreamingPort is LedSerialPort))
{
throw new ApplicationException("No valid streaming port");
}
_stopTime = null;
_collectedRecords = new List<String>();
SyncStreamingBuffer(SyncMarkRecord.DecodeEveryPackage);
((LedSerialPort)StreamingPort).OnRawRecordReceived += GenesisMeterStreamingQuality_OnRawRecordReceived;
_startTime = DateTimeOffset.UtcNow;
LogRawData(true);
IsRunning = true;
}
private void GenesisMeterStreamingQuality_OnRawRecordReceived(Object sender, BasePortDataEventArgs e)
{
_collectedRecords.Add(e.GetData().ToString());
if (_tillDecodedCount.HasValue)
{
if (_sd.DecodeMsg(e.GetData().ToString()))
{
_tillDecodedCount = _tillDecodedCount.Value - 1;
if (_tillDecodedCount <= 0)
{
IsRunning = false;
LastQualityResult = StopStreamingQualityCheck(10);
}
}
}
}
/// <summary>
/// Stop the streaming check.
/// </summary>
/// <param name="sampleRateHz"></param>
/// <returns></returns>
/// <exception cref="ApplicationException"></exception>
public QualityResult StopStreamingQualityCheck(Int32 sampleRateHz)
{
_stopTime = DateTimeOffset.UtcNow;
if (!IsRunning && !_startTime.HasValue)
{
return new QualityResult();
}
if (StreamingPort == null || !(StreamingPort is LedSerialPort))
{
throw new ApplicationException("No valid streaming port");
}
LogRawData(false);
((LedSerialPort)StreamingPort).OnRawRecordReceived -= GenesisMeterStreamingQuality_OnRawRecordReceived;
SyncStreamingBuffer(SyncMarkRecord.SkipDecoding);
IsRunning = false;
if (_stopTime != null && _startTime != null)
return new QualityResult(_collectedRecords, _stopTime.Value - _startTime.Value, sampleRateHz);
return new QualityResult();
}
/// <summary>
///
/// </summary>
public class QualityResult
{
/// <summary>
/// Number of records received (read line for LED message)
/// </summary>
public readonly Int32 TotalLinesCount;
/// <summary>
/// Total records decoded
/// </summary>
public readonly Int32 TotalDecodedCount;
/// <summary>
/// Total errors
/// </summary>
public readonly Int32 TotalTransportErrorCount;
/// <summary>
/// Validated without errors
/// </summary>
public readonly Int32 TotalValidationWithoutErrorsCount;
/// <summary>
/// Expected lines
/// </summary>
public readonly Int32 ExpectedLinesCount;
/// <summary>
/// Time
/// </summary>
public readonly TimeSpan TotalTime;
/// <summary>
/// Error counter
/// </summary>
public readonly Dictionary<UInt16, Int32> ErrorOccurredCounter;
/// <summary>
/// The real result of quality check
/// </summary>
/// <param name="collectedRecords"></param>
/// <param name="ts"></param>
/// <param name="sampleRateHz"></param>
public QualityResult(List<String> collectedRecords, TimeSpan ts, Int32 sampleRateHz)
{
TotalLinesCount = collectedRecords.Count;
TotalTime = ts;
ExpectedLinesCount = (Int32)(Math.Round(ts.TotalSeconds * sampleRateHz, 0));
ErrorOccurredCounter = new Dictionary<UInt16, Int32>();
foreach (var rawText in collectedRecords)
{
var sd = new StreamingDecoder(false);
if (!sd.DecodeMsg(rawText))
{
TotalTransportErrorCount++;
continue;
}
//here the decoding is valid including the CRC
TotalDecodedCount++;
//the DecodeMsg has assigned either a DataCalib or DataFlowTest data set
var calibrationRecord = sd.DataCalib;
var flowTestRecord = sd.DataFlowTest;
var bendDetectRecord = sd.DataBendDetectTest;
if (flowTestRecord != null)
{
TotalValidationWithoutErrorsCount++;
continue;
}
if (bendDetectRecord != null)
{
TotalValidationWithoutErrorsCount++;
continue;
}
if (calibrationRecord != null)
{
if (calibrationRecord.Validation == 0)
{
TotalValidationWithoutErrorsCount++;
}
else
{
if (ErrorOccurredCounter.ContainsKey(calibrationRecord.Validation))
{
ErrorOccurredCounter[calibrationRecord.Validation] += 1;
}
else
{
ErrorOccurredCounter.Add(calibrationRecord.Validation, 1);
}
}
}
}
}
/// <summary>
/// The quality result as dummy zero
/// </summary>
public QualityResult()
{
TotalLinesCount = 0;
TotalTime = TimeSpan.Zero;
ErrorOccurredCounter = new Dictionary<UInt16, Int32>();
}
}
}
}
@@ -0,0 +1,298 @@
using System;
using System.Collections.Generic;
using TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.Applications;
using TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.GenesisConfig;
using TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.GenesisCore.Consts;
using TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.Interfaces.Protocols.TransmitProtocol;
using TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.Registers;
using Xylem.Common.Hardware.WaterMeter.WaterMeterCore;
using IMeter = TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.IMeter;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.GenesisCore
{
/// <summary>
/// Interface of special GenesisMeter derived from IMeter
/// </summary>
public interface IGenesisMeter : IMeter
{
#region properties
/// <summary>
/// Represent <see cref="Register.Configexchange.PcbSerialNumber" />
/// proposed for login
/// </summary>
String PcbId
{
get;
}
/// <summary>
/// A new meter has to be checked for the reboot counter. On retries the reboot counter
/// may have increased on unsuccessfully after-reboot procedure. This would force failing
/// the 'ConnectCordonel'.
/// </summary>
Boolean CheckRebootCtr
{
get;
set;
}
/// <summary>
/// Interface information
/// </summary>
InterfaceInfo InterfaceInfo
{
get;
}
/// <summary>
/// This FW version is supported by the interface "configuration.json".
/// </summary>
Boolean InterfaceSupportsFwVersion
{
get;
}
/// <summary>
/// Transmit protocol access for underlie objects to change response timeout
/// </summary>
ITransmitProtocol TransmitProtocol { get; }
/// <summary>
/// List of all present meter applications installed in meter
/// </summary>
List<MeterApplications> MeterAppListVersion
{
get;
}
/// <summary>
/// Successfully logged on to meter
/// </summary>
Boolean IsLoggedOn
{
get;
}
/// <summary>
/// Core revision of boot code.
/// </summary>
Int32? CoreRevision
{
get;
}
/// <summary>
/// Core revision of boot code as string.
/// </summary>
String StrCoreRevision
{
get;
}
/// <summary>
/// This is the FLEXNETVERSION version which describes the entire packet.
/// </summary>
String FwVersion
{
get;
}
/// <summary>
/// This is the FLEXNETVERSION version which describes the entire packet.
/// </summary>
UInt32? InstalledFwVersion
{
get;
}
/// <summary>
/// This is the Metrology Lookup Table CRC.
/// </summary>
String LutCrc
{
get;
}
/// <summary>
/// This is the meter size.
/// </summary>
String MeterSize { get; }
/// <summary>
/// Length of the meter.
/// </summary>
String MeterLength { get; set; }
/// <summary>
/// Pressure sensor assembled to meter.
/// </summary>
Boolean PressureSensorAssembled { get; }
/// <summary>
/// Region (EMEA, NA or China).
/// </summary>
String Region
{
get;
}
/// <summary>
/// Radio frequency in MHz (433 or 868 or null).
/// </summary>
Int32? RadioFrequencyMhz
{
get;
}
/// <summary>
/// Metrology upgrade permission.
/// </summary>
Byte MetrologyUpgradePermission
{
set; get;
}
/// <summary>
/// Order number under which this meter has to be produced
/// </summary>
Int32 OrderNumber
{
set; get;
}
/// <summary>
/// Radio address
/// </summary>
Int64 RadioAddress
{
set; get;
}
/// <summary>
/// Process configuration
/// </summary>
ProcessConfig Configuration
{
get;
}
/// <summary>
/// Customer serial number for informal issues
/// </summary>
String CustomerSerialNumber
{
get; set;
}
/// <summary>
/// Unlocked the property change ability for special sequences.
/// </summary>
Boolean UnlockEssentialProperties
{
get;
}
#endregion
#region methods
/// <summary>
/// Check region and size.
/// After reading the version, all valid registers are going to be selected.
/// </summary>
void CheckRegionSizeLutCrc();
/// <summary>
/// Unlocked the property change ability for special sequences.
/// </summary>
Boolean EnablePropertyChangeAbility(Boolean unlockPropertyChange);
/// <summary>
/// Set the meter size if previously unlocked.
/// The data types are: - String like "DN50" or
/// </summary>
Boolean SetMeterSize<T>(T meterSize);
/// <summary>
/// Set the pressure sensor if previously unlocked
/// </summary>
Boolean SetPressureSensorAssembled(Boolean pressureSensorAssembled);
/// <summary>
/// Reset the empty pipe alarm
/// </summary>
void ResetAlarm(Alarm clear);
/// <summary>
/// Upload app list to database
/// </summary>
/// <param name="progressName"></param>
/// <param name="version"></param>
/// <returns></returns>
StatusReturn PushProgress(String progressName, String version);
/// <summary>
/// Clear password to force new password reading
/// </summary>
void ClearPassword();
/// <summary>
/// Executes all StoreConfiguration and StoreCalibration for each application.
/// </summary>
/// <returns>true if all configurations are stored</returns>
Boolean StoreAllConfigurations();
/// <summary>
/// Login with identical password as last time to avoid get password from database
/// </summary>
Boolean ReLogin();
/// <summary>
/// Returns meter registers
/// </summary>
/// <returns></returns>
MeterRegisters GetConfigRegistersDefinitions();
/// <summary>
/// Common routine for reboot being able to override this routine which will be called in
/// MeteResetPsu to simulate a reboot.
/// </summary>
/// <returns></returns>
StatusReturn RebootGenesis();
/// <summary>
/// Write Register, optional: wait for result and validate,
/// write register will ALWAYS log the data DON'T use for password write
/// </summary>
/// <typeparam name="T">Data type of Register</typeparam>
/// <param name="regName">Register name</param>
/// <param name="value">Value to save as byte array in raw format</param>
/// <param name="waitForResult">wait until result is ready</param>
/// <param name="checkRegister">check the content of the register by read back</param>
/// <param name="skipRetryErrorCode">skip retries on this error code return</param>
/// <returns>true on successful operation</returns>
Boolean WriteRegister<T>(String regName, T value, Boolean waitForResult = true,
Boolean checkRegister = false, UInt16 skipRetryErrorCode = CommunicationConfig.SkipRetryErrorCode);
/// <summary>
/// Read Register and return byte array
/// </summary>
/// <param name="regName">Register name</param>
/// <param name="expectedLength">expected length for response</param>
/// <param name="skipRetryErrorCode">skip retries on this error code return</param>
/// <returns>value as byte array in raw format or null</returns>
Byte[] ReadRegister(String regName, Int32? expectedLength = null,
UInt16 skipRetryErrorCode = CommunicationConfig.SkipRetryErrorCode);
/// <summary>
/// Clear all pending alarms.
/// </summary>
/// <remarks date="2025-Aug-26" author="Roland Drabesch">
/// - Initial.
/// </remarks>
void ClearAlarm();
#endregion
}
}
@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.GenesisCore
{
/// <summary>
/// Collection of interface information
/// </summary>
public class InterfaceInfo
{
/// <summary>
/// The interface version
/// </summary>
public String InterfaceVersion { get; set; }
/// <summary>
/// List of supported FW versions by this interface
/// </summary>
public List<String> SupportedFwVersions { get; set; }
}
}
@@ -0,0 +1,239 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Ports;
using System.Linq;
using Newtonsoft.Json;
using TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.Interfaces.Ports.PortCore;
using TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.ProcessExec;
using TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.ProcessExec.EventArguments;
using Xylem.Common.Hardware.WaterMeter.WaterMeterCore;
using MeterBatch = TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.MeterBatch;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.GenesisCore
{
/// <summary>
/// Port scanner:
/// using the Windows Device Manager listed ports,
/// tries to open the port with an exception if it cannot be accessed (very time-consuming),
/// tries to use the request protocol to detect a Genesis device.
/// </summary>
public class MeterPortScanner : IProcessState, IDisposable
{
/// <summary>
/// Genesis for test access
/// </summary>
private TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.GenesisCore.GenesisMeter _currentGenesis;
private MeterBatch _meterBatch;
private readonly String _portType;
/// <summary>
/// Auto-detected port name
/// </summary>
public String AutoDetectedPortName;
/// <summary>
/// Port scan result event for message dispatcher to caller
/// </summary>
public event EventHandler<ProcessExecEventArgs> OnProcessUpdate;
/// <summary>
/// Stop the port scan
/// </summary>
public Boolean StopPortScan;
/// <summary>
/// Number of ports
/// </summary>
public Int32 NumberOfPorts;
/// <summary>
/// Actual Port Counter
/// </summary>
public Int32 ActualPortCtr;
/// <summary>
/// Returns the port scan state
/// </summary>
/// <returns></returns>
/// <remarks date="2020-Oct-21" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
public String GetPortScanState()
{
return $@"{Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore.Properties.Resources.StrScanPort} {ActualPortCtr}/{NumberOfPorts}";
}
/// <summary>
/// Ctor
/// </summary>
/// <returns>true if one port has been validated</returns>
/// <remarks date="2020-Dec-11" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
/// <param name="portType">type of communication port to meter like IrDA</param>
public MeterPortScanner(String portType)
{
_portType = portType;
}
/// <inheritdoc />
/// <remarks date="2021-Jan-05" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
/// <remarks date="2021-Mai-11" author="Thomas Wiedebusch">
/// - Remove all meters removed as _meterBatch.Dispose will remove all meters.
/// </remarks>
public void Dispose()
{
// removal from meter batch includes a disposal of meter
_meterBatch?.Dispose();
}
/// <summary>
/// Use initially the port configuration to speed up search,
/// If configuration file contains wrong port setup than scan all serial ports listed in
/// the windows device manager,
/// Read available ports,
/// Try to open port and connect to Genesis meter.
/// </summary>
/// <param name="slot">slot to search for</param>
/// <param name="portConfigFilePathName">configuration of port to speed up search</param>
/// <returns>true if port found</returns>
/// <returns>true if one port has been validated</returns>
/// <remarks date="2020-Oct-14" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
/// <remarks date="2020-Dec-11" author="Thomas Wiedebusch">
/// - Port type from Ctor,
/// - Event message changed:
/// - Overall message: ctr / counts - ongoing scan,
/// - Actual message: Information to log
/// </remarks>
/// <remarks date="2021-Jan-05" author="Thomas Wiedebusch">
/// - Changed exit of function,
/// - Added configuration file handling.
/// </remarks>
/// <remarks date="2021-Mai-11" author="Thomas Wiedebusch">
/// - Remove all meters removed as _meterBatch.Dispose will remove all meters.
/// </remarks>
public Boolean ScanAllSerialPorts(Int32 slot, String portConfigFilePathName)
{
var serialPort = new SerialPort();
var serialPorts = new List<String>();
_meterBatch = new MeterBatch();
serialPorts.AddRange(SerialPort.GetPortNames());
NumberOfPorts = serialPorts.Count;
ActualPortCtr = 0;
// If configuration file exists, read it and check for slot setup. This will speed up the recurrent detection
// process as at the end the detection process the detected slot will be saved.
var slotPortConfigs = new List<SlotConfig>();
if (portConfigFilePathName != null && File.Exists(portConfigFilePathName))
{
using (var tr = new StreamReader(portConfigFilePathName))
{
var fileStream = tr.ReadToEnd();
var slots = JsonConvert.DeserializeObject<SlotConfig[]>(fileStream);
if (slots != null && slots.Length > 0)
slotPortConfigs.AddRange(slots);
}
foreach (var slotPortConfig in slotPortConfigs.Where(slotPortConfig =>
slotPortConfig.Slot == slot && !string.IsNullOrEmpty(slotPortConfig.Request.PortName)))
{
// add port on bottom of port list even if it is doubled that way
NumberOfPorts++;
serialPorts.Add(slotPortConfig.Request.PortName);
break;
}
}
OnProcessUpdate?.Invoke(this, new ProcessExecEventArgs("", 0,
$@"{NumberOfPorts} {Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore.Properties.Resources.StrPortListDeviceManger}"));
var serialPortDetected = false;
StopPortScan = false;
// start with last port,this might be added at current connection of interface
for (var ctr = serialPorts.Count - 1; ctr >= 0; ctr--)
{
if (StopPortScan) break;
ActualPortCtr++;
serialPort.PortName = serialPorts[ctr];
var overallProcessCtrPercent = 100.0 * ActualPortCtr / (NumberOfPorts > 0 ? NumberOfPorts : 1);
OnProcessUpdate?.Invoke(this, new ProcessExecEventArgs(GetPortScanState(), overallProcessCtrPercent,
$@"{serialPort.PortName}: {Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore.Properties.Resources.StrPortAccessRequest}"));
// skip all ports which are already opened, this might be another customer
if (serialPort.IsOpen) continue;
Interfaces.Ports.PortCore.PortConfig portConfig;
try
{
// removal from meter batch includes a disposal of meter
_meterBatch.RemoveAllMeters();
portConfig = new PortConfig
{
PortName = serialPort.PortName,
Type = _portType
};
_currentGenesis = new TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.GenesisCore.GenesisMeter(slot, portConfig, null);
if (_currentGenesis == null) return false;
// configuration has to be set BEFORE adding meter to batch to avoid e.g. auto update files
// from network and therefore have a long network request timeout before the task starts
_currentGenesis.Configuration.UseRegisterWatchService = false;
_currentGenesis.Configuration.UseMinMaxCheck = false;
_currentGenesis.Configuration.AutoUpdateFiles = false;
_meterBatch.AddMeter(_currentGenesis);
}
catch (Exception)
{
OnProcessUpdate?.Invoke(this, new ProcessExecEventArgs(GetPortScanState(), overallProcessCtrPercent,
$@"{serialPort.PortName}: {Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore.Properties.Resources.StrPortFailedToOpen}"));
continue;
}
// if port cannot be opened on access to the port is senseless, try the next port
if (_currentGenesis != null && !_currentGenesis.RequestPort.IsOpen()) continue;
OnProcessUpdate?.Invoke(this, new ProcessExecEventArgs(GetPortScanState(), overallProcessCtrPercent,
$@"{serialPort.PortName}: {Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore.Properties.Resources.StrPortSuccessfullyAccessed}"));
// read PCB ID from meter, this is the indicator, that a Genesis is connected to this port
if (_currentGenesis == null || string.Empty == _currentGenesis.GetPcbId())
{
OnProcessUpdate?.Invoke(this, new ProcessExecEventArgs(GetPortScanState(), overallProcessCtrPercent,
$@"{serialPort.PortName}: {Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore.Properties.Resources.StrRequestPortDetectionFailed}"));
continue;
}
AutoDetectedPortName = serialPort.PortName;
serialPortDetected = true;
// check if needed to store new configuration if slot and port name is not in file
if (!slotPortConfigs.Any(c => c.Slot == slot && c.Request.PortName == AutoDetectedPortName))
{
slotPortConfigs.Add(new SlotConfig() { Slot = slot, Request = portConfig });
var text = JsonConvert.SerializeObject(slotPortConfigs);
if (portConfigFilePathName != null)
File.WriteAllText(portConfigFilePathName, text);
}
// stop loop if one Genesis has been detected
break;
}
serialPort.Dispose();
// removal from meter batch includes a disposal of meter
_meterBatch?.Dispose();
return serialPortDetected;
}
}
}
@@ -0,0 +1,163 @@
using System;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.GenesisCore
{
/// <summary>
/// Power correction parameters used for overestimated power consumption on
/// Cordonel FW update from:
/// EMEA below R1.3.x
/// NA below R2.0.07
/// </summary>
public class PowerCorrection
{
#region Data Base at EOL - Production
/// <summary>
/// Unique identification of PCB
/// </summary>
public String PcbId { get; set; }
/// <summary>
/// Date time UTC at EOL - Production
/// </summary>
public DateTime? ProductionDateTimeUtc { get; set; }
/// <summary>
/// Total used seconds at EOL - Production
/// </summary>
public UInt32 ProductionTotalUsedSeconds_s { get; set; }
/// <summary>
/// Total used charge of batteries at EOL - Production
/// </summary>
public UInt64 ProductionTotalUsedCharge_uAs { get; set; }
/// <summary>
/// Radio system state at EOL - Production
/// </summary>
public Byte? ProductionRadioSystemState { get; set; }
/// <summary>
/// Pulse adapter was installed during at EOL - Production VAKO
/// </summary>
public Boolean ProductionPulseAdapterIsInstalled { get; set; }
/// <summary>
/// Pulse mode during at EOL - Production
/// </summary>
public Byte ProductionPulseMode { get; set; }
/// <summary>
/// Pulse sequence counter during at EOL - Production
/// </summary>
public Byte ProductionPulseSequenceCounter { get; set; }
/// <summary>
/// Pulse distribution at EOL - Production
/// </summary>
public Boolean ProductionPulseEvenDistribution { get; set; }
#endregion
#region Maintenance readout
/// <summary>
/// Detected FW version before maintenance
/// </summary>
public UInt32? ActualFwVersion { get; set; }
/// <summary>
/// Date time UTC at time of maintenance
/// </summary>
public DateTime? ActualDateTimeUtc { get; set; }
/// <summary>
/// Total used seconds of entire runtime
/// </summary>
public UInt32 ActualTotalUsedSeconds_s { get; set; }
/// <summary>
/// Total used charge of batteries of entire runtime
/// </summary>
public UInt64 ActualTotalUsedCharge_uAs { get; set; }
/// <summary>
/// Actual detected radio system state at maintenance
/// </summary>
public Byte? ActualRadioSystemState { get; set; }
/// <summary>
/// Detection of pulse adapter installation
/// </summary>
public Boolean ActualPulseAdapterIsInstalled { get; set; }
/// <summary>
/// Pulse mode during maintenance
/// </summary>
public Byte ActualPulseMode { get; set; }
/// <summary>
/// Pulse sequence counter during maintenance
/// </summary>
public Byte ActualPulseSequenceCounter { get; set; }
/// <summary>
/// Pulse distribution during maintenance
/// </summary>
public Boolean ActualPulseEvenDistribution { get; set; }
/// <summary>
/// Mark pulse adapter as installed on any detected or sequence counted
/// </summary>
public Boolean PulseAdapterMarkedAsInstalled { get; set; }
/// <summary>
/// Remind battery quantity used for estimation of drained load
/// </summary>
public Int32 BatteryQuantity { get; set; }
/// <summary>
/// Remind battery initial load used for estimation of drained load
/// </summary>
public UInt32 InitialBatteryLoad_mAh { get; set; }
#endregion
#region Maintenance calculation
/// <summary>
/// FW version for the update
/// </summary>
public UInt32? RequiredFwVersion { get; set; }
/// <summary>
/// Calculated pulse report length
/// </summary>
public UInt32 PulseReportLength { get; set; }
/// <summary>
/// Total used seconds after EOL and before maintenance
/// </summary>
public UInt32 PostProductionTotalUsedSeconds_s { get; set; }
/// <summary>
/// Overestimated total used charge before maintenance
/// </summary>
public UInt64 OverestimatedTotalUsedCharge_uAs { get; set; }
/// <summary>
/// Based on fixed estimation total used charge before maintenance
/// </summary>
public UInt64 FixedEstimateTotalUsedCharge_uAs { get; set; }
/// <summary>
/// Lowest threshold for total used charge calculated during maintenance
/// </summary>
public UInt64 MinimumTotalUsedCharge_uAs { get; set; }
/// <summary>
/// Corrected total used charge during maintenance
/// </summary>
public UInt64? CorrectedTotalUsedCharge_uAs { get; set; }
#endregion
}
}
@@ -0,0 +1,219 @@
using System;
using System.Linq;
using TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.GenesisCore.Consts;
using TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.Registers;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.GenesisCore
{
/// <summary>
/// Read of required registers and calculation of power correction
/// </summary>
public class PowerCorrectionCalc
{
private readonly TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.GenesisCore.GenesisMeter _currentGenesis;
private readonly PowerCorrection _powCorr;
/// <summary>
/// Ctor
/// </summary>
/// <param name="currentGenesis"></param>
/// <param name="powCorr"></param>
/// <returns>true if successful</returns>
public PowerCorrectionCalc(TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.GenesisCore.GenesisMeter currentGenesis, PowerCorrection powCorr)
{
_currentGenesis = currentGenesis;
_powCorr = powCorr;
}
/// <summary>
/// Calculate the values for power correction
/// </summary>
/// <returns>true if successful</returns>
/// <remarks date="2024-May-15" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
public Boolean PowerCorrEstimation()
{
if (_currentGenesis == null || _powCorr == null)
return false;
var logOnReminder = _currentGenesis.IsLoggedOn;
var retVal = _currentGenesis.ReLogin();
if (retVal)
{
_powCorr.CorrectedTotalUsedCharge_uAs = null;
// read registers
_powCorr.ActualPulseSequenceCounter = RegisterConverter.ByteArrayToValue<Byte>(
_currentGenesis.ReadRegister(Register.Irda.PulseSequence));
_powCorr.ActualPulseEvenDistribution = RegisterConverter.ByteArrayToValue<Boolean>(
_currentGenesis.ReadRegister(Register.Metrologyasst.PulseEvenDistribution));
_powCorr.ActualPulseMode = RegisterConverter.ByteArrayToValue<Byte>(
_currentGenesis.ReadRegister(Register.Metrologyasst.PulseMode));
_powCorr.ActualRadioSystemState = RegisterConverter.ByteArrayToValue<Byte>(
_currentGenesis.ReadRegister(Register.Sensusradio.SystemState));
_powCorr.ActualTotalUsedSeconds_s = RegisterConverter.ByteArrayToValue<UInt32>(
_currentGenesis.ReadRegister(Register.Powermon.BatteryExceededSeconds));
_powCorr.ActualTotalUsedCharge_uAs = RegisterConverter.ByteArrayToValue<UInt64>(
_currentGenesis.ReadRegister(Register.Powermon.BatteryDrainedLoad, 8));
_powCorr.BatteryQuantity = RegisterConverter.ByteArrayToValue<Int32>(
_currentGenesis.ReadRegister(Register.Powermon.BatteryQuantity));
_powCorr.InitialBatteryLoad_mAh = RegisterConverter.ByteArrayToValue<UInt32>(
_currentGenesis.ReadRegister(Register.Powermon.BatteryInitialLoad));
if (!logOnReminder)
_currentGenesis.Logout();
// get actual time from PC
_powCorr.ActualDateTimeUtc = DateTime.UtcNow;
// skip if indicated that a pulse adapter never has been installed
_powCorr.PulseAdapterMarkedAsInstalled =
_powCorr.ProductionPulseAdapterIsInstalled ||
_powCorr.ActualPulseAdapterIsInstalled;
if (!_powCorr.PulseAdapterMarkedAsInstalled)
return true;
// calculate post production used seconds
if (_powCorr.ProductionTotalUsedSeconds_s > _powCorr.ActualTotalUsedSeconds_s)
_powCorr.PostProductionTotalUsedSeconds_s = _powCorr.ActualTotalUsedSeconds_s;
else
_powCorr.PostProductionTotalUsedSeconds_s = _powCorr.ActualTotalUsedSeconds_s -
_powCorr.ProductionTotalUsedSeconds_s;
// preset production used charge if not received from DB as logging of this value
// in early production processes was not granted
if (_powCorr.ProductionTotalUsedCharge_uAs == 0)
_powCorr.ProductionTotalUsedCharge_uAs = (UInt64)(_powCorr.ProductionTotalUsedSeconds_s *
PowCorrConst.FixProductionCurrent_uA);
// calculate pulse report length
if ((_powCorr.ActualPulseMode >= 1 && _powCorr.ActualPulseMode <= 4) ||
(_powCorr.ProductionPulseMode >= 1 && _powCorr.ProductionPulseMode <= 4))
{
_powCorr.PulseReportLength = PowCorrConst.PulseReportLengthMode1To4Even0;
if (_powCorr.ActualPulseEvenDistribution)
_powCorr.PulseReportLength = PowCorrConst.PulseReportLengthMode1To4Even1;
}
else if ((_powCorr.ActualPulseMode >= 5 && _powCorr.ActualPulseMode <= 6) ||
(_powCorr.ProductionPulseMode >= 5 && _powCorr.ProductionPulseMode <= 6))
{
_powCorr.PulseReportLength = PowCorrConst.PulseReportLengthMode5To6Even0;
if (_powCorr.ActualPulseEvenDistribution)
_powCorr.PulseReportLength = PowCorrConst.PulseReportLengthMode5To6Even1;
}
// calculate overestimation based on pulse report length
_powCorr.OverestimatedTotalUsedCharge_uAs = 0;
if ((_powCorr.ActualPulseMode >= 1 && _powCorr.ActualPulseMode <= 6) ||
(_powCorr.ProductionPulseMode >= 1 && _powCorr.ProductionPulseMode <= 6))
{
_powCorr.OverestimatedTotalUsedCharge_uAs =
(UInt64)(_powCorr.PulseReportLength * PowCorrConst.PulseReportLengthEstimate_uA *
_powCorr.PostProductionTotalUsedSeconds_s);
}
Byte radioSystemState = 0;
if (_powCorr.ActualRadioSystemState != null)
{
radioSystemState = (Byte)_powCorr.ActualRadioSystemState;
}
else if (_powCorr.ProductionRadioSystemState != null)
{
radioSystemState = (Byte)_powCorr.ProductionRadioSystemState;
}
if (_currentGenesis.Region == "NA")
{
_powCorr.MinimumTotalUsedCharge_uAs =
(UInt64)(_powCorr.ActualTotalUsedSeconds_s * PowCorrConst.MinNaCurrent_uA);
_powCorr.FixedEstimateTotalUsedCharge_uAs =
(UInt64)(_powCorr.ActualTotalUsedSeconds_s * PowCorrConst.FixNaCurrent_uA);
}
else if (_currentGenesis.Region == "EMEA" &&
(radioSystemState & PowCorrConst.SensusRadioSystemStateTfXModeMask) ==
PowCorrConst.SensusRadioSystemStateTfXModeMask)
{
_powCorr.MinimumTotalUsedCharge_uAs =
(UInt64)(_powCorr.ActualTotalUsedSeconds_s * PowCorrConst.MinEmeaRadioTfxModeCurrent_uA);
_powCorr.FixedEstimateTotalUsedCharge_uAs =
(UInt64)(_powCorr.ActualTotalUsedSeconds_s * PowCorrConst.FixEmeaRadioTfxModeCurrent_uA);
}
else if (_currentGenesis.Region == "EMEA" &&
(radioSystemState & PowCorrConst.SensusRadioSystemStateTfXModeMask) !=
PowCorrConst.SensusRadioSystemStateTfXModeMask)
{
_powCorr.MinimumTotalUsedCharge_uAs =
(UInt64)(_powCorr.ActualTotalUsedSeconds_s * PowCorrConst.MinEmeaRadioRfModeCurrent_uA);
_powCorr.FixedEstimateTotalUsedCharge_uAs =
(UInt64)(_powCorr.ActualTotalUsedSeconds_s * PowCorrConst.FixEmeaRadioRfModeCurrent_uA);
}
if (_powCorr.OverestimatedTotalUsedCharge_uAs > _powCorr.ActualTotalUsedCharge_uAs)
_powCorr.CorrectedTotalUsedCharge_uAs = 0;
else
_powCorr.CorrectedTotalUsedCharge_uAs = _powCorr.ActualTotalUsedCharge_uAs -
_powCorr.OverestimatedTotalUsedCharge_uAs;
}
return retVal;
}
/// <summary>
/// Calculate the values for power correction
/// </summary>
/// <returns>true if successful</returns>
/// <remarks date="2024-May-14" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
public Boolean CorrectPowerConsumption()
{
if (_currentGenesis == null || _powCorr == null || _powCorr.CorrectedTotalUsedCharge_uAs == null)
return false;
// check which value should be applied and set the CorrectedTotalUsedCharge_uAs
if (_powCorr.ProductionPulseAdapterIsInstalled)
{
// avoid undershot below smallest value
if (_powCorr.CorrectedTotalUsedCharge_uAs < _powCorr.MinimumTotalUsedCharge_uAs)
_powCorr.CorrectedTotalUsedCharge_uAs = _powCorr.MinimumTotalUsedCharge_uAs;
}
else // retrofitted
{
// correct to smaller value and mark corrected = actual to log that correction not needed
_powCorr.CorrectedTotalUsedCharge_uAs =
_powCorr.ActualTotalUsedCharge_uAs > _powCorr.FixedEstimateTotalUsedCharge_uAs ?
_powCorr.FixedEstimateTotalUsedCharge_uAs : _powCorr.ActualTotalUsedCharge_uAs;
}
if (_powCorr.ActualTotalUsedCharge_uAs == _powCorr.CorrectedTotalUsedCharge_uAs)
return true;
// save corrected power consumption data to meter
var logOnReminder = _currentGenesis.IsLoggedOn;
var retVal = _currentGenesis.ReLogin();
if (retVal)
{
var retriesLeft = 2;
do
{
// write the new calculated value
retVal = _currentGenesis.WriteRegister(Register.Powermon.BatteryDrainedLoad,
RegisterConverter.ValueToByteArray(_powCorr.CorrectedTotalUsedCharge_uAs));
if (!retVal)
continue;
// store configuration
retVal = _currentGenesis.WriteRegister(Register.Powermon.StoreConfiguration, 1);
if (!retVal)
continue;
var readResult = _currentGenesis.ReadRegister(Register.Powermon.StoreConfiguration);
retVal = readResult != null && readResult.ToList().All(array => array == 0x00);
} while (!retVal && retriesLeft-- > 0);
}
if (!logOnReminder)
_currentGenesis.Logout();
return retVal;
}
}
}
@@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.Registers;
using Xylem.Common.CommonCore.Configuration;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.GenesisCore
{
public class PreadjustmentMeter : TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.GenesisCore.GenesisMeter
{
private settings mySettings = new settings();
public class settings
{
public int Metersize { get; set; } = 2;
}
public void Preparation()
{
//Login
//getRegisterList
Login();
WriteRegister(Register.Genesisflow.CalFactor1, 15625);
WriteRegister(Register.Genesisflow.CalFactor2, 15625);
WriteRegister(Register.Genesisflow.CalFactor3, 15625);
WriteRegister(Register.Genesisflow.ZeroOffset1, 0);
WriteRegister(Register.Genesisflow.ZeroOffset2, 0);
WriteRegister(Register.Genesisflow.ZeroOffset3, 0);
WriteRegister(Register.Genesisflow.LedMode, 6);
WriteRegister(Register.Genesisflow.MeterSize, mySettings.Metersize);
//var r = LocalWebRequest.GetRequest($"{ ServiceUrls.GenesisFinalCheckServiceUrl()}GetMetersizeProgrammingData?MeterSize={mySettings.Metersize.GetHashCode().GetHashCode()}", 2000);
//var dt = JsonConvert.DeserializeObject<Dictionary<string, UInt32>>(r);
// foreach (var item in dt)
// {
// WriteRegister(item.Key, item.Value);
// }
}
public void RunAmp()
{
for (int i = 0; i < 35; i++)
{
}
}
}
}
@@ -0,0 +1,288 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized string similar to ERROR: Missing or invalid register definition (configuration.json)! Search in:.
/// </summary>
internal static string StrErrorMissingConfiguration {
get {
return ResourceManager.GetString("StrErrorMissingConfiguration", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Cannot Open Comport. Check TaskManager for other Genesis relevant programs and close them! Also check if the comport is valid!.
/// </summary>
internal static string StrErrorMsgComPort {
get {
return ResourceManager.GetString("StrErrorMsgComPort", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to ERROR: Could not find a CSD parameter in register list!.
/// </summary>
internal static string StrErrorMsgCsdMissing {
get {
return ResourceManager.GetString("StrErrorMsgCsdMissing", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to ERROR: Could not find register in register list! Check configuration.json for latest version!.
/// </summary>
internal static string StrErrorMsgRegisterNotFound {
get {
return ResourceManager.GetString("StrErrorMsgRegisterNotFound", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to ERROR: Could not write register!.
/// </summary>
internal static string StrErrorMsgRegisterWrite {
get {
return ResourceManager.GetString("StrErrorMsgRegisterWrite", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Read back.
/// </summary>
internal static string StrMeterValue {
get {
return ResourceManager.GetString("StrMeterValue", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Access request..
/// </summary>
internal static string StrPortAccessRequest {
get {
return ResourceManager.GetString("StrPortAccessRequest", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Failed to open..
/// </summary>
internal static string StrPortFailedToOpen {
get {
return ResourceManager.GetString("StrPortFailedToOpen", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Ports listed in the Windows device manager..
/// </summary>
internal static string StrPortListDeviceManger {
get {
return ResourceManager.GetString("StrPortListDeviceManger", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Automatic port scan started..
/// </summary>
internal static string StrPortScanStarted {
get {
return ResourceManager.GetString("StrPortScanStarted", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Successfully accessed..
/// </summary>
internal static string StrPortSuccessfullyAccessed {
get {
return ResourceManager.GetString("StrPortSuccessfullyAccessed", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Read register.
/// </summary>
internal static string StrReadRegister {
get {
return ResourceManager.GetString("StrReadRegister", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Reading registers after maintenance.
/// </summary>
internal static string StrReadRegistersAfterUpdate {
get {
return ResourceManager.GetString("StrReadRegistersAfterUpdate", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Reading registers before maintenance.
/// </summary>
internal static string StrReadRegistersBeforeUpdate {
get {
return ResourceManager.GetString("StrReadRegistersBeforeUpdate", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Compare register.
/// </summary>
internal static string StrRegisterCompare {
get {
return ResourceManager.GetString("StrRegisterCompare", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to ERROR: Comparison failed!.
/// </summary>
internal static string StrRegisterCompareFailed {
get {
return ResourceManager.GetString("StrRegisterCompareFailed", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Successfully compared..
/// </summary>
internal static string StrRegisterCompareSucceeded {
get {
return ResourceManager.GetString("StrRegisterCompareSucceeded", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Execute configuration sequence.....
/// </summary>
internal static string StrRegisterRecoveryExec {
get {
return ResourceManager.GetString("StrRegisterRecoveryExec", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Finalize configuration sequence.....
/// </summary>
internal static string StrRegisterRecoveryFinalization {
get {
return ResourceManager.GetString("StrRegisterRecoveryFinalization", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Prepare configuration sequence.....
/// </summary>
internal static string StrRegisterRecoveryPreparation {
get {
return ResourceManager.GetString("StrRegisterRecoveryPreparation", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to ERROR: Register value is out of range!.
/// </summary>
internal static string StrRegisterValueOutOfRange {
get {
return ResourceManager.GetString("StrRegisterValueOutOfRange", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Cordonel not detected!.
/// </summary>
internal static string StrRequestPortDetectionFailed {
get {
return ResourceManager.GetString("StrRequestPortDetectionFailed", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Scan port.
/// </summary>
internal static string StrScanPort {
get {
return ResourceManager.GetString("StrScanPort", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to WARNING: Register value set to default.
/// </summary>
internal static string StrSetRegisterToDefault {
get {
return ResourceManager.GetString("StrSetRegisterToDefault", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Write register.
/// </summary>
internal static string StrWriteRegister {
get {
return ResourceManager.GetString("StrWriteRegister", resourceCulture);
}
}
}
}
@@ -0,0 +1,195 @@
<?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>
<data name="StrPortAccessRequest" xml:space="preserve">
<value>Teste Zugriff.</value>
</data>
<data name="StrPortFailedToOpen" xml:space="preserve">
<value>Zugriff verweigert.</value>
</data>
<data name="StrPortListDeviceManger" xml:space="preserve">
<value>Kommunikationsanschlüsse im Windows Gerätemanager.</value>
</data>
<data name="StrPortScanStarted" xml:space="preserve">
<value>Automatische Erkennung gestartet.</value>
</data>
<data name="StrPortSuccessfullyAccessed" xml:space="preserve">
<value>Zugriff erfolgreich.</value>
</data>
<data name="StrRequestPortDetectionFailed" xml:space="preserve">
<value>Keinen Cordonel erkannt!</value>
</data>
<data name="StrScanPort" xml:space="preserve">
<value>Suche Anschluß....</value>
</data>
<data name="StrRegisterCompare" xml:space="preserve">
<value>Vergleiche Register</value>
</data>
<data name="StrReadRegister" xml:space="preserve">
<value>Lese Register</value>
</data>
<data name="StrWriteRegister" xml:space="preserve">
<value>Schreibe Register</value>
</data>
<data name="StrReadRegistersBeforeUpdate" xml:space="preserve">
<value>Lese Register vor der Wartung</value>
</data>
<data name="StrReadRegistersAfterUpdate" xml:space="preserve">
<value>Lese Register nach der Wartung</value>
</data>
<data name="StrRegisterRecoveryExec" xml:space="preserve">
<value>Ausführung der Konfigurationsequenz....</value>
</data>
<data name="StrRegisterRecoveryFinalization" xml:space="preserve">
<value>Abschließen der Konfigurationsequenz....</value>
</data>
<data name="StrRegisterRecoveryPreparation" xml:space="preserve">
<value>Vorbereitung der Konfigurationsequenz....</value>
</data>
<data name="StrRegisterCompareFailed" xml:space="preserve">
<value>FEHLER: Vergleich fehlgeschlagen!</value>
</data>
<data name="StrRegisterCompareSucceeded" xml:space="preserve">
<value>Vergleich erfolgreich.</value>
</data>
<data name="StrMeterValue" xml:space="preserve">
<value>Zurückgelesen</value>
</data>
<data name="StrSetRegisterToDefault" xml:space="preserve">
<value>WARNUNG: Registerwert auf Standardwert gesetzt</value>
</data>
<data name="StrRegisterValueOutOfRange" xml:space="preserve">
<value>FEHLER: Registerwert außerhalb des zulässigen Bereiches!</value>
</data>
<data name="StrErrorMsgCsdMissing" xml:space="preserve">
<value>FEHLER: Kein CSD Parameter in Parameterliste gefunden!</value>
</data>
<data name="StrErrorMsgRegisterNotFound" xml:space="preserve">
<value>FEHLER: Register nicht in Registerliste gefunden! Version der Configuration.json prüfen!</value>
</data>
<data name="StrErrorMsgRegisterWrite" xml:space="preserve">
<value>FEHLER: Register konnte nicht geschrieben werden!</value>
</data>
<data name="StrErrorMissingConfiguration" xml:space="preserve">
<value>FEHLER: Konfigurationsdatei (configuration.json) nicht gefunden oder ungültig! Erwartetes Verzeichnis:</value>
</data>
<data name="StrErrorMsgComPort" xml:space="preserve">
<value>Kommunikationsanschluß nicht vorhanden oder von anderer Genesis App blockiert! Bitte TaskManger starten und prüfen!</value>
</data>
</root>
@@ -0,0 +1,195 @@
<?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>
<data name="StrPortAccessRequest" xml:space="preserve">
<value>Access request.</value>
</data>
<data name="StrPortFailedToOpen" xml:space="preserve">
<value>Failed to open.</value>
</data>
<data name="StrPortListDeviceManger" xml:space="preserve">
<value>Ports listed in the Windows device manager.</value>
</data>
<data name="StrPortScanStarted" xml:space="preserve">
<value>Automatic port scan started.</value>
</data>
<data name="StrPortSuccessfullyAccessed" xml:space="preserve">
<value>Successfully accessed.</value>
</data>
<data name="StrRequestPortDetectionFailed" xml:space="preserve">
<value>Cordonel not detected!</value>
</data>
<data name="StrScanPort" xml:space="preserve">
<value>Scan port</value>
</data>
<data name="StrReadRegistersAfterUpdate" xml:space="preserve">
<value>Reading registers after maintenance</value>
</data>
<data name="StrReadRegistersBeforeUpdate" xml:space="preserve">
<value>Reading registers before maintenance</value>
</data>
<data name="StrRegisterCompare" xml:space="preserve">
<value>Compare register</value>
</data>
<data name="StrReadRegister" xml:space="preserve">
<value>Read register</value>
</data>
<data name="StrWriteRegister" xml:space="preserve">
<value>Write register</value>
</data>
<data name="StrRegisterRecoveryExec" xml:space="preserve">
<value>Execute configuration sequence....</value>
</data>
<data name="StrRegisterRecoveryFinalization" xml:space="preserve">
<value>Finalize configuration sequence....</value>
</data>
<data name="StrRegisterRecoveryPreparation" xml:space="preserve">
<value>Prepare configuration sequence....</value>
</data>
<data name="StrRegisterCompareFailed" xml:space="preserve">
<value>ERROR: Comparison failed!</value>
</data>
<data name="StrRegisterCompareSucceeded" xml:space="preserve">
<value>Successfully compared.</value>
</data>
<data name="StrMeterValue" xml:space="preserve">
<value>Read back</value>
</data>
<data name="StrSetRegisterToDefault" xml:space="preserve">
<value>WARNING: Register value set to default</value>
</data>
<data name="StrRegisterValueOutOfRange" xml:space="preserve">
<value>ERROR: Register value is out of range!</value>
</data>
<data name="StrErrorMsgCsdMissing" xml:space="preserve">
<value>ERROR: Could not find a CSD parameter in register list!</value>
</data>
<data name="StrErrorMsgRegisterNotFound" xml:space="preserve">
<value>ERROR: Could not find register in register list! Check configuration.json for latest version!</value>
</data>
<data name="StrErrorMsgRegisterWrite" xml:space="preserve">
<value>ERROR: Could not write register!</value>
</data>
<data name="StrErrorMissingConfiguration" xml:space="preserve">
<value>ERROR: Missing or invalid register definition (configuration.json)! Search in:</value>
</data>
<data name="StrErrorMsgComPort" xml:space="preserve">
<value>Cannot Open Comport. Check TaskManager for other Genesis relevant programs and close them! Also check if the comport is valid!</value>
</data>
</root>
@@ -0,0 +1,26 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
}
}
@@ -0,0 +1,6 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
</SettingsFile>
@@ -0,0 +1,237 @@
using System;
using System.Linq;
using TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.Registers;
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisConfig.Const;
using Xylem.Common.Metrology.Measurements;
using Xylem.Common.Metrology.Measurements.Consts;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.GenesisCore
{
public partial class GenesisMeter
{
/// <summary>
/// Calibration factors for all channels
/// </summary>
private readonly CalibFactor[] _calibFactor = new CalibFactor[MeterConfig.CalibChannels];
/// <summary>
/// Registers needed to store the calibration for the individual channel
/// </summary>
private readonly String[] _registersToStoreCalibFactor =
{
Register.Genesisflow.CalFactor1,
Register.Genesisflow.CalFactor2,
Register.Genesisflow.CalFactor3
};
/// <inheritdoc />
public void InitCalibration()
{
Logger.Info($"Slot:{Slot} - Init calibration and set calibration values of all channels to default");
for (var channel = 0; channel < MeterConfig.CalibChannels; channel++)
{
_calibFactor[channel] = new CalibFactor(channel, _registersToStoreCalibFactor[channel]);
WriteRegister(_registersToStoreCalibFactor[channel],
_calibFactor[channel].GetMeterRawCalibFactorDefault(), checkRegister: true);
}
PreMeasurement();
}
/// <inheritdoc />
public void StartCalibration()
{
StartMeasurement();
}
/// <inheritdoc />
/// <summary>
/// Just stop recording without calculation
/// </summary>
public void StopCalibration()
{
StopMeasurement();
}
/// <inheritdoc />
public MeasurementStates GetCalibrationState()
{
return GetMeasurementState();
}
/// <inheritdoc />
public void BuildAndCheckCalibFactorsAllChannels(Double refVolumeCm, Double? refTimeS, Double reqDeviationPercent, Double maxCalibFactorTolerancePercent = MeterConfig.DefaultMaxCalibFactorTolerancePercent, int? testrunNr = null)
{
for (var channel = 0; channel < MeterConfig.CalibChannels; channel++)
{
_calibFactor[channel] = new CalibFactor(channel, _registersToStoreCalibFactor[channel]);
}
foreach (var item in Enumerable.Where<IMeasurement>(_listOfIMeasurement, m => m.GetType() == typeof(CalibrationRecord)))
{
if (!(item is CalibrationMeasurement))
{
continue;
}
var calib = item as CalibrationMeasurement;
var channel = calib.GetChannel();
if (channel == 0 || channel > MeterConfig.CalibChannels)
{
var message = $"Slot:{Slot}, Channel:{channel} - Calibration channel out of range";
Logger.Warn(message);
throw new ApplicationException(message);
}
Logger.Info($"Slot:{Slot}, Channel:{channel} - Calculate Calibrationfactor Relative(RefVolumeCm:{refVolumeCm}, refTimeS:{refTimeS},reqDeviationPercent:{reqDeviationPercent})");
var calibFactorRel = calib.CalculateCalibFactorRel(refVolumeCm, refTimeS, reqDeviationPercent);
//if the null return indicates an invalid calibration factor the calibFactorX.IsCalculated remains false
if (null == calibFactorRel)
{
var message = $"Slot:{Slot}, Channel:{channel} - Calibration factor not calculated";
Logger.Warn(message);
throw new ApplicationException(message);
}
_calibFactor[channel - 1].BuildMeterCalibFactor(calibFactorRel.Value);
_calibFactor[channel - 1].IsCalculated = true;
Logger.Info($"Slot:{Slot}, Channel:{channel} - New calibration factor({_calibFactor[channel - 1].GetRelativeCalibFactor()}rel/{calibFactorRel})");
Logger.Info($"Slot:{Slot}, Channel:{channel} - Calc /{_calibFactor[channel - 1].GetMeterRawCalibFactor()} * {calibFactorRel.Value}) -> UInt16");
//Setup the required tolerance value to check against
//plus/minus x% tolerance allowed
calib.CalibFactorTolerancePercent = maxCalibFactorTolerancePercent;
if (calib.IsCalibFactorInTolerance(calibFactorRel.Value))
{
continue;
}
var warnMessage = $"Slot:{Slot}, Channel:{channel} - " +
$"Calibration factor is out of range({calibFactorRel.Value}rel)";
Logger.Warn(warnMessage);
// throw new ApplicationException(warnMessage);
}
var t = new JustageResults
{
pcbId = PcbId,
p1Target = reqDeviationPercent,
p1Value = _calibFactor[0].GetMeterRawCalibFactor(),
p2Target = reqDeviationPercent,
p2Value = _calibFactor[1].GetMeterRawCalibFactor(),
p3Target = reqDeviationPercent,
p3Value = _calibFactor[2].GetMeterRawCalibFactor(),
dt = DateTime.UtcNow,
testrunNr = testrunNr
};
try
{
var tmpUrl = "http://10.49.40.25/MeterProcessState/api/TestBench/SetCalibrationValues";
Logger.Info($"Request Url: {tmpUrl}");
//ToDO: Update to service URl
LocalWebRequest.PostAsJson<JustageResults>(t, tmpUrl);
}
catch (Exception ex)
{
Logger.Error($"Request Url: {ex.Message}");
}
}
/// <inheritdoc />
public void SetCalibFactorsAllChannels(Boolean justLog = false)
{
WriteRegister<Byte>(Register.Genesisflow.SampleRate, 2, checkRegister: true);
WriteRegister<UInt16>(Register.Genesisflow.TriggerIdle, 0x1234);
for (var channel = 0; channel < MeterConfig.CalibChannels; channel++)
{
if (_calibFactor[channel].IsCalculated == false)
{
continue;
}
if (justLog)
{
Logger.Warn($"Slot:{Slot} - Calculated calibration factors but not stored to registers");
}
else
{
var registerRawCalibFactor = _calibFactor[channel].GetMeterRawCalibFactor();
var resultWrite = WriteRegister(_calibFactor[channel].RegisterToStoreCalibFactor,
registerRawCalibFactor, checkRegister: true);
Logger.Info($"Slot:{Slot}, Channel:{channel} - Stored calibration factor({_registersToStoreCalibFactor[channel]})");
//if (!string.IsNullOrEmpty(SerialNumber) && CurrentActionText.Contains("PG"))
//{
// var pathMain = NLogHelper.GetPath(_logger);
// var pathRaw = NLogHelper.GetPath(((LedSerialPort)StreamingPort).GetRawLogger());
// var basePath = Path.GetDirectoryName(pathMain);
// //
// var testRunString = CurrentActionText.Replace("PG", "");
//
if (resultWrite)
{
Logger.Warn($"Set calibration went wrong {_calibFactor[channel].RegisterToStoreCalibFactor}, with {registerRawCalibFactor}");
}
}
}
WriteRegister(Register.Genesisflow.ResetAccumulators, true);
//WriteRegister<UInt16>(Register.Genesisflow.ForwardArrow, 0, checkRegister: true);
WriteRegister<UInt16>(Register.Genesisflow.StoreCalibration, 1);
Logger.Info($"Slot:{Slot} - StoreCalibration {RegisterConverter.ByteArrayToValue<UInt16>(ReadRegister(Register.Genesisflow.StoreCalibration))}");
WriteRegister<UInt16>(Register.Genesisflow.TriggerActive, 1);
Logger.Info($"Slot:{Slot} - Set forward arrow of LCD, reset accumulators, set sample rate to 2Hz");
WriteRegister<Byte>(Register.Genesisflow.SampleRate, 10, checkRegister: true);
try
{
if (Enumerable.Any(GetRegistersDic(), a => a.Key.RegisterName == "GENESISFLOW_DelayedLedOff"))
{
WriteRegister("GENESISFLOW_DelayedLedOff", 60 * 60 * 2, true);
Logger.Info($"Slot:{Slot} - GENESISFLOW_DelayedLedOff to {60 * 60 * 2}S");
}
else
{
Logger.Info($"Slot:{Slot} - GENESISFLOW_DelayedLedOff is not present");
}
}
catch (Exception ex)
{
Logger.Info($"Slot:{Slot} - {ex}");
}
}
}
}
@@ -0,0 +1,320 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Xylem.Common.CommonCore.Consts;
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisConfig.Const;
using Xylem.Common.Metrology.Measurements;
using Xylem.Common.Metrology.Measurements.Consts;
using LedMode = TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.GenesisCore.Consts.LedMode;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.GenesisCore
{
public partial class GenesisMeter
{
/// <summary>
/// List of ongoing measurements, base- and calibration-measurements
/// </summary>
private List<IMeasurement> _listOfIMeasurement = new List<IMeasurement>();
/// <summary>
/// All channels required to process
/// </summary>
public Boolean AllChannelsRequired = true;
/// <summary>
/// Quality watch mode can be used to decode intermediate records and check
/// for actual quality of the measurements.
/// </summary>
public Boolean QualityWatchMode;
/// <inheritdoc />
/// <summary>
/// Perpetration of Measurement
/// SampleRate 10 and Led mode Test
/// </summary>
public void InitMeasurement()
{
Logger.Info($"Slot:{Slot} - Init measurement");
PreMeasurement();
}
private void PreMeasurement()
{
if (!SkipPreparationForTestBench)
{
//SkipPreparationForTestBench = true;
//TODO set display unit
//TODO calculated overflow volume for display
WriteRegister<Byte>(Register.Genesisflow.SampleRate, 0x08, checkRegister: true);
WriteRegister(Register.Genesisflow.LedMode, (Byte)LedMode.FlowTestAndCalibData, checkRegister: true);
WriteRegister("GENESISFLOW_SealDisplay", 0, true, true);
try
{
var displayState = ReadRegister(Register.Genesisflow.TriggerIdle);
if (displayState == null)
{
displayState = ReadRegister(Register.Genesisflow.TriggerIdle);
if (displayState == null)
{
Logger.Info($"Slot:{Slot} - Not able to read display state");
return;
}
}
var displayStateString = ByteStyler.ToString(displayState);
if (displayStateString.Substring(0, 2) != "FF" || displayStateString.Substring(0, 5) == "FF-55")
{
WriteRegister(Register.Genesisflow.TriggerIdle, 0, true, true);
displayState = ReadRegister(Register.Genesisflow.TriggerIdle);
displayStateString = ByteStyler.ToString(displayState);
if (displayStateString != "00-00-00-00")
{
WriteRegister(Register.Genesisflow.TriggerActive, 1);
}
}
else
{
WriteLog($"meter not active because display code has an error on code:{displayStateString}");
}
}
catch (Exception)
{
// ignored
}
WriteRegister("GENESISFLOW_DisplayPow10", (new Byte[] { 0x00, 0x00, 0x00, 0xFA }).Reverse().ToArray());
//WriteRegister(Register.Genesisflow.StoreCalibration, 1);
//WriteRegister(Register.Genesisflow.StoreConfiguration, 1);
try
{
if (Enumerable.Any(GetRegistersDic(), a => a.Key.RegisterName == "GENESISFLOW_DelayedLedOff"))
{
WriteRegister("GENESISFLOW_DelayedLedOff", 60 * 60 * 2, false);
}
}
catch (Exception)
{
}
}
else
{
WriteLog($"wait for measurement is starting");
}
ProcessStatus = ProcessState.WaitForMeasurement;
}
/// <inheritdoc />
public void StartMeasurement()
{
_listOfIMeasurement = new List<IMeasurement>
{
new BaseMeasurement(Slot, typeof(FlowTestRecord), IntermediateUpdateTimeS)
};
//add channels for calibration measurement
for (var i = 1; i <= MeterConfig.CalibChannels; i++)
{
_listOfIMeasurement.Add(new CalibrationMeasurement(Slot, typeof(CalibrationRecord), IntermediateUpdateTimeS, i));
}
foreach (var measurement in _listOfIMeasurement)
{
measurement.OnActionStateHasChanged += Measurement_ActionStateHasChanged;
}
Logger.Info($"Slot:{Slot} - Start measurement");
ProcessStatus = ProcessState.MeasurementIsActive;
_listOfIMeasurement.ForEach(m => m.MeasurementState = MeasurementStates.IsWaitingForStartData);
SyncStreamingBuffer(SyncMarkRecord.SyncStart);
}
/// <inheritdoc />
public void StopMeasurement()
{
Logger.Info($"Slot:{Slot} - Stop measurement");
ProcessStatus = ProcessState.MeasurementIsDone;
_listOfIMeasurement.ForEach(m => m.MeasurementState = MeasurementStates.IsWaitingForEndData);
SyncStreamingBuffer(SyncMarkRecord.SyncEnd);
}
/// <summary>
/// Testing the flow direction
/// </summary>
/// <returns></returns>
public Boolean CheckChannelFlowDirection()
{
Boolean? dirPositive = null;
foreach (var cali in _listOfIMeasurement.Where(m => m.GetType() == typeof(CalibrationRecord)))
{
var result = cali.GetIntermediateMeasurementResult();
var channelDirPositive = result.DutVolumeCm > 0.0;
if (!dirPositive.HasValue)
{
dirPositive = channelDirPositive;
}
if (dirPositive != channelDirPositive)
{
return false;
}
}
return true;
}
/// <inheritdoc />
/// <summary>
/// the first measurement is ALWAYS a FlowTestRecord due to the underlying<see cref="GetAllMeasurementResults"/> routine logic.
/// </summary>
public MeasurementResults GetMainMeasurementResult(Double? refVolume, Double? refTimeS, Boolean intermediateMeasurement = false, MeasurementDirection dir = MeasurementDirection.TakeBoth)
{
if (!intermediateMeasurement && GetMeasurementState(0) != MeasurementStates.IsCompleted)
{
throw new ApplicationException("Measurement is not completed");
}
return GetAllMeasurementResults(refVolume, refTimeS, intermediateMeasurement, 0).First();
}
/// <summary>
/// The first measurement is ALWAYS a FlowTestRecord.
/// </summary>
public List<MeasurementResults> GetAllMeasurementResults(Double? refVolume, Double? refTimeS, Boolean intermediateMeasurement = false, Int32? channel = null, MeasurementDirection dir = MeasurementDirection.TakeBoth)
{
//
if (!intermediateMeasurement && GetMeasurementState(channel) != MeasurementStates.IsCompleted)
{
throw new ApplicationException("Measurement is not completed");
}
var mainMeasurement = _listOfIMeasurement.FirstOrDefault(m => m.GetType() == typeof(FlowTestRecord));
if (mainMeasurement == null)
{
throw new ApplicationException("Can not find an ongoing measurement");
}
mainMeasurement.FlowDirectionforCalculatingVol = dir;
var results = new List<MeasurementResults>();
var mainResult = intermediateMeasurement
? mainMeasurement.GetIntermediateMeasurementResult(refVolume, refTimeS)
: mainMeasurement.GetFinalMeasurementResult(refVolume, refTimeS);
results.Add(mainResult);
Logger.Info($"Slot:{Slot}, Channel:{mainMeasurement.GetChannel()} - MeasuredTime({mainResult.DutTimeS}s), " +
$"MeasuredVolume({mainResult.DutVolumeCm}Qm)");
foreach (var otherMeasurement in _listOfIMeasurement.Where(m => m.GetType() != typeof(FlowTestRecord)))
{
try
{
var otherResults = intermediateMeasurement
? otherMeasurement.GetIntermediateMeasurementResult(refVolume, refTimeS)
: otherMeasurement.GetFinalMeasurementResult(refVolume, refTimeS);
Logger.Info($"Slot:{Slot}, Channel:{otherMeasurement.GetChannel()} - ChannelTime({otherResults.DutTimeS}s), " +
$"ChannelVolume({otherResults.DutVolumeCm}Qm)");
results.Add(otherResults);
}
catch (Exception ex)
{
Logger.Warn($"Slot:{Slot}, No Results for channel:{otherMeasurement.GetChannel()} Ex: {ex.Message}");
if (channel == null)
{
throw new ApplicationException($"Can not read result from channel:{otherMeasurement.GetChannel() } Ex: {ex.Message}");
}
}
}
return results;
}
private void AddData(IMeasurementRecord newRecord)
{
foreach (var measurement in _listOfIMeasurement)
{
if (measurement.GetType() != newRecord.GetType())
{
continue;
}
if (measurement.GetChannel() == newRecord.GetChannel())
{
measurement.AddData(newRecord);
}
}
// when every measurement has state IsRunning or every measurement has state IsCompleted, the streaming buffer set to skip decoding
if (_listOfIMeasurement.All(m => m.MeasurementState == MeasurementStates.IsRunning)
|| _listOfIMeasurement.All(m => m.MeasurementState == MeasurementStates.IsCompleted))
{
SyncStreamingBuffer(QualityWatchMode
? SyncMarkRecord.DecodeIntermediateQuality
: SyncMarkRecord.SkipDecoding);
}
}
private void Measurement_ActionStateHasChanged(Object sender, EventArgs e)
{
SyncStreamingBuffer(SyncMarkRecord.DecodeIntermediate);
}
/// <inheritdoc />
public MeasurementStates GetMeasurementState(Int32? onlyChannelNr = null)
{
Logger.Trace($"Slot:{Slot} - Get measurement state");
if (!_listOfIMeasurement.Any())
{
return MeasurementStates.NotStarted;
}
if (onlyChannelNr.HasValue)
{
var measurement = _listOfIMeasurement.First(f => f.GetChannel() == onlyChannelNr.Value);
return measurement.GetMeasurementState();
}
return _listOfIMeasurement.Min(m => m.MeasurementState);
}
/// <inheritdoc />
public Boolean RequestIntermediateMeasurementState(Int32? onlyChannelNr = null)
{
Logger.Trace($"Slot:{Slot} - Get measurement state");
if (!_listOfIMeasurement.Any())
{
return false;
}
Boolean? ret = null;
foreach (var item in _listOfIMeasurement)
{
if (!onlyChannelNr.HasValue || item.GetChannel() == onlyChannelNr.Value)
{
var measurement = _listOfIMeasurement.First(f => onlyChannelNr != null && f.GetChannel() == onlyChannelNr.Value);
if ((measurement.MeasurementState == MeasurementStates.IsRunning
|| measurement.MeasurementState == MeasurementStates.IsWaitingForIntermediateData))
{
measurement.RequestIntermediateRecord();
if (!ret.HasValue)
{
ret = true;
}
}
else
{
ret = false;
}
}
}
return ret.HasValue ? ret.Value : false;
}
}
}
@@ -0,0 +1,313 @@
{
"_comment": "Auto generated from 'Configuration.xls' - DO NOT MANUALLY EDIT THIS TABLE",
"CONFIGEXCHANGE_Privilege": {"type": "uint8_t", "id": 1024, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"CONFIGEXCHANGE_Password": {"type": "uint96_t", "id": 1025, "privilege": {"lvl1": "WO", "lvl2": "WO", "lvl3": "WO", "lvl4": "WO", "lvl5": "WO", "lvl6": "WO", "lvl7": "WO", "lvl8": "WO"}},
"CONFIGEXCHANGE_FOpen": {"type": "RPC", "id": 1026, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"CONFIGEXCHANGE_FClose": {"type": "RPC", "id": 1027, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"CONFIGEXCHANGE_FRead": {"type": "RPC", "id": 1028, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"CONFIGEXCHANGE_FWrite": {"type": "RPC", "id": 1029, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"CONFIGEXCHANGE_FSeek": {"type": "RPC", "id": 1030, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"CONFIGEXCHANGE_FTell": {"type": "RPC", "id": 1031, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"CONFIGEXCHANGE_Remove": {"type": "RPC", "id": 1032, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"CONFIGEXCHANGE_FEOF": {"type": "RPC", "id": 1033, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"CONFIGEXCHANGE_Catalogue": {"type": "RPC", "id": 1034, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"CONFIGEXCHANGE_PCBSerialNumber": {"type": "string", "id": 1036, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RO", "lvl8": "RO"}},
"CONFIGEXCHANGE_ConfigAccessRights": {"type": "uint16_t", "id": 1037, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"CONFIGEXCHANGE_FFlush": {"type": "RPC", "id": 1038, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"CUSTOMER_AlarmStatus0": {"type": "uint32_t", "id": 2304, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RO", "lvl8": "RO"}},
"CUSTOMER_AlarmStatus1": {"type": "uint32_t", "id": 2305, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RO", "lvl8": "RO"}},
"CUSTOMER_TriggerAlarmCancel": {"type": "uint32_t", "id": 2306, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RW", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"CUSTOMER_AlarmStatus2": {"type": "uint32_t", "id": 2307, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RO", "lvl8": "RO"}},
"CUSTOMER_AlarmStatus3": {"type": "uint32_t", "id": 2308, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RO", "lvl8": "RO"}},
"CUSTOMER_AlarmStatus4": {"type": "uint32_t", "id": 2309, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RO", "lvl8": "RO"}},
"CUSTOMER_AlarmStatus5": {"type": "uint32_t", "id": 2310, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RO", "lvl8": "RO"}},
"CUSTOMER_AlarmStatus6": {"type": "uint32_t", "id": 2311, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RO", "lvl8": "RO"}},
"CUSTOMER_AlarmStatus7": {"type": "uint32_t", "id": 2312, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RO", "lvl8": "RO"}},
"CUSTOMER_AlarmEnableMask": {"type": "uint32_t", "id": 2313, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RW", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"CUSTOMER_AlarmBroadcastMask": {"type": "uint32_t", "id": 2314, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RW", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"CUSTOMER_AlarmVisualMask": {"type": "uint32_t", "id": 2315, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RW", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"CUSTOMER_AlarmVisualAutoClearMask": {"type": "uint32_t", "id": 2316, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RW", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"CUSTOMER_ExcessFlowVolumeThreshold": {"type": "uint32_t", "id": 2317, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RW", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"CUSTOMER_LeakTimeThreshold": {"type": "uint32_t", "id": 2318, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RW", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"CUSTOMER_ReverseFlowTimeThreshold": {"type": "uint16_t", "id": 2319, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RW", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"CUSTOMER_Locale": {"type": "uint16_t", "id": 2322, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"CUSTOMER_AppArrangement": {"type": "enum8", "id": 2323, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RO", "lvl8": "RO"}},
"CUSTOMER_RebootCount": {"type": "uint32_t", "id": 2324, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"CUSTOMER_ExcessFlowTimeThreshold": {"type": "uint32_t", "id": 2325, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RW", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"CUSTOMER_LeakFlowThreshold": {"type": "uint32_t", "id": 2326, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RW", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"CUSTOMER_MfgCharge": {"type": "uint32_t", "id": 2327, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RO", "lvl8": "RO"}},
"CUSTOMER_TemperatureHighThreshold": {"type": "int32_t", "id": 2328, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RW", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"CUSTOMER_TemperatureHighDelay": {"type": "uint32_t", "id": 2329, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RW", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"CUSTOMER_TemperatureLowThreshold": {"type": "int32_t", "id": 2330, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RW", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"CUSTOMER_TemperatureLowDelay": {"type": "uint32_t", "id": 2331, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RW", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"CUSTOMER_PressureHighThreshold": {"type": "int32_t", "id": 2332, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RW", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"CUSTOMER_PressureHighDelay": {"type": "uint32_t", "id": 2333, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RW", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"CUSTOMER_PressureLowThreshold": {"type": "int32_t", "id": 2334, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RW", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"CUSTOMER_PressureLowDelay": {"type": "uint32_t", "id": 2335, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RW", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"CUSTOMER_StoreConfiguration": {"type": "uint32_t", "id": 2336, "privilege": {"lvl1": "NA", "lvl2": "NA", "lvl3": "RW", "lvl4": "NA", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"CUSTOMER_SerialNumber": {"type": "string", "id": 2337, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RW", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"CUSTOMER_BackupCalendarSeconds": {"type": "time_t", "id": 2338, "privilege": {"lvl1": "NA", "lvl2": "NA", "lvl3": "NA", "lvl4": "NA", "lvl5": "NA", "lvl6": "NA", "lvl7": "NA", "lvl8": "NA"}},
"CUSTOMER_InstallationTime": {"type": "time_t", "id": 2339, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"CUSTOMER_LocaleDecimalPoint": {"type": "string", "id": 2340, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RO", "lvl8": "RO"}},
"CUSTOMER_LocaleThousandsSeparator": {"type": "string", "id": 2341, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RO", "lvl8": "RO"}},
"CUSTOMER_InternalLoginTest": {"type": "uint32_t", "id": 2342, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"CUSTOMER_NoFlowLimit": {"type": "uint32_t", "id": 2343, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RW", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"CUSTOMER_NoFlowAlarmResetHysteresis": {"type": "uint32_t", "id": 2344, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RW", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"FLEXNETSERIAL_UpgState": {"type": "uint32_t", "id": 6656, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"FLEXNETSERIAL_FwdlState": {"type": "uint32_t", "id": 6657, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"FUNCTEST_GP30Test": {"type": "uint32_t", "id": 2560, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"FUNCTEST_LCDTest": {"type": "uint32_t", "id": 2561, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"FUNCTEST_Iloop": {"type": "uint32_t", "id": 2562, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"FUNCTEST_Pulse": {"type": "uint32_t", "id": 2563, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"FUNCTEST_Pressure": {"type": "uint32_t", "id": 2564, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"FUNCTEST_BatteryVoltage": {"type": "uint32_t", "id": 2565, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RO", "lvl8": "RO"}},
"FUNCTEST_SupplyVoltage": {"type": "uint32_t", "id": 2566, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RO", "lvl8": "RO"}},
"FUNCTEST_Temperature": {"type": "int16_t", "id": 2567, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RO", "lvl8": "RO"}},
"FUNCTEST_RFID": {"type": "uint32_t", "id": 2568, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"FUNCTEST_OpticalOutput": {"type": "uint32_t", "id": 2569, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"FUNCTEST_Radio": {"type": "uint32_t", "id": 2570, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"FUNCTEST_MultiTest": {"type": "uint16_t", "id": 2571, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"FUNCTEST_NFCUID": {"type": "uint64_t", "id": 2572, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"FUNCTEST_CPUTest": {"type": "uint32_t", "id": 2573, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_SampleRate": {"type": "uint8_t", "id": 3840, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_FirstHitLvlUp1": {"type": "int8_t", "id": 3841, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_FirstHitLvlUp2": {"type": "int8_t", "id": 3842, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_FirstHitLvlUp3": {"type": "int8_t", "id": 3843, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_FirstHitLvlDown1": {"type": "int8_t", "id": 3844, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_FirstHitLvlDown2": {"type": "int8_t", "id": 3845, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_FirstHitLvlDown3": {"type": "int8_t", "id": 3846, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_StartHit": {"type": "uint8_t", "id": 3847, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_AmplitudePeakDetectEnd": {"type": "uint8_t", "id": 3848, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_NumFirePulses": {"type": "uint8_t", "id": 3849, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_DisplayPow10": {"type": "int8_t", "id": 3850, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RW", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_DisplayUnits": {"type": "enum8", "id": 3851, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RW", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_MeterSize": {"type": "enum8", "id": 3852, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_CalFactor1": {"type": "uint16_t", "id": 3853, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_CalFactor2": {"type": "uint16_t", "id": 3854, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_CalFactor3": {"type": "uint16_t", "id": 3855, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_ZeroOffset1": {"type": "int32_t", "id": 3856, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_ZeroOffset2": {"type": "int32_t", "id": 3857, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_ZeroOffset3": {"type": "int32_t", "id": 3858, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_ScaledBilling": {"type": "int64_t", "id": 3859, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RO", "lvl8": "RO"}},
"GENESISFLOW_ResetAccumulators": {"type": "bool_t", "id": 3860, "privilege": {"lvl1": "NA", "lvl2": "NA", "lvl3": "NA", "lvl4": "NA", "lvl5": "NA", "lvl6": "NA", "lvl7": "WO", "lvl8": "WO"}},
"GENESISFLOW_ForwardArrow": {"type": "enum8", "id": 3861, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_LedMode": {"type": "enum8", "id": 3862, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_StoreCalibration": {"type": "uint32_t", "id": 3863, "privilege": {"lvl1": "NA", "lvl2": "NA", "lvl3": "NA", "lvl4": "NA", "lvl5": "NA", "lvl6": "NA", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_UnscaledFwd": {"type": "uint64_t", "id": 3864, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_UnscaledRev": {"type": "uint64_t", "id": 3865, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_LowFlowThreshold": {"type": "uint32_t", "id": 3866, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_LowFlowMaxPeriod": {"type": "uint32_t", "id": 3867, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_UpdateThreshold": {"type": "uint32_t", "id": 3868, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_ArrowThreshold": {"type": "uint32_t", "id": 3869, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_FireBuffer1": {"type": "uint8_t", "id": 3870, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_FireBuffer2": {"type": "uint8_t", "id": 3871, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_FireBuffer3": {"type": "uint8_t", "id": 3872, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_TriggerActive": {"type": "bool_t", "id": 3873, "privilege": {"lvl1": "NA", "lvl2": "NA", "lvl3": "RW", "lvl4": "NA", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_TriggerIdle": {"type": "uint16_t", "id": 3874, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_MaxValidDeltaToF": {"type": "uint32_t", "id": 3875, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_MaxValidToF": {"type": "uint32_t", "id": 3876, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_MinValidToF": {"type": "uint32_t", "id": 3877, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_FirstHitPercent1": {"type": "uint8_t", "id": 3878, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_FirstHitPercent2": {"type": "uint8_t", "id": 3879, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_FirstHitPercent3": {"type": "uint8_t", "id": 3880, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_FirstHitShift": {"type": "uint8_t", "id": 3881, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_FirstHitMinimum": {"type": "uint8_t", "id": 3882, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_ToFErrorLimit": {"type": "uint32_t", "id": 3883, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_FirstHitUpdatePeriod": {"type": "uint8_t", "id": 3884, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_PipeFillingDelay": {"type": "uint8_t", "id": 3885, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_ToFTempOffset1": {"type": "int32_t", "id": 3886, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_ToFTempOffset2": {"type": "int32_t", "id": 3887, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_ToFTempOffset3": {"type": "int32_t", "id": 3888, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_ToFTempCalibrate": {"type": "int32_t", "id": 3889, "privilege": {"lvl1": "NA", "lvl2": "NA", "lvl3": "NA", "lvl4": "NA", "lvl5": "NA", "lvl6": "NA", "lvl7": "WO", "lvl8": "WO"}},
"GENESISFLOW_StoreConfiguration": {"type": "uint32_t", "id": 3890, "privilege": {"lvl1": "NA", "lvl2": "NA", "lvl3": "RW", "lvl4": "NA", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_SealDisplay": {"type": "bool_t", "id": 3891, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_TriggerTest": {"type": "bool_t", "id": 3892, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RW", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_MaxValidAmplitude": {"type": "uint32_t", "id": 3893, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_MinValidAmplitude": {"type": "uint32_t", "id": 3894, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_HardErrorLimit": {"type": "uint16_t", "id": 3895, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_Timeout": {"type": "uint8_t", "id": 3896, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_MaxDeltaToFDeviation": {"type": "uint32_t", "id": 3897, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_MaxTempRange": {"type": "uint32_t", "id": 3898, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_MaxDeltaToFRange": {"type": "uint32_t", "id": 3899, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_LookupFileCrc": {"type": "uint32_t", "id": 3900, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_DisplayLeadingZeros": {"type": "bool_t", "id": 3901, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_InstallationCorrectionEnabled": {"type": "bool_t", "id": 3902, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_InstallationDetectionThreshold": {"type": "uint32_t", "id": 3903, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_InstallationType": {"type": "uint32_t", "id": 3904, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_InstallationDetectionStatus": {"type": "uint8_t", "id": 3905, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_FractionalBars": {"type": "bool_t", "id": 3906, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RW", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"GENESISFLOW_CalibrationCount": {"type": "uint8_t", "id": 3907, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RO", "lvl8": "RO"}},
"GENESISFLOW_DelayedLedOff": {"type": "uint16_t", "id": 3908, "privilege": {"lvl1": "NA", "lvl2": "NA", "lvl3": "NA", "lvl4": "NA", "lvl5": "WO", "lvl6": "WO", "lvl7": "WO", "lvl8": "WO"}},
"GENESISFLOW_DisplayVolumeRow2": {"type": "bool_t", "id": 3909, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RW", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"IRDA_PulseReportRate": {"type": "enum8", "id": 5120, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"IRDA_AdapterPresenceLimit": {"type": "uint8_t", "id": 5121, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"IRDA_PulseSequence": {"type": "uint8_t", "id": 5122, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"IRDA_StoreConfiguration": {"type": "uint32_t", "id": 5123, "privilege": {"lvl1": "NA", "lvl2": "NA", "lvl3": "NA", "lvl4": "NA", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"IRDA_AMRDigits": {"type": "uint8_t", "id": 5124, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"IRDA_AMROffset": {"type": "int8_t", "id": 5125, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"IRDA_UI1203Fields": {"type": "uint16_t", "id": 5126, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"IRDA_MfgDate": {"type": "time_t", "id": 5127, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"IRDA_DisplayAMRDigits": {"type": "bool_t", "id": 5128, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"IRDA_AdapterID": {"type": "string", "id": 5129, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RO", "lvl8": "RO"}},
"IRDA_AdapterFwVersion": {"type": "uint16_t", "id": 5130, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RO", "lvl8": "RO"}},
"IRDA_ExtendedResolution": {"type": "bool_t", "id": 5131, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"LOGGER_Quota": {"type": "uint32_t", "id": 2048, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"LOGGER_Drive": {"type": "uint8_t", "id": 2049, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"LOGGER_TriggerLogFlush": {"type": "bool_t", "id": 2050, "privilege": {"lvl1": "NA", "lvl2": "NA", "lvl3": "NA", "lvl4": "NA", "lvl5": "NA", "lvl6": "NA", "lvl7": "WO", "lvl8": "WO"}},
"LOGGER_StoreConfiguration": {"type": "uint32_t", "id": 2051, "privilege": {"lvl1": "NA", "lvl2": "NA", "lvl3": "NA", "lvl4": "NA", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"METROLOGYASST_ILoopMaxFlowRate": {"type": "uint32_t", "id": 4608, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RW", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"METROLOGYASST_StoreConfiguration": {"type": "uint32_t", "id": 4609, "privilege": {"lvl1": "NA", "lvl2": "NA", "lvl3": "RW", "lvl4": "NA", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"METROLOGYASST_PulseWeight": {"type": "uint32_t", "id": 4610, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RW", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"METROLOGYASST_PulseMode": {"type": "enum8", "id": 4611, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RW", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"METROLOGYASST_PulseLength": {"type": "enum8", "id": 4612, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RW", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"METROLOGYASST_FlowUnits": {"type": "enum8", "id": 4613, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RW", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"METROLOGYASST_FlowPoint": {"type": "enum8", "id": 4614, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RW", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"METROLOGYASST_ILoopRate": {"type": "uint32_t", "id": 4615, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RW", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"METROLOGYASST_TemperatureUnits": {"type": "enum8", "id": 4616, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RW", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"METROLOGYASST_PressureUnits": {"type": "enum8", "id": 4617, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RW", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"METROLOGYASST_PressureRate": {"type": "uint32_t", "id": 4618, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RW", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"METROLOGYASST_PressureOffset": {"type": "int32_t", "id": 4619, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RW", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"METROLOGYASST_PressurePresent": {"type": "bool_t", "id": 4620, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"METROLOGYASST_PressureMeasure": {"type": "int32_t", "id": 4621, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"METROLOGYASST_LatestFlowRate": {"type": "int32_t", "id": 4622, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"METROLOGYASST_GenerateFwdPulses": {"type": "uint8_t", "id": 4623, "privilege": {"lvl1": "NA", "lvl2": "NA", "lvl3": "NA", "lvl4": "NA", "lvl5": "NA", "lvl6": "NA", "lvl7": "WO", "lvl8": "WO"}},
"METROLOGYASST_GenerateRevPulses": {"type": "uint8_t", "id": 4624, "privilege": {"lvl1": "NA", "lvl2": "NA", "lvl3": "NA", "lvl4": "NA", "lvl5": "NA", "lvl6": "NA", "lvl7": "WO", "lvl8": "WO"}},
"METROLOGYASST_PulseEvenDistribution": {"type": "bool_t", "id": 4625, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RW", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"METROLOGYASST_PulseResolution": {"type": "uint8_t", "id": 4626, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RO", "lvl8": "RO"}},
"METROLOGYASST_PressureCalibration": {"type": "int32_t", "id": 4627, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RW", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"METROLOGYASST_DisplayEnable": {"type": "uint32_t", "id": 4628, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RW", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"METROLOGYASST_PressureFlowRateCorrectionA": {"type": "int32_t", "id": 4629, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"METROLOGYASST_PressureFlowRateCorrectionB": {"type": "int32_t", "id": 4630, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"NA2WALARMS_StoreConfiguration": {"type": "uint32_t", "id": 5888, "privilege": {"lvl1": "NA", "lvl2": "NA", "lvl3": "RW", "lvl4": "NA", "lvl5": "NA", "lvl6": "NA", "lvl7": "RW", "lvl8": "RW"}},
"NA2WALARMS_PredefEnable": {"type": "uint32_t", "id": 5889, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"NA2WLOGGER_StoreConfiguration": {"type": "uint32_t", "id": 5632, "privilege": {"lvl1": "NA", "lvl2": "NA", "lvl3": "RW", "lvl4": "NA", "lvl5": "NA", "lvl6": "NA", "lvl7": "RW", "lvl8": "RW"}},
"NA2WLOGGER_LimitLogSize": {"type": "uint32_t", "id": 5633, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"NFC_EraseRMA": {"type": "bool_t", "id": 5376, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RO", "lvl8": "RW"}},
"NFC_ForceUpdate": {"type": "uint8_t", "id": 5377, "privilege": {"lvl1": "NA", "lvl2": "NA", "lvl3": "NA", "lvl4": "NA", "lvl5": "NA", "lvl6": "NA", "lvl7": "WO", "lvl8": "WO"}},
"OPTICALPORT_BaudRateCapabilities": {"type": "uint32_t", "id": 1280, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RO", "lvl8": "RO"}},
"OPTICALPORT_PacketSizeCapabilities": {"type": "uint32_t", "id": 1281, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RO", "lvl8": "RO"}},
"OPTICALPORT_ProtocolVersion": {"type": "uint16_t", "id": 1282, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RO", "lvl8": "RO"}},
"OPTICALPORT_BaudRateSelected": {"type": "uint32_t", "id": 1283, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RO", "lvl8": "RO"}},
"OPTICALPORT_PacketSizeSelected": {"type": "uint32_t", "id": 1284, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RO", "lvl8": "RO"}},
"OPTICALPORT_ExternalUartControl": {"type": "uint8_t", "id": 1285, "privilege": {"lvl1": "WO", "lvl2": "WO", "lvl3": "WO", "lvl4": "WO", "lvl5": "WO", "lvl6": "WO", "lvl7": "WO", "lvl8": "WO"}},
"PERIODICLOG_DataLogContents": {"type": "uint32_t", "id": 4352, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"PERIODICLOG_DataLogPeriod": {"type": "uint16_t", "id": 4353, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"PERIODICLOG_AverageFlowPeriod": {"type": "uint16_t", "id": 4354, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"PERIODICLOG_FixedDateReadingContents": {"type": "uint32_t", "id": 4355, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"PERIODICLOG_FixedDateDayOfMonth": {"type": "uint8_t", "id": 4356, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"PERIODICLOG_PeriodicLogLifeTimeCounter": {"type": "uint32_t", "id": 4357, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"PERIODICLOG_ResetCounter": {"type": "uint32_t", "id": 4358, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"POWERMON_BatteryVoltage": {"type": "uint16_t", "id": 256, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RO", "lvl8": "RO"}},
"POWERMON_BatteryManufacturer": {"type": "string", "id": 257, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RO", "lvl8": "RO"}},
"POWERMON_BatterySize": {"type": "enum8", "id": 258, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RO", "lvl8": "RO"}},
"POWERMON_BatteryQuantity": {"type": "uint8_t", "id": 260, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"POWERMON_BatteryRatedVoltage": {"type": "uint8_t", "id": 261, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RO", "lvl8": "RO"}},
"POWERMON_BatteryVoltageMinThreshold": {"type": "uint8_t", "id": 263, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RO", "lvl8": "RO"}},
"POWERMON_BatterySelection": {"type": "uint8_t", "id": 264, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"POWERMON_TotalUsedCharge": {"type": "uint64_t", "id": 265, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"POWERMON_TotalUsedSeconds": {"type": "uint32_t", "id": 266, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"POWERMON_WarnFromClamp": {"type": "uint32_t", "id": 267, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"POWERMON_BatteryMilliAHrRating": {"type": "uint16_t", "id": 268, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RO", "lvl8": "RO"}},
"POWERMON_StoreConfiguration": {"type": "uint32_t", "id": 269, "privilege": {"lvl1": "NA", "lvl2": "NA", "lvl3": "NA", "lvl4": "NA", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"POWERMON_CriticalRepeatLimit": {"type": "uint8_t", "id": 270, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"POWERMON_RemainingSeconds": {"type": "uint32_t", "id": 271, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RO", "lvl8": "RO"}},
"SENSUSRADIO_TxInterval": {"type": "uint16_t", "id": 4096, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_OmTxInterval": {"type": "uint16_t", "id": 4097, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_LatInterval": {"type": "uint8_t", "id": 4098, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_WakeupInterval": {"type": "uint8_t", "id": 4099, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_MbusState": {"type": "uint8_t", "id": 4100, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_FrequencyIndicator": {"type": "uint16_t", "id": 4101, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_FrequencyOffset": {"type": "int16_t", "id": 4102, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_PowerLevel": {"type": "uint8_t", "id": 4103, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_SystemState": {"type": "uint8_t", "id": 4105, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_RadioAddress": {"type": "uint32_t", "id": 4106, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_UtcTimeOffset": {"type": "uint32_t", "id": 4107, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_SentBytesCounter": {"type": "uint16_t", "id": 4108, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_ReceivedBytesCounter": {"type": "uint16_t", "id": 4109, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_ResetCounter": {"type": "uint16_t", "id": 4110, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_BootLoaderState": {"type": "uint8_t", "id": 4111, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_LeakFlowThreshold": {"type": "uint16_t", "id": 4112, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_LeakFlowTimeThreshold": {"type": "uint16_t", "id": 4113, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_BrokenPipeFlowThreshold": {"type": "uint16_t", "id": 4114, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_BrokenPipeFlowTimeThreshold": {"type": "uint16_t", "id": 4115, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_PressureMaxThreshold": {"type": "uint8_t", "id": 4116, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_PressureMinThreshold": {"type": "uint8_t", "id": 4117, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_PressureLimitTimeMaxThreshold": {"type": "uint16_t", "id": 4118, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_PressureLimitTimeMinThreshold": {"type": "uint16_t", "id": 4119, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_PressureMeasurePeriod": {"type": "uint16_t", "id": 4120, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_PressureUnit": {"type": "uint8_t", "id": 4121, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_PressureGaugeOffset": {"type": "uint16_t", "id": 4122, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_TemperatureMaxThreshold": {"type": "uint8_t", "id": 4123, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_TemperatureMinThreshold": {"type": "uint8_t", "id": 4124, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_TemperatureTimeMaxThreshold": {"type": "uint16_t", "id": 4125, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_TemperatureTimeMinThreshold": {"type": "uint16_t", "id": 4126, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_TemperatureMeasurePeriod": {"type": "uint16_t", "id": 4127, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_TemperatureUnit": {"type": "uint8_t", "id": 4128, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_PulseOutWidth": {"type": "uint16_t", "id": 4129, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_PulseOutDivisor": {"type": "uint16_t", "id": 4130, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_PulseOutMode": {"type": "uint8_t", "id": 4131, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_CurrentLoopMax": {"type": "uint16_t", "id": 4132, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_CurrentLoopSource": {"type": "uint8_t", "id": 4133, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_MainAlarmMask": {"type": "uint8_t", "id": 4134, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_ExtendedAlarmMask": {"type": "uint8_t", "id": 4135, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_HistoricalAlarmsDays": {"type": "uint8_t", "id": 4136, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_TestModeTime": {"type": "uint16_t", "id": 4139, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_EncryptionKey": {"type": "uint32_t", "id": 4140, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_Authentification": {"type": "uint32_t", "id": 4141, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_UpgFWVersion": {"type": "uint16_t", "id": 4142, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_CustomerText": {"type": "uint32_t", "id": 4143, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_RadioLastReadTime": {"type": "uint32_t", "id": 4144, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_LowBatDateTime": {"type": "uint32_t", "id": 4145, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_VeryLowBatDateTime": {"type": "uint32_t", "id": 4146, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_Unit": {"type": "uint8_t", "id": 4147, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_ExtendedUnitFlags": {"type": "uint8_t", "id": 4148, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_OTAControlFlags": {"type": "uint8_t", "id": 4149, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_Tfx_Structure": {"type": "uint32_t", "id": 4150, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_Dewa_Structure": {"type": "uint32_t", "id": 4151, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_DataLogContents": {"type": "uint32_t", "id": 4152, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_DataLogPeriod": {"type": "uint16_t", "id": 4153, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_AverageFlowPeriod": {"type": "uint16_t", "id": 4154, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_FixedDateReadingContents": {"type": "uint32_t", "id": 4155, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_FixedDateDayOfMonth": {"type": "uint8_t", "id": 4156, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_MetroRadioLifeTimeCounter": {"type": "uint32_t", "id": 4157, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_PowerLevelOption": {"type": "uint8_t", "id": 4158, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_ImpedanceCodeNew": {"type": "uint16_t", "id": 4159, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_ImpedanceCodeOption": {"type": "uint16_t", "id": 4160, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_IrDAModulePresent": {"type": "bool_t", "id": 4161, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_StoreConfiguration": {"type": "bool_t", "id": 4162, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_LifeTimeSeconds": {"type": "uint32_t", "id": 4163, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_DutyCycleCredit": {"type": "uint32_t", "id": 4164, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_ActivityCredit": {"type": "uint32_t", "id": 4165, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_PersistenceGroup1": {"type": "uint32_t", "id": 4166, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_PersistenceGroup2": {"type": "uint32_t", "id": 4167, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_PersistenceGroup3": {"type": "uint32_t", "id": 4168, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_PersistenceGroup4": {"type": "uint32_t", "id": 4169, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_PressureCalibration": {"type": "uint32_t", "id": 4170, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_TfxSecondaryChannelInfo_1": {"type": "uint32_t", "id": 4171, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_TfxSecondaryChannelInfo_2": {"type": "uint32_t", "id": 4172, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_OmsLastMessageCounter": {"type": "uint32_t", "id": 4173, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_PersistenceGroup5": {"type": "uint32_t", "id": 4174, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SENSUSRADIO_PersistenceGroup6": {"type": "uint32_t", "id": 4175, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SYSTEM_TriggerUpgrade": {"type": "bool_t", "id": 0, "privilege": {"lvl1": "NA", "lvl2": "NA", "lvl3": "NA", "lvl4": "NA", "lvl5": "NA", "lvl6": "NA", "lvl7": "WO", "lvl8": "WO"}},
"SYSTEM_CheckPresence": {"type": "RPC", "id": 1, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SYSTEM_PCBSerialNumber": {"type": "string", "id": 2, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RO", "lvl8": "RO"}},
"SYSTEM_CustomerSerialNumber0": {"type": "string", "id": 3, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SYSTEM_CustomerSerialNumber1": {"type": "string", "id": 4, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SYSTEM_CustomerSerialNumber2": {"type": "string", "id": 5, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SYSTEM_CustomerSerialNumber3": {"type": "string", "id": 6, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SYSTEM_MonotonicSeconds": {"type": "uint32_t", "id": 7, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RO", "lvl8": "RO"}},
"SYSTEM_CalendarSeconds": {"type": "time_t", "id": 8, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SYSTEM_CoreRevision": {"type": "string", "id": 9, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RO", "lvl8": "RO"}},
"SYSTEM_DriveCapacity": {"type": "uint32_t", "id": 10, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SYSTEM_ExitReason": {"type": "status_t", "id": 11, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SYSTEM_CorePlatform": {"type": "uint16_t", "id": 12, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RO", "lvl8": "RO"}},
"SYSTEM_CRC": {"type": "uint16_t", "id": 13, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"SYSTEM_UpgradePermissions": {"type": "uint8_t", "id": 14, "privilege": {"lvl1": "RO", "lvl2": "RO", "lvl3": "RO", "lvl4": "RO", "lvl5": "RO", "lvl6": "RO", "lvl7": "RW", "lvl8": "RW"}},
"SYSTEM_CRC32": {"type": "uint32_t", "id": 15, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"TESTMANAGER_OutputFile": {"type": "string", "id": 25088, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"TESTMANAGER_TestNumber": {"type": "uint32_t", "id": 25089, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"TESTMANAGER_TestStatus": {"type": "enum8", "id": 25090, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"TESTMANAGER_TrapError": {"type": "uint32_t", "id": 25091, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"TESTMANAGER_TestParameter": {"type": "uint32_t", "id": 25092, "privilege": {"lvl1": "RW", "lvl2": "RW", "lvl3": "RW", "lvl4": "RW", "lvl5": "RW", "lvl6": "RW", "lvl7": "RW", "lvl8": "RW"}},
"_comment": "end of table"
}
@@ -15,7 +15,7 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.Interfa
/// <summary> /// <summary>
/// Request port settings /// Request port settings
/// </summary> /// </summary>
public PortConfig Request { get; set; } public PortConfig? Request { get; set; }
/// <summary> /// <summary>
/// Streaming port settings /// Streaming port settings
@@ -0,0 +1,68 @@
using System;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.ProcessExec.EventArguments
{
/// <summary>
/// Event message needed to inform the caller about the ongoing process
/// </summary>
[Serializable]
public class ProcessExecEventArgs : EventArgs
{
/// <summary>
/// Event message for overall process
/// </summary>
public String OverallProcessMessage { get; }
/// <summary>
/// Event message for single process
/// </summary>
public String ActualProcessMessage { get; }
/// <summary>
/// Overall process percentage 0..100
/// </summary>
public Double? OverallProcessPercent { get; }
/// <summary>
/// Single process percentage 0..100
/// </summary>
public Double? ActualProcessPercent { get; }
/// <summary>
/// Status of message
/// </summary>
public StatusReturn StatusReturn { get; }
/// <summary>
/// Object containing specific information
/// </summary>
public Object SpecificInfoObj { get; }
/// <summary>
/// Ctor
/// </summary>
/// <param name="overallProcessMessage">Message for overall process</param>
/// <param name="overallProcessPercent">Internal limited to 0..100 %</param>
/// <param name="actualProcessMessage">Message for actual subprocess</param>
/// <param name="actualProcessPercent">Internal limited to 0..100 %</param>
/// <param name="statusReturn">Status information</param>
/// <param name="specificInfoObj">Specific information as object</param>
/// <remarks date="2026-Jan-08" author="Thomas Wiedebusch">
/// - Object as specific information.
/// </remarks>
public ProcessExecEventArgs(String overallProcessMessage,
Double? overallProcessPercent = null, String actualProcessMessage = null,
Double? actualProcessPercent = null, StatusReturn statusReturn = StatusReturn.Unknown,
Object specificInfoObj = null)
{
OverallProcessMessage = overallProcessMessage;
ActualProcessMessage = actualProcessMessage;
OverallProcessPercent = overallProcessPercent > 100.0 ? 100.0 : overallProcessPercent;
OverallProcessPercent = OverallProcessPercent < 0 ? 0 : OverallProcessPercent;
ActualProcessPercent = actualProcessPercent > 100.0 ? 100.0 : actualProcessPercent;
ActualProcessPercent = ActualProcessPercent < 0 ? 0 : ActualProcessPercent;
StatusReturn = statusReturn;
SpecificInfoObj = specificInfoObj;
}
}
}
@@ -0,0 +1,20 @@
using System;
using TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.ProcessExec.EventArguments;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.ProcessExec
{
/// <summary>
/// Process state interface
/// </summary>
/// <remarks date="2020-Dec-09" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
public interface IProcessState
{
/// <summary>
/// Process update event
/// </summary>
event EventHandler<ProcessExecEventArgs> OnProcessUpdate;
}
}
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.nlog-project.org/schemas/NLog.xsd NLog.xsd"
autoReload="true"
throwExceptions="false"
internalLogLevel="Off" internalLogFile="c:\temp\nlog-internal.log">
<!-- optional, add some variables
https://github.com/nlog/NLog/wiki/Configuration-file#variables
-->
<variable name="myvar" value="myvalue"/>
<!--
See https://github.com/nlog/nlog/wiki/Configuration-file
for information on customizing logging rules and outputs.
-->
<targets>
<!--
add your targets here
See https://github.com/nlog/NLog/wiki/Targets for possible targets.
See https://github.com/nlog/NLog/wiki/Layout-Renderers for the possible layout renderers.
-->
<!--
Write events to a file with the date in the filename.
<target xsi:type="File" name="f" fileName="${basedir}/logs/${shortdate}.log"
layout="${longdate} ${uppercase:${level}} ${message}" />
-->
</targets>
<rules>
<!-- add your logging rules here -->
<!--
Write all events with minimal level of Debug (So Debug, Info, Warn, Error and Fatal, but not Trace) to "f"
<logger name="*" minlevel="Debug" writeTo="f" />
-->
</rules>
</nlog>
@@ -0,0 +1,101 @@
using System;
using System.Globalization;
using System.Threading;
using System.Threading.Tasks;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.ProcessExec
{
/// <summary>
/// Execution of process in separate task.
/// Task execution uses an initialization-, an execution-, an event-
/// and a finalization-routine.
/// Process states are given to successful-, erroneous-ore break-execution as an array of objects to keep it
/// anonymous.
/// </summary>
[Serializable]
public class ProcessExec
{
/// <summary>
/// Definition of void thread call back function
/// </summary>
public delegate void VoidCallbackFunction();
/// <summary>
/// Definition of boolean thread call back function
/// </summary>
public delegate StatusReturn StatusReturnCallbackFunction();
/// <summary>
/// Definition of thread call back function
/// </summary>
/// <param name="success">execution of routine returned success</param>
/// <param name="obj">objects to callback function</param>
public delegate void ExitStateCallbackFunction(StatusReturn success, Object[] obj);
/// <summary>
/// Definition of thread call back function
/// </summary>
private Object[] _exitObjects;
/// <summary>
/// Current task calling the init-, the cyclic execution and the final-function.
/// The task adjusts the current culture.
/// </summary>
/// <param name="initFn">initial function executed in caller task</param>
/// <param name="preExecFn"></param>
/// <param name="execFn">execution function executed in separated new task</param>
/// <param name="finalFn">finalizing function</param>
/// <param name="cultureInfo">language selection passing</param>
/// <param name="exitObjects">exit objects</param>
/// <param name="cancellationToken"></param>
/// <remarks date="2020-Dec-12" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
/// <remarks date="2024-Nov-08" author="Thomas Wiedebusch">
/// - Function for pre-execution before the main execution starts being executed in the new
/// thread.
/// </remarks>
/// <remarks date="2025-Apr-06" author="Thomas Wiedebusch">
/// - CancellationToken.
/// </remarks>
/// <remarks date="2025-Jun-05" author="Thomas Wiedebusch">
/// - Set StatusReturn.Okay if preExecFn is null,
/// - Quick return on cancellation request.
/// </remarks>
public void NewProcess(VoidCallbackFunction initFn, StatusReturnCallbackFunction preExecFn,
StatusReturnCallbackFunction execFn, ExitStateCallbackFunction finalFn,
CultureInfo cultureInfo, Object[] exitObjects, CancellationToken cancellationToken)
{
// return immediately if meanwhile a cancellation was requested
if (cancellationToken.IsCancellationRequested)
return;
_exitObjects = new Object[exitObjects.Length];
_exitObjects = exitObjects;
var success = StatusReturn.Failed;
Thread.CurrentThread.CurrentUICulture = cultureInfo;
Thread.CurrentThread.CurrentCulture = cultureInfo;
initFn?.Invoke();
Task.Factory.StartNew(() =>
{
Thread.CurrentThread.CurrentUICulture = cultureInfo;
Thread.CurrentThread.CurrentCulture = cultureInfo;
if (preExecFn == null)
success = StatusReturn.Okay;
else if (!cancellationToken.IsCancellationRequested)
success = (StatusReturn)preExecFn.DynamicInvoke();
if (execFn == null || success != StatusReturn.Okay || cancellationToken.IsCancellationRequested)
return;
success = (StatusReturn)execFn.DynamicInvoke();
}, cancellationToken)
.ContinueWith(delegate { finalFn?.Invoke(success, _exitObjects); },
TaskContinuationOptions.NotOnCanceled);
}
}
}
@@ -0,0 +1,59 @@
using System;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis
{
/// <summary>
/// Source for final properties of Cordonel
/// </summary>
public enum ProgrammingSource
{
Vako,
Csd,
Order,
ProgramInternal
}
/// <summary>
/// Values for single registers
/// </summary>
public class ProgrammingParameters
{
/// <summary>
/// Single register setup value assignment
/// </summary>
/// <param name="registerName"></param>
/// <param name="registerValue"></param>
/// <param name="programmingSource"></param>
public ProgrammingParameters(String registerName, Byte[] registerValue,
ProgrammingSource programmingSource = ProgrammingSource.Vako)
{
RegisterName = registerName;
RegisterValue = registerValue;
Source = programmingSource;
}
/// <summary>
/// The register name
/// </summary>
public String RegisterName { get; }
/// <summary>
/// The register value converted to raw bytes by register converter
/// </summary>
public Byte[] RegisterValue { get; }
/// <summary>
/// The data source either VAKO, CSD or order based with priorities:
/// - lowest: VAKO
/// - middle: CSD
/// - highest: Order
///
/// ATTENTION: DO NOT REMOVE setter as the Json.Serialize will NOT operate and always set the
/// default (ProgrammingSource.Vako) causing malfunction!!!!!
///
/// </summary>
// ReSharper disable once AutoPropertyCanBeMadeGetOnly.Global
// ATTENTION: DO NOT REMOVE (see comment in description)
public ProgrammingSource Source { get; set; }
}
}
@@ -4,6 +4,7 @@ using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Xylem.Common.Hardware.WaterMeter.WaterMeterRegisters; using Xylem.Common.Hardware.WaterMeter.WaterMeterRegisters;
using IRegister = TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.WaterMeterRegisters.IRegister;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.Registers namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.Registers
{ {
@@ -2,6 +2,7 @@
using TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.Registers.DataTypes; using TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.Registers.DataTypes;
using TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.Registers.Json; using TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.Registers.Json;
using Xylem.Common.Hardware.WaterMeter.WaterMeterRegisters; using Xylem.Common.Hardware.WaterMeter.WaterMeterRegisters;
using IRegister = TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.WaterMeterRegisters.IRegister;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.Registers namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.Registers
{ {
@@ -0,0 +1,93 @@
using System;
using System.IO;
using System.Net;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis
{
public static class RelatePcb
{
public static String GetPcbId(String baseUrl, String serialNumber)
{
var ret = string.Empty;
var url = $"{baseUrl}GetPcbId?SerialNumber={serialNumber}";
var http = (HttpWebRequest)WebRequest.Create(url);
var response = (HttpWebResponse)http.GetResponse();
if (response.StatusCode == HttpStatusCode.OK)
{
var responseStream = response.GetResponseStream();
if (responseStream == null)
{
throw new InvalidOperationException();
}
using (var sr = new StreamReader(responseStream))
{
var responseJson = sr.ReadToEnd();
ret = responseJson.Trim('"');
return ret;
}
}
else
{
return ret;
}
}
public static Int32 GetSerialNumber(String baseUrl, String pcbId)
{
var ret = -1;
if (string.IsNullOrEmpty(pcbId))
{
return ret;
}
var url = $"{baseUrl}GetSerialNumber?PcbId={pcbId}";
var http = (HttpWebRequest)WebRequest.Create(url);
var response = (HttpWebResponse)http.GetResponse();
if (response.StatusCode == HttpStatusCode.OK)
{
var responseStream = response.GetResponseStream();
if (responseStream == null)
{
throw new InvalidOperationException();
}
using (var sr = new StreamReader(responseStream))
{
var responseJson = sr.ReadToEnd();
int.TryParse(responseJson.Trim('"'), out ret);
return ret;
}
}
else
{
return ret;
}
}
public static Boolean MarriagePcbIdWIthSerialNumber(String baseUrl, String pcbId, String serialNumber)
{
var url = $"{baseUrl}SetPcbToSerial?PcbId={pcbId}&SerialNumber={serialNumber}";
var http = (HttpWebRequest)WebRequest.Create(url);
var response = (HttpWebResponse)http.GetResponse();
if (response.StatusCode == HttpStatusCode.OK)
{
return true;
}
else
{
var responseStream = response.GetResponseStream();
if (responseStream == null)
{
throw new InvalidOperationException();
}
using (var sr = new StreamReader(responseStream))
{
sr.ReadToEnd();
return false;
}
}
}
}
}
@@ -0,0 +1,878 @@
using System;
using System.Configuration;
namespace Xylem.Common.CommonCore.Configuration
{
/// <summary>
/// Urls for data base accesses
/// </summary>
public static class ServiceUrls
{
//#if URI_OLD_DNS // this is defined in build configuration 'VPN_Debug' as the new DNS cannot be reached via VPN
// private const String ServerDns = "http://sla12iis01.emea.sensus.net";
// private const String ProductionUiServerDns = "http://sla12iis01.emea.sensus.net";
//#else
private const String ServerDns = "http://delaz1web01.world.fluidtechnology.net";
private const String ProductionUiServerDns = "http://delaz1web01.world.fluidtechnology.net/LaaProductionWeb";
//#endif
private static readonly String DefaultInspectCordonelRequirementInfoUrl =
$"{ProductionUiServerDns}/";
// return code: 404 not found, 400 Error with text, 200 okay
private static readonly String DefaultEolDataForSentinelServiceUrl =
$"{ProductionUiServerDns}/api/cordonel/eolprogress/";
private static readonly String DefaultGetPcbIdsFromSafeServiceUrl =
$"{ServerDns}/MeterProcessState/GetPcbIdsFromSafe?ContainerDbId=";
private static readonly String DefaultGetExportDataServiceUrl =
$"{ServerDns}/MeterProcessState/api/Password/GetExportData?PcbId=";
private static readonly String DefaultGetCordonelMappingServiceUrl =
$"{ServerDns}/MeterProcessState/api/Order/GetCordonelMapping?PcbId=";
private static readonly String DefaultAddPcbIdsToSafeServiceUrl =
$"{ServerDns}/MeterProcessState/AddPcbIdsToSafe?ContainerDbId=";
private static readonly String DefaultGetOrderOverviewServiceUrl =
$"{ServerDns}/MeterProcessState/api/FinalCheck/GetOrderOverview?ProductionOrderNumber=";
private static readonly String DefaultGetOrderDetailsServiceUrl =
$"{ServerDns}/MeterProcessState/api/FinalCheck/GetOrderDetails?ProductionOrderNumber=";
private static readonly String DefaultDownloadFilesPartsServiceUrl =
$"{ServerDns}/MeterProcessState/api/FileUpToDate/GetFileParts?ParentFileId=";
private static readonly String DefaultGetLutUrl =
$"{ServerDns}/MeterProcessState/api/FileUpToDate/GetLutFiles";
private static readonly String DefaultListAllFwPackagesServiceUrl =
$"{ServerDns}/MeterProcessState/api/FileUpToDate/GetFwFiles?FileIsForDeveloperOnly=false&FileCategoryID=1";
private static readonly String DefaultListAllSwPackagesServiceUrl =
$"{ServerDns}/MeterProcessState/api/FileUpToDate/GetFwFiles?FileIsForDeveloperOnly=false&FileCategoryID=5";
private static readonly String DefaultListAllConfigFilePackagesServiceUrl =
$"{ServerDns}/MeterProcessState/api/FileUpToDate/GetFwFiles?FileIsForDeveloperOnly=false&FileCategoryID=6";
private static readonly String DefaultListAllFwUpdateSafesServiceUrl =
$"{ServerDns}/MeterProcessState/api/FileUpToDate/GetFwFiles?FileIsForDeveloperOnly=false&FileCategoryID=4";
private static readonly String DefaultSetCordonelAppVersionServiceUrl =
$"{ServerDns}/MeterProcessState/api/ProccesState/SetCordonelProgress?PcbId=";
private static readonly String DefaultGetCordonelRequirementInfoUrl =
$"{ProductionUiServerDns}/api/cordonel/requirements/pcbid/";
private static readonly String DefaultGetCordonelAppVersionServiceUrl =
$"{ServerDns}/MeterProcessState/api/ProccesState/GetCordonelAppVersion?PcbId=";
private static readonly String DefaultListAllCordonelCustomersWithFilterServiceUrl =
$"{ServerDns}/MeterProcessState/api/Order/GetCordonelCustomers?FilterName=";
private static readonly String DefaultListAllCordonelCustomerOrdersServiceUrl =
$"{ServerDns}/MeterProcessState/api/Order/GetCustomersCordonelOrders?CustomerNumber=";
private static readonly String DefaultListCordonelOrderDetailsServiceUrl =
$"{ServerDns}/MeterProcessState/api/Order/GetCordonelOrderDetails?OrderNr=";
private static readonly String DefaultListAllOrderCordonelsServiceUrl =
$"{ServerDns}/MeterProcessState/api/Order/GetCordonelOrderList?CustomerOrderNumber=";
private static readonly String DefaultDownloadFwUpdateSafeServiceUrl =
$"{ServerDns}/MeterProcessState/GetFWUpdateSafeContainerContent?SafeContainerId=";
private static readonly String DefaultListAllFwUpdateSafesForUserServiceUrl =
$"{ServerDns}/MeterProcessState/GetFWUpdateSafeContainers?UserId=";
private static readonly String DefaultFileContentDownloadServiceUrl =
$"{ServerDns}/MeterProcessState/GetFileContent?FileId=";
private static readonly String DefaultFwUpdateReportUploadServiceUrl =
$"{ServerDns}/MeterProcessState/PostFWUpdateReportFile";
private static readonly String DefaultFwUpdateReportDownloadServiceUrl =
$"{ServerDns}/MeterProcessState/GetFWUpdateReportFile?";
private static readonly String DefaultFwUpdateSafeContainerUploadServiceUrl =
$"{ServerDns}/MeterProcessState/PostFWUpdateSafeOdd";
private static readonly String DefaultEditFwUpdateUserValidityServiceUrl =
$"{ServerDns}/MeterProcessState/EditUserValidity?Id=";
private static readonly String DefaultRefreshFwUpdateUsersHardwareIdServiceUrl =
$"{ServerDns}/MeterProcessState/RefreshUsersHardwareId?Id=";
private static readonly String DefaultRefreshFwUpdateUsersPasswordHashServiceUrl =
$"{ServerDns}/MeterProcessState/RefreshUsersPasswordHash?Id=";
private static readonly String DefaultCreateNewFwUpdateUserServiceUrl =
$"{ServerDns}/MeterProcessState/AddNewUser?";
private static readonly String DefaultListAllFwUpdateUsersServiceUrl =
$"{ServerDns}/MeterProcessState/GetUserList";
private static readonly String DefaultListAllFwUpdateBuilderOperatorsServiceUrl =
$"{ServerDns}/MeterProcessState/GetAllBuilderOperator";
private static readonly String DefaultGetFwUpdateUserByIdServiceUrl =
$"{ServerDns}/MeterProcessState/GetUserList?Id=";
private static readonly String DefaultGetFwUpdateUserByLoginNameServiceUrl =
$"{ServerDns}/MeterProcessState/GetUserList?LogInName=";
private static readonly String DefaultRegisterWatchServiceUrl =
$"{ServerDns}/MeterProcessState/api/RegisterWatch/";
private static readonly String DefaultGenesisGetOrderNumberServiceUrl =
$"{ServerDns}/MeterProcessState/api/Password/ordernumber?PcbId=";
private static readonly String DefaultGenesisGetRadioAddressServiceUrl =
$"{ServerDns}/MeterProcessState/api/Password/radioadress?PcbId=";
private static readonly String DefaultGenesisGetKeySetIdServiceUrl =
$"{ServerDns}/MeterProcessState/api/Password/getkeysetid?PcbId=";
private static readonly String DefaultGenesisSetPickingStateServiceUrl =
$"{ServerDns}/MeterProcessState/api/ProccesState/SetPickingState?PcbID=";
private static readonly String DefaultGenesisGetPasswordServiceUrl =
$"{ServerDns}/MeterProcessState/api/Password/GetPassword?PcbId=";
private static readonly String DefaultGenesisSetPasswordServiceUrl =
$"{ServerDns}/MeterProcessState/api/Password/setpassword?PcbId=";
private static readonly String DefaultGenesisPasswordContainerServiceUrl =
$"{ServerDns}/MeterProcessState/api/Password/GetPasswordHashFileContent?PcbId=";
private static readonly String DefaultMarriageServiceUrl =
$"{ServerDns}/MeterProcessState/api/Marriage/";
private static readonly String DefaultMeterProcessStateUrl =
$"{ServerDns}/MeterProcessState/api/ProccesState/";
private static readonly String DefaultGenesisFinalCheckServiceUrl =
$"{ServerDns}/MeterProcessState/api/FinalCheck/";
private static readonly String DefaultGenesisRadioCheckServiceUrl =
$"{ServerDns}/MeterProcessState/api/RadioCheck/";
private static readonly String DefaultGetSoftwareStartUpAccessUrl =
$"{ServerDns}/MeterProcessState/api/SoftwareAccess/GetVersionIsValid";
private static readonly String DefaultSetSoftwareLicenseUrl =
$"{ServerDns}/MeterProcessState/api/SoftwareAccess/SetVersionIsValid?Program=";
private static readonly String DefaultGetSoftwareLicenseUrl =
$"{ServerDns}/MeterProcessState/api/SoftwareAccess/GetCurrentVersion?Program=";
private static readonly String DefaultGenesisCalibrationResult =
$"{ServerDns}/MeterProcessState/api/GenesisMeter/PostCalibrationResult";
private static readonly String DefaultGetGenesisCalibrationResults =
$"{ServerDns}/MeterProcessState/api/FinalCheck/CalibrationResults/";
private static readonly String DefaultGenesisMeter =
$"{ServerDns}/MeterProcessState/api/GenesisMeter/";
private static readonly String DefaultFileContentController =
$"{ServerDns}/MeterProcessState/api/FileUpToDate/";
private static readonly String DefaultKeyServerCustom =
"https://nodes.sms-esaap.com/keygenproxy/api/v3/custom/";
private static readonly String DefaultMeterInfoForTestBench =
$"{ServerDns}/MeterProcessState/api/TestBench/GetMeterInfoForTestBench?PcbID=";
private static readonly String DefaultCordonelFwInfoUrl =
$"{ServerDns}/MeterProcessState/api/FileUpToDate/GetCordonelFw";
private static readonly String DefaultDbDataAtEolServiceUrl =
$"{ServerDns}/MeterProcessState/api/fwupdate/databaseateol/";
public static readonly String PressureSensorTestURL_GetTestSpec
= $"{ServerDns}/MeterProcessState/api/CordonelPressureSensorTest/GetTestSpec";
public static readonly String PressureSensorTestURL_PostTestResults
= $"{ServerDns}/MeterProcessState/api/CordonelPressureSensorTest/PostTestResults";
public static readonly String PickingURL_GetPcbInfoPicking
= $"{ServerDns}/MeterProcessState/api/LuController/GetPcbInfoPicking?PcbId=";
/// <summary>
/// usage: string.Format(CordonelPressureSensorTestURL_GetTestResults, pcbId);
/// </summary>
public static readonly String PressureSensorTestURL_GetTestResults
= $"{ServerDns}/MeterProcessState/api/CordonelPressureSensorTest/GetTestResults/{0}";
public const String LaaProductionAPI
#if DEBUG == false // when false uses always the production url.
= "http://localhost:52822";
#else
= "http://delaz1web01.world.fluidtechnology.net/";
#endif
/// <summary>
/// GET: test specification for water meter with pressure sensor.
/// </summary>
public static String GetPressureSensorSpecificationURL
#if DEBUG
=> "http://localhost:56011/api/CordonelPressureSensorTest/GetTestSpec";
#else
=> ConfigurationManager.AppSettings[nameof(GetPressureSensorSpecificationURL)]
?? PressureSensorTestURL_GetTestSpec;
#endif
/// <summary>
/// POST: test result for water meter with pressure sensor.
/// </summary>
public static String PostPressureSensorResultURL
#if DEBUG
=> "http://localhost:56011/api/CordonelPressureSensorTest/PostTestResults";
public static String Q3CalibrationResultURL { get; set; }
#else
=> ConfigurationManager.AppSettings[nameof(PostPressureSensorResultURL)]
?? PressureSensorTestURL_PostTestResults;
#endif
/// <summary>
/// GET: a list of test results for the water meter with specified pcbId.
/// </summary>
public static String PressureSensorResultsURL<T>(this T pcbId)
{
#if DEBUG
var url = "http://localhost:56011/api/CordonelPressureSensorTest/GetTestResults/{0}";
#else
var url = ConfigurationManager.AppSettings[nameof(PressureSensorResultsURL)] ?? PressureSensorTestURL_GetTestResults;
#endif
return string.Format(url, pcbId);
}
/// <summary>
/// Get export data
/// </summary>
/// <returns></returns>
public static String GetExportDataServiceUrl()
{
return ConfigurationManager.AppSettings["GetExportDataServiceUrl"] ??
DefaultGetExportDataServiceUrl;
}
/// <summary>
/// Get Cordonel mapping
/// </summary>
/// <returns></returns>
public static String GetCordonelMappingServiceUrl()
{
return ConfigurationManager.AppSettings["GetCordonelMappingServiceUrl"] ??
DefaultGetCordonelMappingServiceUrl;
}
/// <summary>
/// Get Cordonel order overview to check the assignment state
/// </summary>
/// <returns></returns>
public static String GetOrderOverviewServiceUrl()
{
return ConfigurationManager.AppSettings["GetOrderOverviewServiceUrl"] ??
DefaultGetOrderOverviewServiceUrl;
}
/// <summary>
/// Get Cordonel order details to check for order dependent requirements like
/// - MeterSize,
/// - FrequencyIndicator,
/// - PressurePresent.
/// </summary>
/// <returns></returns>
public static String GetOrderDetailsServiceUrl()
{
return ConfigurationManager.AppSettings["GetOrderDetailsServiceUrl"] ??
DefaultGetOrderDetailsServiceUrl;
}
/// <summary>
/// List all Cordonel FW packages.
/// </summary>
/// <returns></returns>
public static String GetLutUrl()
{
return ConfigurationManager.AppSettings["GetLutUrl"] ??
DefaultGetLutUrl;
}
/// <summary>
/// List all Cordonel FW packages.
/// </summary>
/// <returns></returns>
public static String ListAllCordonelFwPackagesUrl()
{
return ConfigurationManager.AppSettings["CordonelFwInfoUrl"] ??
DefaultCordonelFwInfoUrl;
}
/// <summary>
/// List all PCB IDs from a safe. As the safe may be deleted, this information is still accessible.
/// </summary>
/// <returns></returns>
public static String MeterInfoForTestBench()
{
return ConfigurationManager.AppSettings["MeterInfoForTestBenchServiceUrl"] ??
DefaultMeterInfoForTestBench;
}
/// <summary>
/// List all PCB IDs from a safe. As the safe may be deleted, this information is still accessible.
/// </summary>
/// <returns></returns>
public static String ListAllPcbIdsFromSafe()
{
return ConfigurationManager.AppSettings["GetPcbIdsFromSafeServiceUrl"] ??
DefaultGetPcbIdsFromSafeServiceUrl;
}
/// <summary>
/// Add PCB IDs to a safe. As the safe may be deleted, this information is still accessible.
/// </summary>
/// <returns></returns>
public static String AddPcbIdsToSafeServiceUrl()
{
return ConfigurationManager.AppSettings["AddPcbIdsToSafeServiceUrl"] ??
DefaultAddPcbIdsToSafeServiceUrl;
}
/// <summary>
/// Get all Cordonel FW package.
/// </summary>
/// <returns></returns>
public static String DownloadFileParts()
{
return ConfigurationManager.AppSettings["DownloadFilePartsServiceUrl"] ??
DefaultDownloadFilesPartsServiceUrl;
}
/// <summary>
/// FW-Update Safe container list for specific user
/// </summary>
/// <returns></returns>
public static String ListAllFwUpdateSafesForUserServiceUrl()
{
return ConfigurationManager.AppSettings["ListAllFwUpdateSafesForUserServiceUrl"] ??
DefaultListAllFwUpdateSafesForUserServiceUrl;
}
/// <summary>
/// FW-Update Safe container
/// </summary>
/// <returns></returns>
public static String DownloadFwUpdateSafeServiceUrl()
{
return ConfigurationManager.AppSettings["DownloadFwUpdateSafeServiceUrl"] ??
DefaultDownloadFwUpdateSafeServiceUrl;
}
/// <summary>
/// Download the EOL logging data for power correction of overestimated power consumption
/// </summary>
/// <returns></returns>
public static String DownloadDbDataAtEolServiceUrl()
{
return ConfigurationManager.AppSettings["DownloadDbDataAtEolServiceUrl"] ??
DefaultDbDataAtEolServiceUrl;
}
/// <summary>
/// Get EOL data for sentinel
/// </summary>
/// <returns></returns>
public static String EolDataForSentinelServiceUrl()
{
return ConfigurationManager.AppSettings["EolDataForSentinelServiceUrl"] ??
DefaultEolDataForSentinelServiceUrl;
}
/// <summary>
/// Get all Cordonel safes description files.
/// </summary>
/// <returns></returns>
public static String ListAllFwUpdateSafes()
{
return ConfigurationManager.AppSettings["ListAllFwUpdateSafesServiceUrl"] ??
DefaultListAllFwUpdateSafesServiceUrl;
}
/// <summary>
/// Get all Cordonel FW package description files.
/// </summary>
/// <returns></returns>
public static String ListAllFwPackages()
{
return ConfigurationManager.AppSettings["ListAllFwPackagesServiceUrl"] ??
DefaultListAllFwPackagesServiceUrl;
}
/// <summary>
/// Get all Cordonel FW update SW package description files.
/// </summary>
/// <returns></returns>
public static String ListAllSwPackages()
{
return ConfigurationManager.AppSettings["ListAllSwPackagesServiceUrl"] ??
DefaultListAllSwPackagesServiceUrl;
}
/// <summary>
/// Get all Cordonel FW update SW package description files.
/// </summary>
/// <returns></returns>
public static String ListAllConfigurationFilePackages()
{
return ConfigurationManager.AppSettings["ListAllConfigFilePackagesServiceUrl"] ??
DefaultListAllConfigFilePackagesServiceUrl;
}
/// <summary>
/// Set all applications versions installed to a specific Cordonel.
/// </summary>
/// <returns></returns>
public static String UploadCordonelAppVersionServiceUrl()
{
return ConfigurationManager.AppSettings["SetCordonelAppVersionServiceUrl"] ??
DefaultSetCordonelAppVersionServiceUrl;
}
/// <summary>
/// Inspect a specific requirement (read only).
/// </summary>
/// <returns></returns>
public static String InspectCordonelRequirementInfoServiceUrl()
{
return ConfigurationManager.AppSettings["InspectCordonelRequirementInfoServiceUrl"] ??
DefaultInspectCordonelRequirementInfoUrl;
}
/// <summary>
/// Get all production infos for skip process checks or limits for production like:
/// - Battery drained percentage upper limit,
/// - Production due date for a special register,
/// - Required lifetime for assembly line,
/// - Required lifetime for shipping line.
/// </summary>
/// <returns></returns>
public static String GetCordonelRequirementInfoServiceUrl()
{
return ConfigurationManager.AppSettings["GetCordonelRequirementInfoServiceUrl"] ??
DefaultGetCordonelRequirementInfoUrl;
}
/// <summary>
/// Get all production infos for skip process checks or limits for production like:
/// - Battery drained percentage upper limit,
/// - Production due date for a special register,
/// - Required lifetime for assembly line,
/// - Required lifetime for shipping line.
/// </summary>
/// <returns></returns>
public static String GetCordonelRequirementByFANrInfoServiceUrl(String ponr)
{
return $"{ProductionUiServerDns}/api/cordonel/requirements/pono/{ponr}";
}
/// <summary>
/// Get all production infos for skip process checks or limits for production like:
/// - Battery drained percentage upper limit,
/// - Production due date for a special register,
/// - Required lifetime for assembly line,
/// - Required lifetime for shipping line.
/// </summary>
/// <returns></returns>
public static String GetCordonelRequirementByMeterSizeInfoServiceUrl(Int32 size)
{
return $"{ProductionUiServerDns}/api/cordonel/requirements/isize/{size}";
}
/// <summary>
/// Get all applications versions installed to a specific Cordonel.
/// </summary>
/// <returns></returns>
public static String DownloadCordonelAppVersionServiceUrl()
{
return ConfigurationManager.AppSettings["GetCordonelAppVersionServiceUrl"] ??
DefaultGetCordonelAppVersionServiceUrl;
}
/// <summary>
/// List all Cordonel customers with search filter (e.g. %sus% where % is a filter for 0 to multiple
/// alphanumeric characters) to get the customer names and the order numbers.
/// </summary>
/// <returns></returns>
public static String ListAllCordonelCustomersWithFilterServiceUrl()
{
return ConfigurationManager.AppSettings["ListAllCordonelCustomersWithFilterServiceUrl"] ??
DefaultListAllCordonelCustomersWithFilterServiceUrl;
}
/// <summary>
/// Get Cordonel order details to capture the production order
/// </summary>
/// <returns></returns>
public static String ListCordonelOrderDetailsServiceUrl()
{
return ConfigurationManager.AppSettings["ListCordonelOrderDetailsServiceUrl"] ??
DefaultListCordonelOrderDetailsServiceUrl;
}
/// <summary>
/// List all Cordonel orders of a selected customer
/// </summary>
/// <returns></returns>
public static String ListAllCordonelCustomerOrdersServiceUrl()
{
return ConfigurationManager.AppSettings["ListAllCordonelCustomerOrdersServiceUrl"] ??
DefaultListAllCordonelCustomerOrdersServiceUrl;
}
/// <summary>
/// List all Cordonels of a specific order number to get the customer serial number and the Pcb ID.
/// </summary>
/// <returns></returns>
public static String ListAllOrderCordonelsServiceUrl()
{
return ConfigurationManager.AppSettings["ListAllOrderCordonelsServiceUrl"] ??
DefaultListAllOrderCordonelsServiceUrl;
}
/// <summary>
/// Register watch service
/// </summary>
/// <returns></returns>
public static String RegisterWatchServiceUrl()
{
return ConfigurationManager.AppSettings["RegisterWatchServiceUrl"] ??
DefaultRegisterWatchServiceUrl;
}
/// <summary>
/// File content download
/// </summary>
/// <returns></returns>
public static String DownloadFileContentServiceUrl()
{
return ConfigurationManager.AppSettings["FileContentDownloadServiceUrl"] ??
DefaultFileContentDownloadServiceUrl;
}
/// <summary>
/// FW-Update report download as string
/// </summary>
/// <returns></returns>
public static String DownloadFwUpdateReportServiceUrl()
{
return ConfigurationManager.AppSettings["FwUpdateReportDownloadServiceUrl"] ??
DefaultFwUpdateReportDownloadServiceUrl;
}
/// <summary>
/// FW-Update report upload as string
/// </summary>
/// <returns></returns>
public static String UploadFwUpdateReportServiceUrl()
{
return ConfigurationManager.AppSettings["FwUpdateReportUploadServiceUrl"] ??
DefaultFwUpdateReportUploadServiceUrl;
}
/// <summary>
/// FW-Update Safe container upload
/// </summary>
/// <returns></returns>
public static String UploadFwUpdateSafeContainerServiceUrl()
{
return ConfigurationManager.AppSettings["FwUpdateSafeContainerUploadServiceUrl"] ??
DefaultFwUpdateSafeContainerUploadServiceUrl;
}
/// <summary>
/// FW-Update user validation url
/// </summary>
/// <returns></returns>
public static String EditFwUpdateUserValidityServiceUrl()
{
return ConfigurationManager.AppSettings["EditFwUpdateUserValidityServiceUrl"] ??
DefaultEditFwUpdateUserValidityServiceUrl;
}
/// <summary>
/// FW-Update user HW-Id url
/// </summary>
/// <returns></returns>
public static String RefreshFwUpdateUsersHardwareIdServiceUrl()
{
return ConfigurationManager.AppSettings["RefreshFwUpdateUsersHardwareIdServiceUrl"] ??
DefaultRefreshFwUpdateUsersHardwareIdServiceUrl;
}
/// <summary>
/// FW-Update user password hash for encryption url
/// </summary>
/// <returns></returns>
public static String RefreshFwUpdateUsersPasswordHashServiceUrl()
{
return ConfigurationManager.AppSettings["RefreshFwUpdateUsersPasswordHashServiceUrl"] ??
DefaultRefreshFwUpdateUsersPasswordHashServiceUrl;
}
/// <summary>
/// FW-Update create new user url
/// </summary>
/// <returns></returns>
public static String CreateNewFwUpdateUserServiceUrl()
{
return ConfigurationManager.AppSettings["CreateNewFwUpdateUserServiceUrl"] ??
DefaultCreateNewFwUpdateUserServiceUrl;
}
/// <summary>
/// FW-Update list all users url
/// </summary>
/// <returns></returns>
public static String ListAllFwUpdateUsersServiceUrl()
{
return ConfigurationManager.AppSettings["ListAllFwUpdateUsersServiceUrl"] ??
DefaultListAllFwUpdateUsersServiceUrl;
}
/// <summary>
/// FW-Update list all users url
/// </summary>
/// <returns></returns>
public static String ListAllFwUpdateBuilderOperatorsServiceUrl()
{
return ConfigurationManager.AppSettings["ListAllFwUpdateBuilderOperatorsServiceUrl"] ??
DefaultListAllFwUpdateBuilderOperatorsServiceUrl;
}
/// <summary>
/// FW-Update get user information by user Id url
/// </summary>
/// <returns></returns>
public static String GetFwUpdateUserByIdServiceUrl()
{
return ConfigurationManager.AppSettings["GetFwUpdateUserByIdServiceUrl"] ??
DefaultGetFwUpdateUserByIdServiceUrl;
}
/// <summary>
/// FW-Update get user information by user login name url
/// </summary>
/// <returns></returns>
public static String GetFwUpdateUserByLoginNameServiceUrl()
{
return ConfigurationManager.AppSettings["GetFwUpdateUserByLoginNameServiceUrl"] ??
DefaultGetFwUpdateUserByLoginNameServiceUrl;
}
/// <summary>
/// Genesis check radio parameter url
/// </summary>
/// <returns></returns>
public static String GenesisRadioCheckServiceUrl()
{
return ConfigurationManager.AppSettings["GenesisRadioCheckServiceUrl"] ??
DefaultGenesisRadioCheckServiceUrl;
}
/// <summary>
/// Genesis radio parameter get url
/// </summary>
/// <returns></returns>
public static String GenesisFinalCheckServiceUrl()
{
return ConfigurationManager.AppSettings["GenesisFinalCheckServiceUrl"] ??
DefaultGenesisFinalCheckServiceUrl;
}
/// <summary>
/// Marriage service url
/// </summary>
/// <returns></returns>
public static String MarriageServiceUrl()
{
return ConfigurationManager.AppSettings["MarriageServiceUrl"] ??
DefaultMarriageServiceUrl;
}
/// <summary>
/// Genesis process status url
/// </summary>
/// <returns></returns>
public static String MeterProcessStateUrl()
{
return ConfigurationManager.AppSettings["MeterProcessStateUrl"] ??
DefaultMeterProcessStateUrl;
}
/// <summary>
/// Genesis get radio address url
/// </summary>
/// <returns></returns>
public static String GenesisGetRadioAddressServiceUrl()
{
return ConfigurationManager.AppSettings["GenesisGetRadioAddressServiceUrl"] ??
DefaultGenesisGetRadioAddressServiceUrl;
}
/// <summary>
/// Genesis get key set id url
/// </summary>
/// <returns></returns>
public static String GenesisGetOrderNumberServiceUrl()
{
return ConfigurationManager.AppSettings["GenesisGetOrderNumberServiceUrl"] ??
DefaultGenesisGetOrderNumberServiceUrl;
}
/// <summary>
/// Genesis get key set id url
/// </summary>
/// <returns></returns>
public static String GenesisGetKeySetIdServiceUrl()
{
return ConfigurationManager.AppSettings["GenesisGetKeySetIdServiceUrl"] ??
DefaultGenesisGetKeySetIdServiceUrl;
}
/// <summary>
/// Genesis get password url
/// </summary>
/// <returns></returns>
public static String GenesisSetPickingStateServiceUrl()
{
return ConfigurationManager.AppSettings["GenesisSetPickingStateServiceUrl"] ??
DefaultGenesisSetPickingStateServiceUrl;
}
/// <summary>
/// Genesis get password url
/// </summary>
/// <returns></returns>
public static String GenesisGetPasswordServiceUrl()
{
return ConfigurationManager.AppSettings["GenesisGetPasswordServiceUrl"] ??
DefaultGenesisGetPasswordServiceUrl;
}
/// <summary>
/// Genesis get password url
/// </summary>
/// <returns></returns>
public static String GenesisGetPasswordContainerServiceUrl()
{
return ConfigurationManager.AppSettings["GenesisPasswordContainerServiceUrl"] ??
DefaultGenesisPasswordContainerServiceUrl;
}
/// <summary>
/// Genesis set password url
/// </summary>
/// <returns></returns>
public static String GenesisSetPasswordServiceUrl()
{
return ConfigurationManager.AppSettings["GenesisSetPasswordServiceUrl"] ??
DefaultGenesisSetPasswordServiceUrl;
}
/// <summary>
/// Set the SW license
/// </summary>
/// <returns></returns>
public static String SetSoftwareLicenseUrl()
{
return ConfigurationManager.AppSettings["SetSoftwareLicenseUrl"] ??
DefaultSetSoftwareLicenseUrl;
}
/// <summary>
/// Set the SW license
/// </summary>
/// <returns></returns>
public static String GetSoftwareLicenseUrl()
{
return ConfigurationManager.AppSettings["GetSoftwareLicenseUrl"] ??
DefaultGetSoftwareLicenseUrl;
}
/// <summary>
/// Check the SW license with a given name and version
/// </summary>
/// <returns></returns>
public static String GetSoftwareStartUpAccessUrl()
{
return ConfigurationManager.AppSettings["GetSoftwareStartUpAccessUrl"] ??
DefaultGetSoftwareStartUpAccessUrl;
}
/// <summary>
/// Get Genesis calibration results for final check if those have been correctly set
/// </summary>
/// <returns></returns>
public static String GetGenesisCalibrationResultsUrl()
{
return ConfigurationManager.AppSettings["GetGenesisCalibrationResults"] ??
DefaultGetGenesisCalibrationResults;
}
/// <summary>
/// Post Genesis calibration results
/// </summary>
/// <returns></returns>
public static String PostGenesisCalibrationResultUrl()
{
return ConfigurationManager.AppSettings["GenesisCalibrationResult"] ??
DefaultGenesisCalibrationResult;
}
/// <summary>
/// Post Genesis calibration results
/// </summary>
/// <returns></returns>
public static String FileContentControllerUrl()
{
return ConfigurationManager.AppSettings["DefaultFileContentController"] ??
DefaultFileContentController;
}
/// <summary>
/// Root for all function regarding the BSI Key generation service
/// </summary>
/// <returns></returns>
public static String KeyServerCustom()
{
return ConfigurationManager.AppSettings["DefaultKeyServerCustom"] ??
DefaultKeyServerCustom;
}
/// <summary>
/// Root for all function regarding the meter itself
/// </summary>
/// <returns></returns>
public static String GenesisMeter()
{
return ConfigurationManager.AppSettings["GenesisMeter"] ??
DefaultGenesisMeter;
}
public static String GetQ3CalibrationsURI(String currentPcbId)
{
throw new NotImplementedException();
}
}
}
@@ -0,0 +1,67 @@
using System;
using System.Reflection;
using Xylem.Common.CommonCore.Configuration;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.SoftwareAccessHelper
{
/// <summary>
/// Access right and permission handling for software assemblies. The production data base contains the assembly names and
/// validation dates. This avoids usage of not permitted software. New software releases can invalid older versions.
/// </summary>
public static class Access
{
/// <summary>
/// Check this assembly access rights/permissions.
/// </summary>
/// <returns></returns>
public static Boolean HasAccess()
{
return HasAccess(Assembly.GetExecutingAssembly().GetName());
}
/// <summary>
/// Check the assembly name and version.
/// </summary>
/// <param name="assemblyName"></param>
/// <returns></returns>
public static Boolean HasAccess(AssemblyName assemblyName)
{
return HasAccess(assemblyName.Name, assemblyName.Version.Major, assemblyName.Version.Minor,
assemblyName.Version.Build);
}
/// <summary>
/// check the program name and version.
/// </summary>
/// <param name="program"></param>
/// <param name="major"></param>
/// <param name="minor"></param>
/// <param name="build"></param>
/// <returns></returns>
private static Boolean HasAccess(String program, Int32 major, Int32 minor, Int32 build)
{
if (System.Diagnostics.Debugger.IsAttached)
{
return true;
}
return false;
//var url = $"{ServiceUrls.GetSoftwareStartUpAccessUrl()}?Program={program}&Major={major}&Minor={minor}&Build={build}";
//var requestResponse = LocalWebRequest.GetRequest(url, 8000);
//var ret = bool.Parse(requestResponse.Trim('"'));
//return ret;
}
}
public static class Updater
{
public static void CheckAndUpdate()
{
//todo implement
//
}
}
}
@@ -0,0 +1,13 @@
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.SoftwareAccessHelper
{
public static class GrantAccess
{
public static bool GetAccess()
{
return false;
}
}
}
@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Net;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.SoftwareAccessHelper
{
public class HttpResponse<T>
{
public T Value { get; internal set; }
public HttpStatusCode HttpStatusCode { get; internal set; }
public Dictionary<String, String> Errors { get; internal set; }
}
}
@@ -0,0 +1,650 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using Newtonsoft.Json;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.SoftwareAccessHelper
{
/// <summary>
/// Web request
/// </summary>
public static class LocalWebRequest
{
/// <summary>
/// Web request with asynchronous operation and response code or exception response, json object input and/or dictionary
/// </summary>
/// <param name="url"></param>
/// <param name="responseCode"></param>
/// <param name="ex"></param>
/// <param name="timeoutMs"></param>
/// <param name="json"></param>
/// <param name="header"></param>
/// <returns></returns>
public static Boolean PostRequestAsync(String url, ref Int32 responseCode, ref Exception ex, Int32? timeoutMs = null, Object json = null, Dictionary<String, String> header = null)
{
try
{
var r = PostRequestAndGetResponseAsync(url, timeoutMs, json, header);
responseCode = r.StatusCode.GetHashCode();
if (r.StatusCode == HttpStatusCode.OK)
{
return true;
}
if (r.StatusCode == HttpStatusCode.InternalServerError)
{
ex = new Exception(r.Content);
}
}
catch (Exception error)
{
ex = error;
}
return false;
}
/// <summary>
/// Web request with asynchronous operation and true/false return, json object input and/or dictionary
/// </summary>
/// <param name="url"></param>
/// <param name="timeoutMs"></param>
/// <param name="json"></param>
/// <param name="header"></param>
/// <returns></returns>
public static Boolean PostRequestAsync(String url, Int32? timeoutMs = null, Object json = null, Dictionary<String, String> header = null)
{
try
{
var r = PostRequestAndGetResponseAsync(url, timeoutMs, json, header);
if (r.StatusCode == HttpStatusCode.OK)
{
return true;
}
}
catch (Exception)
{
// Log
}
return false;
}
/// <summary>
/// Web request with asynchronous operation with string return, json object input and/or dictionary
/// </summary>
/// <param name="url"></param>
/// <param name="timeoutMs"></param>
/// <param name="json"></param>
/// <param name="header"></param>
/// <returns></returns>
public static String PostRequestAsyncAndGetContent(String url, Int32? timeoutMs = null, Object json = null, Dictionary<String, String> header = null)
{
try
{
var r = PostRequestAndGetResponseAsync(url, timeoutMs, json, header);
if (r.StatusCode == HttpStatusCode.OK)
{
return r.Content;
}
}
catch (Exception)
{
// Log
}
return string.Empty;
}
/// <summary>
/// Web request with asynchronous operation, binary file byte array input, response string output
/// </summary>
/// <param name="url"></param>
/// <param name="fileName"></param>
/// <param name="content"></param>
/// <param name="response"></param>
/// <param name="timeoutMs"></param>
/// <returns></returns>
public static Boolean PostBinaryFileRequestAsync(String url, String fileName, Byte[] content, out String response, Int32? timeoutMs = null)
{
response = null;
return false;
// try
// {
//
// var client = new RestClient(url);
// //WebRequest.DefaultWebProxy = null;
// var request = new RestRequest(Method.POST);
//
// ServicePointManager.Expect100Continue = false;
//
//
// request.AddHeader("Content-Type", "multipart/form-data");
//
//
// request.Files.Add(new FileParameter
// {
// Name = "file",
// Writer = (s) =>
// {
// var stream = new MemoryStream(content);
// stream.CopyTo(s);
// stream.Dispose();
// },
// FileName = fileName,
// ContentType = "multipart/form-data",
// ContentLength = content.Length
// });
//
//
// var r = client.ExecuteAsPost(request, Method.POST.ToString());
// response = r.Content;
// return r.StatusCode == HttpStatusCode.OK;
//
//
// }
// catch (Exception)
// {
// response = string.Empty;
// return false;
//
// }
}
/// <summary>
/// Web request with asynchronous operation, binary file input
/// </summary>
/// <param name="url"></param>
/// <param name="fileName"></param>
/// <param name="content"></param>
/// <param name="timeoutMs"></param>
/// <returns></returns>
public static Boolean PostBinaryFileRequestAsync(String url, String fileName, Byte[] content, Int32? timeoutMs = null)
{
return false;
// try
// {
//
// var client = new RestClient(url);
// // WebRequest.DefaultWebProxy = null;
// var request = new RestRequest(Method.POST);
//
// ServicePointManager.Expect100Continue = false;
//
//
// request.AddHeader("Content-Type", "multipart/form-data");
//
//
// request.Files.Add(new FileParameter
// {
// Name = "file",
// Writer = (s) =>
// {
// var stream = new MemoryStream(content);
// stream.CopyTo(s);
// stream.Dispose();
// },
// FileName = fileName,
// ContentType = "multipart/form-data",
// ContentLength = content.Length
// });
//
//
// var r = client.ExecuteAsPost(request, Method.POST.ToString());
// return r.StatusCode == HttpStatusCode.OK;
//
//
// }
// catch (Exception)
// {
// return false;
//
// }
}
/// <summary>
/// Web request with asynchronous operation
/// </summary>
/// <param name="url"></param>
/// <param name="timeoutMs"></param>
/// <param name="files"></param>
/// <param name="header"></param>
/// <returns></returns>
public static IRestResponse PostBinaryRequestAndGetResponseAsync(String url, Int32? timeoutMs = null,
Dictionary<String, String> files = null, Dictionary<String, String> header = null)
{
// try
// {
//
// var client = new RestClient(url);
// //WebRequest.DefaultWebProxy = null;
// var request = new RestRequest(Method.POST);
//
// ServicePointManager.Expect100Continue = false;
//
// if (header != null)
// {
// foreach (var item in header)
// {
// if (item.Key != "Content-Type" && item.Key != "Accept")
// {
// request.AddHeader(item.Key, item.Value);
// }
//
// }
//
// }
//
// request.AddHeader("Content-Type", "multipart/form-data");
//
// if (files != null)
// {
// foreach (var item in files)
// {
// request.AddFile(item.Key, item.Value);
// }
//
// }
//
// var r = client.ExecuteAsPost(request, Method.POST.ToString());
// return r;
//
//
// }
// catch (Exception error)
// {
// return new RestResponse
// {
// StatusCode = HttpStatusCode.InternalServerError,
// Content = error.ToString()
// };
//
// }
}
/// <summary>
/// Post Request Async
/// </summary>
/// <remarks date="2024-Sep-09" author="Stoyan Slatev">
/// - Initial.
/// </remarks>
/// <param name="url"></param>
/// <param name="timeoutMs"></param>
/// <param name="json"></param>
/// <param name="httpStatus"></param>
/// <returns></returns>
public static String PostRequestAsync(String url, Double timeoutMs, out HttpStatusCode httpStatus, Object json = null)
{
try
{
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
httpClient.Timeout = TimeSpan.FromMilliseconds(timeoutMs);
var postedJson = JsonConvert.SerializeObject(json, Formatting.Indented);
var postedBody = new StringContent(postedJson);
postedBody.Headers.ContentType = new MediaTypeWithQualityHeaderValue("application/json");
var posted = httpClient
.PostAsync(url, postedBody)
.Result;
httpStatus = posted.StatusCode;
return posted.Content.ReadAsStringAsync().Result;
}
catch (Exception error)
{
httpStatus = HttpStatusCode.ServiceUnavailable;
return error.Message;
}
}
/// <summary>
/// Web request
/// </summary>
/// <param name="url"></param>
/// <param name="httpStatus"></param>
/// <param name="timeoutMs"></param>
/// <returns></returns>
public static String GetRequest(String url, Double timeoutMs, out HttpStatusCode httpStatus)
{
try
{
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
httpClient.Timeout = TimeSpan.FromMilliseconds(timeoutMs);
var response = httpClient
.GetAsync(url)
.Result;
httpStatus = response.StatusCode;
return response.Content.ReadAsStringAsync().Result;
}
catch (Exception error)
{
httpStatus = HttpStatusCode.ServiceUnavailable;
return error.Message;
}
}
/// <summary>
/// Web request with asynchronous operation
/// </summary>
/// <param name="url"></param>
/// <param name="timeoutMs"></param>
/// <param name="json"></param>
/// <param name="header"></param>
/// <returns></returns>
public static IRestResponse PostRequestAndGetResponseAsync(String url, Int32? timeoutMs = null, Object json = null,
Dictionary<String, String> header = null)
{
// try
// {
//
// var client = new RestClient(url);
// client.AddDefaultHeader("Accept", "application/json");
// //WebRequest.DefaultWebProxy = null;
// ServicePointManager.Expect100Continue = false;
// var request = new RestRequest(Method.POST);
//
//
// if (header != null)
// {
// foreach (var item in header)
// {
// if (item.Key != "Content-Type" && item.Key != "Accept")
// {
// request.AddHeader(item.Key, item.Value);
// }
//
// }
// }
// request.AddHeader("Content-Type", "application/json");
// request.AddHeader("Accept", "application/json");
//
// if (json != null)
// {
// request.AddJsonBody(json);
// }
//
// var r = client.ExecuteAsPost(request, Method.POST.ToString());
// return r;
// }
// catch (Exception error)
// {
// return new RestResponse
// {
// StatusCode = HttpStatusCode.InternalServerError,
// Content = error.ToString()
// };
// }
}
#region HTTP String extensions
public static HttpResponse<T> DeleteAsJson<T>(this String url, Object json = null, Action<RestRequestHeaders> headersHandler = null, Int32? timeoutMs = null)
{
return Method.DELETE.AsJson<T>(url, headersHandler, json, timeoutMs);
}
public static HttpResponse<T> GetAsJson<T>(this String url, Object json = null, Action<RestRequestHeaders> headersHandler = null, Int32? timeoutMs = null)
{
return Method.GET.AsJson<T>(url, headersHandler, json, timeoutMs);
}
public static HttpResponse<T> PostAsJson<T>(this String url, Object json = null, Action<RestRequestHeaders> headersHandler = null, Int32? timeoutMs = null)
{
return Method.POST.AsJson<T>(url, headersHandler, json, timeoutMs);
}
public static HttpResponse<T> PutAsJson<T>(this String url, Object json = null, Action<RestRequestHeaders> headersHandler = null, Int32? timeoutMs = null)
{
return Method.PUT.AsJson<T>(url, headersHandler, json, timeoutMs);
}
#endregion HTTP String extensions
#region HTTP Object extensions
public static HttpResponse<T> DeleteAsJson<T>(this Object json, String url, Action<RestRequestHeaders> headersHandler = null, Int32? timeoutMs = null)
{
return Method.DELETE.AsJson<T>(url, headersHandler, json, timeoutMs);
}
public static HttpResponse<T> GetAsJson<T>(this Object json, String url, Action<RestRequestHeaders> headersHandler = null, Int32? timeoutMs = null)
{
return Method.GET.AsJson<T>(url, headersHandler, json, timeoutMs);
}
public static HttpResponse<T> GetAsJson<T>(String url, Action<RestRequestHeaders> headersHandler = null, Int32? timeoutMs = null)
{
return Method.GET.AsJson<T>(url, headersHandler, null, timeoutMs);
}
public static HttpResponse<T> PostAsJson<T>(this Object json, String url, Action<RestRequestHeaders> headersHandler = null, Int32? timeoutMs = null)
{
return Method.POST.AsJson<T>(url, headersHandler, json, timeoutMs);
}
public static HttpResponse<T> PutAsJson<T>(this Object json, String url, Action<RestRequestHeaders> headersHandler = null, Int32? timeoutMs = null)
{
return Method.PUT.AsJson<T>(url, headersHandler, json, timeoutMs);
}
#endregion HTTP Object extensions
/// <summary>
/// Web request
/// </summary>
/// <param name="url"></param>
/// <param name="timeoutMs"></param>
/// <param name="header"></param>
/// <param name="isRetry"></param>
/// <returns></returns>
public static String DeleteRequest(String url, Int32? timeoutMs = null, Dictionary<String, String> header = null, Boolean isRetry = false)
{
var ret = DeleteRequestWithError(url, out var temp, timeoutMs, header, isRetry);
if (temp != 200)
{
throw new ApplicationException($"WebRequest Status {temp}");
}
return ret;
}
/// <summary>
/// Web request with asynchronous operation, error code response
/// </summary>
/// <param name="url"></param>
/// <param name="errorCode"></param>
/// <param name="timeoutMs"></param>
/// <param name="header"></param>
/// <param name="isRetry"></param>
/// <returns></returns>
public static String DeleteRequestWithError(String url, out Int32 errorCode, Int32? timeoutMs = null, Dictionary<String, String> header = null, Boolean isRetry = false)
{
var client = new RestClient(url);
var request = new RestRequest(Method.DELETE);
ServicePointManager.Expect100Continue = false;
if (!timeoutMs.HasValue)
{
timeoutMs = 800;
}
request.Timeout = timeoutMs.Value;
if (header != null)
{
foreach (var item in header)
{
if (item.Key != "Accept")
{
request.AddHeader(item.Key, item.Value);
}
}
}
request.AddHeader("Accept", "application/json");
var r = client.Execute(request);
errorCode = r.StatusCode.GetHashCode();
if (r.StatusCode == HttpStatusCode.OK)
{
return r.Content;
}
if (r.StatusCode != 0)
return r.Content;
return !isRetry ? DeleteRequest(url, timeoutMs, header, true) : r.Content;
}
/// <summary>
/// Web request
/// </summary>
/// <param name="url"></param>
/// <param name="timeoutMs"></param>
/// <param name="header"></param>
/// <param name="isRetry"></param>
/// <returns></returns>
public static String GetRequest(String url, Int32? timeoutMs = null, Dictionary<String, String> header = null, Boolean isRetry = false)
{
//if (true && (url.Contains("sla12iis01/MeterProcessState") || url.Contains("sla12iis01.emea.sensus.net/MeterProcessState")))
//{
// url = url.Replace("sla12iis01/MeterProcessState", "delaz1web01/MeterProcessState").Replace("sla12iis01.emea.sensus.net/MeterProcessState", "delaz1web01/MeterProcessState")
//}
var ret = GetRequestWithError(url, out var temp, timeoutMs, header, isRetry);
if (temp != 200)
{
throw new ApplicationException($"WebRequest Status {temp}");
}
return ret;
}
/// <summary>
/// Web request with asynchronous operation, error code response
/// </summary>
/// <param name="url"></param>
/// <param name="errorCode"></param>
/// <param name="timeoutMs"></param>
/// <param name="header"></param>
/// <param name="isRetry"></param>
/// <returns></returns>
public static String GetRequestWithError(String url, out Int32 errorCode, Int32? timeoutMs = null, Dictionary<String, String> header = null, Boolean isRetry = false)
{
var client = new RestClient(url);
var request = new RestRequest(Method.GET);
ServicePointManager.Expect100Continue = false;
if (!timeoutMs.HasValue)
{
timeoutMs = 800;
}
request.Timeout = timeoutMs.Value;
if (header != null)
{
foreach (var item in header)
{
if (item.Key != "Accept")
{
request.AddHeader(item.Key, item.Value);
}
}
}
request.AddHeader("Accept", "application/json");
var r = client.Get(request);
errorCode = r.StatusCode.GetHashCode();
if (r.StatusCode == HttpStatusCode.OK)
{
return r.Content;
}
if (r.StatusCode != 0)
return r.Content;
return !isRetry ? GetRequest(url, timeoutMs, header, true) : r.Content;
}
private static HttpResponse<T> AsJson<T>(this Method method, String url, Action<RestRequestHeaders> headersHandler = null, Object model = null, Int32? timeoutMs = null)
{
var httpResponse = new HttpResponse<T>();
try
{
var client = new RestClient(url);
var request = new RestRequest(method);
var headers = new RestRequestHeaders(request)
{
ContentType = "application/json",
Accept = "application/json"
};
headersHandler?.Invoke(headers);
if (model != null)
{
if (method == Method.GET)
{
request.AddObject(model);
}
else
{
request.AddJsonBody(model);
}
}
ServicePointManager.Expect100Continue = false;
var response = client.Execute(request);
httpResponse.HttpStatusCode = response.StatusCode;
if (HttpStatusCode.OK <= response.StatusCode && response.StatusCode < HttpStatusCode.BadRequest)
{
if (!string.IsNullOrWhiteSpace(response.Content))
{
httpResponse.Value = JsonConvert.DeserializeObject<T>(response.Content);
}
else
{
httpResponse.Errors = new Dictionary<String, String>()
{
{ nameof(response.Content), $"{response.Content}" },
};
}
}
else
{
httpResponse.Errors = JsonConvert.DeserializeObject<Dictionary<String, String>>(response.Content);
if (httpResponse.Errors is null)
{
httpResponse.Errors = new Dictionary<String, String>()
{
{ nameof(response.ErrorException), $"{response.ErrorException}" },
{ nameof(response.ErrorMessage), $"{response.ErrorMessage}" },
{ nameof(response.Content), $"{response.Content}" },
};
}
}
}
catch (Exception error)
{
httpResponse.HttpStatusCode = HttpStatusCode.InternalServerError;
httpResponse.Errors = new Dictionary<String, String>()
{
{ nameof(Exception), $"{error}" }
};
}
return httpResponse;
}
}
}
@@ -0,0 +1,27 @@
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.SoftwareAccessHelper
{
public class RestRequestHeaders
{
private readonly RestRequest request;
internal RestRequestHeaders(RestRequest request)
{
this.request = request;
}
public string Accept
{
set => this.request.AddHeader(nameof(Accept), value);
}
public string Authorization
{
set => this.request.AddHeader(nameof(Authorization), value);
}
public string ContentType
{
set => this.request.AddHeader("Content-Type", value);
}
}
}
@@ -0,0 +1,37 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Xylem.Common.Hardware.WaterMeter.WaterMeterCore;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.BatchActions
{
/// <summary>
/// Applies an action to a list of meters in a separate thread
/// </summary>
public abstract class BatchCall
{
/// <summary>
/// Starts a new task for a list of meters
/// </summary>
/// <param name="meters"></param>
public void RunAction(IEnumerable<IMeter> meters)
{
var listOfTask = new List<Task>();
foreach (var meter in meters)
{
listOfTask.Add(Task.Factory.StartNew(() =>
{
DoSingleAction(meter);
}));
}
Task.WaitAll(listOfTask.ToArray());
}
/// <summary>
/// Apply a single action to a specific meter
/// </summary>
/// <param name="meter"></param>
public abstract void DoSingleAction(IMeter meter);
}
}
@@ -0,0 +1,14 @@
using Xylem.Common.Hardware.WaterMeter.WaterMeterCore;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.BatchActions
{
/// <inheritdoc />
public class BatchCallConnectMeter : TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.BatchActions.BatchCall
{
/// <inheritdoc />
public override void DoSingleAction(IMeter meter)
{
meter.ConnectMeter();
}
}
}
@@ -0,0 +1,14 @@
using Xylem.Common.Hardware.WaterMeter.WaterMeterCore;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.BatchActions
{
/// <inheritdoc />
public class BatchCallInitCalibration : TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.BatchActions.BatchCall
{
/// <inheritdoc />
public override void DoSingleAction(IMeter meter)
{
meter.InitCalibration();
}
}
}
@@ -0,0 +1,14 @@
using Xylem.Common.Hardware.WaterMeter.WaterMeterCore;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.BatchActions
{
/// <inheritdoc />
public class BatchCallInitMeasurement : TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.BatchActions.BatchCall
{
/// <inheritdoc />
public override void DoSingleAction(IMeter meter)
{
meter.InitMeasurement();
}
}
}
@@ -0,0 +1,14 @@
using Xylem.Common.Hardware.WaterMeter.WaterMeterCore;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.BatchActions
{
/// <inheritdoc />
public class BatchCallLogin : TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.BatchActions.BatchCall
{
/// <inheritdoc />
public override void DoSingleAction(IMeter meter)
{
meter.Login();
}
}
}
@@ -0,0 +1,14 @@
using Xylem.Common.Hardware.WaterMeter.WaterMeterCore;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.BatchActions
{
/// <inheritdoc />
public class BatchCallSetCalibrationFactor : TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.BatchActions.BatchCall
{
/// <inheritdoc />
public override void DoSingleAction(IMeter meter)
{
meter.SetCalibFactorsAllChannels();
}
}
}
@@ -0,0 +1,14 @@
using Xylem.Common.Hardware.WaterMeter.WaterMeterCore;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.BatchActions
{
/// <inheritdoc />
public class BatchCallStartCalibration : TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.BatchActions.BatchCall
{
/// <inheritdoc />
public override void DoSingleAction(IMeter meter)
{
meter.StartCalibration();
}
}
}
@@ -0,0 +1,14 @@
using Xylem.Common.Hardware.WaterMeter.WaterMeterCore;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.BatchActions
{
/// <inheritdoc />
public class BatchCallStartMeasurement : TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.BatchActions.BatchCall
{
/// <inheritdoc />
public override void DoSingleAction(IMeter meter)
{
meter.StartMeasurement();
}
}
}
@@ -0,0 +1,14 @@
using Xylem.Common.Hardware.WaterMeter.WaterMeterCore;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.BatchActions
{
/// <inheritdoc />
public class BatchCallStopCalibration : TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.BatchActions.BatchCall
{
/// <inheritdoc />
public override void DoSingleAction(IMeter meter)
{
meter.StopCalibration();
}
}
}
@@ -0,0 +1,14 @@
using Xylem.Common.Hardware.WaterMeter.WaterMeterCore;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.BatchActions
{
/// <inheritdoc />
public class BatchCallStopMeasurement : TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.BatchActions.BatchCall
{
/// <inheritdoc />
public override void DoSingleAction(IMeter meter)
{
meter.StopMeasurement();
}
}
}
@@ -0,0 +1,14 @@
using Xylem.Common.Hardware.WaterMeter.WaterMeterCore;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.BatchActions
{
/// <inheritdoc />
public class BatchCallTestBenchDispose: TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.BatchActions.BatchCall
{
/// <inheritdoc />
public override void DoSingleAction(IMeter meter)
{
meter.TestBenchDispose();
}
}
}
@@ -0,0 +1,103 @@
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.Consts
{
/// <summary>
/// Display codes to keep the user informed about the production and processing step.
/// This is useful as the user doesn't need to connect the device to a PC, he can
/// immediately inspect the status of the device.
/// </summary>
public enum DisplayCodes
{
//general information
/// <summary>
/// Status not set
/// </summary>
None = 0x0000,
/// <summary>
/// Error state
/// </summary>
Error = 0xFFFF,
//Production process
//assembly line
//Picking
/// <summary>
/// Picking in progress
/// </summary>
PickingStarted = 0x7700,
/// <summary>
/// Picking succeeded, next step can be initiated
/// </summary>
PickingTested = 0x7777,
/// <summary>
/// Picking failed
/// </summary>
PickingFailed = 0xFF77,
//Pressure
/// <summary>
/// Pressure testing succeeded, next step can be initiated
/// </summary>
PressureTested = 0x1111,
/// <summary>
/// Pressure test failed
/// </summary>
PressureTestedFailed = 0xFF11,
/// <summary>
/// Pressure test failed
/// </summary>
PressureTestedPending = 0x0011,
//Marriage
/// <summary>
/// Connection between PCBID, Serial Number and Order number done
/// </summary>
Mounted = 0x2222,
//Test bench
/// <summary>
/// Zero flow test succeeded, next step can be initiated
/// </summary>
ZeroFlow = 0x3333,
/// <summary>
/// Zero flow test failed
/// </summary>
ZeroFlowFailed = 0xFF33,
/// <summary>
/// Flow calibration succeeded, next step can be initiated
/// </summary>
FlowCalibrated = 0x4444,
/// <summary>
/// Flow calibration failed
/// </summary>
FlowCalibrationOurOfRange = 0xFF44,
/// <summary>
/// Flow test succeeded, next step can be initiated
/// </summary>
FlowTested = 0x5555,
/// <summary>
/// Flow test failed
/// </summary>
FlowTestFailed = 0xFF55,
//End of line / final test
/// <summary>
/// Final test failed, else the display will be switched to operational mode,
/// showing the actual accumulated volume
/// </summary>
FinalTestFailed = 0xFF66,
//FWUpdate
/// <summary>
/// FW update is ongoing
/// </summary>
FwUpdateActive = 0x8888,
/// <summary>
/// FW update failed
/// </summary>
FwUpdateFailed = 0xFF88,
/// <summary>
/// FW update succeeded
/// </summary>
FwUpToDate = 0x9999,
}
}
@@ -0,0 +1,35 @@
using System;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.DataPackages
{
public class FlowDeviations
{
/// <summary>
/// Flowrate for setting up the Pumps on bench
/// </summary>
public Double RequierdFlowQmPerH { get; set; }
/// <summary>
/// how long the flow should last
/// </summary>
public Double RequierdTimeS { get; set; }
/// <summary>
/// Corrected measurement of flowrate from Refrence meter
/// </summary>
public Double MeasuredRefFlowQmPerH { get; set; }
/// <summary>
/// how long the mesurement was running
/// </summary>
public Double RefTimeS { get; set; }
/// <summary>
/// Measurement of flowrate from DUT
/// </summary>
public Double MeasuredDutFlowQmPerH { get; set; }
/// <summary>
/// how long the mesurement was running for DUT
/// </summary>
public Double DutTimeS { get; set; }
}
}
@@ -0,0 +1,289 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Xylem.Common.Metrology.Measurements;
using Xylem.Common.Metrology.Measurements.Consts;
using DisplayCodes = TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.Consts.DisplayCodes;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore
{
/// <inheritdoc />
/// <summary>
/// IMeter is the highest level interface between a meter with direct communication to a test bench.
/// has general things like calibration, measurement and set up routines.
/// no specific meter stuff in here!
/// it is always disposable
/// </summary>
[Guid("7BD20046-DF8C-44A6-8F6B-687FAA26FA71")
, ComVisible(true)
, InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IMeter : IDisposable
{
#region events
/// <summary>
/// occurs when ProcessState has changed
/// </summary>
event EventHandler OnProcessStatusChanged;
/// <summary>
/// occurs when ErrorState has changed
/// </summary>
event EventHandler OnErrorStatusChanged;
/// <summary>
/// occurs when Init is completed
/// </summary>
event EventHandler OnInitCompleted;
/// <summary>
/// occurs when the initialization for Measurement is completed
/// </summary>
event EventHandler OnMeasurementInitCompleted;
/// <summary>
/// occurs when the Measurement is completed
/// </summary>
event EventHandler OnMeasurementCompleted;
/// <summary>
/// occurs when the initialization for calibration is completed
/// </summary>
event EventHandler OnCalibInitCompleted;
/// <summary>
/// occurs when the calibration is completed
/// </summary>
event EventHandler OnCalibCompleted;
/// <summary>
/// occurs when meter gets disposed
/// </summary>
event EventHandler OnDisposeCompleted;
#endregion
#region properties
/// <summary>
/// unique meter identification
/// </summary>
String SerialNumber { get; set; }
/// <summary>
/// read-only to see current Process state <see cref="ProcessState" />
/// </summary>
ProcessState ProcessStatus { get; }
/// <summary>
/// the current slot in test-bench
/// </summary>
Int32 Slot { get; set; }
/// <summary>
/// Setup of intermediate update time for measurement updates and overflow detections,
/// has to be calculated depending on flow-rate and nominal diameter (DN)
/// </summary>
Int32 IntermediateUpdateTimeS { get; set; }
/// <summary>
/// Skip the test bench preparation process
/// </summary>
Boolean SkipPreparationForTestBench { get; set; }
/// <summary>
/// Set the current action test
/// </summary>
String CurrentActionText { get; set; }
#endregion
#region method
/// <summary>
/// Read the PcbId from IMeter, if device has no readable PcbId simulate one
/// </summary>
/// <returns></returns>
String GetPcbId();
/// <summary>
/// Open Com ports, try some communication, login
/// </summary>
void ConnectMeter();
/// <summary>
/// Setup up meter from config file. just a workaround for vb6 calls. please do not use if your working with .net
/// </summary>
/// <param name="slot">Slot Number for Test bench</param>
/// <param name="ignoreCorruptedData">don´t send CRC error or telegrams with error flag to caller</param>
/// <param name="useRequest"></param>
/// <param name="useStreaming"></param>
void SetupFromConfigFile(Int32 slot, Boolean ignoreCorruptedData = true, Boolean useRequest = true, Boolean useStreaming = true);
/// <summary>
/// Logout from device
/// </summary>
Boolean Logout();
/// <summary>
/// Start Login with password service
/// </summary>
Boolean Login();
/// <summary>
/// Start Login without password service and a fixed password
/// </summary>
/// <param name="password">password for login</param>
/// <param name="runImmediately">execute immediately</param>
/// <param name="skipReadMeterFwAndAssignRegisters">skip app readout and register generation to speed up
/// the initial connection process</param>
Boolean Login(String password, Boolean runImmediately = true, Boolean skipReadMeterFwAndAssignRegisters = false);
/// <summary>
/// set up measurement parameter and set meter into test-mode
/// </summary>
void InitMeasurement();
/// <summary>
/// Starting a Measurement
/// Meter must be initialized <see cref="InitMeasurement" />
/// Start to receive record from meter and decode this record into <code>MeasurementRecord</code>
/// <see cref="IMeasurementRecord" />
/// </summary>
[ComVisible(false)]
void StartMeasurement();
/// <summary>
/// Meter must have a active measurement <see cref="StartMeasurement" />
/// Stop receive record from meter and decode record
/// </summary>
void StopMeasurement();
/// <remarks date="2018JAN09" author="drabesch">
/// - simplify the measurement results handling
/// - getting the main measurement of the entire device (combination of all paths)
/// - add MeasurementResult
/// - remove all other methods
/// </remarks>
/// <summary>
/// After a completed measurement , you can grab <see cref="MeasurementResults"/>
/// </summary>
/// <returns>Calculated results</returns>
MeasurementResults GetMainMeasurementResult(Double? refVolume, Double? refTimeS, Boolean intermediateMeasurement = false, MeasurementDirection dir = MeasurementDirection.TakeBoth);
/// <summary>
/// The first measurement is ALWAYS a FlowTestRecord.
/// </summary>
List<MeasurementResults> GetAllMeasurementResults(Double? refVolume, Double? refTimeS,
Boolean intermediateMeasurement = false, Int32? channel = null, MeasurementDirection dir = MeasurementDirection.TakeBoth);
/// <summary>
/// get current state of the running measurement
/// </summary>
/// <param name="onlyChannelNr">leave empty for an aggregate state for all measurements or pass the channel number to check</param>
/// <returns></returns>
MeasurementStates GetMeasurementState(Int32? onlyChannelNr = null );
/// <summary>
/// Request for intermediate measurement state.
/// </summary>
/// <param name="onlyChannelNr"></param>
/// <returns></returns>
Boolean RequestIntermediateMeasurementState(Int32? onlyChannelNr = null);
/// <summary>
/// set up calibration parameter (calibration factor to default) and set meter into calibration mode
/// </summary>
void InitCalibration();
/// <summary>
/// Starting a Calibration
/// Meter must be initialized <see cref="InitCalibration" />
/// Start to receive record from meter, decode and store this record
/// no <see cref="IMeasurementRecord" /> available
/// To finish calibration process run <see cref="StopCalibration" />
/// </summary>
[ComVisible(false)]
void StartCalibration();
/// <summary>
/// Meter must have an active Stop Record for calibration
/// </summary>
void StopCalibration();
/// <summary>
/// Get current state of the running calibration
/// </summary>
/// <returns></returns>
MeasurementStates GetCalibrationState();
/// <summary>
/// Calculate calibration factor for static and flying start / stop
/// Results kept internal and not being saved to meter.
/// if you want to store them on meter use <see cref="SetCalibFactorsAllChannels" />
/// </summary>
/// <param name="refVolumeCm">the reference volume is essential for calculation of calibration factor</param>
/// <param name="refTimeS">the reference time is needed for flying start/stop</param>
/// <param name="reqDeviationPercent">the required deviation to set the scale apart from 0</param>
/// <param name="maxCalibFactorTolerancePercent"> override the default max calibration factor tolerance</param>
void BuildAndCheckCalibFactorsAllChannels(Double refVolumeCm, Double? refTimeS = null, Double reqDeviationPercent = 0.0, Double maxCalibFactorTolerancePercent = 0.0);
/// <summary>
/// Save calculated calibration on meter if no calibration results available an exception occurred
/// </summary>
void SetCalibFactorsAllChannels(Boolean justLog = false);
/// <summary>
/// To control the LCD from meter for status information etc.
/// </summary>
/// <param name="release">if set to true the meter will show his normal screen, if set to false the next parameter will shown in display</param>
/// <param name="textInHex">test shown in LCD in byte array as hex value (0x33,0xFF shows 33FF on screen)</param>
void SetLcdText(Boolean release, Byte[] textInHex);
/// <summary>
/// Sets Display text and update production database
/// </summary>
/// <param name="newState">New ProductionState</param>
/// <param name="webRequest">web logging required per default true, for offline usage set to false</param>
void SetProcessState(DisplayCodes newState, Boolean webRequest = true);
/// <summary>
/// Get last Process State
/// </summary>
DisplayCodes GetLastProcessState();
/// <summary>
/// Add external text to internal log file handling
/// </summary>
/// <param name="text">text to log</param>
void WriteLog(String text);
/// <summary>
/// Enable/Disable Raw record Logging
/// </summary>
/// <param name="on">True = Write Raw record into log/ false = Stop write raw record into log </param>
void LogRawData(Boolean on);
/// <summary>
/// Check if the meter has any errors that can occur on a measurement
/// the error reason has find out in the log files
/// </summary>
/// <returns>false = everything is good, detect at least one error</returns>
Boolean CheckStateAfterMeasurement();
#endregion
/// <summary>
/// Clear all object set up on runtime
/// </summary>
void DisposeMeter();
/// <summary>
/// Dispose the entire test bench
/// </summary>
void TestBenchDispose();
}
}
@@ -0,0 +1,98 @@
using System;
using System.Runtime.InteropServices;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore
{
/// <summary>
/// Can hold various <see cref="TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.IMeter"/>s and hold connection record to relieve the meter.
/// Every contact with meter has to go over <see cref="IMeterBatch"/> even if you have just only one.
/// </summary>
[Guid("3E6F2741-00D3-42FC-9F86-09065D03E35B")
, ComVisible(true)
, InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IMeterBatch : IDisposable
{
/// <summary>
/// holds all <see cref="TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.IMeter"/>
/// Add <see cref="AddMeter"/> and delete with <see cref="RemoveMeter"/>
/// </summary>
void AddMeter(TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.IMeter meterToAdd);
/// <summary>
/// Remove Meter from batch and clear communication
/// </summary>
/// <param name="meterToRemove"> meter to be removed</param>
void RemoveMeter(TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.IMeter meterToRemove);
/// <summary>
/// Get meter from slot number.
/// </summary>
/// <param name="slot"></param>
/// <returns>null if slot has no genesis</returns>
TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.IMeter GetMeter(Int32 slot);
/// <summary>
/// Remove all Meters and comports
/// </summary>
void RemoveAllMeters();
/// <summary>
///
/// </summary>
/// <returns></returns>
TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.IMeter[] GetCurrentMeter();
/// <summary>
/// Detect all meters
/// </summary>
/// <returns></returns>
Int32[] GetCurrentMeterSlots();
/// <summary>
/// login to all meters
/// </summary>
void MetersLogin();
/// <summary>
/// Initialize all meters
/// </summary>
void MetersInit();
/// <summary>
/// Initialize calibration for all meters
/// </summary>
void MetersInitCalibration();
/// <summary>
/// Initialize measurement for all meters
/// </summary>
void MetersInitMeasurement();
/// <summary>
/// Store new calculated calibration to all meters
/// </summary>
void MetersSaveCalculatedCalibration();
/// <summary>
/// Start calibration for all meters
/// </summary>
void MetersStartCalibration();
/// <summary>
/// Start measurement for all meters
/// </summary>
void MetersStartMeasurement();
/// <summary>
/// Stop calibration of all meters
/// </summary>
void MetersStopCalibration();
/// <summary>
/// Stop measurements of all meters
/// </summary>
void MetersStopMeasurement();
}
}
@@ -0,0 +1,55 @@
using System;
using System.Runtime.InteropServices;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore
{
/// <summary>
/// Interface for <see cref="TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.IMeter"/> Events
/// you can use <see cref="IMeterEvents"/> without events (so with out <see cref="TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.IMeter"/>)
/// </summary>
[Guid("205F5E52-8929-4C69-B270-1B57FC3F5A92"), ComVisible(true)
, InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IMeterEvents
{
#region events
/// <summary>
/// occurs when ProcessState has changed
/// </summary>
event EventHandler OnProcessStatusChanged;
/// <summary>
/// occurs when ErrorState has changed
/// </summary>
event EventHandler OnErrorStatusChanged;
/// <summary>
/// occurs when Init is completed
/// </summary>
event EventHandler OnInitCompleted;
/// <summary>
/// occurs when the initializations for Measurement is completed
/// </summary>
event EventHandler OnMeasurementInitCompleted;
/// <summary>
/// occurs when the Measurement is completed
/// </summary>
event EventHandler OnMeasurementCompleted;
/// <summary>
/// occurs when the initializations for calibration is completed
/// </summary>
event EventHandler OnCalibInitCompleted;
/// <summary>
/// occurs when the calibration is completed
/// </summary>
event EventHandler OnCalibCompleted;
#endregion
}
}
@@ -0,0 +1,10 @@
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore
{
public enum MeasurementDirection
{
TakeBoth,
TakeOnlyForward,
TakeOnlyBackward,
}
}
@@ -0,0 +1,263 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using log4net;
using BatchCallConnectMeter = TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.BatchActions.BatchCallConnectMeter;
using BatchCallInitCalibration = TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.BatchActions.BatchCallInitCalibration;
using BatchCallInitMeasurement = TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.BatchActions.BatchCallInitMeasurement;
using BatchCallLogin = TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.BatchActions.BatchCallLogin;
using BatchCallSetCalibrationFactor = TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.BatchActions.BatchCallSetCalibrationFactor;
using BatchCallStartCalibration = TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.BatchActions.BatchCallStartCalibration;
using BatchCallStartMeasurement = TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.BatchActions.BatchCallStartMeasurement;
using BatchCallStopCalibration = TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.BatchActions.BatchCallStopCalibration;
using BatchCallStopMeasurement = TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.BatchActions.BatchCallStopMeasurement;
using IWaterMeterWithRegisters = TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.WaterMeterRegisters.IWaterMeterWithRegisters;
using MeterTypeRegisters = TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.WaterMeterRegisters.MeterTypeRegisters;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore
{
/// <summary>
/// Can hold various <see cref="TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.IMeter"/>s and hold connection record to relieve the meter.
/// Every contact with meter has to go over <see cref="MeterBatch"/> even if you have only one.
/// </summary>
[Guid("CC3D4FEF-3EA6-47B2-9916-6F9AD4AE1F4B"),
ComVisible(true),
ClassInterface(ClassInterfaceType.None),
ComSourceInterfaces(typeof(TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.IMeterBatch))]
public class MeterBatch : TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.IMeterBatch
{
private readonly List<MeterTypeRegisters> _meterTypeRegistersCollection = new List<MeterTypeRegisters>();
private static readonly ILog _logger = LogManager.GetLogger(typeof(MeterBatch));
private readonly String _sourceLocation;
/// <summary>
/// ctor
/// </summary>
public MeterBatch(String sourceLocation = "")
{
_sourceLocation = sourceLocation;
_logger.Info("Meter batch created");
}
private readonly List<TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.IMeter> _listOfMeters = new List<TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.IMeter>();
/// <summary>
/// Registered list of meters
/// </summary>
public List<TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.IMeter> ListOfMeters => _listOfMeters;
/// <inheritdoc />
public void AddMeter(TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.IMeter meterToAdd)
{
_logger.Info($"Slot:{meterToAdd.Slot} - Meter assigned to batch");
var add = meterToAdd as IWaterMeterWithRegisters;
if (add != null)
{
AddMeterTypeToBatch(add);
}
_listOfMeters.Add(meterToAdd);
meterToAdd.ConnectMeter();
}
private void AddMeterTypeToBatch(IWaterMeterWithRegisters meterToAdd)
{
if (_meterTypeRegistersCollection.All(mtr => mtr.MeterType == meterToAdd.GetType()))
{
_meterTypeRegistersCollection.Add(new MeterTypeRegisters(meterToAdd.GetType()));
meterToAdd.LoadConfiguration(!string.IsNullOrEmpty(_sourceLocation) ? _sourceLocation : Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)));
}
}
//private void AddMeterTypeToBatch(IWaterMeterWithRegisters meterToAdd)
//{
// if (_meterTypeRegistersCollection.All(mtr => mtr.MeterType == meterToAdd.GetType()))
// {
// _meterTypeRegistersCollection.Add(new MeterTypeRegisters(meterToAdd.GetType(),
// meterToAdd.LoadConfiguration()));
// }
// List<IRegister> allRegisters =
// _meterTypeRegistersCollection.First(f => f.MeterType == meterToAdd.GetType()).Registers;
// if (allRegisters == null || !allRegisters.Any())
// {
// throw new ApplicationException($"No valid RegisterConfiguration found for meter type {meterToAdd.GetType()}. Check Configuration");
// }
// meterToAdd.SetConfigRegisterDefinitions(allRegisters);
//}
/// <inheritdoc />
public TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.IMeter[] GetCurrentMeter()
{
if (_listOfMeters == null || _listOfMeters.Count == 0)
{
return new TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.IMeter[0];
}
return _listOfMeters.ToArray();
}
/// <inheritdoc />
public Int32[] GetCurrentMeterSlots()
{
if (_listOfMeters == null || _listOfMeters.Count == 0)
{
return new Int32[0];
}
var ret = new Int32[_listOfMeters.Count];
for (var i = 0; i < _listOfMeters.Count; i++)
{
ret[i] = _listOfMeters[i].Slot;
}
return ret;
}
/// <inheritdoc />
public void RemoveMeter(TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.IMeter meterToRemove)
{
meterToRemove?.DisposeMeter();
_listOfMeters.Remove(meterToRemove);
_logger.Info($"Slot:{ meterToRemove?.Slot} - Meter removed from batch");
}
/// <inheritdoc />
public void MetersLogin()
{
_logger.Info("Batch call Login to all meters");
var batchCall = new BatchCallLogin();
batchCall.RunAction(ListOfMeters);
}
/// <inheritdoc />
public void MetersInit()
{
_logger.Info("Batch call to init all meters");
var batchCall = new BatchCallConnectMeter();
batchCall.RunAction(ListOfMeters);
}
/// <inheritdoc />
public void MetersInitCalibration()
{
_logger.Info("Batch call to init calibration all meters");
var batchCall = new BatchCallInitCalibration();
batchCall.RunAction(ListOfMeters);
}
/// <inheritdoc />
public void MetersInitMeasurement()
{
_logger.Info("Batch call to init measurement all meters");
var batchCall = new BatchCallInitMeasurement();
batchCall.RunAction(ListOfMeters);
}
/// <inheritdoc />
public void MetersSaveCalculatedCalibration()
{
_logger.Info("Batch call to save calculated calibration on all meters");
var batchCall = new BatchCallSetCalibrationFactor();
batchCall.RunAction(ListOfMeters);
}
/// <inheritdoc />
public void MetersStartCalibration()
{
_logger.Info("Batch call to start calibration on all meters");
var batchCall = new BatchCallStartCalibration();
batchCall.RunAction(ListOfMeters);
}
/// <inheritdoc />
public void MetersStartMeasurement()
{
_logger.Info("Batch call to start measurement on all meters");
var batchCall = new BatchCallStartMeasurement();
batchCall.RunAction(ListOfMeters);
}
/// <inheritdoc />
public void MetersStopCalibration()
{
_logger.Info("Batch call to stop calibration on all meters");
var batchCall = new BatchCallStopCalibration();
batchCall.RunAction(ListOfMeters);
}
/// <inheritdoc />
public void MetersStopMeasurement()
{
_logger.Info("Batch call to stop measurement on all meters");
var batchCall = new BatchCallStopMeasurement();
batchCall.RunAction(ListOfMeters);
}
/// <inheritdoc />
public TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.IMeter GetMeter(Int32 slot)
{
return ListOfMeters.Find(f => f.Slot == slot);
}
/// <inheritdoc />
public void RemoveAllMeters()
{
try
{
foreach (var item in ListOfMeters)
{
_logger.Info($"Slot:{ item.Slot} - Meter disposed");
item.DisposeMeter();
}
ListOfMeters.Clear();
}
catch (Exception ex)
{
_logger.Error("Error on RemoveAllMeters, prop. not all comports are closed",ex);
}
}
/// <inheritdoc />
public void Dispose()
{
try
{
_logger.Info("Dispose batch");
RemoveAllMeters();
GC.Collect();
}
catch (Exception ex)
{
_logger.Error("Error on batch disposing, possible comport error",ex);
}
}
public void DisposeTestBench()
{
_logger.Info("Dispose batch make sure green LED is off");
var batchCall = new BatchCallStopMeasurement();
batchCall.RunAction(ListOfMeters);
}
}
}
@@ -0,0 +1,9 @@
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore
{
public enum MeterTypes
{
Cordonel,
MagFlux,
eRegister,
}
}
@@ -0,0 +1,21 @@
using System;
using System.IO.Ports;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore
{
/// <summary>
/// holds port connection information
/// is used for all <see cref="IPort"/>
/// </summary>
public class PortConfig
{
/// <summary>
/// using dotNets <see cref="SerialPort"/> for connection
/// </summary>
public SerialPort SerialPort;
/// <summary>
/// Command Separator
/// </summary>
public Type SerialPortType;
}
}
@@ -0,0 +1,16 @@
using System;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.WaterMeterRegisters
{
/// <summary>
/// Register interface description
/// </summary>
public interface IRegister : IComparable
{
/// <summary>
/// Build the register identification out of application- and register-name
/// </summary>
/// <returns></returns>
String GetIdent();
}
}
@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.WaterMeterRegisters
{
/// <summary>
/// Water meter with registers
/// </summary>
public interface IWaterMeterWithRegisters
{
/// <summary>
/// Assigning configuration.json register definitions to meter
/// </summary>
/// <param name="allRegisters"></param>
void SetConfigRegisterDefinitions(List<TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.WaterMeterRegisters.IRegister> allRegisters);
/// <summary>
/// Load registers from configuration.json file
/// </summary>
/// <param name="location"></param>
void LoadConfiguration(String location);
}
}
@@ -0,0 +1,38 @@
using System;
namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Genesis.WaterMeterCore.WaterMeterRegisters
{
/// <summary>
/// a meter type which contains registers
/// </summary>
public class MeterTypeRegisters
{
/// <summary>
/// meter type
/// </summary>
public readonly Type MeterType;
///// <summary>
///// ctor, sets meter type and references registers is already assigned
///// </summary>
///// <param name="meterType"></param>
///// <param name="registers"></param>
//public MeterTypeRegisters(Type meterType, List<IRegister> registers)
//{
// if (registers == null || !registers.Any())
// {
// registers = new List<IRegister>();
// }
// Registers = registers;
// MeterType = meterType;
//}
/// <summary>
/// ctor, sets meter type and references registers is already assigned
/// </summary>
/// <param name="meterType"></param>
public MeterTypeRegisters(Type meterType)
{
MeterType = meterType;
}
}
}
@@ -227,20 +227,6 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.communication.Utils
return _serialPort.ReadExisting(); return _serialPort.ReadExisting();
} }
public void ResetInputBuffer()
{
if (!IsOpen)
throw new InvalidOperationException("Serial port not open");
_serialPort.DiscardInBuffer();
}
public void ResetOutputBuffer()
{
if (!IsOpen)
throw new InvalidOperationException("Serial port not open");
_serialPort.DiscardOutBuffer();
}
public Encoding Encoding => _serialPort?.Encoding ?? _encoding; public Encoding Encoding => _serialPort?.Encoding ?? _encoding;
public int BytesToRead => (_serialPort != null && _serialPort.IsOpen) ? _serialPort.BytesToRead : 0; public int BytesToRead => (_serialPort != null && _serialPort.IsOpen) ? _serialPort.BytesToRead : 0;
@@ -110,7 +110,6 @@ namespace TBF.Rig.RegisterReaders.GenesisRegReader.implementations
{ {
Flush = 0, Flush = 0,
ProcessAndSave, ProcessAndSave,
CalculateStoredData,
} }
public enum CommunicationInterface public enum CommunicationInterface
File diff suppressed because it is too large Load Diff
@@ -13,29 +13,46 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
{ {
public class CliRunner public class CliRunner
{ {
//static readonly ILog log = LogManager.GetLogger(typeof(CliRunner));
private readonly ILog log; private readonly ILog log;
private readonly List<CliTaskInfo> taskPool = new List<CliTaskInfo>(); private List<Task> taskPool = new List<Task>();
private long startTimeMs; private long startTime;
private long incommingTimeMs; private long incommingTime;
public List<CliTaskInfo> TaskPool public List<Task> TaskPool { get { return taskPool; } }
public void AddTask(Task task) { taskPool.Add(task); }
public void WaitAll() { Task.WaitAll(taskPool.ToArray()); }
public void Clear() { taskPool.Clear(); }
public void CancelAll() { Task.WhenAll(taskPool).ContinueWith(t => { }); }
public void StartAll()
{ {
get { return taskPool; } taskPool.ForEach(t => t.Start());
}
public bool AreTasksDone()
{
return taskPool.All(task => task.IsCompleted);
} }
public long StartTime public long StartTime
{ {
get { return startTimeMs; } get => startTime;
} }
public long IncommingTime public long IncommingTime
{ {
get { return incommingTimeMs; } get => incommingTime;
}
public bool TimeOutReceived(long timeout)
{
return (DateTime.Now.Ticks - startTime) > timeout;
} }
public CliRunner(bool isCliLogging) public CliRunner(bool isCliLogging)
{ {
ResetStartTime(); startTime = DateTime.Now.Ticks;
if (isCliLogging) if (isCliLogging)
{ {
@@ -43,180 +60,42 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
{ {
log = new ScopedLoggerFactory().CreateLogger<CliRunner>( log = new ScopedLoggerFactory().CreateLogger<CliRunner>(
@"C:\TBF\Logs\CliRunner.txt", @"C:\TBF\Logs\CliRunner.txt",
10, 10, // maxFileSizeMB
7, 7, // maxBackups
log4net.Core.Level.Debug, log4net.Core.Level.Debug,
true, true, // zipRolledFiles
true, true, // singleZipPerDay
TimeSpan.FromMinutes(2) TimeSpan.FromMinutes(2) // zipScanInterval
); );
} }
catch (Exception ex) catch (Exception ex)
{ {
// Fallback to console or handle gracefully
Console.WriteLine($"Failed to initialize logger: {ex.Message}"); Console.WriteLine($"Failed to initialize logger: {ex.Message}");
} }
} }
} }
public void ResetStartTime() /// <summary>
{ ///
startTimeMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); /// </summary>
} /// <param name="fileName"></param>
/// <param name="args"></param>
public void Clear() /// <typeparam name="T"></typeparam>
{
foreach (var item in taskPool)
{
try
{
item?.Cts?.Dispose();
}
catch
{
}
try
{
if (item?.Process != null)
{
item.Process.Dispose();
}
}
catch
{
}
}
taskPool.Clear();
}
public void WaitAll()
{
var tasks = taskPool
.Where(t => t != null && t.Task != null)
.Select(t => t.Task)
.ToArray();
if (tasks.Length == 0)
return;
try
{
Task.WaitAll(tasks);
}
catch (AggregateException)
{
RefreshTaskStates();
}
}
public bool AreTasksDone()
{
RefreshTaskStates();
return taskPool.Count > 0 && taskPool.All(t => t.State != CliTaskState.Running);
}
public bool TimeOutReceived(long timeoutMs)
{
long nowMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
return (nowMs - startTimeMs) > timeoutMs;
}
public void RefreshTaskStates()
{
foreach (var item in taskPool)
{
if (item == null || item.Task == null)
continue;
if (item.State == CliTaskState.TimedOut)
continue;
if (!item.Task.IsCompleted)
{
item.State = CliTaskState.Running;
}
else if (item.Task.IsCanceled)
{
item.State = CliTaskState.Canceled;
}
else if (item.Task.IsFaulted)
{
item.State = CliTaskState.Faulted;
}
else
{
item.State = CliTaskState.Completed;
}
}
}
public void CancelUndoneTasksAsTimedOut()
{
foreach (var item in taskPool)
{
if (item == null || item.Task == null)
continue;
if (item.Task.IsCompleted)
{
if (item.Task.IsCanceled)
item.State = CliTaskState.Canceled;
else if (item.Task.IsFaulted)
item.State = CliTaskState.Faulted;
else
item.State = CliTaskState.Completed;
continue;
}
item.State = CliTaskState.TimedOut;
try
{
item.Cts?.Cancel();
}
catch (Exception ex)
{
log?.Warn("Cancel token failed", ex);
}
try
{
if (item.Process != null && !item.Process.HasExited)
{
item.Process.Kill();
}
}
catch (Exception ex)
{
log?.Warn("Kill process failed", ex);
}
}
}
public void AddSendAsync(SerialPortData data, SerialPortData.EMeterArg eMeterArg) public void AddSendAsync(SerialPortData data, SerialPortData.EMeterArg eMeterArg)
{ {
AddSendAsync(data.SerialPortCmdClientPath, data.DefaultArgSettings(eMeterArg)); var task = SendAsync(data.SerialPortCmdClientPath, data.DefaultArgSettings(eMeterArg));
taskPool.Add(task);
} }
public void AddSendAsync(string fileName, string args) public void AddSendAsync(string fileName, string args)
{ {
ResetStartTime(); var task = SendAsync(fileName, args);
taskPool.Add(task);
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)
public async Task<string> SendAsync(string fileName, string args, CancellationToken ct = default)
{ {
var psi = new ProcessStartInfo var psi = new ProcessStartInfo
{ {
@@ -228,84 +107,41 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
CreateNoWindow = true CreateNoWindow = true
}; };
using (var process = new Process { StartInfo = psi, EnableRaisingEvents = true }) using var process = new Process { StartInfo = psi, EnableRaisingEvents = true };
process.Start();
Task<string> stdOutTask = process.StandardOutput.ReadToEndAsync();
Task<string> stdErrTask = process.StandardError.ReadToEndAsync();
try
{ {
info.Process = process; await Task.WhenAll(stdOutTask, stdErrTask, process.WaitForExitAsync(ct));
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();
string allOutput = (stdOutTask.Result ?? "") + (stdErrTask.Result ?? "");
log?.Debug(allOutput);
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;
}
} }
catch (OperationCanceledException)
{
if (!process.HasExited)
{
process.Kill();
}
throw;
}
//comming answer from serial port - good place for time stamp
incommingTime = DateTime.Now.Ticks;
string allOutput = (stdOutTask.Result ?? "") + (stdErrTask.Result ?? "");
log?.Debug(allOutput);
return allOutput;
} }
public void AddRunAndCaptureJsonAsync<T>(SerialPortData data, SerialPortData.EMeterArg eMeterArg) where T : new() public void AddRunAndCaptureJsonAsync<T>(SerialPortData data, SerialPortData.EMeterArg eMeterArg) where T : new()
{ {
AddRunAndCaptureJsonAsync<T>( var task = RunAndCaptureJsonAsync<T>(data.SerialPortCmdClientPath, data.DefaultArgSettings(eMeterArg));
data.SerialPortCmdClientPath, taskPool.Add(task);
data.DefaultArgSettings(eMeterArg));
} }
public void AddRunAndCaptureJsonAsync<T>(string fileName, string args) where T : new() public async Task<T> RunAndCaptureJsonAsync<T>(string fileName, string args, CancellationToken ct = default) where T : new()
{
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 var psi = new ProcessStartInfo
{ {
@@ -317,121 +153,80 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
CreateNoWindow = true CreateNoWindow = true
}; };
using (var process = new Process { StartInfo = psi, EnableRaisingEvents = true }) using var process = new Process { StartInfo = psi, EnableRaisingEvents = true };
{ process.Start();
info.Process = process;
try var stdoutTask = process.StandardOutput.ReadToEndAsync();
{ var stderrTask = process.StandardError.ReadToEndAsync();
process.Start();
var stdoutTask = process.StandardOutput.ReadToEndAsync(); await Task.WhenAll(stdoutTask, stderrTask, process.WaitForExitAsync(ct));
var stderrTask = process.StandardError.ReadToEndAsync();
try string allOutput = (stdoutTask.Result ?? "") + (stderrTask.Result ?? "");
{ log?.Debug(allOutput);
await Task.WhenAll(stdoutTask, stderrTask, process.WaitForExitAsync(ct));
}
catch (OperationCanceledException)
{
if (info.State != CliTaskState.TimedOut)
info.State = CliTaskState.Canceled;
if (!process.HasExited) string json = ExtractJson(allOutput);
{ if (TryJsonStringDeserialize(json, out T result)) return result;
process.Kill(); return default;
}
throw;
}
incommingTimeMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
string allOutput = (stdoutTask.Result ?? "") + (stderrTask.Result ?? "");
log?.Debug(allOutput);
string json = ExtractJson(allOutput);
T result;
if (TryJsonStringDeserialize(json, out result))
{
info.State = CliTaskState.Completed;
return result;
}
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() public bool TryJsonStringDeserialize<T>(string json, out T runAndCaptureJsonAsync) where T : new()
{ {
if (json != null) if (json != null)
{ {
try try
{ {
value = JsonConvert.DeserializeObject<T>(json); runAndCaptureJsonAsync = JsonConvert.DeserializeObject<T>(json);
return true; return true;
} }
catch (Exception ex) catch (Exception ex)
{ {
log?.Debug(ex.Message); log.Debug(ex.Message);
value = TryConvert<T>(json); runAndCaptureJsonAsync = TryConvert<T>(json);
return true; return true;
} }
} }
value = default(T); runAndCaptureJsonAsync = default;
return false; return false;
} }
private static T TryConvert<T>(string json) where T : new() private static T TryConvert<T>(string json) where T : new()
{ {
T obj = new T();
try T obj = new T();
{
JObject jObject = JObject.Parse(json);
foreach (PropertyInfo prop in typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance)) try
{ {
if (!prop.CanWrite) JObject jObject = JObject.Parse(json);
continue;
JToken token; foreach (PropertyInfo prop in typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance))
if (jObject.TryGetValue(prop.Name, StringComparison.OrdinalIgnoreCase, out token))
{ {
try if (!prop.CanWrite) continue;
{
object value = token.ToObject(prop.PropertyType); JToken token;
prop.SetValue(obj, value); if (jObject.TryGetValue(prop.Name, StringComparison.OrdinalIgnoreCase, out token))
}
catch
{ {
try
{
object value = token.ToObject(prop.PropertyType);
prop.SetValue(obj, value);
}
catch
{
// leave default if conversion fails
}
} }
// else → keep default value
} }
} }
} catch (Exception ex)
catch (Exception ex) {
{ Console.WriteLine($"TryConvert failed: {ex.Message}");
Console.WriteLine($"TryConvert failed: {ex.Message}"); }
}
return obj;
return obj;
} }
public string ExtractJson(string text) public string ExtractJson(string text)
@@ -446,20 +241,6 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
return null; return null;
} }
internal void AddTaskForTest(Task task, string name = "TestTask", CancellationTokenSource cts = null)
{
taskPool.Add(new CliTaskInfo
{
Task = task,
Cts = cts,
Name = name,
State = task.IsCompleted
? (task.IsCanceled ? CliTaskState.Canceled :
task.IsFaulted ? CliTaskState.Faulted :
CliTaskState.Completed)
: CliTaskState.Running
});
}
} }
} }
@@ -1,25 +0,0 @@
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
{
public class CliTaskInfo
{
public Task Task { get; set; }
public CancellationTokenSource Cts { get; set; }
public Process Process { get; set; }
public CliTaskState State { get; set; } = CliTaskState.Running;
public string Name { get; set; }
public bool UseResult
{
get
{
return State == CliTaskState.Completed
&& Task != null
&& Task.Status == TaskStatus.RanToCompletion;
}
}
}
}
@@ -1,13 +0,0 @@
namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
{
public enum CliTaskState
{
Running,
Completed,
TimedOut,
Canceled,
Faulted
}
}

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