using File_Watcher.Models; using System.Diagnostics; using System.IO.Ports; namespace File_Watcher.Helpers; internal static partial class HelperSerial { private record Record(List Data, string Destination, ILogger Logger, CancellationToken CancellationToken); private static Record? _Record; private static SerialPort? _SerialPort; private static void PCLToPDF(string fullPath) { string ghostPCLFileName = Path.Combine(AppContext.BaseDirectory, "gpcl6win64.exe"); if (!File.Exists(ghostPCLFileName)) throw new Exception("Ghost PCL FileName doesn't Exist!"); string lincPDFCFileName = Path.Combine(AppContext.BaseDirectory, "LincPDFC.exe"); if (!File.Exists(lincPDFCFileName)) throw new Exception("Linc PDFC FileName doesn't Exist!"); string pdfFile; string fileName; string arguments; for (int i = 1; i < 3; i++) { if (i == 1) { fileName = ghostPCLFileName; pdfFile = $"{fullPath}-ghost.pdf"; arguments = $"-dSAFER -dBATCH -dNOPAUSE -sOutputFile=\"{pdfFile}\" -sDEVICE=pdfwrite \"{fullPath}\""; // arguments = $"-dSAFER -dBATCH -dNOPAUSE -dFIXEDMEDIA -dFitPage -dAutoRotatePages=/All -dDEVICEWIDTHPOINTS=792 -dDEVICEHEIGHTPOINTS=612 -sOutputFile=\"{pdfFile}\" -sDEVICE=pdfwrite \"{fullPath}\""; } else if (i == 2) { fileName = lincPDFCFileName; pdfFile = $"{fullPath}-linc.pdf"; arguments = $"-i \"{fullPath}\" -o \"{pdfFile}\""; } else throw new Exception(); Process process = Process.Start(fileName, arguments); long breakAfter = DateTime.Now.AddSeconds(30).Ticks; for (short j = 0; j < short.MaxValue; j++) { if (process.HasExited || process.WaitForExit(500) || DateTime.Now.Ticks > breakAfter) break; } if (!File.Exists(pdfFile)) throw new Exception("PDF file wasn't created"); } } private static List GetBytes(List bytes) { List results = []; foreach (byte @byte in bytes) results.Add(@byte); return results; } private static void SerialPortWrite(string destination, DateTime dateTime, List bytes, string v, bool convert) { if (_SerialPort is null) throw new NullReferenceException(nameof(_SerialPort)); string directory = Path.Combine(destination, _SerialPort.PortName); if (!Directory.Exists(destination)) _ = Directory.CreateDirectory(destination); string fileName = Path.Combine(directory, $"{_SerialPort.PortName}-{v}-{dateTime:yyyyMMddHHmmssfff}.pcl"); File.WriteAllBytes(fileName, bytes.ToArray()); if (convert) PCLToPDF(fileName); } private static int? SearchBytes(byte[] haystack, byte[] needle) { int? result = null; int k; int len = needle.Length; int limit = haystack.Length - len; for (int i = 0; i <= limit; i++) { k = 0; for (; k < len; k++) { if (needle[k] != haystack[i + k]) break; } if (k == len) { result = i; break; } } return result; } private static bool Contains() { if (_Record is null) throw new NullReferenceException(nameof(_Record)); bool result; // char endOfLine = '\u001b'; // lock (_Record) // result = _Record.Data.Contains(Convert.ToByte(endOfLine)); // if (!result) // { // } int? index = null; // byte[] pageDelimiter = // { // Convert.ToByte(27), // Convert.ToByte(69) // }; lock (_Record) { byte[] bytes = _Record.Data.ToArray(); // index = Array.IndexOf(bytes, pageDelimiter); // if (index == -1) // { // } byte[] documentDelimiter = [ Convert.ToByte(32), Convert.ToByte(83), Convert.ToByte(116), Convert.ToByte(97), Convert.ToByte(116), Convert.ToByte(105), Convert.ToByte(115), Convert.ToByte(116), Convert.ToByte(105), Convert.ToByte(99), Convert.ToByte(115), Convert.ToByte(58) ]; index = SearchBytes(bytes, documentDelimiter); } result = index is not null; return result; } private static void PinChanged(object sender, SerialPinChangedEventArgs serialPinChangedEventArgs) { if (_Record is null) throw new NullReferenceException(nameof(_Record)); try { _Record.Logger.LogDebug($"EventType = {serialPinChangedEventArgs.EventType}"); } catch (Exception exception) { _Record.Logger.LogError(exception, "Error"); } } private static void DataReceived(object? sender, SerialDataReceivedEventArgs dataReceivedEventArgs) { if (_Record is null) throw new NullReferenceException(nameof(_Record)); if (_SerialPort is null) throw new NullReferenceException(nameof(_SerialPort)); DateTime dateTime = DateTime.Now; try { _Record.Logger.LogDebug($"EventType = {dataReceivedEventArgs.EventType}"); List? bytes; lock (_Record) { byte[] buffer = new byte[_SerialPort.BytesToRead]; int count = _SerialPort.Read(buffer, 0, buffer.Length); if (count == 0) bytes = null; else { _Record.Data.AddRange(buffer.Take(count)); bytes = dataReceivedEventArgs.EventType != SerialData.Eof ? null : GetBytes(_Record.Data); } } if (bytes is not null) SerialPortWrite(_Record.Destination, dateTime, bytes, nameof(SerialData.Eof), convert: false); } catch (Exception exception) { string fileName = Path.Combine(_Record.Destination, _SerialPort.PortName, $"{dateTime:yyyyMMddHHmmssfff}.err"); File.WriteAllLines(fileName, [exception.Message, Environment.NewLine, Environment.NewLine, string.Concat(exception.StackTrace)]); } } private static void ErrorReceived(object sender, SerialErrorReceivedEventArgs serialErrorReceivedEventArgs) { if (_Record is null) throw new NullReferenceException(nameof(_Record)); try { _Record.Logger.LogDebug($"EventType = {serialErrorReceivedEventArgs.EventType}"); } catch (Exception exception) { _Record.Logger.LogError(exception, "Error"); } } private static void SerialPortWriteConditionally(SerialConfiguration serialConfiguration, ILogger logger) { if (_Record is null) throw new NullReferenceException(nameof(_Record)); DateTime dateTime = DateTime.Now; logger.LogDebug($"Worker:Process:SerialPort running at: {dateTime} serial port {serialConfiguration.PortName} status with Length = {_Record.Data.Count}."); bool contains = Contains(); if (contains) { List bytes; if (_Record is null) throw new NullReferenceException(nameof(_Record)); lock (_Record) { bytes = GetBytes(_Record.Data); _Record.Data.Clear(); } SerialPortWrite(_Record.Destination, dateTime, bytes, nameof(Contains), convert: true); } } private static void SerialPortClose() { if (_SerialPort is not null) { if (_Record is null) throw new NullReferenceException(nameof(_Record)); lock (_Record) { _SerialPort.Close(); int length = _Record is null ? 0 : _Record.Data.Count; if (_Record is null) throw new NullReferenceException(nameof(_Record)); _Record.Logger.LogDebug($"Serial port {_SerialPort.PortName} closed with Length = {length}."); } } } internal static bool ReadWrite(AppSettings appSettings, ILogger logger, CancellationToken cancellationToken) { _Record ??= new([], appSettings.SerialConfiguration.Destination, logger, cancellationToken); if (_SerialPort is null) { string ghostPCLFileName = Path.Combine(AppContext.BaseDirectory, appSettings.SerialConfiguration.GhostPCLFileName); if (!File.Exists(ghostPCLFileName)) throw new Exception("Ghost PCL FileName doesn't Exist!"); string lincPDFCFileName = Path.Combine(AppContext.BaseDirectory, appSettings.SerialConfiguration.LincPDFCFileName); if (!File.Exists(lincPDFCFileName)) throw new Exception("Linc PDFC FileName doesn't Exist!"); _SerialPort = new SerialPort { PortName = appSettings.SerialConfiguration.PortName, // BaudRate = 9600, BaudRate = 115200, DataBits = 8, Parity = Parity.None, StopBits = StopBits.One, // Handshake = Handshake.None, Handshake = Handshake.RequestToSend, // DtrEnable = true, // RtsEnable = true, ReadTimeout = 5000 }; string[] portNames = SerialPort.GetPortNames(); string[] matchPortNames = (from l in portNames where l == appSettings.SerialConfiguration.PortName select l).ToArray(); if (matchPortNames.Length == 0) throw new Exception($"Didn't find matching COM port! {string.Join(Environment.NewLine, portNames)}"); if (matchPortNames.Length != 1) throw new Exception($"Matching count is more than one! {string.Join(Environment.NewLine, portNames)}"); _SerialPort.Open(); _SerialPort.DiscardInBuffer(); _SerialPort.DiscardOutBuffer(); logger.LogDebug("Waiting for data."); _SerialPort.PinChanged += PinChanged; _SerialPort.DataReceived += DataReceived; _SerialPort.ErrorReceived += ErrorReceived; } SerialPortWriteConditionally(appSettings.SerialConfiguration, logger); if (cancellationToken.IsCancellationRequested) SerialPortClose(); return true; } }