feat(asic, poseidon): add optical diagnostic logging, enhanced debug controls, and ASIC/Poseidon configuration updates

This commit is contained in:
2026-09-29 12:38:57 +02:00
parent 161b20fea7
commit 21324985db
33 changed files with 965 additions and 13 deletions
+2 -2
View File
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// Build Number
// Revision
//
[assembly: AssemblyVersion("3.9.3145.0")]
[assembly: AssemblyFileVersion("3.9.3145.0")]
[assembly: AssemblyVersion("3.9.3147.0")]
[assembly: AssemblyFileVersion("3.9.314.0")]
@@ -38,6 +38,7 @@ namespace TBF.Rig.RegisterReaders.AllyReader
private readonly List<AllyOpticalSample> opticalSamples = new List<AllyOpticalSample>();
private readonly Queue<string> pendingOpticalLines = new Queue<string>();
private readonly AllyOpticalDiagnosticWriter opticalDiagnosticWriter = new AllyOpticalDiagnosticWriter();
private readonly AllyReaderCfg allyCfg;
private IAllyTransport commandTransport;
private AllyCommandService commandService;
@@ -794,6 +795,29 @@ namespace TBF.Rig.RegisterReaders.AllyReader
});
}
private void CaptureOpticalDiagnostic(string line, DateTime receivedUtc, string status,
AllyOpticalSample sample, AllyOpticalTelegramRaw telegram)
{
if (allyCfg == null || !allyCfg.EnableDetailedLogPerWM) return;
opticalDiagnosticWriter.Write(true, allyCfg.OpticalDiagnosticFormat,
allyCfg.RawOpticalDataFormat, allyCfg.IncludeParsedValues,
Sequences.ProcessData.BatchNr, Position > 0 ? Position.ToString() : Name,
Name, SerialNr, receivedUtc, "OpticalText/0x" + ((byte)activeOpticalOutputMode).ToString("X2"),
status, Encoding.ASCII.GetBytes(line), line,
telegram == null ? (object)null : telegram.Counter,
sample == null ? (object)null : sample.Sequence,
sample == null ? (object)null : sample.RawFlow,
sample == null ? (object)null : sample.RawVolume,
telegram == null ? (object)null : telegram.VolumeRawExtended,
telegram == null ? (object)null : telegram.VolumeDeltaRaw,
telegram == null ? (object)null : sample.ExtendedVolumeLiters,
null, // Meter time is not supplied by the ALLY C6 payload.
telegram == null ? (object)null : telegram.ElapsedSeconds,
telegram == null ? status : telegram.Flags.ToString(),
sample == null ? (object)null : sample.IsEmptyPipe,
sample == null ? (object)null : sample.IsFastHptc);
}
private void ProcessOpticalText(string text)
{
ProcessOpticalText(text, DateTime.UtcNow);
@@ -831,6 +855,7 @@ namespace TBF.Rig.RegisterReaders.AllyReader
// either format as the known C2 layout.
if (activeOpticalOutputMode != AllyOpticalOutputMode.LegacyC2)
{
CaptureOpticalDiagnostic(line, receivedAtUtc, "UnparsedMode", null, null);
allyLog.InfoFormat(
"ALLY_OPTO RAW CANDIDATE; mode=0x{0:X2}; port=COM{1}; bytes={2}; ascii='{3}'; hex={4}",
(byte)activeOpticalOutputMode,
@@ -844,6 +869,7 @@ namespace TBF.Rig.RegisterReaders.AllyReader
AllyOpticalSample sample;
if (!AllyOpticalSample.TryParse(line, receivedAtUtc, out sample))
{
CaptureOpticalDiagnostic(line, receivedAtUtc, "ParseRejected", null, null);
if (AllyOpticalSample.IsMetrologyPacket(line))
{
rejectedOpticalTelegramCount++;
@@ -875,6 +901,7 @@ namespace TBF.Rig.RegisterReaders.AllyReader
uint previousRawVolumeBefore = previousRawVolume;
if (!TryExtendRawVolume(sample.RawVolume, sample.RawFlow, out volumeDeltaRaw, out volumeRollover))
{
CaptureOpticalDiagnostic(line, receivedAtUtc, "BackwardAccumulatorRejected", sample, null);
rejectedOpticalTelegramCount++;
allyLog.WarnFormat(
"ALLY_OPTO VOLUME REJECTED; telegram=#{0}; port=COM{1}; sequence=0x{2:X2}; rawVolume=0x{3:X8}; rawFlow={4}; previousRawVolume=0x{5:X8}; reason=backward-accumulator",
@@ -937,7 +964,9 @@ namespace TBF.Rig.RegisterReaders.AllyReader
allyLog.InfoFormat("ALLY_OPTO TEST START; telegram=#{0}; volumeL={1:F6}; elapsedHostS={2:F3}", rawTelegram.Counter, rawTelegram.VolumeLiters, rawTelegram.ElapsedSeconds);
}
allyLog.Info(rawTelegram.ToLogRecord());
CaptureOpticalDiagnostic(line, receivedAtUtc, "Accepted", sample, rawTelegram);
if (allyCfg == null || !allyCfg.EnableDetailedLogPerWM)
allyLog.Info(rawTelegram.ToLogRecord());
log.DebugFormat(
"ALLY_OPTO parsed COM{0}: sequence=0x{1:X2}, rawVolume=0x{2:X8}, flow={3}, volume={4:F6} l, elapsed={5:F3} s, emptyPipe={6}, fastHptc={7}",
@@ -17,6 +17,10 @@ namespace TBF.Rig.RegisterReaders.AllyReader
public int OptoBaudRate;
public AllyMeterSize ConfiguredMeterSize;
public double MeterPulsesPerLiter;
public bool EnableDetailedLogPerWM;
public string OpticalDiagnosticFormat;
public string RawOpticalDataFormat;
public bool IncludeParsedValues;
private AllyReaderCfg()
{
@@ -50,6 +54,10 @@ namespace TBF.Rig.RegisterReaders.AllyReader
OptoBaudRate = 9600;
ConfiguredMeterSize = AllyMeterSize.AutoDetect;
MeterPulsesPerLiter = 1000D;
EnableDetailedLogPerWM = false;
OpticalDiagnosticFormat = "Csv";
RawOpticalDataFormat = "Hex";
IncludeParsedValues = true;
}
public int ParamsCount()
@@ -185,6 +193,10 @@ namespace TBF.Rig.RegisterReaders.AllyReader
OptoBaudRate = OptoBaudRate,
ConfiguredMeterSize = ConfiguredMeterSize,
MeterPulsesPerLiter = MeterPulsesPerLiter
,EnableDetailedLogPerWM = EnableDetailedLogPerWM
,OpticalDiagnosticFormat = OpticalDiagnosticFormat
,RawOpticalDataFormat = RawOpticalDataFormat
,IncludeParsedValues = IncludeParsedValues
};
}
}
@@ -6,7 +6,7 @@ namespace TBF.Rig.RegisterReaders.AllyReader
protected override void Dispose(bool disposing) { if (disposing && components != null) components.Dispose(); base.Dispose(disposing); }
private void InitializeComponent()
{
tabControl1 = new System.Windows.Forms.TabControl(); tabPage1 = new System.Windows.Forms.TabPage(); tabPage2 = new System.Windows.Forms.TabPage();
tabControl1 = new System.Windows.Forms.TabControl(); tabPage1 = new System.Windows.Forms.TabPage(); tabPage2 = new System.Windows.Forms.TabPage(); tabPage3 = new System.Windows.Forms.TabPage(); logsCfgCtrl = new AllyReaderLogsCfgCtrl();
classNameLabel = new System.Windows.Forms.Label(); nameLabel = new System.Windows.Forms.Label(); nameTextBox = new System.Windows.Forms.TextBox();
muxBoardNrLabel = new System.Windows.Forms.Label(); muxBoardNrTextBox = new System.Windows.Forms.TextBox(); label3 = new System.Windows.Forms.Label();
groupLabel = new System.Windows.Forms.Label(); groupTextBox = new System.Windows.Forms.TextBox(); label4 = new System.Windows.Forms.Label();
@@ -15,7 +15,7 @@ namespace TBF.Rig.RegisterReaders.AllyReader
groupBox1 = new System.Windows.Forms.GroupBox(); label1 = new System.Windows.Forms.Label(); comboBoxCommunicationInterface = new System.Windows.Forms.ComboBox(); rfidSerialPortNrLabel = new System.Windows.Forms.Label(); rfidPortNrTextBox = new System.Windows.Forms.TextBox();
groupBox2 = new System.Windows.Forms.GroupBox(); label2 = new System.Windows.Forms.Label(); headPortNrTextBox = new System.Windows.Forms.TextBox();
tabControl1.SuspendLayout(); tabPage1.SuspendLayout(); optoDataGroupBox.SuspendLayout(); groupBox1.SuspendLayout(); groupBox2.SuspendLayout(); SuspendLayout();
tabControl1.Controls.Add(tabPage1); tabControl1.Controls.Add(tabPage2); tabControl1.Location = new System.Drawing.Point(3,3); tabControl1.Name="tabControl1"; tabControl1.SelectedIndex=0; tabControl1.Size=new System.Drawing.Size(611,432);
tabControl1.Controls.Add(tabPage1); tabControl1.Controls.Add(tabPage2); tabControl1.Controls.Add(tabPage3); tabControl1.Location = new System.Drawing.Point(3,3); tabControl1.Name="tabControl1"; tabControl1.SelectedIndex=0; tabControl1.Size=new System.Drawing.Size(611,432);
tabPage1.Controls.Add(groupBox2); tabPage1.Controls.Add(label4); tabPage1.Controls.Add(label3); tabPage1.Controls.Add(groupBox1); tabPage1.Controls.Add(optoDataGroupBox); tabPage1.Controls.Add(groupTextBox); tabPage1.Controls.Add(groupLabel); tabPage1.Controls.Add(muxBoardNrTextBox); tabPage1.Controls.Add(muxBoardNrLabel); tabPage1.Controls.Add(nameTextBox); tabPage1.Controls.Add(nameLabel); tabPage1.Controls.Add(classNameLabel); tabPage1.Location=new System.Drawing.Point(4,25); tabPage1.Name="tabPage1"; tabPage1.Padding=new System.Windows.Forms.Padding(3); tabPage1.Size=new System.Drawing.Size(603,403); tabPage1.Text="Config"; tabPage1.UseVisualStyleBackColor=true;
classNameLabel.AutoSize=true; classNameLabel.Location=new System.Drawing.Point(149,11); classNameLabel.Name="classNameLabel"; classNameLabel.Text="ClassName";
nameLabel.AutoSize=true; nameLabel.Location=new System.Drawing.Point(6,44); nameLabel.Name="nameLabel"; nameLabel.Text="Name";
@@ -44,8 +44,10 @@ namespace TBF.Rig.RegisterReaders.AllyReader
label2.AutoSize=true; label2.Location=new System.Drawing.Point(321,18); label2.Name="label2"; label2.Text="Serial port nr.:";
headPortNrTextBox.Enabled=false; headPortNrTextBox.Location=new System.Drawing.Point(439,15); headPortNrTextBox.Name="headPortNrTextBox"; headPortNrTextBox.Size=new System.Drawing.Size(44,22);
tabPage2.Location=new System.Drawing.Point(4,25); tabPage2.Name="tabPage2"; tabPage2.Padding=new System.Windows.Forms.Padding(3); tabPage2.Size=new System.Drawing.Size(603,403); tabPage2.Text="Test"; tabPage2.UseVisualStyleBackColor=true;
tabPage3.Controls.Add(logsCfgCtrl); tabPage3.Location=new System.Drawing.Point(4,25); tabPage3.Name="tabPage3"; tabPage3.Padding=new System.Windows.Forms.Padding(3); tabPage3.Size=new System.Drawing.Size(603,403); tabPage3.Text="Logs"; tabPage3.UseVisualStyleBackColor=true;
logsCfgCtrl.Location=new System.Drawing.Point(-4,-4); logsCfgCtrl.Name="logsCfgCtrl"; logsCfgCtrl.Size=new System.Drawing.Size(611,432);
AutoScaleDimensions=new System.Drawing.SizeF(8F,16F); AutoScaleMode=System.Windows.Forms.AutoScaleMode.Font; Controls.Add(tabControl1); Margin=new System.Windows.Forms.Padding(4); Name="AllyReaderCfgCtrl"; Size=new System.Drawing.Size(617,438); tabControl1.ResumeLayout(false); tabPage1.ResumeLayout(false); tabPage1.PerformLayout(); optoDataGroupBox.ResumeLayout(false); optoDataGroupBox.PerformLayout(); groupBox1.ResumeLayout(false); groupBox1.PerformLayout(); groupBox2.ResumeLayout(false); groupBox2.PerformLayout(); ResumeLayout(false);
}
private System.Windows.Forms.TabControl tabControl1; private System.Windows.Forms.TabPage tabPage1; private System.Windows.Forms.TabPage tabPage2; private System.Windows.Forms.Label classNameLabel,nameLabel,muxBoardNrLabel,groupLabel,label1,label2,label3,label4,ipAddressLabel,tcpipPortLabel,optoSerialPortLabel,rfidSerialPortNrLabel; private System.Windows.Forms.TextBox nameTextBox,muxBoardNrTextBox,groupTextBox,ipAddressTextBox,tcpipPortTextBox,optoSerialPortTextBox,rfidPortNrTextBox,headPortNrTextBox; private System.Windows.Forms.GroupBox optoDataGroupBox,groupBox1,groupBox2; private System.Windows.Forms.RadioButton radioButton1,radioButton2; private System.Windows.Forms.ComboBox comboBoxCommunicationInterface;
private System.Windows.Forms.TabControl tabControl1; private System.Windows.Forms.TabPage tabPage1; private System.Windows.Forms.TabPage tabPage2; private System.Windows.Forms.TabPage tabPage3; private AllyReaderLogsCfgCtrl logsCfgCtrl; private System.Windows.Forms.Label classNameLabel,nameLabel,muxBoardNrLabel,groupLabel,label1,label2,label3,label4,ipAddressLabel,tcpipPortLabel,optoSerialPortLabel,rfidSerialPortNrLabel; private System.Windows.Forms.TextBox nameTextBox,muxBoardNrTextBox,groupTextBox,ipAddressTextBox,tcpipPortTextBox,optoSerialPortTextBox,rfidPortNrTextBox,headPortNrTextBox; private System.Windows.Forms.GroupBox optoDataGroupBox,groupBox1,groupBox2; private System.Windows.Forms.RadioButton radioButton1,radioButton2; private System.Windows.Forms.ComboBox comboBoxCommunicationInterface;
}
}
@@ -18,6 +18,7 @@ namespace TBF.Rig.RegisterReaders.AllyReader
tabPage2.Controls.Add(manualTestControl);
tabPage1.Text = "Settings";
tabPage2.Text = "Manual test";
tabPage3.Text = "Logs";
groupBox1.Text = "Touch-Read communication";
groupBox2.Text = "Touch-Read settings";
muxBoardNrLabel.Text = "Configured meter size";
@@ -34,9 +35,13 @@ namespace TBF.Rig.RegisterReaders.AllyReader
radioButton2.Checked = true;
}
public IComponentCfg Config { get { return config; } set { config = value as AllyReaderCfg; Redraw(); manualTestControl.Config = config; } }
public IComponentCfg Config { get { return config; } set { config = value as AllyReaderCfg; Redraw(); manualTestControl.Config = config; logsCfgCtrl.Config = config; } }
public bool ShowMore { get { return false; } }
public void Unlock() { nameTextBox.Enabled = muxBoardNrTextBox.Enabled = groupTextBox.Enabled = optoSerialPortTextBox.Enabled = tcpipPortTextBox.Enabled = rfidPortNrTextBox.Enabled = headPortNrTextBox.Enabled = true; }
public void Unlock()
{
nameTextBox.Enabled = muxBoardNrTextBox.Enabled = groupTextBox.Enabled = optoSerialPortTextBox.Enabled = tcpipPortTextBox.Enabled = rfidPortNrTextBox.Enabled = headPortNrTextBox.Enabled = true;
logsCfgCtrl.Unlock();
}
public CfgUpdateFlags VerifyCfg(ref string message)
{
@@ -48,7 +53,7 @@ namespace TBF.Rig.RegisterReaders.AllyReader
if (!int.TryParse(tcpipPortTextBox.Text, out n) || n <= 0) return Invalid(ref message, "Optical baud rate");
if (!int.TryParse(rfidPortNrTextBox.Text, out n) || n <= 0) return Invalid(ref message, "Touch-Read serial port nr.");
if (!int.TryParse(headPortNrTextBox.Text, out n) || n <= 0) return Invalid(ref message, "Touch-Read baud rate");
return CfgUpdateFlags.None;
return logsCfgCtrl.VerifyCfg(ref message);
}
public CfgUpdateFlags UpdateCfg()
{
@@ -58,7 +63,7 @@ namespace TBF.Rig.RegisterReaders.AllyReader
config.MeterPulsesPerLiter = double.Parse(groupTextBox.Text, CultureInfo.InvariantCulture);
config.OptoComPortNr = int.Parse(optoSerialPortTextBox.Text); config.OptoBaudRate = int.Parse(tcpipPortTextBox.Text);
config.CommandComPortNr = int.Parse(rfidPortNrTextBox.Text); config.CommandBaudRate = int.Parse(headPortNrTextBox.Text);
return CfgUpdateFlags.RestartRqrd;
return CfgUpdateFlags.RestartRqrd | logsCfgCtrl.UpdateCfg();
}
public void Closing() { manualTestControl.StopOpticalStream(); }
private void Redraw()
@@ -0,0 +1,36 @@
namespace TBF.Rig.RegisterReaders.AllyReader
{
partial class AllyReaderLogsCfgCtrl
{
private System.ComponentModel.IContainer components = null;
protected override void Dispose(bool disposing) { if (disposing && components != null) components.Dispose(); base.Dispose(disposing); }
private void InitializeComponent()
{
groupBoxOpticalDiagnostics = new System.Windows.Forms.GroupBox();
checkBoxEnableDetailedLogPerWM = new System.Windows.Forms.CheckBox();
labelOpticalDiagnosticFormat = new System.Windows.Forms.Label();
comboBoxOpticalDiagnosticFormat = new System.Windows.Forms.ComboBox();
labelRawOpticalDataFormat = new System.Windows.Forms.Label();
comboBoxRawOpticalDataFormat = new System.Windows.Forms.ComboBox();
checkBoxIncludeParsedValues = new System.Windows.Forms.CheckBox();
groupBoxOpticalDiagnostics.SuspendLayout(); SuspendLayout();
groupBoxOpticalDiagnostics.Controls.Add(checkBoxEnableDetailedLogPerWM); groupBoxOpticalDiagnostics.Controls.Add(labelOpticalDiagnosticFormat); groupBoxOpticalDiagnostics.Controls.Add(comboBoxOpticalDiagnosticFormat); groupBoxOpticalDiagnostics.Controls.Add(labelRawOpticalDataFormat); groupBoxOpticalDiagnostics.Controls.Add(comboBoxRawOpticalDataFormat); groupBoxOpticalDiagnostics.Controls.Add(checkBoxIncludeParsedValues);
groupBoxOpticalDiagnostics.Location = new System.Drawing.Point(5, 4); groupBoxOpticalDiagnostics.Name = "groupBoxOpticalDiagnostics"; groupBoxOpticalDiagnostics.Size = new System.Drawing.Size(591, 161); groupBoxOpticalDiagnostics.TabStop = false; groupBoxOpticalDiagnostics.Text = "Optical diagnostic logging";
checkBoxEnableDetailedLogPerWM.AutoSize = true; checkBoxEnableDetailedLogPerWM.Enabled = false; checkBoxEnableDetailedLogPerWM.Location = new System.Drawing.Point(18, 30); checkBoxEnableDetailedLogPerWM.Name = "checkBoxEnableDetailedLogPerWM"; checkBoxEnableDetailedLogPerWM.Size = new System.Drawing.Size(189, 20); checkBoxEnableDetailedLogPerWM.Text = "Enable detailed log per WM"; checkBoxEnableDetailedLogPerWM.UseVisualStyleBackColor = true;
labelOpticalDiagnosticFormat.AutoSize = true; labelOpticalDiagnosticFormat.Location = new System.Drawing.Point(18, 68); labelOpticalDiagnosticFormat.Name = "labelOpticalDiagnosticFormat"; labelOpticalDiagnosticFormat.Text = "Output format:";
comboBoxOpticalDiagnosticFormat.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; comboBoxOpticalDiagnosticFormat.Enabled = false; comboBoxOpticalDiagnosticFormat.Location = new System.Drawing.Point(212, 64); comboBoxOpticalDiagnosticFormat.Name = "comboBoxOpticalDiagnosticFormat"; comboBoxOpticalDiagnosticFormat.Size = new System.Drawing.Size(160, 24);
labelRawOpticalDataFormat.AutoSize = true; labelRawOpticalDataFormat.Location = new System.Drawing.Point(18, 100); labelRawOpticalDataFormat.Name = "labelRawOpticalDataFormat"; labelRawOpticalDataFormat.Text = "RAW data encoding:";
comboBoxRawOpticalDataFormat.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; comboBoxRawOpticalDataFormat.Enabled = false; comboBoxRawOpticalDataFormat.Location = new System.Drawing.Point(212, 96); comboBoxRawOpticalDataFormat.Name = "comboBoxRawOpticalDataFormat"; comboBoxRawOpticalDataFormat.Size = new System.Drawing.Size(160, 24);
checkBoxIncludeParsedValues.AutoSize = true; checkBoxIncludeParsedValues.Enabled = false; checkBoxIncludeParsedValues.Location = new System.Drawing.Point(393, 99); checkBoxIncludeParsedValues.Name = "checkBoxIncludeParsedValues"; checkBoxIncludeParsedValues.Size = new System.Drawing.Size(153, 20); checkBoxIncludeParsedValues.Text = "Include parsed values"; checkBoxIncludeParsedValues.UseVisualStyleBackColor = true;
AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F); AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; Controls.Add(groupBoxOpticalDiagnostics); Name = "AllyReaderLogsCfgCtrl"; Size = new System.Drawing.Size(611, 432);
groupBoxOpticalDiagnostics.ResumeLayout(false); groupBoxOpticalDiagnostics.PerformLayout(); ResumeLayout(false);
}
private System.Windows.Forms.GroupBox groupBoxOpticalDiagnostics;
private System.Windows.Forms.CheckBox checkBoxEnableDetailedLogPerWM;
private System.Windows.Forms.Label labelOpticalDiagnosticFormat;
private System.Windows.Forms.ComboBox comboBoxOpticalDiagnosticFormat;
private System.Windows.Forms.Label labelRawOpticalDataFormat;
private System.Windows.Forms.ComboBox comboBoxRawOpticalDataFormat;
private System.Windows.Forms.CheckBox checkBoxIncludeParsedValues;
}
}
@@ -0,0 +1,68 @@
using System;
using System.Windows.Forms;
using Common;
namespace TBF.Rig.RegisterReaders.AllyReader
{
public partial class AllyReaderLogsCfgCtrl : UserControl
{
private AllyReaderCfg config;
private bool unlocked;
public AllyReaderLogsCfgCtrl()
{
InitializeComponent();
comboBoxOpticalDiagnosticFormat.Items.AddRange(new object[] { "Csv", "Log" });
comboBoxRawOpticalDataFormat.Items.AddRange(new object[] { "Disabled", "Hex", "Ascii", "Text", "Base64" });
checkBoxEnableDetailedLogPerWM.CheckedChanged += CheckBoxEnableDetailedLogPerWM_CheckedChanged;
}
public AllyReaderCfg Config { get { return config; } set { config = value; Redraw(); } }
public void Unlock()
{
unlocked = true;
checkBoxEnableDetailedLogPerWM.Enabled = true;
UpdateEnabledState();
}
public CfgUpdateFlags VerifyCfg(ref string message)
{
if (config == null || comboBoxOpticalDiagnosticFormat.SelectedItem == null || comboBoxRawOpticalDataFormat.SelectedItem == null)
{
message += Environment.NewLine + "Optical diagnostic logging configuration is not valid.";
return CfgUpdateFlags.Error;
}
return CfgUpdateFlags.None;
}
public CfgUpdateFlags UpdateCfg()
{
if (config == null) return CfgUpdateFlags.Error;
config.EnableDetailedLogPerWM = checkBoxEnableDetailedLogPerWM.Checked;
config.OpticalDiagnosticFormat = comboBoxOpticalDiagnosticFormat.Text;
config.RawOpticalDataFormat = comboBoxRawOpticalDataFormat.Text;
config.IncludeParsedValues = checkBoxIncludeParsedValues.Checked;
return CfgUpdateFlags.RestartRqrd;
}
private void Redraw()
{
if (config == null) return;
checkBoxEnableDetailedLogPerWM.Checked = config.EnableDetailedLogPerWM;
comboBoxOpticalDiagnosticFormat.SelectedItem = string.IsNullOrEmpty(config.OpticalDiagnosticFormat) ? "Csv" : config.OpticalDiagnosticFormat;
comboBoxRawOpticalDataFormat.SelectedItem = string.IsNullOrEmpty(config.RawOpticalDataFormat) ? "Hex" : config.RawOpticalDataFormat;
checkBoxIncludeParsedValues.Checked = config.IncludeParsedValues;
UpdateEnabledState();
}
private void CheckBoxEnableDetailedLogPerWM_CheckedChanged(object sender, EventArgs e) { UpdateEnabledState(); }
private void UpdateEnabledState()
{
bool enabled = unlocked && checkBoxEnableDetailedLogPerWM.Checked;
comboBoxOpticalDiagnosticFormat.Enabled = enabled;
comboBoxRawOpticalDataFormat.Enabled = enabled;
checkBoxIncludeParsedValues.Enabled = enabled;
}
}
}
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<resheader name="resmimetype"><value>text/microsoft-resx</value></resheader>
<resheader name="version"><value>2.0</value></resheader>
<resheader name="reader"><value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value></resheader>
<resheader name="writer"><value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value></resheader>
</root>
@@ -0,0 +1,209 @@
using System;
using System.Globalization;
using System.IO;
using System.Text;
using log4net;
using TBF.Rig.Diagnostics;
using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed.parserer;
namespace TBF.Rig.RegisterReaders.AsicReader
{
/// <summary>
/// Optional per-watermeter optical diagnostics for ASIC readers.
/// </summary>
internal sealed class AsicOpticalDiagnosticWriter
{
private readonly string diagnosticRoot;
internal AsicOpticalDiagnosticWriter(string root = @"C:\TBF\Logs\ASIC")
{
diagnosticRoot = root;
}
private static readonly ILog LegacyLog = LogManager.GetLogger("AsicOptical");
private readonly object sync = new object();
private StreamWriter writer;
public void Write(
AsicReaderCfg cfg,
int batchNr,
int wmPosition,
string serialNumber,
int telegramIndex,
bool isMeasurementData,
string rawLine,
byte[] rawBytes,
DiagnosticLedState7Data parsedData,
double extendedVolume,
double extendedTimestamp)
{
try
{
if (!cfg.EnableDetailedLogPerWM)
{
LegacyLog.Info(CreateLegacyMessage(
batchNr, wmPosition, serialNumber, telegramIndex,
isMeasurementData, rawLine, rawBytes, parsedData,
extendedVolume, extendedTimestamp, cfg));
return;
}
lock (sync)
{
string extension = IsLogFormat(cfg.OpticalDiagnosticFormat) ? ".log" : ".csv";
OpticalLogArchive.Append(diagnosticRoot, batchNr, directory =>
{
string path = Path.Combine(directory, "ASIC_WM_" + Math.Max(0, wmPosition) + extension);
try
{
EnsureWriter(path, extension == ".csv");
if (extension == ".csv")
WriteCsvRow(cfg, batchNr, wmPosition, serialNumber, telegramIndex,
isMeasurementData, rawLine, rawBytes, parsedData,
extendedVolume, extendedTimestamp);
else
WriteTextEntry(cfg, batchNr, wmPosition, serialNumber, telegramIndex,
isMeasurementData, rawLine, rawBytes, parsedData,
extendedVolume, extendedTimestamp);
}
finally
{
if (writer != null)
{
writer.Dispose();
writer = null;
}
}
}, ex => LegacyLog.Error("ASIC optical archive failed; source data retained.", ex));
}
}
catch (Exception ex)
{
// Diagnostics must never stop the measurement data stream.
LegacyLog.Error("Unable to write detailed ASIC optical diagnostic.", ex);
}
}
private void EnsureWriter(string path, bool writeCsvHeader)
{
Directory.CreateDirectory(Path.GetDirectoryName(path));
bool newFile = !File.Exists(path) || new FileInfo(path).Length == 0;
writer = new StreamWriter(
new FileStream(path, FileMode.Append, FileAccess.Write, FileShare.Read),
new UTF8Encoding(false));
writer.AutoFlush = true;
if (writeCsvHeader && newFile)
{
writer.WriteLine("PcTimestamp;BatchNr;WmPosition;SerialNumber;TelegramIndex;Capture;ParseStatus;RawFormat;Raw;ExtendedTimeS;ExtendedVolume;ParsedValues");
}
}
private void WriteCsvRow(
AsicReaderCfg cfg, int batchNr, int wmPosition, string serialNumber,
int telegramIndex, bool isMeasurementData, string rawLine, byte[] rawBytes,
DiagnosticLedState7Data parsedData, double extendedVolume, double extendedTimestamp)
{
string rawFormat = NormalizedRawFormat(cfg.RawOpticalDataFormat);
string parsedValues = cfg.IncludeParsedValues && parsedData != null ? parsedData.ToString() : String.Empty;
writer.WriteLine(String.Join(";", new[]
{
Csv(DateTime.Now.ToString("O", CultureInfo.InvariantCulture)),
Csv(batchNr.ToString(CultureInfo.InvariantCulture)),
Csv(wmPosition.ToString(CultureInfo.InvariantCulture)),
Csv(serialNumber),
Csv(telegramIndex.ToString(CultureInfo.InvariantCulture)),
Csv(isMeasurementData ? "Measurement" : "Flush"),
Csv(parsedData == null ? "Invalid" : "Parsed"),
Csv(rawFormat),
Csv(FormatRaw(rawFormat, rawLine, rawBytes)),
Csv(cfg.IncludeParsedValues ? Number(extendedTimestamp) : String.Empty),
Csv(cfg.IncludeParsedValues ? Number(extendedVolume) : String.Empty),
Csv(parsedValues)
}));
}
private void WriteTextEntry(
AsicReaderCfg cfg, int batchNr, int wmPosition, string serialNumber,
int telegramIndex, bool isMeasurementData, string rawLine, byte[] rawBytes,
DiagnosticLedState7Data parsedData, double extendedVolume, double extendedTimestamp)
{
string rawFormat = NormalizedRawFormat(cfg.RawOpticalDataFormat);
writer.WriteLine("{0:O} | batch={1} | wm={2} | serial={3} | telegram={4} | capture={5} | parse={6}",
DateTime.Now, batchNr, wmPosition, serialNumber ?? String.Empty, telegramIndex,
isMeasurementData ? "Measurement" : "Flush", parsedData == null ? "Invalid" : "Parsed");
writer.WriteLine("RAW [{0}] {1}", rawFormat, FormatRaw(rawFormat, rawLine, rawBytes));
if (cfg.IncludeParsedValues)
{
writer.WriteLine("EXTENDED time_s={0}; volume={1}", Number(extendedTimestamp), Number(extendedVolume));
writer.WriteLine("PARSED {0}", parsedData == null ? String.Empty : parsedData.ToString());
}
}
private static string CreateLegacyMessage(
int batchNr, int wmPosition, string serialNumber, int telegramIndex,
bool isMeasurementData, string rawLine, byte[] rawBytes,
DiagnosticLedState7Data parsedData, double extendedVolume,
double extendedTimestamp, AsicReaderCfg cfg)
{
string rawFormat = NormalizedRawFormat(cfg.RawOpticalDataFormat);
return String.Format(CultureInfo.InvariantCulture,
"batch={0}; wm={1}; serial={2}; telegram={3}; capture={4}; parse={5}; raw[{6}]={7}; extendedTimeS={8}; extendedVolume={9}; parsed={10}",
batchNr, wmPosition, serialNumber ?? String.Empty, telegramIndex,
isMeasurementData ? "Measurement" : "Flush", parsedData == null ? "Invalid" : "Parsed",
rawFormat, FormatRaw(rawFormat, rawLine, rawBytes),
cfg.IncludeParsedValues ? Number(extendedTimestamp) : String.Empty,
cfg.IncludeParsedValues ? Number(extendedVolume) : String.Empty,
cfg.IncludeParsedValues && parsedData != null ? parsedData.ToString() : String.Empty);
}
private static bool IsLogFormat(string format)
{
return String.Equals(format, "Log", StringComparison.OrdinalIgnoreCase);
}
private static string NormalizedRawFormat(string format)
{
if (String.Equals(format, "Ascii", StringComparison.OrdinalIgnoreCase)) return "Ascii";
if (String.Equals(format, "Text", StringComparison.OrdinalIgnoreCase)) return "Text";
if (String.Equals(format, "Base64", StringComparison.OrdinalIgnoreCase)) return "Base64";
if (String.Equals(format, "Hex", StringComparison.OrdinalIgnoreCase)) return "Hex";
return "Disabled";
}
private static string FormatRaw(string format, string rawLine, byte[] rawBytes)
{
rawBytes = rawBytes ?? new byte[0];
if (format == "Disabled") return String.Empty;
if (format == "Text") return rawLine ?? String.Empty;
if (format == "Base64") return Convert.ToBase64String(rawBytes);
if (format == "Ascii") return ToEscapedAscii(rawBytes);
return BitConverter.ToString(rawBytes).Replace("-", " ");
}
private static string ToEscapedAscii(byte[] bytes)
{
StringBuilder result = new StringBuilder();
foreach (byte value in bytes)
{
if (value == 13) result.Append("\\r");
else if (value == 10) result.Append("\\n");
else if (value == 9) result.Append("\\t");
else if (value >= 32 && value <= 126) result.Append((char)value);
else result.Append("\\x").Append(value.ToString("X2", CultureInfo.InvariantCulture));
}
return result.ToString();
}
private static string Number(double value)
{
return Double.IsNaN(value) || Double.IsInfinity(value)
? String.Empty
: value.ToString("R", CultureInfo.InvariantCulture);
}
private static string Csv(string value)
{
value = value ?? String.Empty;
return "\"" + value.Replace("\"", "\"\"") + "\"";
}
}
}
@@ -2,6 +2,8 @@ using System;
using TBF.Rig.Generic;
using TBF.Rig.TestMethods.iPerlCommunication.iPerlHead;
using TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.common;
using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed.parserer;
using TBF.Rig.Sequences;
namespace TBF.Rig.RegisterReaders.AsicReader
{
@@ -15,6 +17,10 @@ namespace TBF.Rig.RegisterReaders.AsicReader
/// </summary>
public class AsicReader : IperlHead, ISmartReader
{
private readonly AsicReaderCfg asicCfg;
private readonly AsicOpticalDiagnosticWriter opticalDiagnosticWriter =
new AsicOpticalDiagnosticWriter();
public AsicReader()
{
}
@@ -22,6 +28,7 @@ namespace TBF.Rig.RegisterReaders.AsicReader
public AsicReader(IComponentCfg cfg)
: base(cfg)
{
asicCfg = cfg as AsicReaderCfg;
}
// The original IperlHead API keeps the communication interface strongly
@@ -51,5 +58,35 @@ namespace TBF.Rig.RegisterReaders.AsicReader
SetCommunicationInterface(parsedInterface);
}
/// <summary>
/// Captures ASIC diagnostic data after the parser has updated the
/// rollover-corrected time and volume counters.
/// </summary>
protected override void NotifyOpticalTelegramCaptured(
string rawLine,
byte[] rawBytes,
DiagnosticLedState7Data parsedData,
int telegramIndex,
bool isMeasurementData,
double extendedVolume,
double extendedTimestamp)
{
if (asicCfg == null)
return;
opticalDiagnosticWriter.Write(
asicCfg,
ProcessData.BatchNr,
Position,
SerialNr,
telegramIndex,
isMeasurementData,
rawLine,
rawBytes,
parsedData,
extendedVolume,
extendedTimestamp);
}
}
}
@@ -1,3 +1,4 @@
using System.Collections.Generic;
using System.Xml.Serialization;
using TBF.Rig.Generic;
using TBF.Rig.TestMethods.iPerlCommunication.iPerlHead;
@@ -15,6 +16,16 @@ namespace TBF.Rig.RegisterReaders.AsicReader
[XmlRoot("AsicReaderCfg")]
public class AsicReaderCfg : IperlHeadCfg
{
public bool EnableDetailedLogPerWM;
public string OpticalDiagnosticFormat = "Csv";
public string RawOpticalDataFormat = "Hex";
public bool IncludeParsedValues = true;
public override IComponentCfgCtrl GetControl(IList<Config.Entities.Component> cmpntEntities)
{
return new AsicReaderCfgCtrl();
}
public static readonly XmlSerializer Serializer =
XmlSerializer.FromTypes(new[] { typeof(AsicReaderCfg) })[0];
@@ -0,0 +1,35 @@
namespace TBF.Rig.RegisterReaders.AsicReader
{
partial class AsicReaderCfgCtrl
{
private System.ComponentModel.IContainer components = null;
protected override void Dispose(bool disposing) { if (disposing && components != null) components.Dispose(); base.Dispose(disposing); }
private void InitializeComponent()
{
tabControl = new System.Windows.Forms.TabControl();
settingsTabPage = new System.Windows.Forms.TabPage();
manualTestTabPage = new System.Windows.Forms.TabPage();
logsTabPage = new System.Windows.Forms.TabPage();
settingsCfgCtrl = new TBF.Rig.TestMethods.iPerlCommunication.iPerlHead.IperlHeadCfgCtrl();
manualTestCfgCtrl = new TBF.Rig.TestMethods.iPerlCommunication.iPerlHead.IperlHeadCfgCtrl();
logsCfgCtrl = new AsicReaderLogsCfgCtrl();
tabControl.SuspendLayout(); settingsTabPage.SuspendLayout(); manualTestTabPage.SuspendLayout(); logsTabPage.SuspendLayout(); SuspendLayout();
tabControl.Controls.Add(settingsTabPage); tabControl.Controls.Add(manualTestTabPage); tabControl.Controls.Add(logsTabPage); tabControl.Location = new System.Drawing.Point(3,3); tabControl.Name = "tabControl"; tabControl.SelectedIndex = 0; tabControl.Size = new System.Drawing.Size(611,432);
settingsTabPage.Controls.Add(settingsCfgCtrl); settingsTabPage.Location = new System.Drawing.Point(4,25); settingsTabPage.Name = "settingsTabPage"; settingsTabPage.Size = new System.Drawing.Size(603,403); settingsTabPage.Text = "Settings"; settingsTabPage.UseVisualStyleBackColor = true;
settingsCfgCtrl.Location = new System.Drawing.Point(-4,-4); settingsCfgCtrl.Name = "settingsCfgCtrl"; settingsCfgCtrl.Size = new System.Drawing.Size(617,438);
manualTestTabPage.Controls.Add(manualTestCfgCtrl); manualTestTabPage.Location = new System.Drawing.Point(4,25); manualTestTabPage.Name = "manualTestTabPage"; manualTestTabPage.Size = new System.Drawing.Size(603,403); manualTestTabPage.Text = "Manual test"; manualTestTabPage.UseVisualStyleBackColor = true;
manualTestCfgCtrl.Location = new System.Drawing.Point(-4,-4); manualTestCfgCtrl.Name = "manualTestCfgCtrl"; manualTestCfgCtrl.Size = new System.Drawing.Size(617,438);
logsTabPage.Controls.Add(logsCfgCtrl); logsTabPage.Location = new System.Drawing.Point(4,25); logsTabPage.Name = "logsTabPage"; logsTabPage.Size = new System.Drawing.Size(603,403); logsTabPage.Text = "Logs"; logsTabPage.UseVisualStyleBackColor = true;
logsCfgCtrl.Location = new System.Drawing.Point(-4,-4); logsCfgCtrl.Name = "logsCfgCtrl"; logsCfgCtrl.Size = new System.Drawing.Size(611,432);
AutoScaleDimensions = new System.Drawing.SizeF(8F,16F); AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; Controls.Add(tabControl); Name = "AsicReaderCfgCtrl"; Size = new System.Drawing.Size(617,438);
tabControl.ResumeLayout(false); settingsTabPage.ResumeLayout(false); manualTestTabPage.ResumeLayout(false); logsTabPage.ResumeLayout(false); ResumeLayout(false);
}
private System.Windows.Forms.TabControl tabControl;
private System.Windows.Forms.TabPage settingsTabPage;
private System.Windows.Forms.TabPage manualTestTabPage;
private System.Windows.Forms.TabPage logsTabPage;
private TBF.Rig.TestMethods.iPerlCommunication.iPerlHead.IperlHeadCfgCtrl settingsCfgCtrl;
private TBF.Rig.TestMethods.iPerlCommunication.iPerlHead.IperlHeadCfgCtrl manualTestCfgCtrl;
private AsicReaderLogsCfgCtrl logsCfgCtrl;
}
}
@@ -0,0 +1,41 @@
using System;
using System.Windows.Forms;
using Common;
using TBF.Rig.Generic;
using TBF.Rig.TestMethods.iPerlCommunication.iPerlHead;
namespace TBF.Rig.RegisterReaders.AsicReader
{
public partial class AsicReaderCfgCtrl : UserControl, IComponentCfgCtrl
{
private AsicReaderCfg config;
public AsicReaderCfgCtrl() { InitializeComponent(); }
public bool ShowMore { get { return false; } }
public IComponentCfg Config
{
get { return config; }
set
{
config = value as AsicReaderCfg;
settingsCfgCtrl.Config = config;
settingsCfgCtrl.ShowOnlyTab(false);
manualTestCfgCtrl.Config = config;
manualTestCfgCtrl.ShowOnlyTab(true);
logsCfgCtrl.Config = config;
}
}
public void Unlock() { settingsCfgCtrl.Unlock(); logsCfgCtrl.Unlock(); }
public void Closing() { settingsCfgCtrl.Closing(); manualTestCfgCtrl.Closing(); }
public CfgUpdateFlags VerifyCfg(ref string message)
{
CfgUpdateFlags flags = settingsCfgCtrl.VerifyCfg(ref message);
return flags == CfgUpdateFlags.None ? logsCfgCtrl.VerifyCfg(ref message) : flags;
}
public CfgUpdateFlags UpdateCfg()
{
CfgUpdateFlags flags = settingsCfgCtrl.UpdateCfg();
if ((flags & CfgUpdateFlags.Error) != 0) return flags;
return flags | logsCfgCtrl.UpdateCfg();
}
}
}
@@ -0,0 +1,30 @@
namespace TBF.Rig.RegisterReaders.AsicReader
{
partial class AsicReaderLogsCfgCtrl
{
private System.ComponentModel.IContainer components = null;
protected override void Dispose(bool disposing) { if (disposing && components != null) components.Dispose(); base.Dispose(disposing); }
private void InitializeComponent()
{
groupBox = new System.Windows.Forms.GroupBox(); enableDetailedLogCheckBox = new System.Windows.Forms.CheckBox(); diagnosticFormatLabel = new System.Windows.Forms.Label(); diagnosticFormatComboBox = new System.Windows.Forms.ComboBox(); rawFormatLabel = new System.Windows.Forms.Label(); rawFormatComboBox = new System.Windows.Forms.ComboBox(); includeParsedValuesCheckBox = new System.Windows.Forms.CheckBox();
groupBox.SuspendLayout(); SuspendLayout();
groupBox.Controls.Add(enableDetailedLogCheckBox); groupBox.Controls.Add(diagnosticFormatLabel); groupBox.Controls.Add(diagnosticFormatComboBox); groupBox.Controls.Add(rawFormatLabel); groupBox.Controls.Add(rawFormatComboBox); groupBox.Controls.Add(includeParsedValuesCheckBox);
groupBox.Location = new System.Drawing.Point(5,4); groupBox.Name = "groupBox"; groupBox.Size = new System.Drawing.Size(591,161); groupBox.TabStop = false; groupBox.Text = "Optical diagnostic logging";
enableDetailedLogCheckBox.AutoSize = true; enableDetailedLogCheckBox.Enabled = false; enableDetailedLogCheckBox.Location = new System.Drawing.Point(18,30); enableDetailedLogCheckBox.Name = "enableDetailedLogCheckBox"; enableDetailedLogCheckBox.Text = "Enable detailed log per WM";
diagnosticFormatLabel.AutoSize = true; diagnosticFormatLabel.Location = new System.Drawing.Point(18,68); diagnosticFormatLabel.Text = "Output format:";
diagnosticFormatComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; diagnosticFormatComboBox.Enabled = false; diagnosticFormatComboBox.Location = new System.Drawing.Point(212,64); diagnosticFormatComboBox.Size = new System.Drawing.Size(160,24);
rawFormatLabel.AutoSize = true; rawFormatLabel.Location = new System.Drawing.Point(18,100); rawFormatLabel.Text = "RAW data encoding:";
rawFormatComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; rawFormatComboBox.Enabled = false; rawFormatComboBox.Location = new System.Drawing.Point(212,96); rawFormatComboBox.Size = new System.Drawing.Size(160,24);
includeParsedValuesCheckBox.AutoSize = true; includeParsedValuesCheckBox.Enabled = false; includeParsedValuesCheckBox.Location = new System.Drawing.Point(393,99); includeParsedValuesCheckBox.Text = "Include parsed values";
AutoScaleDimensions = new System.Drawing.SizeF(8F,16F); AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; Controls.Add(groupBox); Name = "AsicReaderLogsCfgCtrl"; Size = new System.Drawing.Size(611,432);
groupBox.ResumeLayout(false); groupBox.PerformLayout(); ResumeLayout(false);
}
private System.Windows.Forms.GroupBox groupBox;
private System.Windows.Forms.CheckBox enableDetailedLogCheckBox;
private System.Windows.Forms.Label diagnosticFormatLabel;
private System.Windows.Forms.ComboBox diagnosticFormatComboBox;
private System.Windows.Forms.Label rawFormatLabel;
private System.Windows.Forms.ComboBox rawFormatComboBox;
private System.Windows.Forms.CheckBox includeParsedValuesCheckBox;
}
}
@@ -0,0 +1,55 @@
using System;
using System.Windows.Forms;
using Common;
namespace TBF.Rig.RegisterReaders.AsicReader
{
public partial class AsicReaderLogsCfgCtrl : UserControl
{
private AsicReaderCfg config;
private bool unlocked;
public AsicReaderLogsCfgCtrl()
{
InitializeComponent();
diagnosticFormatComboBox.Items.AddRange(new object[] { "Csv", "Log" });
rawFormatComboBox.Items.AddRange(new object[] { "Disabled", "Hex", "Ascii", "Text", "Base64" });
enableDetailedLogCheckBox.CheckedChanged += (s, e) => UpdateEnabledState();
}
public AsicReaderCfg Config { get { return config; } set { config = value; Redraw(); } }
public void Unlock() { unlocked = true; enableDetailedLogCheckBox.Enabled = true; UpdateEnabledState(); }
public CfgUpdateFlags VerifyCfg(ref string message)
{
if (config == null || diagnosticFormatComboBox.SelectedItem == null || rawFormatComboBox.SelectedItem == null)
{
message += Environment.NewLine + "Optical diagnostic logging configuration is not valid.";
return CfgUpdateFlags.Error;
}
return CfgUpdateFlags.None;
}
public CfgUpdateFlags UpdateCfg()
{
if (config == null) return CfgUpdateFlags.Error;
config.EnableDetailedLogPerWM = enableDetailedLogCheckBox.Checked;
config.OpticalDiagnosticFormat = diagnosticFormatComboBox.Text;
config.RawOpticalDataFormat = rawFormatComboBox.Text;
config.IncludeParsedValues = includeParsedValuesCheckBox.Checked;
return CfgUpdateFlags.RestartRqrd;
}
private void Redraw()
{
if (config == null) return;
enableDetailedLogCheckBox.Checked = config.EnableDetailedLogPerWM;
diagnosticFormatComboBox.SelectedItem = string.IsNullOrEmpty(config.OpticalDiagnosticFormat) ? "Csv" : config.OpticalDiagnosticFormat;
rawFormatComboBox.SelectedItem = string.IsNullOrEmpty(config.RawOpticalDataFormat) ? "Hex" : config.RawOpticalDataFormat;
includeParsedValuesCheckBox.Checked = config.IncludeParsedValues;
UpdateEnabledState();
}
private void UpdateEnabledState()
{
bool enabled = unlocked && enableDetailedLogCheckBox.Checked;
diagnosticFormatComboBox.Enabled = enabled;
rawFormatComboBox.Enabled = enabled;
includeParsedValuesCheckBox.Enabled = enabled;
}
}
}
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<resheader name="resmimetype"><value>text/microsoft-resx</value></resheader>
<resheader name="version"><value>2.0</value></resheader>
<resheader name="reader"><value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value></resheader>
<resheader name="writer"><value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value></resheader>
</root>
@@ -412,12 +412,15 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
try
{
value = JsonConvert.DeserializeObject<T>(json);
CaptureDiagnosticJson(value, json);
return value != null;
}
catch (Exception ex)
{
log?.Debug(ex.Message);
return TryConvert(json, out value);
bool converted = TryConvert(json, out value);
if (converted) CaptureDiagnosticJson(value, json);
return converted;
}
}
@@ -425,6 +428,14 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
return false;
}
private static void CaptureDiagnosticJson<T>(T value, string json)
{
var data = (object)value as JsonDataFromPoseidon;
if (data == null) return;
data.DiagnosticRawJson = json;
data.DiagnosticReceivedUtc = DateTime.UtcNow;
}
private static bool TryConvert<T>(string json, out T value) where T : new()
{
T obj = new T();
@@ -4,6 +4,11 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
{
public class JsonDataFromPoseidon
{
// Original extracted CLI JSON; not optical wire bytes or reserialized data.
[Newtonsoft.Json.JsonIgnore]
public string DiagnosticRawJson { get; set; }
[Newtonsoft.Json.JsonIgnore]
public System.DateTime DiagnosticReceivedUtc { get; set; }
public bool? NfcTagDetected { get; set; }
public int? ProductType { get; set; }
public string ProductTypeVersion { get; set; }
@@ -23,6 +23,10 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
public int ComPortNr;
public string CliFileName;
public int MeterType;
public bool EnableDetailedLogPerWM;
public string OpticalDiagnosticFormat;
public string RawOpticalDataFormat;
public bool IncludeParsedValues;
/// <summary> Procedure parameters </summary>
@@ -38,6 +42,10 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
"Serial port number", /// 0
"CLI program name", /// 1
"Meter Type", /// 2
"Enable detailed log per WM", /// 3
"Optical diagnostic format", /// 4
"RAW optical data format", /// 5
"Include parsed values", /// 6
};
public string ParamName(int i) { return paramNames[i]; }
public int ParamsCount() { return paramNames.Length; }
@@ -53,6 +61,14 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
case 2:
return new string[] { "74" };
case 3:
case 6:
return new string[] { bool.FalseString, bool.TrueString };
case 4:
return new string[] { "Csv", "Log" };
case 5:
return new string[] { "Disabled", "Hex", "Ascii", "Text", "Base64" };
default:
return null;
}
@@ -66,6 +82,10 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
ComPortNr = 3;
CliFileName = "HatCLI.exe";
MeterType = 74;
EnableDetailedLogPerWM = false;
OpticalDiagnosticFormat = "Csv";
RawOpticalDataFormat = "Hex";
IncludeParsedValues = true;
}
public bool ValidateParam(int i, string strValue, out string message)
@@ -85,6 +105,15 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
case 2:
if (int.TryParse(strValue, out idummy) && idummy > 0) return true;
break;
case 3:
case 6:
bool boolValue;
if (bool.TryParse(strValue, out boolValue)) return true;
break;
case 4:
case 5:
if (ParamValues(i).Contains(strValue)) return true;
break;
default:
message = "Invalid index";
return false;
@@ -101,6 +130,10 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
case 0: ComPortNr = int.Parse(str); return CfgUpdateFlags.RestartRqrd;
case 1: CliFileName = str; return CfgUpdateFlags.RestartRqrd;
case 2: MeterType = int.Parse(str); return CfgUpdateFlags.RestartRqrd;
case 3: EnableDetailedLogPerWM = bool.Parse(str); return CfgUpdateFlags.RestartRqrd;
case 4: OpticalDiagnosticFormat = str; return CfgUpdateFlags.RestartRqrd;
case 5: RawOpticalDataFormat = str; return CfgUpdateFlags.RestartRqrd;
case 6: IncludeParsedValues = bool.Parse(str); return CfgUpdateFlags.RestartRqrd;
default: return CfgUpdateFlags.None;
}
}
@@ -139,6 +172,10 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
case 0: return ComPortNr.ToString();
case 1: return CliFileName;
case 2: return MeterType.ToString();
case 3: return EnableDetailedLogPerWM.ToString();
case 4: return OpticalDiagnosticFormat;
case 5: return RawOpticalDataFormat;
case 6: return IncludeParsedValues.ToString();
default:
return string.Format("{0}: Com{1}, CliName =`{2}`, MeterType = {3}",
Name, ComPortNr, CliFileName, MeterType);
@@ -150,6 +187,10 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
prms.ComPortNr = this.ComPortNr;
prms.CliFileName = this.CliFileName;
prms.MeterType = this.MeterType;
prms.EnableDetailedLogPerWM = this.EnableDetailedLogPerWM;
prms.OpticalDiagnosticFormat = this.OpticalDiagnosticFormat;
prms.RawOpticalDataFormat = this.RawOpticalDataFormat;
prms.IncludeParsedValues = this.IncludeParsedValues;
prms.ProcParams = this.ProcParams;
}
}
@@ -29,6 +29,8 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
internal const string SimulatedCliFileName = "cmdSleepTest.exe";
public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); }
private readonly TBF.Rig.RegisterReaders.PoseidonReader.PoseidonOpticalDiagnosticWriter opticalDiagnosticWriter =
new TBF.Rig.RegisterReaders.PoseidonReader.PoseidonOpticalDiagnosticWriter();
readonly PoseidonCfg registerReaderCfg;
readonly ControlBoard.IControlBoard controlBoard;
@@ -560,6 +562,7 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
}
}
CaptureCliDiagnostic(data);
CliRunner.Clear();
_currentOp = _lastOpTimedOut ? CurrentPoseidonOp.Error : CurrentPoseidonOp.Done;
return Event.Done;
@@ -569,6 +572,25 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
}
private void CaptureCliDiagnostic(JsonDataFromPoseidon data)
{
if (registerReaderCfg == null) return;
string raw = data == null ? null : data.DiagnosticRawJson;
DateTime received = data == null || data.DiagnosticReceivedUtc == default(DateTime)
? DateTime.UtcNow : data.DiagnosticReceivedUtc;
opticalDiagnosticWriter.Write(registerReaderCfg.EnableDetailedLogPerWM,
registerReaderCfg.OpticalDiagnosticFormat, registerReaderCfg.RawOpticalDataFormat,
registerReaderCfg.IncludeParsedValues, Sequences.ProcessData.BatchNr,
Position > 0 ? Position.ToString() : Name, Name, wmSerialNr, received,
"CLI/ExtractedJson", lastCliReadSucceeded ? "Accepted" : "Rejected",
System.Text.Encoding.UTF8.GetBytes(raw ?? ""), raw,
null, null, null, null,
lastCliReadSucceeded ? (object)(_isReadingStart ? beginWMState : endWMState) : null,
fullTimeInMilis / 1000D, data == null ? null : data.Reading,
data == null ? null : data.Reading_Units, _isReadingStart ? "START" : "END",
lastCliReadFailureReason);
}
public static bool TryParseCliReading(string reading, out double value)
{
value = 0;
@@ -31,6 +31,10 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
public ECommunicationInterface CommunicationInterface; /// Communication Interface: NFC, touch capl
public string CliProgramName;
public string CliMeterType;
public bool EnableDetailedLogPerWM;
public string OpticalDiagnosticFormat = "Csv";
public string RawOpticalDataFormat = "Hex";
public bool IncludeParsedValues = true;
/// <summary> Procedure parameters </summary>
@@ -31,12 +31,16 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
{
config = value as PoseidonCfg;
Redraw();
logsCfgCtrl.Config = config;
}
}
public PoseidonCfgCtrl()
{
InitializeComponent();
tabPage1.Text = "Settings";
tabPage2.Text = "Manual test";
tabPage3.Text = "Logs";
InitComPortsComboByList(listOfComPoertsComboBox, GetAvailableComPorts());
InitComboByList(cliProgramComboBox, GetAvailableCliPrograms());
@@ -113,11 +117,14 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
meterTypeComboBox.Enabled = true;
listOfComPoertsComboBox.Enabled = true;
button_refreshComPorts.Enabled = true;
logsCfgCtrl.Unlock();
}
public CfgUpdateFlags VerifyCfg(ref string message)
{
CfgUpdateFlags flags = CfgUpdateFlags.None;
flags |= logsCfgCtrl.VerifyCfg(ref message);
int dummy;
@@ -214,6 +221,7 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
config.HeadCommunicationComPortNr = int.Parse(headPortNrTextBox.Text);
config.CliProgramName = cliProgramComboBox.Text;
config.CliMeterType = meterTypeComboBox.Text;
flags |= logsCfgCtrl.UpdateCfg();
return flags;
}
@@ -57,6 +57,8 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
this.nameLabel = new System.Windows.Forms.Label();
this.classNameLabel = new System.Windows.Forms.Label();
this.tabPage2 = new System.Windows.Forms.TabPage();
this.tabPage3 = new System.Windows.Forms.TabPage();
this.logsCfgCtrl = new PoseidonLogsCfgCtrl();
this.tabControl1.SuspendLayout();
this.tabPage1.SuspendLayout();
this.groupBox3.SuspendLayout();
@@ -69,6 +71,7 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
//
this.tabControl1.Controls.Add(this.tabPage1);
this.tabControl1.Controls.Add(this.tabPage2);
this.tabControl1.Controls.Add(this.tabPage3);
this.tabControl1.Location = new System.Drawing.Point(3, 4);
this.tabControl1.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
this.tabControl1.Name = "tabControl1";
@@ -341,6 +344,15 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
this.tabPage2.Text = "Test";
this.tabPage2.UseVisualStyleBackColor = true;
//
// tabPage3
//
this.tabPage3.Controls.Add(this.logsCfgCtrl);
this.tabPage3.Location = new System.Drawing.Point(4, 29);
this.tabPage3.Name = "tabPage3";
this.tabPage3.Size = new System.Drawing.Size(679, 507);
this.tabPage3.Text = "Logs";
this.logsCfgCtrl.Location = new System.Drawing.Point(0, 0);
this.logsCfgCtrl.Size = new System.Drawing.Size(679, 507);
// PoseidonCfgCtrl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 20F);
@@ -394,6 +406,8 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
private System.Windows.Forms.Label nameLabel;
private System.Windows.Forms.Label classNameLabel;
private System.Windows.Forms.TabPage tabPage2;
private System.Windows.Forms.TabPage tabPage3;
private PoseidonLogsCfgCtrl logsCfgCtrl;
private System.Windows.Forms.GroupBox groupBox2;
private System.Windows.Forms.TextBox headPortNrTextBox;
private System.Windows.Forms.Label label2;
@@ -0,0 +1,30 @@
namespace TBF.Rig.RegisterReaders.PoseidonReader
{
partial class PoseidonLogsCfgCtrl
{
private System.ComponentModel.IContainer components = null;
protected override void Dispose(bool disposing) { if (disposing && components != null) components.Dispose(); base.Dispose(disposing); }
private void InitializeComponent()
{
groupBox = new System.Windows.Forms.GroupBox(); enableDetailedLogCheckBox = new System.Windows.Forms.CheckBox(); diagnosticFormatLabel = new System.Windows.Forms.Label(); diagnosticFormatComboBox = new System.Windows.Forms.ComboBox(); rawFormatLabel = new System.Windows.Forms.Label(); rawFormatComboBox = new System.Windows.Forms.ComboBox(); includeParsedValuesCheckBox = new System.Windows.Forms.CheckBox();
groupBox.SuspendLayout(); SuspendLayout();
groupBox.Controls.Add(enableDetailedLogCheckBox); groupBox.Controls.Add(diagnosticFormatLabel); groupBox.Controls.Add(diagnosticFormatComboBox); groupBox.Controls.Add(rawFormatLabel); groupBox.Controls.Add(rawFormatComboBox); groupBox.Controls.Add(includeParsedValuesCheckBox);
groupBox.Location = new System.Drawing.Point(5,4); groupBox.Name = "groupBox"; groupBox.Size = new System.Drawing.Size(650,161); groupBox.TabStop = false; groupBox.Text = "Optical diagnostic logging";
enableDetailedLogCheckBox.AutoSize = true; enableDetailedLogCheckBox.Enabled = false; enableDetailedLogCheckBox.Location = new System.Drawing.Point(18,30); enableDetailedLogCheckBox.Text = "Enable detailed log per WM";
diagnosticFormatLabel.AutoSize = true; diagnosticFormatLabel.Location = new System.Drawing.Point(18,68); diagnosticFormatLabel.Text = "Output format:";
diagnosticFormatComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; diagnosticFormatComboBox.Enabled = false; diagnosticFormatComboBox.Location = new System.Drawing.Point(212,64); diagnosticFormatComboBox.Size = new System.Drawing.Size(160,28);
rawFormatLabel.AutoSize = true; rawFormatLabel.Location = new System.Drawing.Point(18,106); rawFormatLabel.Text = "RAW data encoding:";
rawFormatComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; rawFormatComboBox.Enabled = false; rawFormatComboBox.Location = new System.Drawing.Point(212,102); rawFormatComboBox.Size = new System.Drawing.Size(160,28);
includeParsedValuesCheckBox.AutoSize = true; includeParsedValuesCheckBox.Enabled = false; includeParsedValuesCheckBox.Location = new System.Drawing.Point(393,105); includeParsedValuesCheckBox.Text = "Include parsed values";
AutoScaleDimensions = new System.Drawing.SizeF(9F,20F); AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; Controls.Add(groupBox); Name = "PoseidonLogsCfgCtrl"; Size = new System.Drawing.Size(679,507);
groupBox.ResumeLayout(false); groupBox.PerformLayout(); ResumeLayout(false);
}
private System.Windows.Forms.GroupBox groupBox;
private System.Windows.Forms.CheckBox enableDetailedLogCheckBox;
private System.Windows.Forms.Label diagnosticFormatLabel;
private System.Windows.Forms.ComboBox diagnosticFormatComboBox;
private System.Windows.Forms.Label rawFormatLabel;
private System.Windows.Forms.ComboBox rawFormatComboBox;
private System.Windows.Forms.CheckBox includeParsedValuesCheckBox;
}
}
@@ -0,0 +1,55 @@
using System;
using System.Windows.Forms;
using Common;
namespace TBF.Rig.RegisterReaders.PoseidonReader
{
public partial class PoseidonLogsCfgCtrl : UserControl
{
private PoseidonCfg config;
private bool unlocked;
public PoseidonLogsCfgCtrl()
{
InitializeComponent();
diagnosticFormatComboBox.Items.AddRange(new object[] { "Csv", "Log" });
rawFormatComboBox.Items.AddRange(new object[] { "Disabled", "Hex", "Ascii", "Text", "Base64" });
enableDetailedLogCheckBox.CheckedChanged += (s, e) => UpdateEnabledState();
}
public PoseidonCfg Config { get { return config; } set { config = value; Redraw(); } }
public void Unlock() { unlocked = true; enableDetailedLogCheckBox.Enabled = true; UpdateEnabledState(); }
public CfgUpdateFlags VerifyCfg(ref string message)
{
if (config == null || diagnosticFormatComboBox.SelectedItem == null || rawFormatComboBox.SelectedItem == null)
{
message += Environment.NewLine + "Optical diagnostic logging configuration is not valid.";
return CfgUpdateFlags.Error;
}
return CfgUpdateFlags.None;
}
public CfgUpdateFlags UpdateCfg()
{
if (config == null) return CfgUpdateFlags.Error;
config.EnableDetailedLogPerWM = enableDetailedLogCheckBox.Checked;
config.OpticalDiagnosticFormat = diagnosticFormatComboBox.Text;
config.RawOpticalDataFormat = rawFormatComboBox.Text;
config.IncludeParsedValues = includeParsedValuesCheckBox.Checked;
return CfgUpdateFlags.RestartRqrd;
}
private void Redraw()
{
if (config == null) return;
enableDetailedLogCheckBox.Checked = config.EnableDetailedLogPerWM;
diagnosticFormatComboBox.SelectedItem = string.IsNullOrEmpty(config.OpticalDiagnosticFormat) ? "Csv" : config.OpticalDiagnosticFormat;
rawFormatComboBox.SelectedItem = string.IsNullOrEmpty(config.RawOpticalDataFormat) ? "Hex" : config.RawOpticalDataFormat;
includeParsedValuesCheckBox.Checked = config.IncludeParsedValues;
UpdateEnabledState();
}
private void UpdateEnabledState()
{
bool enabled = unlocked && enableDetailedLogCheckBox.Checked;
diagnosticFormatComboBox.Enabled = enabled;
rawFormatComboBox.Enabled = enabled;
includeParsedValuesCheckBox.Enabled = enabled;
}
}
}
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<resheader name="resmimetype"><value>text/microsoft-resx</value></resheader>
<resheader name="version"><value>2.0</value></resheader>
<resheader name="reader"><value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value></resheader>
<resheader name="writer"><value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value></resheader>
</root>
@@ -45,6 +45,11 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
public const int StartEndFilterSamplesCount2 = 20; /// StartEndFilterSamplesCount = 2 * StartEndFilterSamplesCount2 + 1
public const int FeatureVectorSize = 9;
private readonly PoseidonOpticalDiagnosticWriter opticalDiagnosticWriter = new PoseidonOpticalDiagnosticWriter();
private DateTime? diagnosticFirstUtc;
private uint? diagnosticLastAccumulator;
private long diagnosticExtendedAccumulator;
readonly PoseidonCfg _poseidonCfg;
@@ -541,6 +546,10 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
OptoHeadService.Con connection = new OptoHeadService.Con($"COM{iHeadCfg.OptoComPortNr}", iHeadCfg.DebugLevel);
_optoHeadService = new OptoHeadService(connection);
diagnosticFirstUtc = null;
diagnosticLastAccumulator = null;
diagnosticExtendedAccumulator = 0;
_optoHeadService.DiagnosticReceived = CaptureOpticalDiagnostic;
return _optoHeadService.CreateSerialConnection();
}
}
@@ -572,6 +581,36 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader
return false;
}
private void CaptureOpticalDiagnostic(byte[] raw, DateTime receivedUtc,
WaterMetrologyData data, bool simulatedPayload)
{
if (_poseidonCfg == null) return;
WaterMetrologyDataC2 parsed = data == null ? null : (data.C7Data ?? data.C2Data);
bool wrapped = false;
long? extended = null;
if (parsed != null && !simulatedPayload)
{
diagnosticExtendedAccumulator = PoseidonOpticalDiagnosticWriter.ExtendAccumulator(
parsed.Accumulator, diagnosticLastAccumulator, diagnosticExtendedAccumulator, out wrapped);
diagnosticLastAccumulator = parsed.Accumulator;
extended = diagnosticExtendedAccumulator;
}
if (!diagnosticFirstUtc.HasValue) diagnosticFirstUtc = receivedUtc;
opticalDiagnosticWriter.Write(_poseidonCfg.EnableDetailedLogPerWM,
_poseidonCfg.OpticalDiagnosticFormat, _poseidonCfg.RawOpticalDataFormat,
_poseidonCfg.IncludeParsedValues, Sequences.ProcessData.BatchNr,
Position > 0 ? Position.ToString() : Name, Name, SerialNr, receivedUtc,
simulatedPayload ? "OpticalService/SimulatedPayload" : "OpticalService/DriverBytes",
parsed == null ? "ParseRejected" : "Parsed",
raw, null,
parsed == null ? (object)null : parsed.Accumulator,
extended, wrapped,
parsed == null ? (object)null : parsed.FlowRateLPerS,
parsed == null ? (object)null : wmVolume,
(receivedUtc - diagnosticFirstUtc.Value).TotalSeconds,
null, null, "Stream", data == null ? null : data.ToString());
}
private void OnOptoHandler(object sender, CommonRR.IPerl.communication.OptoReceivedEventArgs e)
{
//received data from optohead
@@ -64,6 +64,9 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7
/// </summary>
public WaterMetrologyData WaterMetrologyData { get; private set; }
// Driver bytes and parse outcome, including rejected packets.
public Action<byte[], DateTime, WaterMetrologyData, bool> DiagnosticReceived { get; set; }
public OptoHeadService(Con con)
{
Connection = con;
@@ -151,12 +154,25 @@ namespace TBF.Rig.RegisterReaders.PoseidonReader.communication.C7
while (!dissableRunLoop)
{
_bRunStarted = true;
WaterMetrologyData = ParseData(RunReading());
byte[] rawDiagnosticData = RunReading();
DateTime receivedUtc = DateTime.UtcNow;
WaterMetrologyData = ParseData(rawDiagnosticData);
if (OnOptoReceivedHandler != null && WaterMetrologyData != null)
{
log.Debug($"Received OptoData: {WaterMetrologyData}");
OnOptoReceivedHandler?.Invoke(this, new CommonRR.IPerl.communication.OptoReceivedEventArgs(WaterMetrologyData?.ToString(), WaterMetrologyData));
}
try
{
// Reflect the CURRENT ParseData branch, including its legacy
// simulation condition. Do not label simulated values as wire data.
DiagnosticReceived?.Invoke(rawDiagnosticData, receivedUtc, WaterMetrologyData,
Connection?.DebugModeSetting != DebugMode.Simulate);
}
catch (Exception ex)
{
log.Warn("Poseidon optical diagnostic callback failed.", ex);
}
}
}
@@ -1107,6 +1107,15 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead
timestampExtLast);
}
NotifyOpticalTelegramCaptured(
line,
bytes,
data,
optoDataCount,
true,
data == null ? Double.NaN : volumeRawExtLast,
data == null ? Double.NaN : timestampExtLast);
optoDataCount++;
}
else
@@ -1115,6 +1124,15 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead
DiagnosticLedState7Data data =
(DiagnosticLedState7Data)parser.ParseLine(line, false);
NotifyOpticalTelegramCaptured(
line,
bytes,
data,
optoDataCount,
false,
data == null ? Double.NaN : volumeRawExtLast,
data == null ? Double.NaN : timestampExtLast);
flowDirectionDetection.WriteToFifo(volumeRawExtLast, timestampExtLast);
}
}
@@ -1133,6 +1151,22 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead
}
}
/// <summary>
/// Gives a derived register-reader family access to the exact optical
/// line received from the serial port. The default implementation keeps
/// legacy iPerl behavior unchanged.
/// </summary>
protected virtual void NotifyOpticalTelegramCaptured(
string rawLine,
byte[] rawBytes,
DiagnosticLedState7Data parsedData,
int telegramIndex,
bool isMeasurementData,
double extendedVolume,
double extendedTimestamp)
{
}
public string ReadOptoData()
{
if (optoSerialPort is null) return "";
@@ -13,7 +13,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(IperlHeadCfg) })[0];
public override XmlSerializer GetSerializer() { return Serializer; }
public IComponentCfgCtrl GetControl(IList<Config.Entities.Component> cmpntEntities) { return new IperlHeadCfgCtrl(); }
public virtual IComponentCfgCtrl GetControl(IList<Config.Entities.Component> cmpntEntities) { return new IperlHeadCfgCtrl(); }
///
/// Serialized parameters
@@ -30,6 +30,14 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead
InitializeComponent();
}
public void ShowOnlyTab(bool manualTest)
{
tabControl1.Appearance = TabAppearance.FlatButtons;
tabControl1.ItemSize = new System.Drawing.Size(0, 1);
tabControl1.SizeMode = TabSizeMode.Fixed;
tabControl1.SelectedTab = manualTest ? tabPage2 : tabPage1;
}
private void WaterMeterCfgCtrl_Load(object sender, EventArgs e)
{
nameLabel.Text = Strings.Name;
+37
View File
@@ -53,6 +53,21 @@
<conversionPattern value="%date %-5level %message%newline" />
</layout>
</appender>
<!-- Fallback when ASIC per-WM diagnostics are disabled. -->
<appender name="AsicLog" type="log4net.Appender.RollingFileAppender">
<file value="C:\TBF\Logs\ASIC.log" />
<appendToFile value="true" />
<rollingStyle value="Composite" />
<datePattern value="'.'yyyy-MM-dd" />
<maximumFileSize value="10MB" />
<maxSizeRollBackups value="20" />
<staticLogFileName value="true" />
<countDirection value="1" />
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date %-5level %message%newline" />
</layout>
</appender>
<appender name="LogCache" type="AppDiagnostic.LogCacheAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
@@ -74,6 +89,11 @@
<logger name="ProcessData"><level value="INFO" /><appender-ref ref="ProcessData" /></logger>
<logger name="AllyOptical" additivity="false"><level value="INFO" /><appender-ref ref="AllyLog" /></logger>
<logger name="AsicOptical" additivity="false"><level value="INFO" /><appender-ref ref="AsicLog" /></logger>
<!-- Set program loggers -->
<logger name="TBF"> <appender-ref ref="TbfLog" /> <level value="WARN" /> </logger>
@@ -89,4 +109,21 @@
<logger name="TBF.Rig.Scales"> <level value="WARN" /> </logger>
<logger name="TBF.Rig.StateMachine"> <level value="INFO" /> </logger>
<logger name="TBF.Rig.State"> <level value="WARN" /> </logger>
<appender name="PoseidonOpticalLog" type="log4net.Appender.RollingFileAppender">
<file value="C:\TBF\Logs\Poseidon.log" />
<appendToFile value="true" />
<rollingStyle value="Composite" />
<datePattern value="'.'yyyy-MM-dd" />
<maximumFileSize value="10MB" />
<maxSizeRollBackups value="20" />
<staticLogFileName value="true" />
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date %-5level %message%newline" />
</layout>
</appender>
<logger name="PoseidonOptical" additivity="false">
<level value="INFO" />
<appender-ref ref="PoseidonOpticalLog" />
</logger>
</log4net>
+37
View File
@@ -1630,6 +1630,8 @@
<SubType>UserControl</SubType>
</Compile>
<Compile Include="Rig\RegisterReaders\AllyReader\AllyMeterReader.cs" />
<Compile Include="Rig\RegisterReaders\AllyReader\AllyOpticalDiagnosticWriter.cs" />
<Compile Include="Rig\RegisterReaders\PoseidonReader\PoseidonOpticalDiagnosticWriter.cs" />
<Compile Include="Rig\RegisterReaders\AllyReader\AllyOpticalTelegramRaw.cs" />
<Compile Include="Rig\RegisterReaders\AllyReader\AllyMeterSize.cs" />
<Compile Include="Rig\RegisterReaders\AllyReader\AllyOpticalSample.cs" />
@@ -1640,6 +1642,12 @@
<Compile Include="Rig\RegisterReaders\AllyReader\AllyReaderCfgCtrl.Designer.cs">
<DependentUpon>AllyReaderCfgCtrl.cs</DependentUpon>
</Compile>
<Compile Include="Rig\RegisterReaders\AllyReader\AllyReaderLogsCfgCtrl.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="Rig\RegisterReaders\AllyReader\AllyReaderLogsCfgCtrl.Designer.cs">
<DependentUpon>AllyReaderLogsCfgCtrl.cs</DependentUpon>
</Compile>
<Compile Include="Rig\RegisterReaders\AllyReader\AllyReaderManualTestCtrl.cs">
<SubType>UserControl</SubType>
</Compile>
@@ -1659,6 +1667,20 @@
<Compile Include="Rig\RegisterReaders\AllyReader\Factory.cs" />
<Compile Include="Rig\RegisterReaders\AsicReader\AsicReader.cs" />
<Compile Include="Rig\RegisterReaders\AsicReader\AsicReaderCfg.cs" />
<Compile Include="Rig\RegisterReaders\AsicReader\AsicOpticalDiagnosticWriter.cs" />
<Compile Include="Rig\Diagnostics\OpticalLogArchive.cs" />
<Compile Include="Rig\RegisterReaders\AsicReader\AsicReaderCfgCtrl.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="Rig\RegisterReaders\AsicReader\AsicReaderCfgCtrl.Designer.cs">
<DependentUpon>AsicReaderCfgCtrl.cs</DependentUpon>
</Compile>
<Compile Include="Rig\RegisterReaders\AsicReader\AsicReaderLogsCfgCtrl.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="Rig\RegisterReaders\AsicReader\AsicReaderLogsCfgCtrl.Designer.cs">
<DependentUpon>AsicReaderLogsCfgCtrl.cs</DependentUpon>
</Compile>
<Compile Include="Rig\RegisterReaders\AsicReader\Factory.cs" />
<Compile Include="Rig\RegisterReaders\GenesisRegReader\GenesisCfgCtrl.designer.cs">
<DependentUpon>GenesisCfgCtrl.cs</DependentUpon>
@@ -1802,6 +1824,12 @@
<Compile Include="Rig\RegisterReaders\PoseidonReader\PoseidonCfgCtrl.designer.cs">
<DependentUpon>PoseidonCfgCtrl.cs</DependentUpon>
</Compile>
<Compile Include="Rig\RegisterReaders\PoseidonReader\PoseidonLogsCfgCtrl.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="Rig\RegisterReaders\PoseidonReader\PoseidonLogsCfgCtrl.Designer.cs">
<DependentUpon>PoseidonLogsCfgCtrl.cs</DependentUpon>
</Compile>
<Compile Include="Rig\RegisterReaders\PoseidonReader\PoseidonHeadTestCtrl.cs">
<SubType>UserControl</SubType>
</Compile>
@@ -3886,9 +3914,15 @@
<EmbeddedResource Include="Rig\RegisterReaders\AllyReader\AllyReaderCfgCtrl.resx">
<DependentUpon>AllyReaderCfgCtrl.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Rig\RegisterReaders\AllyReader\AllyReaderLogsCfgCtrl.resx">
<DependentUpon>AllyReaderLogsCfgCtrl.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Rig\RegisterReaders\AllyReader\AllyReaderManualTestCtrl.resx">
<DependentUpon>AllyReaderManualTestCtrl.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Rig\RegisterReaders\AsicReader\AsicReaderLogsCfgCtrl.resx">
<DependentUpon>AsicReaderLogsCfgCtrl.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Rig\RegisterReaders\iPerlReaderUNI\IPerlUniCfgCtrl.resx">
<DependentUpon>IPerlUniCfgCtrl.cs</DependentUpon>
</EmbeddedResource>
@@ -3919,6 +3953,9 @@
<EmbeddedResource Include="Rig\RegisterReaders\PoseidonReader\PoseidonCfgCtrl.resx">
<DependentUpon>PoseidonCfgCtrl.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Rig\RegisterReaders\PoseidonReader\PoseidonLogsCfgCtrl.resx">
<DependentUpon>PoseidonLogsCfgCtrl.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Rig\RegisterReaders\PoseidonReader\PoseidonHeadTestCtrl.resx">
<DependentUpon>PoseidonHeadTestCtrl.cs</DependentUpon>
</EmbeddedResource>