Added scales
This commit is contained in:
		| @@ -5,6 +5,9 @@ using System.Windows; | |||||||
| using System.Windows.Controls; | using System.Windows.Controls; | ||||||
| using System.IO; | using System.IO; | ||||||
| using Elwig.Helpers; | using Elwig.Helpers; | ||||||
|  | using Elwig.Helpers.Weighing; | ||||||
|  | using System.Collections.Generic; | ||||||
|  | using System.Windows.Threading; | ||||||
|  |  | ||||||
| namespace Elwig { | namespace Elwig { | ||||||
|     public partial class App : Application { |     public partial class App : Application { | ||||||
| @@ -12,15 +15,17 @@ namespace Elwig { | |||||||
|         public static readonly string DataPath = @"C:\ProgramData\Elwig\"; |         public static readonly string DataPath = @"C:\ProgramData\Elwig\"; | ||||||
|         public static readonly string ExePath = @"C:\Program Files\Elwig\"; |         public static readonly string ExePath = @"C:\Program Files\Elwig\"; | ||||||
|         public static readonly Config Config = new(DataPath + "config.ini"); |         public static readonly Config Config = new(DataPath + "config.ini"); | ||||||
|  |         public static IEnumerable<IScale> Scales { get; private set; } | ||||||
|  |  | ||||||
|         public static bool IsPrintingReady => Documents.Html.IsReady && Documents.Pdf.IsReady; |         public static bool IsPrintingReady => Documents.Html.IsReady && Documents.Pdf.IsReady; | ||||||
|         public static System.Windows.Threading.Dispatcher MainDispatcher { get; private set; } |         public static Dispatcher MainDispatcher { get; private set; } | ||||||
|  |  | ||||||
|         public App() : base() { |         public App() : base() { | ||||||
|             System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance); |             System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance); | ||||||
|             Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), "Elwig")); |             Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), "Elwig")); | ||||||
|             Directory.CreateDirectory(DataPath); |             Directory.CreateDirectory(DataPath); | ||||||
|             MainDispatcher = Dispatcher; |             MainDispatcher = Dispatcher; | ||||||
|  |             Scales = Array.Empty<IScale>(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         protected override void OnStartup(StartupEventArgs evt) { |         protected override void OnStartup(StartupEventArgs evt) { | ||||||
| @@ -32,6 +37,25 @@ namespace Elwig { | |||||||
|             } |             } | ||||||
|             Utils.RunBackground("HTML Initialization", () => Documents.Html.Init(PrintingReadyChanged)); |             Utils.RunBackground("HTML Initialization", () => Documents.Html.Init(PrintingReadyChanged)); | ||||||
|             Utils.RunBackground("PDF Initialization", () => Documents.Pdf.Init(PrintingReadyChanged)); |             Utils.RunBackground("PDF Initialization", () => Documents.Pdf.Init(PrintingReadyChanged)); | ||||||
|  |  | ||||||
|  |             var list = new LinkedList<IScale>(); | ||||||
|  |             foreach (var s in Config.Scales) { | ||||||
|  |                 try { | ||||||
|  |                     var scaleNr = int.Parse(s[0]); | ||||||
|  |                     var type = s[1].ToLower(); | ||||||
|  |                     var model = s[2]; | ||||||
|  |                     var cnx = s[3]; | ||||||
|  |                     var empty = s[4]; | ||||||
|  |                     var filling = s[5]; | ||||||
|  |                     if (type == "systec") { | ||||||
|  |                         list.AddLast(new SystecScale(scaleNr, model, cnx, empty, filling)); | ||||||
|  |                     } | ||||||
|  |                 } catch (Exception e) { | ||||||
|  |                     MessageBox.Show($"Unable to create scale {s[0]}:\n\n{e.Message}", "Scale Error", MessageBoxButton.OK, MessageBoxImage.Error); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             Scales = list; | ||||||
|  |  | ||||||
|             base.OnStartup(evt); |             base.OnStartup(evt); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -24,6 +24,7 @@ | |||||||
|     <PackageReference Include="PdfSharp" Version="1.50.5147" /> |     <PackageReference Include="PdfSharp" Version="1.50.5147" /> | ||||||
|     <PackageReference Include="PuppeteerSharp" Version="9.1.0" /> |     <PackageReference Include="PuppeteerSharp" Version="9.1.0" /> | ||||||
|     <PackageReference Include="RazorLight" Version="2.3.1" /> |     <PackageReference Include="RazorLight" Version="2.3.1" /> | ||||||
|  |     <PackageReference Include="System.IO.Ports" Version="7.0.0" /> | ||||||
|     <PackageReference Include="System.Text.Encoding.CodePages" Version="7.0.0" /> |     <PackageReference Include="System.Text.Encoding.CodePages" Version="7.0.0" /> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -43,7 +43,7 @@ namespace Elwig.Helpers { | |||||||
|                         AutoFlush = true |                         AutoFlush = true | ||||||
|                     }; |                     }; | ||||||
|                 } catch (Exception e) { |                 } catch (Exception e) { | ||||||
|                     MessageBox.Show($"Unable to open database log file:\n\n{e}", "Database Log", MessageBoxButton.OK, MessageBoxImage.Error); |                     MessageBox.Show($"Unable to open database log file:\n\n{e.Message}", "Database Log", MessageBoxButton.OK, MessageBoxImage.Error); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -1,4 +1,6 @@ | |||||||
|  | using System.Collections.Generic; | ||||||
| using System.IO; | using System.IO; | ||||||
|  | using System.Linq; | ||||||
| using System.Text; | using System.Text; | ||||||
| using IniParser; | using IniParser; | ||||||
| using IniParser.Model; | using IniParser.Model; | ||||||
| @@ -9,9 +11,12 @@ namespace Elwig.Helpers { | |||||||
|         private readonly string FileName; |         private readonly string FileName; | ||||||
|         public string DatabaseFile = App.DataPath + "database.sqlite3"; |         public string DatabaseFile = App.DataPath + "database.sqlite3"; | ||||||
|         public string? DatabaseLog = null; |         public string? DatabaseLog = null; | ||||||
|  |         public IEnumerable<string[]> Scales; | ||||||
|  |         private readonly LinkedList<string[]> ScaleList = new(); | ||||||
|  |  | ||||||
|         public Config(string filename) { |         public Config(string filename) { | ||||||
|             FileName = filename; |             FileName = filename; | ||||||
|  |             Scales = ScaleList; | ||||||
|             Read(); |             Read(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -37,12 +42,27 @@ namespace Elwig.Helpers { | |||||||
|             } else { |             } else { | ||||||
|                 DatabaseLog = App.DataPath + log; |                 DatabaseLog = App.DataPath + log; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  |             ScaleList.Clear(); | ||||||
|  |             Scales = ScaleList; | ||||||
|  |             if (ini != null) { | ||||||
|  |                 foreach (var s in ini.Sections.Where(s => s.SectionName.StartsWith("scale."))) { | ||||||
|  |                     ScaleList.AddLast(new string[] { | ||||||
|  |                         s.SectionName[6..], s.Keys["type"], s.Keys["model"], s.Keys["connection"], s.Keys["empty"], s.Keys["filling"] | ||||||
|  |                     }); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         public void Write() { |         public void Write() { | ||||||
|             using var file = new StreamWriter(FileName, false, Encoding.UTF8); |             using var file = new StreamWriter(FileName, false, Encoding.UTF8); | ||||||
|             file.Write($"\r\n[database]\r\nfile = {DatabaseFile}\r\n"); |             file.Write($"\r\n[database]\r\nfile = {DatabaseFile}\r\n"); | ||||||
|             if (DatabaseLog != null) file.Write($"log = {DatabaseLog}\r\n"); |             if (DatabaseLog != null) file.Write($"log = {DatabaseLog}\r\n"); | ||||||
|  |             foreach (var s in ScaleList) { | ||||||
|  |                 file.Write($"\r\n[scale.{s[0]}]\r\ntype = {s[1]}\r\nmodel = {s[2]}\r\nconnection = {s[3]}\r\n"); | ||||||
|  |                 if (s[4] != null) file.Write($"empty = {s[4]}\r\n"); | ||||||
|  |                 if (s[5] != null) file.Write($"filling = {s[5]}\r\n"); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										66
									
								
								Elwig/Helpers/Weighing/IScale.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								Elwig/Helpers/Weighing/IScale.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,66 @@ | |||||||
|  | using System; | ||||||
|  | using System.Threading.Tasks; | ||||||
|  |  | ||||||
|  | namespace Elwig.Helpers.Weighing { | ||||||
|  |     /// <summary> | ||||||
|  |     /// Interface for controlling a industrial scale | ||||||
|  |     /// </summary> | ||||||
|  |     public interface IScale : IDisposable { | ||||||
|  |         /// <summary> | ||||||
|  |         /// Manufacturer of the scale | ||||||
|  |         /// </summary> | ||||||
|  |         string Manufacturer { get; } | ||||||
|  |  | ||||||
|  |         /// <summary> | ||||||
|  |         /// Model of the scale | ||||||
|  |         /// </summary> | ||||||
|  |         string Model { get; } | ||||||
|  |  | ||||||
|  |         /// <summary> | ||||||
|  |         /// Unique number of the scale | ||||||
|  |         /// </summary> | ||||||
|  |         int ScaleNr { get; } | ||||||
|  |  | ||||||
|  |         /// <summary> | ||||||
|  |         /// Internal identifying number of the scale in its system | ||||||
|  |         /// </summary> | ||||||
|  |         int InternalScaleNr { get; } | ||||||
|  |  | ||||||
|  |         /// <summary> | ||||||
|  |         /// Indicates if the scale is currently processing a request or not | ||||||
|  |         /// </summary> | ||||||
|  |         bool IsReady { get; } | ||||||
|  |  | ||||||
|  |         /// <summary> | ||||||
|  |         /// Indicates if the the clearance for filling the scale container has been granted | ||||||
|  |         /// </summary> | ||||||
|  |         bool HasFillingClearance { get; } | ||||||
|  |  | ||||||
|  |         /// <summary> | ||||||
|  |         /// Get the current weight on the scale without performing a weighing process | ||||||
|  |         /// </summary> | ||||||
|  |         /// <returns>Result of the weighing process (probably without a weighing id)</returns> | ||||||
|  |         Task<WeighingResult> GetCurrentWeight(); | ||||||
|  |  | ||||||
|  |         /// <summary> | ||||||
|  |         /// Perform a weighing process | ||||||
|  |         /// </summary> | ||||||
|  |         /// <returns>Result of the weighing process (including a weighing id)</returns> | ||||||
|  |         Task<WeighingResult> Weigh(); | ||||||
|  |  | ||||||
|  |         /// <summary> | ||||||
|  |         /// Empty the scale container or grant clearance to do so | ||||||
|  |         /// </summary> | ||||||
|  |         Task Empty(); | ||||||
|  |  | ||||||
|  |         /// <summary> | ||||||
|  |         /// Grant clearance to fill the scale container | ||||||
|  |         /// </summary> | ||||||
|  |         Task GrantFillingClearance(); | ||||||
|  |  | ||||||
|  |         /// <summary> | ||||||
|  |         /// Revoke clearance to fill the scale container | ||||||
|  |         /// </summary> | ||||||
|  |         Task RevokeFillingClearance(); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										227
									
								
								Elwig/Helpers/Weighing/SystecScale.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										227
									
								
								Elwig/Helpers/Weighing/SystecScale.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,227 @@ | |||||||
|  | using System; | ||||||
|  | using System.IO; | ||||||
|  | using System.IO.Ports; | ||||||
|  | using System.Net.Sockets; | ||||||
|  | using System.Text; | ||||||
|  | using System.Text.RegularExpressions; | ||||||
|  | using System.Threading.Tasks; | ||||||
|  |  | ||||||
|  | namespace Elwig.Helpers.Weighing { | ||||||
|  |     public class SystecScale : IScale { | ||||||
|  |  | ||||||
|  |         protected enum Output { RTS, DTR, OUT1, OUT2 }; | ||||||
|  |  | ||||||
|  |         protected SerialPort? Serial = null; | ||||||
|  |         protected TcpClient? Tcp = null; | ||||||
|  |         protected StreamReader Reader; | ||||||
|  |         protected StreamWriter Writer; | ||||||
|  |  | ||||||
|  |         protected readonly Output? EmptyMode = null; | ||||||
|  |         protected readonly Output? FillingClearanceMode = null; | ||||||
|  |         protected readonly int EmptyDelay; | ||||||
|  |  | ||||||
|  |         protected static readonly Regex SerialRe = new(@"^serial://([A-Za-z0-9]+):([0-9]+)(,([5-9]),([NOEMSnoems]),(0|1|1\.5|2|))?$", RegexOptions.Compiled); | ||||||
|  |         protected static readonly Regex TcpRe = new(@"^tcp://[A-Za-z0-9:._-]+(:[0-9]+)?$", RegexOptions.Compiled); | ||||||
|  |  | ||||||
|  |         public string Manufacturer => "SysTec"; | ||||||
|  |         public int InternalScaleNr => 1; | ||||||
|  |         public string Model { get; private set; } | ||||||
|  |         public int ScaleNr { get; private set; } | ||||||
|  |         public bool IsReady { get; private set; } | ||||||
|  |         public bool HasFillingClearance { get; private set; } | ||||||
|  |  | ||||||
|  |         public SystecScale(int scaleNr, string model, string connection, string? empty = null, string? fill = null) { | ||||||
|  |             ScaleNr = scaleNr; | ||||||
|  |             Model = model; | ||||||
|  |             IsReady = true; | ||||||
|  |             HasFillingClearance = false; | ||||||
|  |  | ||||||
|  |             Stream stream; | ||||||
|  |  | ||||||
|  |             if (connection.StartsWith("serial:")) { | ||||||
|  |                 var m = SerialRe.Match(connection); | ||||||
|  |                 if (!m.Success) | ||||||
|  |                     throw new ArgumentException("Invalid connection string for scheme \"serial\""); | ||||||
|  |  | ||||||
|  |                 var stop = m.Groups[6].Value; | ||||||
|  |                 var parity = m.Groups[5].Value.ToUpper(); | ||||||
|  |                 var data = m.Groups[4].Value; | ||||||
|  |                 Serial = new() { | ||||||
|  |                     PortName = m.Groups[1].Value, | ||||||
|  |                     BaudRate = int.Parse(m.Groups[2].Value), | ||||||
|  |                     Parity = parity == "E" ? Parity.Even : | ||||||
|  |                              parity == "O" ? Parity.Odd : | ||||||
|  |                              parity == "M" ? Parity.Mark : | ||||||
|  |                              parity == "S" ? Parity.Space : | ||||||
|  |                                              Parity.None, | ||||||
|  |                     DataBits = data == "" ? 8 : int.Parse(data), | ||||||
|  |                     StopBits = (StopBits)(stop == "" ? 1 : stop == "1.5" ? 3 : stop[0] - '0'), | ||||||
|  |                     Handshake = Handshake.None, | ||||||
|  |                 }; | ||||||
|  |                 Serial.Open(); | ||||||
|  |                 stream = Serial.BaseStream; | ||||||
|  |             } else if (connection.StartsWith("tcp:")) { | ||||||
|  |                 var m = TcpRe.Match(connection); | ||||||
|  |                 if (!m.Success) | ||||||
|  |                     throw new ArgumentException("Invalid connection string for scheme \"tcp\""); | ||||||
|  |  | ||||||
|  |                 Tcp = new() { | ||||||
|  |                     SendTimeout = 250, | ||||||
|  |                     ReceiveTimeout = 250, | ||||||
|  |                 }; | ||||||
|  |                 Tcp.Connect(m.Groups[1].Value, int.Parse(m.Groups[2].Value)); | ||||||
|  |                 stream = Tcp.GetStream(); | ||||||
|  |             } else { | ||||||
|  |                 throw new ArgumentException("Unsupported scheme"); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (empty != null) { | ||||||
|  |                 var parts = empty.Split(':'); | ||||||
|  |                 EmptyMode = ConvertOutput(parts[0]); | ||||||
|  |                 EmptyDelay = int.Parse(parts[1]); | ||||||
|  |             } | ||||||
|  |             FillingClearanceMode = ConvertOutput(fill); | ||||||
|  |  | ||||||
|  |             Writer = new(stream, Encoding.ASCII, -1, true); | ||||||
|  |             Reader = new(stream, Encoding.ASCII, false, -1, true); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public void Dispose() { | ||||||
|  |             Writer.Close(); | ||||||
|  |             Reader.Close(); | ||||||
|  |             Serial?.Close(); | ||||||
|  |             Tcp?.Close(); | ||||||
|  |             GC.SuppressFinalize(this); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         protected static Output? ConvertOutput(string? value) { | ||||||
|  |             if (value == null) return null; | ||||||
|  |             value = value.ToUpper(); | ||||||
|  |             if (value == "RTS") { | ||||||
|  |                 return Output.RTS; | ||||||
|  |             } else if (value == "DTR") { | ||||||
|  |                 return Output.DTR; | ||||||
|  |             } else if (value == "OUT1") { | ||||||
|  |                 return Output.OUT1; | ||||||
|  |             } else if (value == "OUT2") { | ||||||
|  |                 return Output.OUT2; | ||||||
|  |             } | ||||||
|  |             throw new ArgumentException("Invalid value for argument empty"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public async Task SendCommand(string command) { | ||||||
|  |             await Writer.WriteAsync($"<{command}>"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public async Task<string> ReceiveResponse() { | ||||||
|  |             var line = await Reader.ReadLineAsync(); | ||||||
|  |             if (line == null || line.Length < 4 || !line.StartsWith("<") || !line.EndsWith(">")) { | ||||||
|  |                 throw new IOException("Invalid response from scale"); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             var error = line[1..3]; | ||||||
|  |             if (error[0] == '0') { | ||||||
|  |                 if (error[1] != '0') { | ||||||
|  |                     throw new IOException($"Invalid response from scale (error code {error}"); | ||||||
|  |                 } | ||||||
|  |             } else if (error[0] == '1') { | ||||||
|  |                 string msg = $"Unbekannter Fehler (Fehler code {error})"; | ||||||
|  |                 switch (error[1]) { | ||||||
|  |                     case '1': msg = "Allgemeiner Waagenfehler"; break; | ||||||
|  |                     case '2': msg = "Waage in Überlast"; break; | ||||||
|  |                     case '3': msg = "Waage in Bewegung"; break; | ||||||
|  |                     case '5': msg = "Tarierungs- oder Nullsetzfehler"; break; | ||||||
|  |                     case '6': msg = "Drucker nicht bereit"; break; | ||||||
|  |                     case '7': msg = "Druckmuster enthält ungültiges Kommando"; break; | ||||||
|  |                 } | ||||||
|  |                 throw new IOException($"Waagenfehler {error}: {msg}"); | ||||||
|  |             } else if (error[0] == '3') { | ||||||
|  |                 string msg = $"Unbekannter Fehler (Fehler code {error})"; | ||||||
|  |                 switch (error[1]) { | ||||||
|  |                     case '1': msg = "Übertragunsfehler"; break; | ||||||
|  |                     case '2': msg = "Ungültiger Befehl"; break; | ||||||
|  |                     case '3': msg = "Ungültiger Parameter"; break; | ||||||
|  |                 } | ||||||
|  |                 throw new IOException($"Kommunikationsfehler {error}: {msg}"); | ||||||
|  |             } else { | ||||||
|  |                 throw new IOException($"Invalid response from scale (error code {error})"); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return line[3..(line.Length - 1)]; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         protected async Task<WeighingResult> Weigh(bool incIdentNr) { | ||||||
|  |             await SendCommand(incIdentNr ? $"RM{InternalScaleNr}" : $"RN{InternalScaleNr}"); | ||||||
|  |             string line = await ReceiveResponse(); | ||||||
|  |  | ||||||
|  |             var status     = line[ 0.. 2]; | ||||||
|  |             var date       = line[ 2..10]; | ||||||
|  |             var time       = line[10..15]; | ||||||
|  |             var identNr    = line[15..19]; | ||||||
|  |             var scaleNr    = line[19..20]; | ||||||
|  |             var brutto     = line[20..28]; | ||||||
|  |             var tara       = line[28..36]; | ||||||
|  |             var netto      = line[36..44]; | ||||||
|  |             var unit       = line[44..46]; | ||||||
|  |             var taraCode   = line[46..48]; | ||||||
|  |             var zone       = line[48..49]; | ||||||
|  |             var terminalNr = line[49..52]; | ||||||
|  |             var crc16      = line[52..60]; | ||||||
|  |  | ||||||
|  |             return new() { | ||||||
|  |                 Weight = int.TryParse(netto.Trim(), out int w) ? w : null, | ||||||
|  |                 WeighingId = identNr.Trim().Length > 0 ? identNr.Trim() : null, | ||||||
|  |                 Date = date, | ||||||
|  |                 Time = time, | ||||||
|  |             }; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public async Task<WeighingResult> Weigh() { | ||||||
|  |             return await Weigh(true); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public async Task<WeighingResult> GetCurrentWeight() { | ||||||
|  |             return await Weigh(false); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public async Task Empty() { | ||||||
|  |             if (EmptyMode == Output.RTS && Serial != null) { | ||||||
|  |                 Serial.RtsEnable = true; | ||||||
|  |                 await Task.Delay(EmptyDelay); | ||||||
|  |                 Serial.RtsEnable = false; | ||||||
|  |             } else if (EmptyMode == Output.DTR && Serial != null) { | ||||||
|  |                 Serial.DtrEnable = true; | ||||||
|  |                 await Task.Delay(EmptyDelay); | ||||||
|  |                 Serial.DtrEnable = false; | ||||||
|  |             } else if (EmptyMode == Output.OUT1 || EmptyMode == Output.OUT2) { | ||||||
|  |                 int output = EmptyMode == Output.OUT1 ? 1 : 2; | ||||||
|  |                 await SendCommand($"OS{output:02i}"); | ||||||
|  |                 await ReceiveResponse(); | ||||||
|  |                 await Task.Delay(EmptyDelay); | ||||||
|  |                 await SendCommand($"OC{output:02i}"); | ||||||
|  |                 await ReceiveResponse(); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         protected async Task SetFillingClearance(bool status) { | ||||||
|  |             if (FillingClearanceMode == Output.RTS && Serial != null) { | ||||||
|  |                 Serial.RtsEnable = status; | ||||||
|  |             } else if (FillingClearanceMode == Output.DTR && Serial != null) { | ||||||
|  |                 Serial.DtrEnable = status; | ||||||
|  |             } else if (FillingClearanceMode == Output.OUT1 || FillingClearanceMode == Output.OUT2) { | ||||||
|  |                 string cmd = status ? "OS" : "OC"; | ||||||
|  |                 int output = FillingClearanceMode == Output.OUT1 ? 1 : 2; | ||||||
|  |                 await SendCommand($"{cmd}{output:02i}"); | ||||||
|  |                 await ReceiveResponse(); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public async Task GrantFillingClearance() { | ||||||
|  |             await SetFillingClearance(true); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public async Task RevokeFillingClearance() { | ||||||
|  |             await SetFillingClearance(false); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										26
									
								
								Elwig/Helpers/Weighing/WeighingResult.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								Elwig/Helpers/Weighing/WeighingResult.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | |||||||
|  | namespace Elwig.Helpers.Weighing { | ||||||
|  |     /// <summary> | ||||||
|  |     /// Result of a weighing process on an industrial scale | ||||||
|  |     /// </summary> | ||||||
|  |     public class WeighingResult { | ||||||
|  |         /// <summary> | ||||||
|  |         /// Measured net weight in kg | ||||||
|  |         /// </summary> | ||||||
|  |         public int? Weight = null; | ||||||
|  |  | ||||||
|  |         /// <summary> | ||||||
|  |         /// Weighing id (or IdentNr) provided by the scale | ||||||
|  |         /// </summary> | ||||||
|  |         public string? WeighingId = null; | ||||||
|  |  | ||||||
|  |         /// <summary> | ||||||
|  |         /// Date string provided by the scale | ||||||
|  |         /// </summary> | ||||||
|  |         public string? Date = null; | ||||||
|  |  | ||||||
|  |         /// <summary> | ||||||
|  |         /// Time string provided by the scale | ||||||
|  |         /// </summary> | ||||||
|  |         public string? Time = null; | ||||||
|  |     } | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user