diff --git a/Elwig/App.xaml.cs b/Elwig/App.xaml.cs index 08be304..1f04ac8 100644 --- a/Elwig/App.xaml.cs +++ b/Elwig/App.xaml.cs @@ -53,6 +53,8 @@ namespace Elwig { public static string? BranchFaxNr { get; private set; } public static string? BranchMobileNr { get; private set; } public static IList Scales { get; private set; } + public static IList CommandScales => Scales.Where(s => s is ICommandScale).Cast().ToList(); + public static IList EventScales => Scales.Where(s => s is IEventScale).Cast().ToList(); public static ClientParameters Client { get; set; } public static bool IsPrintingReady => Html.IsReady && Pdf.IsReady; diff --git a/Elwig/Helpers/Weighing/IEventScale.cs b/Elwig/Helpers/Weighing/IEventScale.cs index 5c7da71..d0b550d 100644 --- a/Elwig/Helpers/Weighing/IEventScale.cs +++ b/Elwig/Helpers/Weighing/IEventScale.cs @@ -4,5 +4,8 @@ /// public interface IEventScale : IScale { + public event EventHandler WeighingEvent; + + delegate void EventHandler(object sender, WeighingEventArgs args); } } diff --git a/Elwig/Helpers/Weighing/Scale.cs b/Elwig/Helpers/Weighing/Scale.cs index 88c446b..97850e3 100644 --- a/Elwig/Helpers/Weighing/Scale.cs +++ b/Elwig/Helpers/Weighing/Scale.cs @@ -24,7 +24,7 @@ namespace Elwig.Helpers.Weighing { int? limit = config.Limit != null ? int.Parse(config.Limit) : null; if (config.Type == "SysTec-IT") { return new SysTecITScale(config.Id, config.Model!, config.Connection!, config.Empty, config.Filling, limit, config.Log); - } else if (config.Type == "Schember-evt") { + } else if (config.Type == "Schember-Evt") { return new SchemberEventScale(config.Id, config.Model!, config.Connection!, config.Empty, config.Filling, limit, config.Log); } else { throw new ArgumentException($"Invalid scale type: \"{config.Type}\""); @@ -39,7 +39,7 @@ namespace Elwig.Helpers.Weighing { Tcp = Utils.OpenTcpConnection(cnx); Stream = Tcp.GetStream(); } else { - throw new ArgumentException("Unsupported scheme"); + throw new ArgumentException($"Unsupported scheme: \"{cnx.Split(':')[0]}\""); } LogPath = log; diff --git a/Elwig/Helpers/Weighing/SchemberEventScale.cs b/Elwig/Helpers/Weighing/SchemberEventScale.cs index 88559e3..a556059 100644 --- a/Elwig/Helpers/Weighing/SchemberEventScale.cs +++ b/Elwig/Helpers/Weighing/SchemberEventScale.cs @@ -1,5 +1,12 @@ -namespace Elwig.Helpers.Weighing { - public class SchemberEventScale : Scale, IEventScale { +using System; +using System.IO; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows; + +namespace Elwig.Helpers.Weighing { + public class SchemberEventScale : Scale, IEventScale, IDisposable { public string Manufacturer => "Schember"; public int InternalScaleNr => 1; @@ -8,15 +15,74 @@ 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; + public SchemberEventScale(string id, string model, string cnx, string? empty = null, string? filling = null, int? limit = null, string? log = null) : base(cnx, empty, filling, limit, log) { ScaleId = id; Model = model; IsReady = true; HasFillingClearance = false; - Stream.WriteTimeout = 250; - Stream.ReadTimeout = 6000; + BackgroundThread = new Thread(new ParameterizedThreadStart(BackgroundLoop)); + BackgroundThread.Start(); } + protected virtual void RaiseWeighingEvent(WeighingEventArgs evt) { + App.MainDispatcher.BeginInvoke(() => 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(); + RaiseWeighingEvent(new WeighingEventArgs(data)); + } catch (Exception ex) { + MessageBox.Show($"Beim Wiegen ist ein Fehler Aufgetreten:\n\n{ex.Message}", "Waagenfehler", + MessageBoxButton.OK, MessageBoxImage.Error); + } + } + } + + protected async Task Receive() { + string? line = null; + using (var reader = new StreamReader(Stream, Encoding.ASCII, false, -1, true)) { + line = await reader.ReadLineAsync(); + if (LogPath != null) await File.AppendAllTextAsync(LogPath, $"{line}\r\n"); + } + if (line == null || line.Length != 32 || line[0] != ' ' || line[9] != ' ' || line[15] != ' ' || line[20] != ' ') { + throw new IOException($"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 IOException($"Unsupported unit in weighing event: '{unit}'"); + } + + identNr = identNr.Length > 0 && identNr != "0" ? identNr : null; + var parsedDate = DateOnly.Parse(date); + return new() { + Weight = int.Parse(netto), + WeighingId = identNr, + FullWeighingId = identNr != null ? $"{parsedDate:yyyy-MM-dd}/{identNr}" : null, + Date = parsedDate, + Time = TimeOnly.Parse(time), + }; + } } } diff --git a/Elwig/Helpers/Weighing/WeighingEventArgs.cs b/Elwig/Helpers/Weighing/WeighingEventArgs.cs new file mode 100644 index 0000000..e74d5fa --- /dev/null +++ b/Elwig/Helpers/Weighing/WeighingEventArgs.cs @@ -0,0 +1,12 @@ +using System; + +namespace Elwig.Helpers.Weighing { + public class WeighingEventArgs : EventArgs { + + public WeighingResult Result { get; set; } + + public WeighingEventArgs(WeighingResult result) { + Result = result; + } + } +} diff --git a/Elwig/Windows/DeliveryAdminWindow.xaml.cs b/Elwig/Windows/DeliveryAdminWindow.xaml.cs index ffa5b30..3c8069d 100644 --- a/Elwig/Windows/DeliveryAdminWindow.xaml.cs +++ b/Elwig/Windows/DeliveryAdminWindow.xaml.cs @@ -76,17 +76,20 @@ namespace Elwig.Windows { if (IsReceipt) { Title = $"Übernahme - {App.BranchName} - Elwig"; TodayOnlyInput.IsChecked = true; - var n = App.Scales.Count; + var n = App.CommandScales.Count; if (n < 1) WeighingAButton.Visibility = Visibility.Hidden; if (n < 2) WeighingBButton.Visibility = Visibility.Hidden; if (n < 3) WeighingCButton.Visibility = Visibility.Hidden; if (n < 4) WeighingDButton.Visibility = Visibility.Hidden; if (n == 1) WeighingAButton.Content = "Wiegen"; - if (n > 1) WeighingAButton.Content = $"Wiegen {App.Scales[0].ScaleId}"; - if (n >= 2) WeighingBButton.Content = $"Wiegen {App.Scales[1].ScaleId}"; - if (n >= 3) WeighingCButton.Content = $"Wiegen {App.Scales[2].ScaleId}"; - if (n >= 4) WeighingDButton.Content = $"Wiegen {App.Scales[3].ScaleId}"; + if (n > 1) WeighingAButton.Content = $"Wiegen {App.CommandScales[0].ScaleId}"; + if (n >= 2) WeighingBButton.Content = $"Wiegen {App.CommandScales[1].ScaleId}"; + if (n >= 3) WeighingCButton.Content = $"Wiegen {App.CommandScales[2].ScaleId}"; + if (n >= 4) WeighingDButton.Content = $"Wiegen {App.CommandScales[3].ScaleId}"; WeighingManualButton.Margin = new Thickness(10, 10 + n * 32, 10, 10); + foreach (var s in App.EventScales) { + s.WeighingEvent += Scale_Weighing; + } } else { WeighingManualButton.Visibility = Visibility.Hidden; WeighingAButton.Visibility = Visibility.Hidden; @@ -967,35 +970,43 @@ namespace Elwig.Windows { FinishButton.IsEnabled = false; NewDeliveryPartButton.IsEnabled = false; CancelCreatingButton.IsEnabled = false; + var s = App.CommandScales[index]; try { - var s = App.Scales[index]; - if (s is not ICommandScale cs) return; - var res = await cs.Weigh(); - if ((res.Weight ?? 0) > 0 && res.FullWeighingId != null) { - WeightInput.Text = $"{res.Weight:N0}"; - ScaleId = s.ScaleId; - WeighingId = res.FullWeighingId; - } else { - WeightInput.Text = ""; - ScaleId = null; - WeighingId = null; - } - LastScaleError = null; - } catch (Exception e) { - LastScaleError = e.Message.Split(": ")[^1]; - WeightInput.Text = ""; - ScaleId = null; - WeighingId = null; - MessageBox.Show($"Beim Wiegen ist ein Fehler aufgetreten:\n\n{e.Message}", "Waagenfehler", + var res = await s.Weigh(); + OnWeighingResult(s, res); + } catch (Exception ex) { + LastScaleError = ex.Message.Split(": ")[^1]; + OnWeighingResult(s, new() { Weight = 0 }); + MessageBox.Show($"Beim Wiegen ist ein Fehler aufgetreten:\n\n{ex.Message}", "Waagenfehler", MessageBoxButton.OK, MessageBoxImage.Error); } ManualWeighingReason = null; ManualWeighingInput.IsChecked = false; - base.TextBox_TextChanged(WeightInput, null); EnableWeighingButtons(); + } + + private void OnWeighingResult(IScale scale, WeighingResult res) { + if ((res.Weight ?? 0) > 0 && res.FullWeighingId != null) { + WeightInput.Text = $"{res.Weight:N0}"; + ScaleId = scale.ScaleId; + WeighingId = res.FullWeighingId; + ManualWeighingReason = null; + ManualWeighingInput.IsChecked = false; + } else { + WeightInput.Text = ""; + ScaleId = null; + WeighingId = null; + } + LastScaleError = null; + TextBox_TextChanged(WeightInput, null); UpdateButtons(); } + private void Scale_Weighing(object sender, WeighingEventArgs evt) { + if (sender is not IScale scale) return; + OnWeighingResult(scale, evt.Result); + } + private async void SearchInput_TextChanged(object sender, RoutedEventArgs evt) { TextFilter = SearchInput.Text.ToLower().Split(" ").ToList().FindAll(e => e.Length > 0); await RefreshDeliveryListQuery(true); @@ -1511,11 +1522,11 @@ namespace Elwig.Windows { private void EnableWeighingButtons() { WeighingManualButton.IsEnabled = true; - var n = App.Scales.Count; - WeighingAButton.IsEnabled = n > 0 && App.Scales[0].IsReady; - WeighingBButton.IsEnabled = n > 1 && App.Scales[1].IsReady; - WeighingCButton.IsEnabled = n > 2 && App.Scales[2].IsReady; - WeighingDButton.IsEnabled = n > 3 && App.Scales[3].IsReady; + var n = App.CommandScales.Count; + WeighingAButton.IsEnabled = n > 0 && App.CommandScales[0].IsReady; + WeighingBButton.IsEnabled = n > 1 && App.CommandScales[1].IsReady; + WeighingCButton.IsEnabled = n > 2 && App.CommandScales[2].IsReady; + WeighingDButton.IsEnabled = n > 3 && App.CommandScales[3].IsReady; } private async Task UpdateLsNr() {