Weighing: Restructure class structure
This commit is contained in:
		| @@ -4,6 +4,31 @@ using System.Linq; | ||||
| using Microsoft.Extensions.Configuration; | ||||
|  | ||||
| namespace Elwig.Helpers { | ||||
|  | ||||
|     public record struct ScaleConfig { | ||||
|         public string Id; | ||||
|         public string? Type; | ||||
|         public string? Model; | ||||
|         public string? Connection; | ||||
|         public string? Empty; | ||||
|         public string? Filling; | ||||
|         public string? Limit; | ||||
|         public string? Log; | ||||
|         public string? _Log; | ||||
|  | ||||
|         public ScaleConfig(string id, string? type, string? model, string? cnx, string? empty, string? filling, string? limit, string? log) { | ||||
|             Id = id; | ||||
|             Type = type; | ||||
|             Model = model; | ||||
|             Connection = cnx; | ||||
|             Empty = empty; | ||||
|             Filling = filling; | ||||
|             Limit = limit; | ||||
|             _Log = log; | ||||
|             Log = log != null ? Path.Combine(App.DataPath, log) : null; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public class Config { | ||||
|  | ||||
|         private readonly string FileName; | ||||
| @@ -11,8 +36,8 @@ namespace Elwig.Helpers { | ||||
|         public string DatabaseFile = App.DataPath + "database.sqlite3"; | ||||
|         public string? DatabaseLog = null; | ||||
|         public string? Branch = null; | ||||
|         public IList<string?[]> Scales; | ||||
|         private readonly List<string?[]> ScaleList = []; | ||||
|         public IList<ScaleConfig> Scales; | ||||
|         private readonly List<ScaleConfig> ScaleList = []; | ||||
|         private static readonly string[] trueValues = ["1", "true", "yes", "on"]; | ||||
|  | ||||
|         public Config(string filename) { | ||||
| @@ -34,12 +59,10 @@ namespace Elwig.Helpers { | ||||
|             ScaleList.Clear(); | ||||
|             Scales = ScaleList; | ||||
|             foreach (var s in scales) { | ||||
|                 string? scaleLog = config[$"scale.{s}:log"]; | ||||
|                 if (scaleLog != null) scaleLog = Path.Combine(App.DataPath, scaleLog); | ||||
|                 ScaleList.Add([ | ||||
|                 ScaleList.Add(new( | ||||
|                     s, config[$"scale.{s}:type"], config[$"scale.{s}:model"], config[$"scale.{s}:connection"], | ||||
|                     config[$"scale.{s}:empty"], config[$"scale.{s}:filling"], config[$"scale.{s}:limit"], scaleLog | ||||
|                 ]); | ||||
|                     config[$"scale.{s}:empty"], config[$"scale.{s}:filling"], config[$"scale.{s}:limit"], config[$"scale.{s}:log"] | ||||
|                 )); | ||||
|             } | ||||
|         } | ||||
|  | ||||
| @@ -51,11 +74,11 @@ namespace Elwig.Helpers { | ||||
|             file.Write($"\r\n[database]\r\nfile = {DatabaseFile}\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"); | ||||
|                 if (s[6] != null) file.Write($"limit = {s[6]}\r\n"); | ||||
|                 if (s[7] != null) file.Write($"log = {s[7]}\r\n"); | ||||
|                 file.Write($"\r\n[scale.{s.Id}]\r\ntype = {s.Type}\r\nmodel = {s.Model}\r\nconnection = {s.Connection}\r\n"); | ||||
|                 if (s.Empty != null) file.Write($"empty = {s.Empty}\r\n"); | ||||
|                 if (s.Filling != null) file.Write($"filling = {s.Filling}\r\n"); | ||||
|                 if (s.Limit != null) file.Write($"limit = {s.Limit}\r\n"); | ||||
|                 if (s._Log != null) file.Write($"log = {s._Log}\r\n"); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|   | ||||
							
								
								
									
										95
									
								
								Elwig/Helpers/Weighing/Scale.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								Elwig/Helpers/Weighing/Scale.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,95 @@ | ||||
| using System.IO.Ports; | ||||
| using System.IO; | ||||
| using System.Net.Sockets; | ||||
| using System; | ||||
|  | ||||
| namespace Elwig.Helpers.Weighing { | ||||
|     public abstract class Scale : IDisposable { | ||||
|  | ||||
|         protected enum Output { RTS, DTR, OUT1, OUT2 }; | ||||
|  | ||||
|         protected SerialPort? Serial = null; | ||||
|         protected SerialPort? ControlSerialEmpty = null, ControlSerialFilling = null; | ||||
|         protected TcpClient? Tcp = null; | ||||
|         protected Stream Stream; | ||||
|  | ||||
|         protected readonly Output? EmptyMode = null; | ||||
|         protected readonly Output? FillingClearanceMode = null; | ||||
|         protected readonly int EmptyDelay; | ||||
|  | ||||
|         public int? WeightLimit { get; private set; } | ||||
|         public string? LogPath { get; private set; } | ||||
|  | ||||
|         public static IScale FromConfig(ScaleConfig config) { | ||||
|             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") { | ||||
|                 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}\""); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         protected Scale(string cnx, string? empty, string? filling, int? limit, string? log) { | ||||
|             if (cnx.StartsWith("serial:")) { | ||||
|                 Serial = Utils.OpenSerialConnection(cnx); | ||||
|                 Stream = Serial.BaseStream; | ||||
|             } else if (cnx.StartsWith("tcp:")) { | ||||
|                 Tcp = Utils.OpenTcpConnection(cnx); | ||||
|                 Stream = Tcp.GetStream(); | ||||
|             } else { | ||||
|                 throw new ArgumentException("Unsupported scheme"); | ||||
|             } | ||||
|  | ||||
|             LogPath = log; | ||||
|  | ||||
|             if (empty != null) { | ||||
|                 var parts = empty.Split(':'); | ||||
|                 if (parts.Length == 3) { | ||||
|                     if (parts[0] != Serial?.PortName) | ||||
|                         ControlSerialEmpty = Utils.OpenSerialConnection($"serial://{parts[0]}:9600"); | ||||
|                 } else if (parts.Length != 2) { | ||||
|                     throw new ArgumentException("Invalid value for 'empty'"); | ||||
|                 } | ||||
|                 EmptyMode = ConvertOutput(parts[^2]); | ||||
|                 EmptyDelay = int.Parse(parts[^1]); | ||||
|             } | ||||
|  | ||||
|             WeightLimit = limit; | ||||
|             if (filling != null) { | ||||
|                 var parts = filling.Split(':'); | ||||
|                 if (parts.Length == 2) { | ||||
|                     if (parts[0] != Serial?.PortName) | ||||
|                         ControlSerialFilling = parts[0] != ControlSerialEmpty?.PortName ? Utils.OpenSerialConnection($"serial://{parts[0]}:9600") : ControlSerialEmpty; | ||||
|                 } else if (parts.Length != 1) { | ||||
|                     throw new ArgumentException("Invalid value for 'filling'"); | ||||
|                 } | ||||
|                 FillingClearanceMode = ConvertOutput(parts[^1]); | ||||
|             } | ||||
|  | ||||
|             if (FillingClearanceMode != null && WeightLimit == null) | ||||
|                 throw new ArgumentException("Weight limit has to be set, if filling clearance supervision is enabled"); | ||||
|         } | ||||
|  | ||||
|         public void Dispose() { | ||||
|             Stream.Close(); | ||||
|             Serial?.Close(); | ||||
|             ControlSerialEmpty?.Close(); | ||||
|             ControlSerialFilling?.Close(); | ||||
|             Tcp?.Close(); | ||||
|             GC.SuppressFinalize(this); | ||||
|         } | ||||
|  | ||||
|         protected static Output? ConvertOutput(string? value) { | ||||
|             return value switch { | ||||
|                 null => null, | ||||
|                 "RTS" => Output.RTS, | ||||
|                 "DTR" => Output.DTR, | ||||
|                 "OUT1" => Output.OUT1, | ||||
|                 "OUT2" => Output.OUT2, | ||||
|                 _ => throw new ArgumentException($"Invalid value for argument: '{value}'"), | ||||
|             }; | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										22
									
								
								Elwig/Helpers/Weighing/SchemberEventScale.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								Elwig/Helpers/Weighing/SchemberEventScale.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| namespace Elwig.Helpers.Weighing { | ||||
|     public class SchemberEventScale : Scale, IEventScale { | ||||
|  | ||||
|         public string Manufacturer => "Schember"; | ||||
|         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 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; | ||||
|         } | ||||
|  | ||||
|     } | ||||
| } | ||||
| @@ -1,23 +1,11 @@ | ||||
| using System; | ||||
| using System.IO; | ||||
| using System.IO.Ports; | ||||
| using System.Net.Sockets; | ||||
| using System.Text; | ||||
| using System.Threading.Tasks; | ||||
| 
 | ||||
| namespace Elwig.Helpers.Weighing { | ||||
|     public class SystecScale : ICommandScale { | ||||
| 
 | ||||
|         protected enum Output { RTS, DTR, OUT1, OUT2 }; | ||||
| 
 | ||||
|         protected SerialPort? Serial = null; | ||||
|         protected SerialPort? ControlSerialEmpty = null, ControlSerialFilling = null; | ||||
|         protected TcpClient? Tcp = null; | ||||
|         protected Stream Stream; | ||||
| 
 | ||||
|         protected readonly Output? EmptyMode = null; | ||||
|         protected readonly Output? FillingClearanceMode = null; | ||||
|         protected readonly int EmptyDelay; | ||||
|     public class SysTecITScale : Scale, ICommandScale { | ||||
| 
 | ||||
|         public string Manufacturer => "SysTec"; | ||||
|         public int InternalScaleNr => 1; | ||||
| @@ -25,74 +13,15 @@ namespace Elwig.Helpers.Weighing { | ||||
|         public string ScaleId { get; private set; } | ||||
|         public bool IsReady { get; private set; } | ||||
|         public bool HasFillingClearance { get; private set; } | ||||
|         public int? WeightLimit { get; private set; } | ||||
|         public string? LogPath { get; private set; } | ||||
| 
 | ||||
|         public SystecScale(string id, string model, string connection, string? empty = null, string? filling = null, int? limit = null, string? log = null) { | ||||
|         public SysTecITScale(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; | ||||
|             LogPath = log; | ||||
| 
 | ||||
|             if (connection.StartsWith("serial:")) { | ||||
|                 Serial = Utils.OpenSerialConnection(connection); | ||||
|                 Stream = Serial.BaseStream; | ||||
|             } else if (connection.StartsWith("tcp:")) { | ||||
|                 Tcp = Utils.OpenTcpConnection(connection); | ||||
|                 Stream = Tcp.GetStream(); | ||||
|             } else { | ||||
|                 throw new ArgumentException("Unsupported scheme"); | ||||
|             } | ||||
|             Stream.WriteTimeout = 250; | ||||
|             Stream.ReadTimeout = 11000; | ||||
| 
 | ||||
|             if (empty != null) { | ||||
|                 var parts = empty.Split(':'); | ||||
|                 if (parts.Length == 3) { | ||||
|                     if (parts[0] != Serial?.PortName) | ||||
|                         ControlSerialEmpty = Utils.OpenSerialConnection($"serial://{parts[0]}:9600"); | ||||
|                 } else if (parts.Length != 2) { | ||||
|                     throw new ArgumentException("Invalid value for 'empty'"); | ||||
|                 } | ||||
|                 EmptyMode = ConvertOutput(parts[^2]); | ||||
|                 EmptyDelay = int.Parse(parts[^1]); | ||||
|             } | ||||
| 
 | ||||
|             WeightLimit = limit; | ||||
|             if (filling != null) { | ||||
|                 var parts = filling.Split(':'); | ||||
|                 if (parts.Length == 2) { | ||||
|                     if (parts[0] != Serial?.PortName) | ||||
|                         ControlSerialFilling = parts[0] != ControlSerialEmpty?.PortName ? Utils.OpenSerialConnection($"serial://{parts[0]}:9600") : ControlSerialEmpty; | ||||
|                 } else if (parts.Length != 1) { | ||||
|                     throw new ArgumentException("Invalid value for 'filling'"); | ||||
|                 } | ||||
|                 FillingClearanceMode = ConvertOutput(parts[^1]); | ||||
|             } | ||||
| 
 | ||||
|             if (FillingClearanceMode != null && WeightLimit == null) | ||||
|                 throw new ArgumentException("Weight limit has to be set, if filling clearance supervision is enabled"); | ||||
|         } | ||||
| 
 | ||||
|         public void Dispose() { | ||||
|             Stream.Close(); | ||||
|             Serial?.Close(); | ||||
|             ControlSerialEmpty?.Close(); | ||||
|             ControlSerialFilling?.Close(); | ||||
|             Tcp?.Close(); | ||||
|             GC.SuppressFinalize(this); | ||||
|         } | ||||
| 
 | ||||
|         protected static Output? ConvertOutput(string? value) { | ||||
|             return value switch { | ||||
|                 null => null, | ||||
|                 "RTS" => Output.RTS, | ||||
|                 "DTR" => Output.DTR, | ||||
|                 "OUT1" => Output.OUT1, | ||||
|                 "OUT2" => Output.OUT2, | ||||
|                 _ => throw new ArgumentException($"Invalid value for argument: '{value}'"), | ||||
|             }; | ||||
|         } | ||||
| 
 | ||||
|         protected async Task SendCommand(string command) { | ||||
		Reference in New Issue
	
	Block a user