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? 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 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), }; } } }