using Edge.Core.Processor;using Edge.Core.IndustryStandardInterface.Pump; using Edge.Core.Parser.BinaryParser.Util; using SinochemCarplateService.Models; using SinochemCloudClient.Models; using SinochemPosClient.Models; using System; using System.Collections.Generic; using System.Configuration; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using Wayne.Lib.StateEngine; using WayneChina_IcCardReader_SinoChem.MessageEntity; using WayneChina_IcCardReader_SinoChem.MessageEntity.Incoming; using WayneChina_IcCardReader_SinoChem.MessageEntity.Outgoing; using Edge.Core.IndustryStandardInterface.Pump; namespace SinochemInternetPlusApp { public class ReceiptLine { public ReceiptLine(byte[] bytes, int lineWidth) { Line = new byte[lineWidth]; bytes.CopyTo(Line, 0); } public byte[] Line { get; set; } } public class FuelingPoint : StateManager { #region Fields //Immutable after construction public int FuelingPointId { get; } private byte initialSqNo = 0; private byte sqNo; private object syncObj = new object(); private Queue outboundMsgQueue = new Queue(); private object queueSyncObj = new object(); private object evSyncObj = new object(); private List requestIdList = new List(); private object reqIdSyncObj = new object(); private bool printerIdle = true; private object printerSyncObj = new object(); private byte currentSqNo { get; set; } private object sqNoSyncObj = new object(); private IFdcPumpController callingPump; #endregion #region Timeout values //in seconds public int CardReaderDisplayTimeout { get { return 10; } } //in milliseconds public int CardReaderBackToIdleTimeout { get { return 2000; } } #endregion #region Properties /// /// Current physical nozzle id, reflecting the running nozzle of this FP. /// public int CurrentNozzleId { get; set; } /// /// The physical nozzles associated with this fueling point /// public IEnumerable AssociatedNozzles { get; set; } public Eps Eps { get; set; } public EpsTransaction CurrentEpsTrx { get; set; } public TransactionMode CurrentTrxMode { get; set; } public long? AuthorizationId { get; set; } public byte ResetSqNo; public override string EntityType => "FuelingPoint"; public override string EntitySubType => ""; public IEnumerable ActiveTrx { get; set; } public CardOnlineVerificationRequest OnlineVerificationRequest { get; set; } public WayneChina_IcCardReader_SinoChem.Handler CurrentCardReader => Eps.GetHandler(FuelingPointId); public SignDataResponse SignedData { get; internal set; } public List CurrentReceipt { get; set; } public bool CardReaderDisabled { get; set; } = false; public byte IdleStateCardReaderSqNo { get; set; } public int GetPrinterCount { get; set; } /// /// Site id aka Station number /// public string StationNo => App.AppSettings["SinochemSiteId"]; /// /// Site name aka Station name /// public string StationName => App.AppSettings["SinochemSiteName"]; private bool printReceiptEnabled => Convert.ToBoolean(App.AppSettings["PrintReceiptEnabled"]); private bool printQRCodeEnabled => Convert.ToBoolean(App.AppSettings["PrintQrCodeOnReceiptEnabled"]); #endregion #region Request Id operations public void AddRequestId(int reqIid) { lock (reqIdSyncObj) { requestIdList.Add(reqIid); } } public void RemoveRequestId(int reqIid) { lock (reqIdSyncObj) { requestIdList.Remove(reqIid); } } public bool ContainsRequestId(int reqIid) { lock (reqIdSyncObj) { return requestIdList.Contains(reqIid); } } public void ClearAllRequestIds() { lock (reqIdSyncObj) { foreach (var id in requestIdList) { debugLogger.Add($"Clearing RequestId: {id}"); } requestIdList.Clear(); } } #endregion #region Constructor public FuelingPoint(int nozzleId, IEnumerable associatedNozzles, Eps eps) : base(nozzleId, "FuelingPoint") { FuelingPointId = nozzleId; AssociatedNozzles = associatedNozzles; Eps = eps; } #endregion #region DB & Trx handling /// /// Create an eps trx given the mop type. /// /// internal void CreateEpsTransaction(TransactionMode mop) { CurrentEpsTrx = EpsTransaction.CreateEpsTrx(CurrentNozzleId, mop, debugLogger); } internal void LockTrxInXiaofei2AsEpsTrx() { if (CurrentEpsTrx.MoveFromXiaofei2()) { } else { debugLogger.Add("trx in xiaofei2 not found!!!!"); } } #endregion #region Cloud & POS interactions internal void NotifyPosAync() { ThreadPool.QueueUserWorkItem(_ => { TrxNotificationResponse response = Eps.NotifySuccessfulTrxToPos(CurrentEpsTrx.Model, debugLogger); if (response != null && response.IsSuccessful()) { stateMachine.IncomingEvent(new StateEngineEvent(EventType.PosNotifyOk)); } else { stateMachine.IncomingEvent(new StateEngineEvent(EventType.PosNotifyFailed)); } }); } internal void SendPaymentToCloudAsync() { ThreadPool.QueueUserWorkItem(_ => { PaymentResponse response = Eps.SendPaymentToCloud(CurrentEpsTrx.Model, debugLogger); if (response != null && response.IsSuccessful()) { stateMachine.IncomingEvent(GenericEvent.Create(EventType.CloudPaymentOk, this, response)); } else { stateMachine.IncomingEvent(new StateEngineEvent(EventType.CloudPaymentFailed)); } }); } internal void SendBalanceQueryToCloudAsync(string cardNo, string encryptedPin, string tid, int nozzleId) { ThreadPool.QueueUserWorkItem(_ => { BalanceInquiryResponse response = Eps.SendBalanceInquiryToCloud(cardNo, encryptedPin, tid, nozzleId, debugLogger); if (response != null && response.IsSuccessful()) { stateMachine.IncomingEvent(GenericEvent.Create(EventType.CloudBalanceOk, this, response)); } else { stateMachine.IncomingEvent(new StateEngineEvent(EventType.CloudBalanceFailed)); } }); } #endregion #region Pump interactions internal void AuthorizePumpAsync(decimal authAmount) { Eps.AuthorizePumpAsync(callingPump, CurrentNozzleId, authAmount); } internal List GetAllNozzlesOnThisSide() { List nozzles = new List(); foreach (var fp in CurrentCardReader.SupportedNozzles) { var fuelingPoint = this.Eps.GetFuelingPoint(fp); if (fuelingPoint != null) nozzles.AddRange(fuelingPoint.AssociatedNozzles); } return nozzles; } #endregion #region Eps state config and signal protected override void ConfigStates() { States.CONFIGURATION.Config(stateMachine.StateTransitionLookup); } public void SignalShutdown() { Console.Out.WriteLine("SignalShutdown"); stateMachine.IncomingEvent(new StateEngineEvent(EventType.ShutdownRequest)); } public void FinalStateReached(string name) { Console.Out.WriteLine(name + " FinalStateReached"); } #endregion #region Card Plate public void SignalNewCarplate(CarPlateTrxRequest request) { lock (evSyncObj) { if (request != null && AssociatedNozzles.Contains(Convert.ToInt32(request.gun))) { debugLogger.AddIfActive ($"New car plate info arrived: Gun: {request.gun}, License plate No: {request.car_Number}, Balance: {request.amount}"); stateMachine.IncomingEvent(GenericEvent.Create(EventType.CarPlateScanned, this, request)); } } } #endregion #region Display on dispenser interactions public void SignalDisplayResponseReceived(DisplayResponse response) { debugLogger.AddIfActive("DisplayResponse from big screen"); stateMachine.IncomingEvent(new GenericEvent( EventType.DisplayResponseReceived, this, new DisplayResponseEventArgs(response))); } public void SignalTrxOpRequest(TransactionOperation request) { debugLogger.AddIfActive($"Transaction operation request from big screen, Trx id: {request.TrxId}"); stateMachine.IncomingEvent(new GenericEvent(EventType.TrxOpRequest, this, new TransactionOperationEventArgs(request))); } #endregion #region Card reader signals public void SingalAckReceived(ACK cardReaderMessage) { lock (sqNoSyncObj) { if (cardReaderMessage.MessageSeqNumber == currentSqNo) { debugLogger.AddIfActive($"Received card reader message with MsgSqNo = {cardReaderMessage.MessageSeqNumber}"); outboundMsgQueue.Dequeue(); debugLogger.AddIfActive($"Removed the message from the queue"); } } stateMachine.IncomingEvent(new GenericEvent(EventType.CardReaderAck, this, new CardReaderAckEventArgs(cardReaderMessage))); } public void SignalCardReaderDisconnected() { stateMachine.IncomingEvent(new StateEngineEvent(EventType.CardReaderDisconnected)); } public void SignalCardReaderDisabled() { stateMachine.IncomingEvent(new StateEngineEvent(EventType.ICCardReaderDisabled)); } public void SignalCardReaderHeartbeat(HeartBeat heartBeat) { SendNextCardReaderMessage(); } public void SignalSignedDataArrived(SignDataResponse cardReaderMessage) { debugLogger.AddIfActive("sending ack for SignDataResponse"); SendAckToCardReader(cardReaderMessage.SourceAddress, cardReaderMessage.MessageSeqNumber); stateMachine.IncomingEvent(new GenericEvent(EventType.DataSigned, this, new SignedDataEventArgs(cardReaderMessage))); } public void SingalCardReaderStateEvent(CardReaderStateEvent cardReaderStateEvent) { debugLogger.AddIfActive($"CardReaderStateEvent \n source address: {cardReaderStateEvent.SourceAddress} \n SqNo: {cardReaderStateEvent.MessageSeqNumber} \n Reader state: {cardReaderStateEvent.State.ToString()}"); SendAckToCardReader(cardReaderStateEvent.SourceAddress, cardReaderStateEvent.MessageSeqNumber); stateMachine.IncomingEvent(new GenericEvent(EventType.ReaderStateChanged, this, new CardReaderStateEventArgs(cardReaderStateEvent))); } private void SendAckToCardReader(byte srcAddress, byte sqNo) { ACK ack = new ACK { SourceAddress = srcAddress, MessageSeqNumber = sqNo }; if (CurrentCardReader != null) CurrentCardReader.Write(ack); } public void SignalCardExternalCheckFailure(CardExternalCheckErrorRequest cardReaderMessage) { debugLogger.AddIfActive($"IC Card check failure, Error reason: {cardReaderMessage.ErrorType.ToString()}"); SendAckToCardReader(cardReaderMessage.SourceAddress, cardReaderMessage.MessageSeqNumber); stateMachine.IncomingEvent(new GenericEvent(EventType.ExternalCheckFailure, this, new ExternalCheckFailedEventArgs(cardReaderMessage))); } public void SignalCardOnlineVerification(CardOnlineVerificationRequest cardReaderMessage) { debugLogger.AddIfActive($"IC Card online verification request, Card No: {cardReaderMessage.CardNo}, Encrypted PIN: {cardReaderMessage.EncryptedPIN}, TID: {cardReaderMessage.TID}"); SendAckToCardReader(cardReaderMessage.SourceAddress, cardReaderMessage.MessageSeqNumber); stateMachine.IncomingEvent(new GenericEvent(EventType.OnlineVerification, this, new CardOnlineVerificationEventArgs(cardReaderMessage))); } #endregion #region Pump signals internal void SignalNozzleLifted(IFdcPumpController callingPump, int sitewiseNozzleId) { debugLogger.Add("SignalNozzleLifted, nozzleid -- " + sitewiseNozzleId); this.callingPump = callingPump; stateMachine.IncomingEvent( new GenericEvent( EventType.NozzleLifted, this, new NozzleLiftedEventArgs() { NozzleId = sitewiseNozzleId })); } internal void SignalNozzleReplaced(int sitewiseNozzleId) { debugLogger.Add("SignalNozzleReplaced, nozzleid -- " + sitewiseNozzleId); stateMachine.IncomingEvent( new GenericEvent( EventType.NozzleReplaced, this, new NozzleReplacedEventArgs() { NozzleId = sitewiseNozzleId })); } internal void SignalAuthOk(long? authId) { debugLogger.Add("SignalAuthOk -- " + authId); AuthorizationId = authId; var arg = new GenericEventArg(DateTime.Now.ToString("HH:mm:ss")); stateMachine.IncomingEvent(GenericEvent.Create(EventType.PumpAuthOk, this, arg)); } internal void SignalAuthFailed() { debugLogger.Add("SignalAuthFailed"); stateMachine.IncomingEvent(new StateEngineEvent(EventType.PumpAuthFailed)); } internal void SignalFuelingDone(int nozzleId, int seqNum, decimal fuelAmount, decimal fuelingQty, long authId) { debugLogger.Add("SignalFuelingDone -- " + authId); stateMachine.IncomingEvent(new GenericEvent(EventType.FuelingDone, this, new FuelingDoneEventArgs { NozzleId = nozzleId, FuelingSqNo = seqNum, Amount = fuelAmount, Quantity = fuelingQty, AuthId = authId })); } #endregion #region Card reader support /// /// Sender side's sequence number, 01H-0FH, when program restarted, use 00H. /// /// The sequence number byte. public byte GetSenderSideSqNo() { lock (syncObj) { if (initialSqNo == 0) { sqNo = initialSqNo; initialSqNo = 1; return sqNo; } byte nextSqNo = (byte)(sqNo++ % 16); if (nextSqNo == 0) { sqNo++; return initialSqNo; } return nextSqNo; } } public byte CardReaderSrcAddr { get { return (byte)(CurrentCardReader?.GetAddressForNozzleId(FuelingPointId)); } } public void SendCommand(IcCardReaderMessageBase command, out byte sqNo) { command.MessageSeqNumber = GetSenderSideSqNo(); command.SourceAddress = CardReaderSrcAddr; sqNo = command.MessageSeqNumber; PendMessage(command); } public void PendMessage(IcCardReaderMessageBase msg) { lock (queueSyncObj) { outboundMsgQueue.Enqueue(msg); } } public void SendNextCardReaderMessage() { lock (queueSyncObj) { if (outboundMsgQueue.Count > 0) { var msgToSend = outboundMsgQueue.Peek(); lock (sqNoSyncObj) { currentSqNo = msgToSend.MessageSeqNumber; } debugLogger.AddIfActive($"Peek and send Card reader message {msgToSend.GetType().ToString()} with MsgSqNo = {msgToSend.MessageSeqNumber}"); CurrentCardReader?.Write(msgToSend); } else { var eot = new EOT { SourceAddress = CardReaderSrcAddr, MessageSeqNumber = 0 }; CurrentCardReader?.Write(eot); } } } #endregion #region Receipt public void BuildReceipt() { if (CurrentReceipt == null) CurrentReceipt = new List(); else CurrentReceipt.Clear(); List bodyLines = new List(); List header = new List(); List product = new List(); List payment = new List(); ReceiptModel receiptModel = ReceiptModelBuilder.BuildReceiptModel(CurrentEpsTrx, CurrentTrxMode); string lineSeparator = "------------------------------"; string emptyLine = " "; string receiptHeaderReceiptType = string.Format($" {receiptModel.TrxModeName}小票 "); string stationName = "油站名称:" + StationName; string trxTimeStamp = "时间:" + Utilities.ConvertDateTimeToReadble(DateTime.Now); string runningNumberLine = "流水号:" + receiptModel.RunningNumber; string cardNoLine = "卡号:" + receiptModel.CardNo; string gradeNameLine = "油品:" + receiptModel.GradeName; string nozzleIdLine = "枪号:" + receiptModel.NozzleId; string ppuLine = "单价:" + receiptModel.PPU + "元/升"; string qtyLine = "数量:" + receiptModel.Qty + "升"; string amountLine = "金额:" + receiptModel.Amount + "元"; string dueAmountLine = string.Format($"应付: {receiptModel.DueAmount}元"); string discountLine = string.Format($"优惠: {receiptModel.DiscountAmount}元"); string payAmountLine = string.Format($"实付: {receiptModel.PayAmount}元"); header.Add(receiptHeaderReceiptType); header.Add(emptyLine); header.Add(stationName); header.Add(trxTimeStamp); header.Add(runningNumberLine); header.Add(cardNoLine); header.Add(lineSeparator); //Add header bodyLines.AddRange(header); product.Add(gradeNameLine); product.Add(nozzleIdLine); product.Add(ppuLine); product.Add(qtyLine); product.Add(amountLine); product.Add(lineSeparator); //Add product details bodyLines.AddRange(product); payment.Add(dueAmountLine); payment.Add(discountLine); payment.Add(payAmountLine); payment.Add(lineSeparator); //Add payment details bodyLines.AddRange(payment); //QR code if (printQRCodeEnabled) { string invoicePromptLine = string.Format(" 如需发票,请扫描二维码 "); bodyLines.Add(invoicePromptLine); bodyLines.Add(emptyLine); } //Thanks line string thanksLine = " 谢谢惠顾,欢迎再次光临 "; CreateReceiptLine(bodyLines); if (printQRCodeEnabled) { debugLogger.Add("EInvocie URL: " + receiptModel.InvoiceUrl); CreateQRCode(receiptModel.InvoiceUrl); //CreateQRCode("http://invoicetest-invoicetest-invoicetest-invoicetest-invoicetest-invoicetestinvoicetest.com/orderno=12345678901234567890123456789012345678901234567890"); } CreateReceiptEnd(thanksLine); } private void CreateReceiptLine(List lines) { List targetBytes = new List(); foreach (var line in lines) { var bytes = Encoding.GetEncoding("GB2312").GetBytes(line); targetBytes.Add(0x01); targetBytes.AddRange(EnsureLength(bytes)); CurrentReceipt.Add(new ReceiptLine(targetBytes.ToArray(), 31)); targetBytes.Clear(); } } private void CreateQRCode(string url) { int frameLen = 80; byte[] source = Encoding.ASCII.GetBytes(url); List target = new List(); if (source.Length <= frameLen) { byte[] buffer = new byte[source.Length]; Buffer.BlockCopy(source, 0, buffer, 0, source.Length); target.Add(0x04); target.AddRange(buffer); CurrentReceipt.Add(new ReceiptLine(target.ToArray(), source.Length + 1)); target.Clear(); } else { for (int i = 0; i < source.Length; i += frameLen) { if (source.Length - i < frameLen) { byte[] buffer = new byte[source.Length - i]; Buffer.BlockCopy(source, i, buffer, 0, source.Length - i); target.Add(0x04); target.AddRange(buffer); CurrentReceipt.Add(new ReceiptLine(target.ToArray(), source.Length - i + 1)); } else { byte[] buffer = new byte[frameLen]; Buffer.BlockCopy(source, i, buffer, 0, frameLen); target.Add(0x03); target.AddRange(buffer); CurrentReceipt.Add(new ReceiptLine(target.ToArray(), frameLen + 1)); } target.Clear(); } } } private void CreateReceiptEnd(string endLine) { List targetBytes = new List(); var bytes = Encoding.GetEncoding("GB2312").GetBytes(endLine); targetBytes.Add(0x02); targetBytes.AddRange(bytes); CurrentReceipt.Add(new ReceiptLine(targetBytes.ToArray(), 31)); targetBytes.Clear(); } private byte[] EnsureLength(byte[] bytes) { if (bytes.Length < 30) { List targetBytes = new List(); targetBytes.AddRange(bytes); for (int i = 0; i < 30 - bytes.Length; i++) { targetBytes.Add(0x20); } return targetBytes.ToArray(); } else { return bytes.Take(30).ToArray(); } } public byte[] GetNextReceiptLine(int i) { debugLogger.Add("nfe current i = " + i); debugLogger.Add("nfe total count = " + CurrentReceipt.Count); if (i <= CurrentReceipt.Count - 1) return CurrentReceipt.ElementAt(i).Line; return null; } #endregion #region Card reader trx handling public void SetICCardReaderToCarPlateIdle(out byte sqNo) { StartFuelPresetProcessRequest setCardReaderToIdle = new StartFuelPresetProcessRequest(StartFuelPresetProcessReason.CarPlatePaymentIsInProcessing) { MessageSeqNumber = GetSenderSideSqNo(), SourceAddress = CardReaderSrcAddr }; sqNo = setCardReaderToIdle.MessageSeqNumber; PendMessage(setCardReaderToIdle); } public void NotifyCardReaderTrxDone(out byte sqNo) { NotifyTransactionIsDoneRequest trxDoneRequest = new NotifyTransactionIsDoneRequest() { MessageSeqNumber = GetSenderSideSqNo(), SourceAddress = CardReaderSrcAddr }; sqNo = trxDoneRequest.MessageSeqNumber; PendMessage(trxDoneRequest); } public void CloseICCardReader(out byte sqNo) { CloseCardReaderRequest closeCardReader = new CloseCardReaderRequest { MessageSeqNumber = GetSenderSideSqNo(), SourceAddress = CardReaderSrcAddr }; sqNo = closeCardReader.MessageSeqNumber; PendMessage(closeCardReader); } public void OpenCardReader(out byte? sqNo) { OpenCardReaderRequest openCardReader = new OpenCardReaderRequest { MessageSeqNumber = GetSenderSideSqNo(), SourceAddress = CardReaderSrcAddr }; sqNo = openCardReader.MessageSeqNumber; PendMessage(openCardReader); } public void SendICCardDisplay(string carPlate, out byte sqNo) { string licenseNo = carPlate; byte[] newbytes = new byte[64]; for (int i = 0; i < 64; i++) { newbytes[i] = 0x20; } byte[] bytes = Encoding.GetEncoding("gb2312").GetBytes(licenseNo); if (bytes.Count() < 64) bytes.CopyTo(newbytes, 0); DisplayRequest displayRequest = new DisplayRequest(newbytes, CardReaderDisplayTimeout) { MessageSeqNumber = GetSenderSideSqNo(), SourceAddress = CardReaderSrcAddr }; sqNo = displayRequest.MessageSeqNumber; PendMessage(displayRequest); } public byte[] GetMAC(EpsTransactionModel epsTrxModel) { debugLogger.AddIfActive($"fuel amount: {epsTrxModel.amount}"); debugLogger.AddIfActive($"fuel quantity: {epsTrxModel.qty}"); string cardNo = epsTrxModel.card_no;// "8888118001000078417"; string carPlate = string.IsNullOrEmpty(epsTrxModel.car_number) ? "晋A12345" : epsTrxModel.car_number; byte[] chsByte = Encoding.Unicode.GetBytes(carPlate[0].ToString()); byte[] b1 = { chsByte[1], chsByte[0] }; string asciiBytes = carPlate.Substring(1, 6).PadRight(8, ' '); byte[] b2 = Encoding.ASCII.GetBytes(asciiBytes); byte[] newBytes = new byte[b1.Length + b2.Length]; b1.CopyTo(newBytes, 0); b2.CopyTo(newBytes, 2); if (string.IsNullOrEmpty(epsTrxModel.car_number)) newBytes = new byte[10] { 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }; string ts = epsTrxModel.created_time.ToString("yyyyMMddHHmmss");//"20180425110509"; double fuelAmount = epsTrxModel.amount;//10.00; double fuelVolume = epsTrxModel.qty;//1.00; int nozzleNumber = epsTrxModel.jihao; string tid = epsTrxModel.tid;//"111001000633"; var targetSignBytes = cardNo.PadLeft(20, '0').ToBCD() .Concat(newBytes) .Concat(ts.ToBCD() .Concat(((int)((decimal)fuelAmount * 100)).GetBinBytes(4)) .Concat(((int)((decimal)fuelVolume * 100)).GetBinBytes(4)) .Concat(nozzleNumber.GetBCDBytes(2))); return targetSignBytes.ToArray(); //string cardNumber = "08888118001000078417";//carPlateTrxRequest.card_No; ////string carPlate = Encoding.GetEncoding("gbk").GetString(Encoding.GetEncoding("gbk").GetBytes("晋A12345"));//carPlateTrxRequest.car_Number)); //string carPlate = "晋A12345"; //byte[] b = Encoding.Unicode.GetBytes(carPlate[0].ToString()); //byte[] b1 = { b[1], b[0] }; //string sss = carPlate.Substring(0, 6).PadRight(8, ' '); //byte[] b2 = Encoding.ASCII.GetBytes(sss); //byte[] newBytes = new byte[b1.Length + b2.Length]; //b1.CopyTo(newBytes, 0); //b2.CopyTo(newBytes, 2); //string ts = "20180425110509"; //DateTime fuelingTime = DateTime.Now; //int fuelAmount = 10; //int fuelVolume = 1; //int nozzleNumber = 2; //var targetSignBytes = cardNumber.PadRight(20, ' ').ToBCD() // .Concat(newBytes) // //.Concat(Encoding.GetEncoding("gbk").GetBytes(carPlate)) // .Concat(ts.ToBCD()// fuelingTime.ToString("yyyyMMddHHmmss")) // .Concat(fuelAmount.GetBinBytes(4)) // .Concat(fuelVolume.GetBinBytes(4)) // .Concat(nozzleNumber.GetBCDBytes(2))); //return targetSignBytes.ToArray(); //string cardNumber = carPlateTrxRequest.card_No; //string carPlate = Encoding.GetEncoding("gbk").GetString(Encoding.GetEncoding("gbk").GetBytes(carPlateTrxRequest.car_Number)); //DateTime fuelingTime = DateTime.Now; //int fuelAmount = 99; //int fuelVolume = 14; //int nozzleNumber = 1; //var targetSignBytes = cardNumber.PadRight(20, ' ').ToBCD() // .Concat(Encoding.GetEncoding("gbk").GetBytes(carPlate)) // .Concat(ASCIIEncoding.ASCII.GetBytes(fuelingTime.ToString("yyyyMMddHHmmss")) // .Concat(fuelAmount.GetBinBytes(4)) // .Concat(fuelVolume.GetBinBytes(4)) // .Concat(nozzleNumber.GetBCDBytes(2))); //var expected = new byte[] { 0xFA, 0xD2, }.Concat((targetSignBytes.Count() + 1).GetBCDBytes(2)) // .Concat(new byte[] { 0x05 }) // .Concat(targetSignBytes) // .Concat(new byte[] { 0x84, 0xb0 }); var signDataRequest = new SignDataRequest(targetSignBytes.ToArray()) { MessageSeqNumber = GetSenderSideSqNo(), SourceAddress = CardReaderSrcAddr }; sqNo = signDataRequest.MessageSeqNumber; PendMessage(signDataRequest); } #endregion #region Printer public bool GetPrinter() { lock (printerSyncObj) { if (printerIdle == true) { printerIdle = false; return true; } else { GetPrinterCount++; return false; } } } public void ReleasePrinter() { lock (printerSyncObj) { printerIdle = true; } } #endregion #region Cleanup public void Cleanup() { CurrentEpsTrx = null; CurrentTrxMode = TransactionMode.Unknown; AuthorizationId = null; CurrentNozzleId = Eps.InvalidNozzleId; GetPrinterCount = 0; } #endregion } }