laatzen/Common/Ui/GenesisToolBox/Infrastructure/TempMeterModels.cs
2023-10-05 09:21:54 +02:00

302 lines
9.5 KiB
C#

namespace Xylem.Common.Ui.GenesisToolBox.Infrastructure
{
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Timers;
using SystemThreadingThread = System.Threading.Thread;
internal interface ITempMeterForm
{
void AddMessage(string message);
double AvgTOF();
IAsyncResult BeginInvoke(Delegate @delegate);
void StartRecording();
}
public class CordonelTempLut
{
public int Id { get; set; }
public int PcbId { get; set; }
public double RefTempC { get; set; }
public double AvgTof { get; set; }
public bool Active { get; set; }
public DateTime? Timestamp { get; set; }
}
public class RefTempRange
{
public Double Min { get; set; }
public Double Max { get; set; }
}
public class TemperatureSource : IDisposable
{
[DllImport("GMH3x32E.dll")]
public static extern Int16 UniversalOpenCom(Int16 ini16COMPortNumber, UInt32 inui32BaudRate, Int16 inui16ConverterType, Int16 ini16Parity, Int16 ini16StoppBits);
[DllImport("GMH3x32E.dll")]
public static extern Int16 GMH_CloseCom();
[DllImport("GMH3x32E.dll")]
unsafe public static extern Int16 GMH_Transmit(Int16 ini16DeviceAddress, Int16 ini16TransmitCode, Int16* refi16ptrPriority, double* refdblptrFloatValue, Int32* refi32ptrIntegerValue);
public TemperatureSource() => UniversalOpenCom(Appsettings.GMHPort, 4800, 8, 0, 0);
public double GetTemperature()
{
var result = default(short);
var priority = default(short);
var temperature = default(double);
var value = default(int);
unsafe
{
result = GMH_Transmit(1, 0, &priority, &temperature, &value);
}
return temperature;
}
public void Dispose() => GMH_CloseCom();
}
partial class AutomaticTemperatureCalibration
{
private const string WORKING_DIR = @".\temperature_calibrations";
private const string MESSUREMENTS_FILE = @"_messurements.txt";
private const string AGGREGATIONS_FILE = @"_aggregations.txt";
private const NumberStyles ANY = NumberStyles.Any;
private readonly string pcbId;
private readonly string messurementsFile;
private readonly string aggregationsFile;
private readonly ITempMeterForm tempMeterForm;
private readonly CultureInfo en;
private readonly CultureInfo de;
private TemperatureSource temperatureSource;
private Timer longTimer;
private Timer shortTimer;
private bool messuring;
public AutomaticTemperatureCalibration(string pcbId, ITempMeterForm genesisMeter)
{
this.pcbId = pcbId;
this.tempMeterForm = genesisMeter;
this.messurementsFile = this.GetOrCreateMessurementsFile(this.pcbId);
this.aggregationsFile = this.GetOrCreateAggregationsFile(this.pcbId);
this.temperatureSource = new TemperatureSource();
this.en = new CultureInfo("en-US");
this.de = new CultureInfo("de-DE");
}
public void StartMessuring()
{
this.messuring = false;
this.temperatureSource = new TemperatureSource();
this.shortTimer = new Timer(Appsettings.MessurementStep)
{
Enabled = true,
AutoReset = true
};
this.shortTimer.Elapsed += this.ShortTimerElapsed;
this.shortTimer.Stop();
this.longTimer = new Timer(Appsettings.MessurementDauer)
{
Enabled = true,
AutoReset = true
};
this.longTimer.Elapsed += this.LongTimerElapsed;
this.LongTimerElapsed(null, null);
this.longTimer.Start();
File.AppendAllText(this.aggregationsFile, Environment.NewLine);
}
public void StopMessuring()
{
this.shortTimer?.Stop();
this.shortTimer?.Dispose();
this.shortTimer = null;
this.longTimer?.Stop();
this.longTimer?.Dispose();
this.longTimer = null;
this.temperatureSource?.Dispose();
this.temperatureSource = null;
}
private void LongTimerElapsed(Object sender, ElapsedEventArgs _)
{
this.messuring = !this.messuring;
SystemThreadingThread.Sleep(1_000);
if (this.messuring)
{
this.tempMeterForm.StartRecording();
this.shortTimer.Start();
}
else
{
this.shortTimer.Stop();
this.ParseMessurements();
}
}
private void ShortTimerElapsed(Object sender, ElapsedEventArgs args)
{
lock (this.shortTimer)
{
this.tempMeterForm.BeginInvoke(new Action(() =>
{
var currentTOF = this.tempMeterForm.AvgTOF();
var currentT = this.temperatureSource.GetTemperature();
var messurement = $"[{args.SignalTime:yyyy-MM-dd hh:mm:ss}]\t{this.pcbId,9}\t{currentT,5:00.00}\t{currentTOF,14:0.000000000000}";
if (this.messuring)
{
this.tempMeterForm.AddMessage(messurement);
File.AppendAllLines(this.messurementsFile, new[] { messurement });
}
}));
}
}
private String GetOrCreateMessurementsFile(string pcbId)
{
Directory.CreateDirectory(WORKING_DIR);
var filePath = $@"{WORKING_DIR}\{this.pcbId}{MESSUREMENTS_FILE}";
File.AppendAllText(filePath, Environment.NewLine);
return filePath;
}
private String GetOrCreateAggregationsFile(string pcbId)
{
Directory.CreateDirectory(WORKING_DIR);
var filePath = $@"{WORKING_DIR}\{this.pcbId}{AGGREGATIONS_FILE}";
if (!File.Exists(filePath))
{
File.WriteAllLines(filePath, new[] { Messurements.Header });
}
return filePath;
}
private void ParseMessurements()
{
var messurementLines = File.ReadAllLines(this.messurementsFile);
var messurements = new Messurements(this.pcbId);
File.WriteAllText(this.messurementsFile, string.Empty);
foreach (var messurementLine in messurementLines)
{
if (string.IsNullOrWhiteSpace(messurementLine))
{
continue;
}
var tokens = messurementLine
.Split(new[] { '\t' }, StringSplitOptions.RemoveEmptyEntries);
if (tokens.Length != 4)
{
continue;
}
var dateString = tokens[0];
var pcbString = tokens[1];
var tString = tokens[2];
var tofString = tokens[3];
var currentT = default(double);
var currentTOF = default(double);
try
{
var tParsed = double.TryParse(tString, ANY, this.en, out currentT) || double.TryParse(tString, ANY, this.de, out currentT);
var tofParsed = double.TryParse(tofString, ANY, this.en, out currentTOF) || double.TryParse(tofString, ANY, this.de, out currentTOF);
}
catch
{
continue;
}
messurements.Add(currentT, currentTOF);
}
File.AppendAllLines(this.aggregationsFile, new[] { messurements.ToString() });
}
}
class Messurements
{
private readonly string pcbId;
// _______________________________ t _____ tof _________________
private readonly ICollection<Tuple<double, double>> messurements
= new List<Tuple<double, double>>();
public Messurements(string pcbId)
=> this.pcbId = pcbId;
public double MinT => this.messurements.Min(x => x.Item1);
public double MinTOF => this.messurements.Min(x => x.Item2);
public double AvgT => this.messurements.Average(x => x.Item1);
public double AvgTOF => this.messurements.Average(x => x.Item2);
public double MaxT => this.messurements.Max(x => x.Item1);
public double MaxTOF => this.messurements.Max(x => x.Item2);
public double DifT => Math.Abs(this.MinT - this.MaxT);
public double DifTOF => Math.Abs(this.MinTOF - this.MaxTOF);
public int Count => this.messurements.Count;
public override String ToString()
=> $"{this.pcbId}"
+ $"\t{this.MinT:0.00}"
+ $"\t{this.MinTOF:0.0000000000}"
+ $"\t{this.AvgT:0.00}"
+ $"\t{this.AvgTOF:0.0000000000}"
+ $"\t{this.MaxT:0.00}"
+ $"\t{this.MaxTOF:0.0000000000}"
+ $"\t{this.DifT:0.00}"
+ $"\t{this.DifTOF:0.0000000000}"
+ $"\t{this.Count}";
public void Add(double t, double tof)
=> this.messurements.Add(new Tuple<double, double>(t, tof));
public static string Header
=> $"Pcb Id\tMin °C\tMin TOF\tAvg °C\tAvg TOF\tMax °C\tMax TOF\tDif °C\tDif TOF\tCount";
}
}