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: \"{cnx.Split(':')[0]}\""); } 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}'"), }; } } }