| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290 |
- using System;
- using System.Collections.Generic;
- using System.Collections.ObjectModel;
- using System.Configuration;
- using System.IO.Ports;
- using System.Linq;
- using System.Text;
- using System.Threading;
- using Timer = System.Timers.Timer;
- using System.Collections;
- using HengShan_Pump_NonIC.MessageEntity;
- using Edge.Core.Processor;using Edge.Core.IndustryStandardInterface.Pump;
- using Wayne.FDCPOSLibrary;
- using System.Xml;
- using Edge.Core.Database.Models;
- using System.Threading.Tasks;
- namespace HengShan_Pump_NonIC
- {
- /// <summary>
- /// this is kind of HS non IC pump that have a build-in auto auth self function by hardware, so outside(fcc) can't auth it, it's
- /// a 'lift nozzle, and fueling pump'.
- /// basically it only have 2 states:
- /// idle: 不允许加油--加油结束--油枪关--电机关--D30--D20--金额加油
- /// fueling: 允许加油--加油过程--油枪打开--电机打开--D30--D20--金额加油
- /// </summary>
- public class PumpHandlerForSelfAuthPump : PumpHandler
- {
- private object syncObject = new object();
- // by seconds, change this value need change the correlated deviceOfflineCountdownTimer's interval as well
- private const int lastLogicalDeviceStateExpiredTime = 3;
- private DateTime lastLogicalDeviceStateReceivedTime;
- private System.Timers.Timer deviceOfflineCountdownTimer;
- //static ILog fdcLogger = log4net.LogManager.GetLogger("FdcServer");
- //static ILog logger = log4net.LogManager.GetLogger("PumpHandler");
- static NLog.Logger logger = NLog.LogManager.LoadConfiguration("nlog.config").GetLogger("PumpHandler");
- /// <summary>
- /// 恒山非IC油机
- /// </summary>
- /// <param name="pumpId"></param>
- /// <param name="nozzlesXmlConfiguration"></param>
- public PumpHandlerForSelfAuthPump(int pumpId, string nozzlesXmlConfiguration) : base(pumpId, nozzlesXmlConfiguration)
- {
- logger.Info("Pump: " + this.PumpId + ", PumpHandlerForSelfAuthPump");
- this.deviceOfflineCountdownTimer = new System.Timers.Timer(1000);
- this.deviceOfflineCountdownTimer.Elapsed += (_, __) =>
- {
- if (DateTime.Now.Subtract(this.lastLogicalDeviceStateReceivedTime).TotalSeconds
- >= lastLogicalDeviceStateExpiredTime)
- {
- //if (this.lastLogicalDeviceState != LogicalDeviceState.FDC_OFFLINE)
- //{
- // this.lastLogicalDeviceState = LogicalDeviceState.FDC_OFFLINE;
- logger.Info("Pump: " + this.PumpId + ", " + " seems offline due to long time no see pump data incoming");
- // var safe0 = this.OnStateChange;
- // safe0?.Invoke(this, new FdcPumpControllerOnStateChangeEventArg(LogicalDeviceState.FDC_OFFLINE, null));
- // logger.Trace("Pump: " + this.pumpId + ", " + " OnStateChange event fired and back");
- //}
- }
- };
- this.deviceOfflineCountdownTimer.Start();
- }
- public override async Task Process(IContext<byte[], NonICMessageTemplateBase> context)
- {
- if (!isOnFdcServerInitCalled) return;
- this.lastLogicalDeviceStateReceivedTime = DateTime.Now;
- this.context = context;
- if (context.Incoming.Message is GetNozzleStatusResponse getNozzleStatusResponse)
- {
- //this.isSafeForSend = true;
- this.lastLogicalDeviceStateReceivedTime = DateTime.Now;
- //var getNozzleStatusResponse = context.Incoming.Message as GetNozzleStatusResponse;
- // put the price by reading the real price.
- this.nozzles.First().RealPriceOnPhysicalPump = getNozzleStatusResponse.单价;
- var latestStatus = getNozzleStatusResponse.GetPumpStatus();
- if (latestStatus.Any(f => f == GetNozzleStatusResponse.PumpStatus.允许加油)
- && latestStatus.Any(f => f == GetNozzleStatusResponse.PumpStatus.油枪打开)
- && latestStatus.Any(f => f == GetNozzleStatusResponse.PumpStatus.加油过程)
- && latestStatus.Any(f => f == GetNozzleStatusResponse.PumpStatus.电机打开))
- {
- /* 正处于加油状态下 */
- if (this.previousUnfinishedFuelingNozzleStatus != null
- && this.previousUnfinishedFuelingNozzleStatus.流水号 != getNozzleStatusResponse.流水号)
- {
- logger.Info("Pump: " + this.PumpId + ", " + "Detected a fast put back and pull out nozzle case(action time < polling time cause nozzle place back not detected)," +
- "\r\n will fire the trx done event for earlier trx(may have volume/money data loss!!!) with most recoverable data(most likely a bit less than real)->\r\n "
- + "seqNo: " + this.previousUnfinishedFuelingNozzleStatus.流水号
- + ", amount: " + this.previousUnfinishedFuelingNozzleStatus.加油金额
- + ", volume: " + this.previousUnfinishedFuelingNozzleStatus.加油量
- + ", price: " + this.previousUnfinishedFuelingNozzleStatus.单价);
- logger.Info("Pump: " + this.PumpId + ", " + " State switched to FDC_READY(simulate)");
- this.lastLogicalDeviceState = LogicalDeviceState.FDC_READY;
- this.FireOnStateChangeEvent(LogicalDeviceState.FDC_READY);
- var previousFuelingAmount = this.previousUnfinishedFuelingNozzleStatus.加油金额;
- var previousFuelingVol = this.previousUnfinishedFuelingNozzleStatus.加油量;
- var previousPrice = this.previousUnfinishedFuelingNozzleStatus.单价;
- var previousSeqNo = this.previousUnfinishedFuelingNozzleStatus.流水号;
- if (this.logicalNozzleIdToLastFuelSaleTrxMapping.ContainsKey(1))
- this.logicalNozzleIdToLastFuelSaleTrxMapping[1] = new FuelSaleTransaction()
- {
- TransactionSeqNumberFromPhysicalPump = this.previousUnfinishedFuelingNozzleStatus.流水号.ToString()
- };
- else
- this.logicalNozzleIdToLastFuelSaleTrxMapping.Add(1, new FuelSaleTransaction()
- {
- TransactionSeqNumberFromPhysicalPump = this.previousUnfinishedFuelingNozzleStatus.流水号.ToString()
- });
- //ThreadPool.QueueUserWorkItem(o =>
- //{
- var totalizer = await base.QueryTotalizerAsync(1);
- this.FireOnCurrentFuellingStatusChangeEvent(new FdcTransaction()
- {
- // use previousUnfinishedFuelingNozzleStatus could miss reading the last trx correct numbers(less than actual number)
- //, obviously this is caused by pump hardware design, impossible to recovery it back by our application.
- Nozzle = this.nozzles.First(),
- Amount = previousFuelingAmount,
- Volumn = previousFuelingVol,
- Price = previousPrice,
- SequenceNumberGeneratedOnPhysicalPump = previousSeqNo,
- AmountTotalizer = totalizer.Item1,
- VolumeTotalizer = totalizer.Item2,
- Finished = true,
- });
- //});
- }
- this.previousUnfinishedFuelingNozzleStatus = getNozzleStatusResponse;
- if (this.lastLogicalDeviceState != LogicalDeviceState.FDC_FUELLING)
- {
- //status code: B1
- logger.Debug("Pump: " + this.PumpId + ", " + "收到新状态: 处于加油状态下");
- logger.Debug("Pump: " + this.PumpId + ", " + " State switched to FDC_CALLING(by simulate)");
- this.lastLogicalDeviceState = LogicalDeviceState.FDC_CALLING;
- base.FireOnStateChangeEvent(LogicalDeviceState.FDC_CALLING);
- logger.Debug("Pump: " + this.PumpId + ", " + " State switched to FDC_FUELLING(流水号: " + getNozzleStatusResponse.流水号 + ")");
- this.lastLogicalDeviceState = LogicalDeviceState.FDC_FUELLING;
- base.FireOnStateChangeEvent(LogicalDeviceState.FDC_FUELLING);
- }
- logger.Debug("Pump: " + this.PumpId + ", " + " fueling in progress with amt: " + getNozzleStatusResponse.加油金额
- + ", vol: " + getNozzleStatusResponse.加油量 + ", seq: " + getNozzleStatusResponse.流水号);
- //fire fuelling progress.
- base.FireOnCurrentFuellingStatusChangeEvent(new FdcTransaction()
- {
- // 恒山油机只有一把枪
- Nozzle = this.nozzles.First(),
- Amount = getNozzleStatusResponse.加油金额,
- Volumn = getNozzleStatusResponse.加油量,
- Price = getNozzleStatusResponse.单价,
- SequenceNumberGeneratedOnPhysicalPump = getNozzleStatusResponse.流水号,
- Finished = false,
- });
- }
- else if (latestStatus.Any(f => f == GetNozzleStatusResponse.PumpStatus.不允许加油)
- && latestStatus.Any(f => f == GetNozzleStatusResponse.PumpStatus.加油结束))
- {
- /* 油机首次上电也会进入此处,并不断发送上一次的加油记录,这种情况下的交易记录并无法判断其之前是否已经发送至上层系统(比如是否已经存入数据库),
- 所以此处不判断而是往上层系统里送入,由系统判断重复情况。 而其它正常加油过程中的交易记录仅在油机状态变化时才送入系统。*/
- // status code: 40
- this.previousUnfinishedFuelingNozzleStatus = null;
- if (this.lastLogicalDeviceState != LogicalDeviceState.FDC_READY)
- {
- logger.Info("Pump: " + this.PumpId + ", " + "收到新状态: 加油结束(seq No.: " + getNozzleStatusResponse.流水号.ToString() + ")");
- logger.Info("Pump: " + this.PumpId + ", " + " State switched to FDC_READY");
- lastLogicalDeviceState = LogicalDeviceState.FDC_READY;
- base.FireOnStateChangeEvent(LogicalDeviceState.FDC_READY);
- // zero trx, do nothing.
- if (getNozzleStatusResponse.加油量 == 0 || getNozzleStatusResponse.加油金额 == 0)
- {
- logger.Debug("Pump: " + this.PumpId + ", " + "0 amount trx, will ignore");
- return;
- }
- // repeat received last fuel sale message, do nothing.
- if (base.logicalNozzleIdToLastFuelSaleTrxMapping.ContainsKey(1)
- && base.logicalNozzleIdToLastFuelSaleTrxMapping[1].TransactionSeqNumberFromPhysicalPump
- == getNozzleStatusResponse.流水号.ToString())
- {
- logger.Info("Pump: " + this.PumpId + ", fuel trx seq No. have NOT changed(previous seq No.: "
- + base.logicalNozzleIdToLastFuelSaleTrxMapping[1].TransactionSeqNumberFromPhysicalPump + "), will ignore");
- return;
- }
- // lastSale exists and 流水号 diff
- if (base.logicalNozzleIdToLastFuelSaleTrxMapping.ContainsKey(1)
- && base.logicalNozzleIdToLastFuelSaleTrxMapping[1].TransactionSeqNumberFromPhysicalPump
- != getNozzleStatusResponse.流水号.ToString())
- {
- logger.Info("Pump: " + base.PumpId
- + ", Detect a fule trx with 流水号: " + getNozzleStatusResponse.流水号 + " which is diff from previous fule trx(previous 流水号:" +
- this.logicalNozzleIdToLastFuelSaleTrxMapping[1].TransactionSeqNumberFromPhysicalPump + "), will generate a new fule sale trx with vol: " + getNozzleStatusResponse.加油量);
- this.logicalNozzleIdToLastFuelSaleTrxMapping[1] = new FuelSaleTransaction() { TransactionSeqNumberFromPhysicalPump = getNozzleStatusResponse.流水号.ToString() };
- }
- // lastSale not exists
- if (!this.logicalNozzleIdToLastFuelSaleTrxMapping.ContainsKey(1))
- {
- logger.Info("Pump: " + base.PumpId + ", very first initial trx detected on this pump, will generate a new fule sale trx(seq: " + getNozzleStatusResponse.流水号 + ", vol: " + getNozzleStatusResponse.加油量 + ", amt: " + getNozzleStatusResponse.加油金额 + ")");
- this.logicalNozzleIdToLastFuelSaleTrxMapping.Add(1, new FuelSaleTransaction() { TransactionSeqNumberFromPhysicalPump = getNozzleStatusResponse.流水号.ToString() });
- }
- var amount = getNozzleStatusResponse.加油金额;
- var fuelingVol = getNozzleStatusResponse.加油量;
- var price = getNozzleStatusResponse.单价;
- var seqNo = getNozzleStatusResponse.流水号;
- logger.Info("Pump: " + base.PumpId + ", fire trx done with amt: " + amount + ", vol: " + fuelingVol
- + ", price: " + price + ", seq No.: " + seqNo);
- //ThreadPool.QueueUserWorkItem(o =>
- //{
- var totalizer = await this.QueryTotalizerAsync(1);
- base.FireOnCurrentFuellingStatusChangeEvent(new FdcTransaction()
- {
- // 恒山油机 一个加油点只有一把枪
- Nozzle = this.nozzles.First(),
- Amount = amount,
- Volumn = fuelingVol,
- Price = price,
- SequenceNumberGeneratedOnPhysicalPump = seqNo,
- AmountTotalizer = totalizer.Item1,
- VolumeTotalizer = totalizer.Item2,
- Finished = true,
- });
- //});
- }
- }
- else
- {
- if (logger.IsTraceEnabled)
- logger.Trace("Unhandled GetNozzleStatusResponse is incoming: " + getNozzleStatusResponse.ToLogString());
- }
- }
- else
- {
- await base.Process(context);
- }
- }
- /// <summary>
- ///
- /// </summary>
- /// <param name="logicalNozzleId">useless for this type of pump, it always one pump one nozzle</param>
- /// <returns></returns>
- public override async Task<bool> AuthorizeAsync(byte logicalNozzleId)
- {
- return false;
- }
- /// <summary>
- ///
- /// </summary>
- /// <param name="moneyAmount"></param>
- /// <param name="logicalNozzleId">useless for this type of pump, it always one pump one nozzle</param>
- /// <returns></returns>
- public override async Task<bool> AuthorizeWithAmountAsync(int moneyAmount, byte logicalNozzleId)
- {
- return false;
- }
- /// <summary>
- ///
- /// </summary>
- /// <param name="volume"></param>
- /// <param name="logicalNozzleId">useless for this type of pump, it always one pump one nozzle</param>
- /// <returns></returns>
- public override async Task<bool> AuthorizeWithVolumeAsync(int volumn, byte logicalNozzleId)
- {
- return false;
- }
- }
- }
|