using System; using System.Collections; using System.Collections.Generic; using System.Text; using System.Threading; using System.Runtime.InteropServices; using System.Net; using System.Net.Sockets; using Wayne.FDCPOSLibrary; using Microsoft.Extensions.Logging; using Microsoft.Extensions.DependencyInjection; namespace Wayne.FDCPOSInterface { public class FuellingInfo { public DateTime dateTime; public int pumpNumber; public int nozzle; public int productNo; public string productName; public string productUM; public decimal amount; public decimal volume; public decimal price; public int transactionId; public FuellingInfo(int pumpNumber, int nozzle, int productNo, string productName, string productUM, decimal amount, decimal volume, decimal price, DateTime dateTime, int transactionId) { this.pumpNumber = pumpNumber; this.nozzle = nozzle; this.productNo = productNo; this.productName = productName; this.productUM = productUM; this.amount = amount; this.volume = volume; this.price = price; this.dateTime = dateTime; this.transactionId = transactionId; } } public class FDCPOSClientIX : FDCPOSClient { public string currencySymbol; public bool currencySymbolAfterValue = true; public bool spaceBetweenCurrencySymbolAndValue = true; public int controllerCrc = 0; public int printerWidth = 24; public FDCPOSClientIX(FDCPOSManager _fdcposManager, Messages.HeartbeatCallback _heartbeatCallback, string posInfo) : base(_fdcposManager, _heartbeatCallback, null) { currencySymbol = System.Globalization.RegionInfo.CurrentRegion.CurrencySymbol; readPOSInfo(posInfo); } void readPOSInfo(string posInfo) { try { posInfo = posInfo.Substring(posInfo.IndexOf('(', 0) + 1, posInfo.Length - 1 - posInfo.IndexOf('(', 0) - 1); //FDCPOSManager.tracer.WriteLine(string.Format("posInfo={0}", posInfo)); Dictionary posInfoParamDict; posInfoParamDict = ParsePOSInfoString(posInfo); string key = "currencySymbol"; if (posInfoParamDict.ContainsKey(key) && posInfoParamDict[key] != null && posInfoParamDict[key] != "") this.currencySymbol = posInfoParamDict[key]; key = "currencySymbolAfterValue"; if (posInfoParamDict.ContainsKey(key) && posInfoParamDict[key] != null && posInfoParamDict[key] != "") { if (posInfoParamDict[key] == "0" || posInfoParamDict[key].ToUpper() == "FALSE") this.currencySymbolAfterValue = false; } key = "spaceBetweenCurrencySymbolAndValue"; if (posInfoParamDict.ContainsKey(key) && posInfoParamDict[key] != null && posInfoParamDict[key] != "") { if (posInfoParamDict[key] == "0" || posInfoParamDict[key].ToUpper() == "FALSE") this.spaceBetweenCurrencySymbolAndValue = false; } key = "controllerCrc"; if (posInfoParamDict.ContainsKey(key) && posInfoParamDict[key] != null && posInfoParamDict[key] != "") { try { this.controllerCrc = Convert.ToInt32(posInfoParamDict[key]); } catch (Exception ex) { } } key = "printerWidth"; if (posInfoParamDict.ContainsKey(key) && posInfoParamDict[key] != null && posInfoParamDict[key] != "") { try { this.printerWidth = Convert.ToInt32(posInfoParamDict[key]); } catch (Exception ex) { } } } catch (Exception ex) { //FDCPOSManager.tracer.WriteLine("Exception! " + ex.Message); } } public override byte[] getDSPFields(FuellingInfo fi) { byte[] temp; string sDSPFilelds = GenerateSignedPumpInfoLine(fi.dateTime, fi.pumpNumber, fi.productName, fi.amount, fi.volume, fi.price, currencySymbol, currencySymbolAfterValue, spaceBetweenCurrencySymbolAndValue, fi.productUM, controllerCrc, printerWidth); temp = System.Text.UTF8Encoding.UTF8.GetBytes(sDSPFilelds); return temp; } public override byte[] getCRC(FuellingInfo fi) { byte[] temp; string sCRC = ""; temp = System.Text.ASCIIEncoding.ASCII.GetBytes(sCRC); return temp; } public static string GenerateSignedPumpInfoLine( DateTime dateTime, int pumpNumber, string productName, decimal totalAmount, decimal volume, decimal price, string currencySymbol, bool currencySymbolAfterValue, bool spaceBetweenCurrencySymbolAndValue, string volumeUnit, int controllerCrc, int printerWidth) { SignedFuellingInfo signedFillingInfo = new SignedFuellingInfo(); SignedFuellingInfo.Data data = new SignedFuellingInfo.Data(); data.ControllerModuleCrc = controllerCrc; data.CurrencySymbol = currencySymbol; data.CurrencySymbolAfterValue = currencySymbolAfterValue; data.DateTime = dateTime; data.Price = price; data.PrinterWidth = printerWidth; data.ProductName = productName; data.PumpNumber = pumpNumber; data.SpaceBetweenCurrencySymbolAndValue = spaceBetweenCurrencySymbolAndValue; data.TotalAmount = totalAmount; data.Volume = volume; data.VolumeUnit = volumeUnit; return signedFillingInfo.EncodeReceiptText(data); } } public class FDCPOSClient : IDisposable { //static NLog.Logger fdcSocketLogger = NLog.LogManager.LoadConfiguration("nlog.config").GetLogger("FdcServerSocket"); private ILogger fdcSocketLogger;// = ServiceBuilder.Provider //.GetRequiredService().CreateLogger("FdcServerSocket"); public string sID; public string workstationID; public string applicationSender; public FdcClientTcpHandler FdcClientTcpHandler; public string sIPAddress; private TcpClient _socketChannelResponse = null; [ComVisible(false)] public TcpClient socketChannelResponse { get { return _socketChannelResponse; } set { _socketChannelResponse = value; } } private bool _connected = false; [ComVisible(false)] public bool connected { get { return _connected; } set { _connected = value; } } private bool _logon = false; [ComVisible(false)] public bool logon { get { return _logon; } set { _logon = value; } } private TcpClient _socketChannelUnsolicited = null; [ComVisible(false)] public TcpClient socketChannelUnsolicited { get { return _socketChannelUnsolicited; } set { _socketChannelUnsolicited = value; } } FDCPOSManager fdcposManager; public Heartbeat heartbeat; Messages.HeartbeatCallback heartbeatCallback; static public POSType GetType(string posInfo) { if (posInfo.Contains(POSType.IXTerminal.ToString())) return POSType.IXTerminal; else return POSType.Generic; } public static Dictionary ParsePOSInfoString(string posInfoString) { Dictionary posInfoStringParamDict = new Dictionary(); string[] listItems = posInfoString.Split(';'); foreach (string listItem in listItems) { string trimmedListItem = listItem.Trim(); if (trimmedListItem.Length > 0) { int equalSignIndex = trimmedListItem.IndexOf('='); string paramName = trimmedListItem.Substring(0, equalSignIndex); string paramValue = trimmedListItem.Substring(equalSignIndex + 1, trimmedListItem.Length - equalSignIndex - 1); posInfoStringParamDict[paramName] = paramValue; } } return posInfoStringParamDict; } public FDCPOSClient(FDCPOSManager _fdcposManager, Messages.HeartbeatCallback _heartbeatCallback, ILogger logger) { this.fdcSocketLogger = logger; heartbeat = new Heartbeat(); fdcposManager = _fdcposManager; heartbeat.OnHeartbeatInterval += new EventHandler(heartbeat_OnHeartbeatInterval); heartbeat.OnClientHeartbeatTimeout += new EventHandler(heartbeat_OnHeartbeatTimeout); heartbeatCallback = _heartbeatCallback; } ~FDCPOSClient() { if (heartbeat != null) heartbeat.Dispose(); heartbeat = null; } public void Dispose() { try { if (this.fdcSocketLogger != null) this.fdcSocketLogger.LogInformation("FDCPOSClient: " + this.workstationID + "-" + this.applicationSender + " is on disposing"); if (heartbeat != null) heartbeat.Dispose(); heartbeat = null; this.FdcClientTcpHandler.Dispose(); } catch { } } private void heartbeat_OnHeartbeatTimeout(object sender, EventArgs e) { try { string clientId = FDCPOSClient.getClientID(workstationID, applicationSender); //FDCPOSManager.tracer.WriteLine(string.Format("disconnect client '{0}'", clientId)); if (this.fdcSocketLogger != null) this.fdcSocketLogger.LogInformation(string.Format("disconnecting client '{0}' due to OnHeartbeatTimeout", clientId)); this.fdcposManager.DisconnectClient(this); } catch (Exception ex) { //FDCPOSManager.tracer.WriteLine(string.Format("Exception disconnect client '{0}', error: {1}", clientId, ex.Message)); } } private void heartbeat_OnHeartbeatInterval(object sender, EventArgs e) { if (heartbeatCallback != null) heartbeatCallback.Invoke(workstationID, applicationSender); } public static string getClientID(string workstationID, string applicationSender) { return (workstationID ?? "") + "§§§" + (applicationSender ?? ""); } public static void Remove(string clientID) { } public virtual byte[] getDSPFields(FuellingInfo fi) { byte[] temp; string sDSPFields = ""; temp = System.Text.UTF8Encoding.UTF8.GetBytes(sDSPFields); return temp; } public virtual byte[] getCRC(FuellingInfo fi) { return getCRC("DeviceID TransactionNo Volume Amount ", fi.pumpNumber, fi.nozzle, fi.transactionId, fi.volume, fi.amount); } private byte[] getCRC(string fieldsNames, int deviceId, int nozzle, int transactionId, decimal volume, decimal amount) { try { //FDCPOSManager.tracer.WriteLineIf(//FDCPOSManager.tracer.CheckTraceLevel(4), "init"); Crc16Ccitt crccrypter = new Crc16Ccitt(InitialCrcValue.Zeros); byte[] temp; // = new byte[8]; byte[] data = new byte[fieldsNames.Length + 1 + 2 + 5 + 5 + 3]; // add fields names System.Text.ASCIIEncoding.ASCII.GetBytes(fieldsNames).CopyTo(data, 0); //FDCPOSManager.tracer.WriteLineIf(//FDCPOSManager.tracer.CheckTraceLevel(4), "1"); // add deviceId data[fieldsNames.Length] = Convert.ToByte(deviceId); //FDCPOSManager.tracer.WriteLineIf(//FDCPOSManager.tracer.CheckTraceLevel(4), "2"); // add transactionId - bcd4 string sTrId = transactionId.ToString(); sTrId = sTrId.PadLeft(4, '0'); temp = System.Text.ASCIIEncoding.ASCII.GetBytes(sTrId); data[fieldsNames.Length + 1] = (byte)((temp[0] - 0x30) * 16 + (temp[1] - 0x30)); data[fieldsNames.Length + 2] = (byte)((temp[2] - 0x30) * 16 + (temp[3] - 0x30)); //FDCPOSManager.tracer.WriteLineIf(//FDCPOSManager.tracer.CheckTraceLevel(4), "3"); // add volume - bin8+bcd8 string stemp = FDCConvert.ToString(volume); int decpos = stemp.IndexOf(FDCConvert.DecimalSeparator); if (decpos != -1) stemp = stemp.Replace(FDCConvert.DecimalSeparator, ""); else decpos = stemp.Length; //for (int i = 0; i < 8; i++) // temp[i] = 0; temp = System.Text.ASCIIEncoding.ASCII.GetBytes(stemp); // bin8 is the decoimal position data[fieldsNames.Length + 3] = Convert.ToByte(decpos); for (int i = 0; i < 5; i++) { if (temp.Length > 2 * i + 1) data[fieldsNames.Length + 4 + i] = (byte)((temp[2 * i] - 0x30) * 16 + (temp[2 * i + 1] - 0x30)); else if (temp.Length > 2 * i) data[fieldsNames.Length + 4 + i] = (byte)((temp[2 * i] - 0x30) * 16); else data[fieldsNames.Length + 4 + i] = 0; } ////FDCPOSManager.tracer.WriteLineIf(//FDCPOSManager.tracer.CheckTraceLevel(4), "4"); // add amount - bin8+bcd8 stemp = FDCConvert.ToString(amount); decpos = stemp.IndexOf(FDCConvert.DecimalSeparator); if (decpos != -1) stemp = stemp.Replace(FDCConvert.DecimalSeparator, ""); else decpos = stemp.Length; //for (int i = 0; i < 8; i++ ) // temp[i] = 0; temp = System.Text.ASCIIEncoding.ASCII.GetBytes(stemp); // bin8 is the decoimal position data[fieldsNames.Length + 8] = Convert.ToByte(decpos); for (int i = 0; i < 5; i++) { if (temp.Length > 2 * i + 1) data[fieldsNames.Length + 9 + i] = (byte)((temp[2 * i] - 0x30) * 16 + (temp[2 * i + 1] - 0x30)); else if (temp.Length > 2 * i) data[fieldsNames.Length + 9 + i] = (byte)((temp[2 * i] - 0x30) * 16); else data[fieldsNames.Length + 9 + i] = 0; } //FDCPOSManager.tracer.WriteLineIf(//FDCPOSManager.tracer.CheckTraceLevel(4), "5"); ushort checksum = crccrypter.ComputeChecksum(data); data[fieldsNames.Length + 13] = 0; data[fieldsNames.Length + 14] = (byte)((checksum & 0xFF00) / 256); data[fieldsNames.Length + 15] = (byte)(checksum & 0x00FF); //FDCPOSManager.tracer.WriteLineIf(//FDCPOSManager.tracer.CheckTraceLevel(4), "end ok"); return data; } catch (Exception ex) { //FDCPOSManager.tracer.WriteLine("Exception! " + ex.Message + " - " + ex.StackTrace); } //FDCPOSManager.tracer.WriteLineIf(//FDCPOSManager.tracer.CheckTraceLevel(4), "end ko"); return null; } } }