using System; using System.IO; using System.IO.Ports; using System.Text; using System.Threading.Tasks; namespace Elwig.Helpers.Weighing { public class GassnerEnqScale : Scale, ICommandScale { public string Manufacturer => "Gassner"; public string Model { get; private set; } public string ScaleTerminalId { get; private set; } public bool IsReady { get; private set; } public bool HasFillingClearance { get; private set; } public GassnerEnqScale(string id, string model, string cnx, string? empty = null, string? filling = null, int? limit = null, string? log = null) : base(cnx, empty, filling, limit, log) { ScaleTerminalId = id; Model = model; IsReady = true; HasFillingClearance = false; Stream.WriteTimeout = 250; Stream.ReadTimeout = 11000; } protected Task SendCommand(string command) => SendCommand(Encoding.ASCII.GetBytes(command)); protected async Task SendCommand(byte[] cmd) { await Stream.WriteAsync(cmd); if (LogPath != null) await File.AppendAllTextAsync(LogPath, Encoding.ASCII.GetString(cmd)); } protected async Task ReceiveResponse() { var line = await Reader.ReadUntilAsync('\x03'); if (LogPath != null) await File.AppendAllTextAsync(LogPath, $"{line}\r\n"); if (line == null || line.Length < 4 || !line.StartsWith('\x02')) { throw new FormatException("Invalid response from scale"); } var status = line[1..3]; if (status[0] == 'E' || status[1] != 'S') { string msg = $"Unbekannter Fehler (Fehler code {status})"; switch (status[1]) { case 'M': msg = "Waage in Bewegung"; break; } throw new WeighingException($"Waagenfehler {status}: {msg}"); } else if (status[0] != ' ') { throw new WeighingException($"Invalid response from scale (error code {status})"); } return line[1..^1]; } protected async Task Weigh(int? internalScaleNr, bool incIdentNr, bool retry = true) { string record; try { await SendCommand(incIdentNr ? "\x05" : "?"); record = await ReceiveResponse(); } catch (IOException) { if (!retry || Tcp == null) throw; ReconnectTcp(); return await Weigh(internalScaleNr, incIdentNr, false); } if (record.Length != 45) throw new FormatException("Invalid response from scale: Received record has invalid size"); var line = record[2..]; var brutto = line[ 0.. 7].Trim(); var tara = line[ 7..14].Trim(); var netto = line[14..21].Trim(); var scaleNr = line[21..23].Trim(); var identNr = line[23..29].Trim(); var date = line[29..37]; var time = line[37..43]; identNr = identNr.Length > 0 && identNr != "0" ? identNr : null; return new() { GrossWeight = int.Parse(brutto), TareWeight = int.Parse(tara), NetWeight = int.Parse(netto), ScaleId = scaleNr, WeighingId = identNr, FullWeighingId = identNr, Date = DateOnly.TryParseExact(date, "yyyyMMdd", out var d) ? d : null, Time = TimeOnly.TryParseExact(time, "HHmmss", out var t) ? t : null, }; } public async Task Weigh(int? scaleNr = null) { return await Weigh(scaleNr, true); } public async Task GetCurrentWeight(int? scaleNr = null) { return await Weigh(scaleNr, false); } public async Task Empty() { SerialPort? p = ControlSerialEmpty ?? Serial; if (EmptyMode == Output.RTS && p != null) { p.RtsEnable = true; await Task.Delay(EmptyDelay); p.RtsEnable = false; } else if (EmptyMode == Output.DTR && p != null) { p.DtrEnable = true; await Task.Delay(EmptyDelay); p.DtrEnable = false; } } protected Task SetFillingClearance(bool status) { SerialPort? p = ControlSerialFilling ?? Serial; if (FillingClearanceMode == Output.RTS && p != null) { p.RtsEnable = status; } else if (FillingClearanceMode == Output.DTR && p != null) { p.DtrEnable = status; } return Task.CompletedTask; } public async Task GrantFillingClearance() { await SetFillingClearance(true); } public async Task RevokeFillingClearance() { await SetFillingClearance(false); } public async Task SetDateAndTime(DateTime dateTime) { await SendCommand($"C{dateTime:yyyyMMddHHmmss}\r"); await ReceiveResponse(); } } }