131 lines
4.9 KiB
C#
131 lines
4.9 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using System.Windows;
|
|
|
|
namespace Elwig.Helpers.Weighing {
|
|
public class AveryEventScale : Scale, IEventScale, IDisposable {
|
|
|
|
public string Manufacturer => "Avery";
|
|
public int InternalScaleNr => 1;
|
|
public string Model { get; private set; }
|
|
public string ScaleId { get; private set; }
|
|
public bool IsReady { get; private set; }
|
|
public bool HasFillingClearance { get; private set; }
|
|
|
|
public event IEventScale.EventHandler<WeighingEventArgs>? WeighingEvent;
|
|
|
|
private bool IsRunning = true;
|
|
private readonly Thread BackgroundThread;
|
|
private readonly string Connection;
|
|
|
|
public AveryEventScale(string id, string model, string cnx, string? log = null, bool required = true) :
|
|
base(cnx, null, null, null, log, true, !required) {
|
|
ScaleId = id;
|
|
Model = model;
|
|
Connection = cnx;
|
|
IsReady = true;
|
|
HasFillingClearance = false;
|
|
Stream.WriteTimeout = -1;
|
|
Stream.ReadTimeout = -1;
|
|
BackgroundThread = new Thread(new ParameterizedThreadStart(BackgroundLoop));
|
|
BackgroundThread.Start();
|
|
}
|
|
|
|
protected virtual void RaiseWeighingEvent(WeighingEventArgs evt) {
|
|
WeighingEvent?.Invoke(this, evt);
|
|
}
|
|
|
|
public new void Dispose() {
|
|
IsRunning = false;
|
|
BackgroundThread.Interrupt();
|
|
BackgroundThread.Join();
|
|
base.Dispose();
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
protected async void BackgroundLoop(object? parameters) {
|
|
while (IsRunning) {
|
|
try {
|
|
var data = await Receive();
|
|
if (data != null)
|
|
RaiseWeighingEvent(new WeighingEventArgs(data.Value));
|
|
} catch (ThreadInterruptedException) {
|
|
// ignore
|
|
} catch (IOException) {
|
|
await Task.Delay(500);
|
|
await Reconnect();
|
|
} catch (TimeoutException) {
|
|
await Task.Delay(500);
|
|
await Reconnect();
|
|
} catch (Exception ex) {
|
|
MessageBox.Show($"Beim Wiegen ist ein Fehler Aufgetreten:\n\n{ex.Message} ({ex.GetType().Name})", "Waagenfehler",
|
|
MessageBoxButton.OK, MessageBoxImage.Error);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected async Task Reconnect() {
|
|
try { Reader.Close(); } catch { }
|
|
try { Stream.Close(); } catch { }
|
|
try { Serial?.Close(); } catch { }
|
|
while (IsRunning) {
|
|
try {
|
|
if (Connection.StartsWith("serial:")) {
|
|
Serial = Utils.OpenSerialConnection(Connection);
|
|
Stream = Serial.BaseStream;
|
|
} else if (Connection.StartsWith("tcp:")) {
|
|
Tcp = Utils.OpenTcpConnection(Connection);
|
|
Stream = Tcp.GetStream();
|
|
}
|
|
Reader = new(Stream, Encoding.ASCII, false, 512);
|
|
break;
|
|
} catch {
|
|
// ignore
|
|
}
|
|
await Task.Delay(1000);
|
|
}
|
|
}
|
|
|
|
protected async Task<WeighingResult?> Receive() {
|
|
var line = "";
|
|
while (line.Length < 33) {
|
|
var ch = Reader.Read();
|
|
if (ch == -1) {
|
|
throw new IOException("Connection closed");
|
|
} else if (line.Length > 0 || ch == ' ') {
|
|
line += char.ToString((char)ch);
|
|
}
|
|
}
|
|
if (LogPath != null) await File.AppendAllTextAsync(LogPath, line);
|
|
if (line == null || line == "") {
|
|
return null;
|
|
} else if (line.Length != 33 || line[0] != ' ' || line[9] != ' ' || line[15] != ' ' || line[20] != ' ' || line[32] != ' ') {
|
|
throw new FormatException($"Invalid event from scale: '{line}'");
|
|
}
|
|
|
|
var date = line[ 1.. 9];
|
|
var time = line[10..15];
|
|
var identNr = line[16..20].Trim();
|
|
var netto = line[21..30].Trim();
|
|
var unit = line[30..32];
|
|
|
|
if (unit != "kg") {
|
|
throw new WeighingException($"Unsupported unit in weighing event: '{unit}'");
|
|
}
|
|
|
|
identNr = identNr.Length > 0 && identNr != "0" ? identNr : null;
|
|
var parsedDate = DateOnly.Parse(date);
|
|
return new() {
|
|
NetWeight = int.Parse(netto),
|
|
WeighingId = identNr,
|
|
FullWeighingId = identNr != null ? $"{parsedDate:yyyy-MM-dd}/{identNr}" : null,
|
|
Date = parsedDate,
|
|
Time = TimeOnly.Parse(time),
|
|
};
|
|
}
|
|
}
|
|
}
|