1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189 |
- using Edge.Core.Database;
- using Edge.Core.Processor;
- using Edge.Core.IndustryStandardInterface.Pump;
- using HengShan_Pump_TQC_IFSF.MessageEntity;
- using HengShan_Pump_TQC_IFSF.MessageEntity.Incoming;
- using HengShan_Pump_TQC_IFSF.MessageEntity.Outgoing;
- using Edge.Core.Parser.BinaryParser.Util;
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Globalization;
- using System.Linq;
- using System.Text;
- using System.Threading;
- using System.Threading.Tasks;
- using System.Xml;
- using Wayne.FDCPOSLibrary;
- using Timer = System.Timers.Timer;
- using Edge.Core.Processor.Dispatcher.Attributes;
- using Edge.Core.Processor.Communicator;
- using Edge.Core.Configuration;
- namespace HengShan_Pump_TQC_IFSF
- {
- #region Ctor parameters
- public class PumpGroupConfiguration
- {
- //public byte AmountDecimalDigits { get; set; }
- //public byte VolumeDecimalDigits { get; set; }
- //public byte PriceDecimalDigits { get; set; }
- //public byte VolumeTotalizerDecimalDigits { get; set; }
- public byte FccIfsfSubnetValue { get; set; }
- public byte FccIfsfNodeValue { get; set; }
- public byte PumpIfsfSubnetValue { get; set; }
- public byte PumpIfsfNodeValue { get; set; }
- public List<PumpConfiguration> PumpConfigurations { get; set; }
- }
- public class PumpConfiguration
- {
- public byte PumpId { get; set; }
- /// <summary>
- /// 0x21 - 0x24
- /// </summary>
- public byte PhysicalId { get; set; }
- public List<NozzleConfiguration> NozzleConfigurations { get; set; }
- }
- public class NozzleConfiguration
- {
- public byte LogicalId { get; set; }
- /// <summary>
- /// 0x11 - 0x18
- /// </summary>
- public byte PhysicalId { get; set; }
- }
- #endregion
- /// <summary>
- /// one TQC connection controls a full physical pump, typically 2 sides.
- /// </summary>
- [MetaPartsRequired(typeof(GenericDeviceProcessor<,>))]
- [MetaPartsRequired(typeof(HengShan_TQC_IFsfMessageTcpIpCommunicator<>))]
- [MetaPartsRequired(typeof(IfsfMessageBase))]
- [MetaPartsDescriptor(
- "lang-zh-cn:HS TQC加油机lang-en-us:HS TQC Pump",
- "lang-zh-cn:用于驱动基于TCP连接的IFSF协议的稳牌-WT30或恒山-TH22加油机,或者其它IFSF兼容的加油机lang-en-us:Used for driven Wayne-WT30 or HengShan-TH22, or other IFSF(on TCP/IP) compatible Pumps",
- new[] { "lang-zh-cn:加油机lang-en-us:Pump" })]
- public class PumpGroupHandler : IEnumerable<IFdcPumpController>, IDeviceHandler<byte[], IfsfMessageBase>
- {
- private object syncObject = new object();
- protected IEnumerable<NozzleExtraInfo> nozzleProductMappings;
- //private System.Timers.Timer heartBeatUdpPolling;
- //protected int heartBeatUdpPollingInterval = 6000;
- //private System.Timers.Timer queryTqcAllPumpStatePolling;
- //private long queryTqcAllPumpStatePollingInterval = 60 * 1000;
- private Guid uniqueId = Guid.NewGuid();
- internal TqcPumpGroupInitializer tqcPumpGroupInitializer;
- //protected static ILog logger = log4net.LogManager.GetLogger("PumpHandler");
- protected static NLog.Logger logger = NLog.LogManager.LoadConfiguration("nlog.config").GetLogger("PumpHandler");
- protected IContext<byte[], IfsfMessageBase> context;
- protected List<PumpHandler> pumpHandlers = new List<PumpHandler>();
- // for test, the tqc configured as subnet 1, node 1.
- protected byte recipientSubnet = 1;
- protected byte recipientNode = 1;
- // originator, it's the FC self.
- public static byte originatorSubnet = 2;
- public static byte originatorNode = 1;
- [ParamsJsonSchemas("PumpGroupHandlerCtorParamsJsonSchemas")]
- public PumpGroupHandler(PumpGroupConfiguration pumpGroupConfiguration, IServiceProvider services)
- {
- originatorSubnet = pumpGroupConfiguration.FccIfsfSubnetValue;
- originatorNode = pumpGroupConfiguration.FccIfsfNodeValue;
- this.recipientSubnet = pumpGroupConfiguration.PumpIfsfSubnetValue;
- this.recipientNode = pumpGroupConfiguration.PumpIfsfNodeValue;
- logger.Info("node " + this.recipientNode + ", Will create " +
- pumpGroupConfiguration.PumpConfigurations.Count + " pump handlers for this TQC connection according from config");
- this.CreatePumpHandlers(pumpGroupConfiguration.PumpConfigurations.Select(pc =>
- {
- XmlDocument doc = new XmlDocument();
- var xml =
- "<Pump pumpId='" + pc.PumpId + "' physicalId='" + pc.PhysicalId + "'>" +
- "<Nozzles>" +
- pc.NozzleConfigurations.Select(nc =>
- "<Nozzle logicalId='" + nc.LogicalId + "' physicalId='" + nc.PhysicalId + "' />")
- .Aggregate((acc, n) => acc + n) +
- "</Nozzles>" +
- "</Pump>";
- doc.LoadXml(xml);
- return doc.FirstChild;
- }));
- this.SetupTqcPumpGroupInitializer();
- }
- /// <summary>
- ///
- /// </summary>
- /// <param name="fccIfsfSubnetValue">fcc as a node in a ifsf subnet, has its subnet value</param>
- /// <param name="fccIfsfNodeValue">fcc as a node in a ifsf subnet, has its node value</param>
- /// <param name="pumpsXmlConfiguration"></param>
- public PumpGroupHandler(int fccIfsfSubnetValue, int fccIfsfNodeValue, string pumpsXmlConfiguration)
- {
- originatorSubnet = (byte)fccIfsfSubnetValue;
- originatorNode = (byte)fccIfsfNodeValue;
- // sample
- //<PumpGroup ifsfSubNet='2' ifsfNode='1'>
- // <Pump pumpId='1' physicalId='0x21'>
- // <Nozzles>
- // <Nozzle logicalId='1' physicalId='0x11' />
- // <Nozzle logicalId='2' physicalId='0x12' />
- // </Nozzles>
- // </Pump>
- // <Pump pumpId='2' physicalId='0x22'>
- // <Nozzles>
- // <Nozzle logicalId='1' physicalId='0x11' />
- // <Nozzle logicalId='2' physicalId='0x12' "/>
- // </Nozzles>
- // </Pump>
- // <Pump pumpId='3' physicalId='0x23'>
- // <Nozzles>
- // <Nozzle logicalId='1' physicalId='0x13' />
- // <Nozzle logicalId='2' physicalId='0x14' />
- // </Nozzles>
- // </Pump>
- // <Pump pumpId='4' physicalId='0x24'>
- // <Nozzles>
- // <Nozzle logicalId='1' physicalId='0x15' />
- // <Nozzle logicalId='2' physicalId='0x16' />
- // </Nozzles>
- // </Pump>
- //</PumpGroup>
- XmlDocument xmlDocument = new XmlDocument();
- xmlDocument.LoadXml(pumpsXmlConfiguration);
- var rootElement = xmlDocument.GetElementsByTagName("PumpGroup").Cast<XmlElement>().First();
- this.recipientSubnet = byte.Parse(rootElement.Attributes["ifsfSubNet"].Value);
- this.recipientNode = byte.Parse(rootElement.Attributes["ifsfNode"].Value);
- var pumpElements = xmlDocument.GetElementsByTagName("Pump").Cast<XmlNode>();
- logger.Info("node " + recipientNode + ", Will create " + pumpElements.Count() + " pump handlers for this TQC connection according from local config");
- this.CreatePumpHandlers(pumpElements);
- this.SetupTqcPumpGroupInitializer();
- }
- protected virtual void SetupTqcPumpGroupInitializer()
- {
- this.tqcPumpGroupInitializer = new TqcPumpGroupInitializer(originatorSubnet, originatorNode, this.recipientSubnet, this.recipientNode, this.pumpHandlers, this.GetNewMessageToken);
- this.tqcPumpGroupInitializer.OnInitTimeout += (cc, dd) =>
- {
- logger.Info("TqcPumpGroupInitializer, node " + this.tqcPumpGroupInitializer.ifsfRecipientNode + ", init timed out, will start it over...");
- this.tqcPumpGroupInitializer.Reset();
- this.tqcPumpGroupInitializer.FeedIn(this.context);
- };
- this.tqcPumpGroupInitializer.OnInitDone += (ee, ff) =>
- {
- logger.Info("TqcPumpGroupInitializer, node " + this.tqcPumpGroupInitializer.ifsfRecipientNode + ", init done, will query all FP status and routed following msg to PumpHandlers");
- // query all FP status, answer will be routed to each PumpHandler to handle.
- this.context.Outgoing.Write(
- new FuellingPointDbRequest_Read_FuelPointState(this.recipientSubnet,
- this.recipientNode,
- originatorSubnet,
- originatorNode,
- this.GetNewMessageToken(),
- 0x20));
- this.pumpHandlers.SelectMany(p => p.Nozzles).ToList().ForEach(n =>
- {
- var boundProductNo = this.nozzleProductMappings.First(c => c.PumpId == n.PumpId && c.NozzleLogicalId == n.LogicalId).ProductBarcode;
- logger.Info("TqcPumpGroupInitializer, node " + this.tqcPumpGroupInitializer.ifsfRecipientNode
- + ", will write back price to nozzle on pump " + n.PumpId + ", logicalNozzleId: " + n.LogicalId + ", boundProductNo: " + boundProductNo
- + " to new Init Price(without decimal points): " + this.tqcPumpGroupInitializer.PriceBook[boundProductNo]);
- n.RealPriceOnPhysicalPump = this.tqcPumpGroupInitializer.PriceBook[boundProductNo];
- });
- };
- }
- protected virtual void CreatePumpHandlers(IEnumerable<XmlNode> pumpElements)
- {
- foreach (XmlNode pumpElement in pumpElements)
- {
- byte pumpPhysicalIdValue;
- var rawPumpPhysicalId = pumpElement.Attributes["physicalId"].Value;//.Substring(2);
- if (rawPumpPhysicalId.StartsWith("0x") || rawPumpPhysicalId.StartsWith("0X"))
- pumpPhysicalIdValue = byte.Parse(pumpElement.Attributes["physicalId"].Value.Substring(2), NumberStyles.HexNumber);
- else
- pumpPhysicalIdValue = byte.Parse(pumpElement.Attributes["physicalId"].Value);
- if (pumpPhysicalIdValue < 0x21 || pumpPhysicalIdValue > 0x24)
- throw new ArgumentException("ifsf fuel point id must be range from 0x21 to 0x24, while the configuration passed in " + rawPumpPhysicalId);
- PumpHandler pumpHandler = new PumpHandler(this, int.Parse(pumpElement.Attributes["pumpId"].Value),
- pumpPhysicalIdValue,
- this.recipientSubnet, this.recipientNode,
- pumpElement.InnerXml, GetNewMessageToken);
- this.pumpHandlers.Add(pumpHandler);
- }
- }
- /// <summary>
- /// will be called at the Init stage of FdcServerApp, that means before the calling the Start() for all the Processors.
- /// </summary>
- /// <param name="parameters"></param>
- public void OnFdcServerInit(Dictionary<string, object> parameters)
- {
- if (parameters != null && parameters.TryGetValue("NozzleProductMapping", out object param))
- {
- this.nozzleProductMappings = param as IEnumerable<NozzleExtraInfo>;
- this.tqcPumpGroupInitializer.NozzleProductConfig = this.nozzleProductMappings;
- }
- this.pumpHandlers.ForEach(ph => ph.OnFdcServerInit(parameters));
- }
- public virtual void Init(IContext<byte[], IfsfMessageBase> context)
- {
- this.context = context;
- this.context.Communicator.OnConnected += (e, f) =>
- {
- // each time communicator get disconnect, will trigger a re-init.
- logger.Info("TqcPumpGroupInitializer, node " + this.tqcPumpGroupInitializer.ifsfRecipientNode + ", OnCommunicator Connected, will start init...");
- this.tqcPumpGroupInitializer.Reset();
- this.tqcPumpGroupInitializer.FeedIn(this.context);
- };
- this.context.Communicator.OnDisconnected += (e, f) =>
- {
- logger.Info("TqcPumpGroupInitializer, node " + this.tqcPumpGroupInitializer.ifsfRecipientNode + ", OnCommunicator Disconnected...");
- this.tqcPumpGroupInitializer.Reset();
- this.pumpHandlers.ForEach(p => p.HandleFpStatusChange(FuellingPointStatus.Inoperative, null));
- };
- this.pumpHandlers.ForEach(p => p.Init(this.context));
- }
- private byte rotateMsgToken = 0;
- public byte GetNewMessageToken()
- {
- if (rotateMsgToken == (0xFF & 0x01F))
- rotateMsgToken = 0;
- else
- rotateMsgToken++;
- return rotateMsgToken;
- }
- public virtual Task Process(IContext<byte[], IfsfMessageBase> context)
- {
- this.context = context;
- if (!this.tqcPumpGroupInitializer.IsInitDone)
- {
- this.tqcPumpGroupInitializer.FeedIn(context);
- return Task.CompletedTask;
- }
- this.RouteMessageToHandlers(context);
- return Task.CompletedTask;
- }
- protected virtual void RouteMessageToHandlers(IContext<byte[], IfsfMessageBase> context)
- {
- switch (context.Incoming.Message)
- {
- case FuellingPointDb_FpStatus_Event fpStatusEvent:
- this.pumpHandlers.Where(h => h.PumpPhysicalId == fpStatusEvent.TargetFuelPointId).ToList().ForEach(p => p.Process(context));
- break;
- case FuellingPointDb_FpStatus_Answer fpStatusAnswer:
- this.pumpHandlers.Where(h => h.PumpPhysicalId == fpStatusAnswer.TargetFuelPointId).ToList().ForEach(p => p.Process(context));
- break;
- case FuellingPointDb_FpRunningTransaction_Event fpRunningTrxEvent:
- this.pumpHandlers.Where(h => h.PumpPhysicalId == fpRunningTrxEvent.TargetFuelPointId).ToList().ForEach(p => p.Process(context));
- break;
- case FuellingPointDb_FpRunningTransaction_Event_ACK fpRunningTrxEvent:
- this.pumpHandlers.Where(h => h.PumpPhysicalId == fpRunningTrxEvent.TargetFuelPointId).ToList().ForEach(p => p.Process(context));
- break;
- case FuellingTrxDb_TransactionBufferStatus_Event trxBufferStatusEvent:
- this.pumpHandlers.Where(h => h.PumpPhysicalId == trxBufferStatusEvent.TargetFuelPointId).ToList().ForEach(p => p.Process(context));
- break;
- case FuellingTrxDb_TransactionBufferStatus_Event_ACK trxBufferStatusEvent:
- this.pumpHandlers.Where(h => h.PumpPhysicalId == trxBufferStatusEvent.TargetFuelPointId).ToList().ForEach(p => p.Process(context));
- break;
- case FuellingTrxDb_TransactionBufferStatus_Answer trxBufferStatusAnswer:
- this.pumpHandlers.Where(h => h.PumpPhysicalId == trxBufferStatusAnswer.TargetFuelPointId).ToList().ForEach(p => p.Process(context));
- break;
- //default: this.pumpHandlers.ForEach(p => p.Process(context)); break;
- }
- }
- public IEnumerator<IFdcPumpController> GetEnumerator()
- {
- return this.pumpHandlers.GetEnumerator();
- }
- IEnumerator IEnumerable.GetEnumerator()
- {
- return this.pumpHandlers.GetEnumerator();
- }
- public Guid Id => this.uniqueId;
- /// <summary>
- /// Initalizer for init default values into TQC pump.
- /// especially for default product price: it will read pre-config values for each product in pump first,
- /// </summary>
- internal class TqcPumpGroupInitializer
- {
- System.Timers.Timer initTimeoutTimer = new Timer(initTimeout);
- const int initTimeout = 10000;
- /// <summary>
- /// will fire when reached timed out time, and state is still not Done.
- /// </summary>
- public event EventHandler OnInitTimeout;
- public event EventHandler OnInitDone;
- public event EventHandler OnInitError;
- /// <summary>
- /// init process will firstly read all necessary config values in TQC, and then execute the write operations.
- /// this event will be fired once those config values were read, and write operation is still not perform.
- /// </summary>
- public event EventHandler OnTqcExistedConfigRead;
- private List<FuellingPointDb_FpStatus_Answer> fpStatus_Answers
- = new List<FuellingPointDb_FpStatus_Answer>();
- private List<LogicalNozzleDb_Nozzle_ProductInfo_PhyId_Answer> logicalNozzleDb_Nozzle_ProductInfo_PhyId_Answers
- = new List<LogicalNozzleDb_Nozzle_ProductInfo_PhyId_Answer>();
- /// <summary>
- /// Gets pre-config value in TQC pump.
- /// </summary>
- public IEnumerable<LogicalNozzleDb_Nozzle_ProductInfo_PhyId_Answer> LogicalNozzleDb_Nozzle_ProductInfo_PhyId_Answers => this.logicalNozzleDb_Nozzle_ProductInfo_PhyId_Answers;
- private List<ProductDb_ProductNo_Answer> productDb_ProductNo_Answers
- = new List<ProductDb_ProductNo_Answer>();
- /// <summary>
- /// Gets pre-config value in TQC pump.
- /// </summary>
- public IEnumerable<ProductDb_ProductNo_Answer> ProductDb_ProductNo_Answers => this.productDb_ProductNo_Answers;
- private List<ProductPerFuellingModeDb_ProductPrice_Answer> productPerFuellingModeDb_ProductPrice_Answers
- = new List<ProductPerFuellingModeDb_ProductPrice_Answer>();
- /// <summary>
- /// Gets pre-config value in TQC pump.
- /// </summary>
- public IEnumerable<ProductPerFuellingModeDb_ProductPrice_Answer> ProductPerFuellingModeDb_ProductPrice_Answers => this.productPerFuellingModeDb_ProductPrice_Answers;
- private Dictionary<int, int> priceBook = new Dictionary<int, int>();
- /// <summary>
- /// Gets or set the init price for each product.
- /// default price init policy is read from pricebook, if found then apply, otherwise use pre-config value read from pump.
- /// should follow-> barcode:rawFormatPriceWithoutDecimalPoints
- /// </summary>
- public Dictionary<int, int> PriceBook => this.priceBook;
- private IEnumerable<NozzleExtraInfo> nozzleProductConfig;
- public IEnumerable<NozzleExtraInfo> NozzleProductConfig
- {
- get
- {
- return this.nozzleProductConfig;
- }
- set
- {
- this.nozzleProductConfig = value;
- this.thisTqcProductBarcodes = this.nozzleProductConfig.Where(n => this.pumpHandlers.Select(p => p.PumpId).Contains(n.PumpId)).Select(s => s.ProductBarcode).Distinct().OrderBy(o => o).ToList();
- //this.thisTqcProductBarcodes = nozzleProductConfig.Select(s => s.ProductBarcode).Distinct().OrderBy(o => o).ToList();
- logger.Info("PumpInitializer, node " + ifsfRecipientNode + " current TQC local configuration indicates total have "
- + this.thisTqcProductBarcodes.Count + " product barcodes: " + this.thisTqcProductBarcodes.Select(s => s.ToString()).Aggregate((acc, n) => acc + ", " + n));
- }
- }
- //= Configurator.Default.NozzleProductConfiguration.Mapping;
- private byte ifsfSelfSubnet;
- private byte ifsfSelfNode;
- private byte ifsfRecipientSubnet;
- public byte ifsfRecipientNode;
- IEnumerable<PumpHandler> pumpHandlers;
- Func<byte> msgTokenGenerator;
- private List<int> thisTqcProductBarcodes;
- private Status currentStatus;
- private Status CurrentStatus
- {
- get { return this.currentStatus; }
- set
- {
- //logger.Debug("PumpInitializer, node " + ifsfRecipientNode + ", Status switched from " + this.currentStatus + " to " + value);
- this.currentStatus = value;
- }
- }
- //private DateTime previousRequestingTime;
- private byte? pendingForAckMsgToken;
- private enum Status
- {
- UnInit = 0,
- Wait_Answer_Query_All_FuelPointState,
- Wait_Answer_Close_All_FuelPoint,
- Wait_Answer_Query_Caculator_Overall_Info,
- Wait_Answer_Read_All_Nozzle_ProductInfo_PhyId,
- Wait_Answer_Read_All_ProductNumber,
- Wait_Answer_Read_All_ProductPrice,
- //Sending_Add_Recipient_Addr,
- Wait_ACK_Add_Recipient_Addr,
- //Sending_Clear_ProductNumber_In_Caculator,
- Wait_ACK_Clear_ProductNumber_In_ProductDb,
- //Sending_Set_ProductNumber_In_Caculator,
- Wait_ACK_Set_ProductNumber_In_ProductDb,
- //Sending_Link_Meter_To_CaculatorSlot,
- Wait_ACK_Link_Meter_To_ProductDb_ProductNoSlot,
- //Sending_Set_AUTH_MODE,
- Wait_ACK_Set_AUTH_MODE,
- //Sending_Set_Price,
- Wait_ACK_Set_Price,
- //Sending_Set_Nozzle_To_CacalatorSlot,
- Wait_ACK_Set_Nozzle_To_ProductDb_ProductNoSlot,
- //Sending_Set_FP_Default_FuellingMode,
- Wait_ACK_Set_FP_Default_FuellingMode,
- //Send_Open_FP,
- //Wait_ACK_Open_FP,
- Done
- }
- /// <summary>
- ///
- /// </summary>
- /// <param name="selfSubnet">fc ifsf subnet value</param>
- /// <param name="selfNode">fc ifsf node value</param>
- /// <param name="ifsfRecipientSubnet">remote ifsf recipient subnet value</param>
- /// <param name="ifsfRecipientNode">remote ifsf recipient node value</param>
- /// <param name="pumpHandlers">pump handlers created from the pump Group handler</param>
- /// <param name="msgTokenGenerator"></param>
- public TqcPumpGroupInitializer(byte selfSubnet, byte selfNode, byte ifsfRecipientSubnet, byte ifsfRecipientNode,
- IEnumerable<PumpHandler> pumpHandlers, Func<byte> msgTokenGenerator)
- {
- this.ifsfSelfSubnet = selfSubnet;
- this.ifsfSelfNode = selfNode;
- this.ifsfRecipientSubnet = ifsfRecipientSubnet;
- this.ifsfRecipientNode = ifsfRecipientNode;
- this.pumpHandlers = pumpHandlers;
- this.msgTokenGenerator = msgTokenGenerator;
- this.initTimeoutTimer.Elapsed += (a, b) =>
- {
- this.initTimeoutTimer.Stop();
- if (!this.IsInitDone)
- {
- var safe = this.OnInitTimeout;
- safe(this, null);
- }
- };
- }
- private byte next_ActualInPump_ProductNumber_In_ProductDb_ProductNoSlot_Index = 1;
- private byte next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index = 1;
- //private byte next_Link_Meter_to_ProductNumber_Index = 1;
- private byte next_site_nozzle_Index = 1;
- private byte next_Fp_Index = 1;
- /// <summary>
- /// if it was Done, return false. otherwise, the init is kicking off, return true.
- /// </summary>
- /// <param name="context"></param>
- /// <returns></returns>
- public bool FeedIn(IContext<byte[], IfsfMessageBase> context)
- {
- if (!this.initTimeoutTimer.Enabled) this.initTimeoutTimer.Start();
- if (IsInitDone) return false;
- switch (this.CurrentStatus)
- {
- case Status.UnInit:
- {
- logger.Info("PumpInitializer, node " + ifsfRecipientNode + " start Init, firstly Query&Close all FuelPoints...");
- logger.Info("PumpInitializer, node " + ifsfRecipientNode + " Send QueryAllFp state(first time)");
- this.pendingForAckMsgToken = this.msgTokenGenerator();
- context.Outgoing.Write(
- new FuellingPointDbRequest_Read_FuelPointState(this.ifsfRecipientSubnet,
- this.ifsfRecipientNode,
- this.ifsfSelfSubnet,
- this.ifsfSelfNode,
- this.pendingForAckMsgToken.Value, 0x20
- ));
- this.CurrentStatus = Status.Wait_Answer_Query_All_FuelPointState;
- break;
- }
- case Status.Wait_Answer_Query_All_FuelPointState:
- {
- if (context.Incoming.Message is IfsfMessage ifsfMsg && ifsfMsg.MessageType == MessageType.IFSF_MESSAGE_TYPE_ACK
- && ifsfMsg.MessageToken == this.pendingForAckMsgToken.Value)
- {
- var historyIncoming = context.Incoming as HistoryKeepIncoming<IfsfMessageBase>;
- this.fpStatus_Answers = historyIncoming.History.Where(h => (h.Item1 is FuellingPointDb_FpStatus_Answer im)
- && im.MessageType == MessageType.IFSF_MESSAGE_TYPE_ANSWER
- && im.MessageToken == this.pendingForAckMsgToken)
- .Select(s => (FuellingPointDb_FpStatus_Answer)s.Item1).ToList();
- logger.Info("PumpInitializer, node " + ifsfRecipientNode + ", read total " + fpStatus_Answers.Count
- + " Fp status, they're " + this.fpStatus_Answers.Select(s => "Fp 0x" + s.TargetFuelPointId.ToHexLogString() + " is " + s.FuelPointState)
- .Aggregate((n, acc) => n + ", " + acc));
- this.pendingForAckMsgToken = this.msgTokenGenerator();
- logger.Info("PumpInitializer, node " + ifsfRecipientNode + " Send CloseFuelPoint(first time) for FP: 0x"
- + this.pumpHandlers.ElementAt(next_Fp_Index - 1).PumpPhysicalId.ToHexLogString());
- this.pendingForAckMsgToken = this.msgTokenGenerator();
- context.Outgoing.Write(
- new FuellingPointDbRequest_Write_CloseFuelPoint(this.ifsfRecipientSubnet,
- this.ifsfRecipientNode,
- this.ifsfSelfSubnet,
- this.ifsfSelfNode,
- this.pendingForAckMsgToken.Value, (byte)(this.pumpHandlers.ElementAt(next_Fp_Index - 1).PumpPhysicalId)
- ));
- this.CurrentStatus = Status.Wait_Answer_Close_All_FuelPoint;
- }
- break;
- }
- case Status.Wait_Answer_Close_All_FuelPoint:
- {
- if (context.Incoming.Message is IfsfMessage ifsfMsg && ifsfMsg.MessageType == MessageType.IFSF_MESSAGE_TYPE_ACK
- && ifsfMsg.MessageToken == this.pendingForAckMsgToken)
- {
- if (++next_Fp_Index <= this.pumpHandlers.Count())
- {
- logger.Info("PumpInitializer, node " + ifsfRecipientNode + " CloseFuelPoint Acked");
- logger.Info("PumpInitializer, node " + ifsfRecipientNode + " Send CloseFuelPoint for FP: 0x"
- + this.pumpHandlers.ElementAt(next_Fp_Index - 1).PumpPhysicalId.ToHexLogString());
- this.pendingForAckMsgToken = this.msgTokenGenerator();
- context.Outgoing.Write(
- new FuellingPointDbRequest_Write_CloseFuelPoint(this.ifsfRecipientSubnet,
- this.ifsfRecipientNode,
- this.ifsfSelfSubnet,
- this.ifsfSelfNode,
- this.pendingForAckMsgToken.Value, (byte)(this.pumpHandlers.ElementAt(next_Fp_Index - 1).PumpPhysicalId)
- ));
- this.CurrentStatus = Status.Wait_Answer_Close_All_FuelPoint;
- }
- else
- {
- this.next_Fp_Index = 1;
- logger.Info("PumpInitializer, node " + ifsfRecipientNode + " sending CaculatorDbRequest_Read_FuelPoint_Product_FuelMode_Meter_Info...");
- this.pendingForAckMsgToken = this.msgTokenGenerator();
- context.Outgoing.Write(
- new CaculatorDbRequest_Read_FuelPoint_Product_FuelMode_Meter_Info(this.ifsfRecipientSubnet,
- this.ifsfRecipientNode,
- this.ifsfSelfSubnet,
- this.ifsfSelfNode,
- this.pendingForAckMsgToken.Value
- ));
- this.CurrentStatus = Status.Wait_Answer_Query_Caculator_Overall_Info;
- }
- }
- break;
- }
- case Status.Wait_Answer_Query_Caculator_Overall_Info:
- {
- if (context.Incoming.Message is IfsfMessage ifsfMsg && ifsfMsg.MessageType == MessageType.IFSF_MESSAGE_TYPE_ANSWER
- && ifsfMsg.MessageToken == this.pendingForAckMsgToken)
- {
- var dataParser = DatabaseDataParser.New().Convert(ifsfMsg.RawDatabaseData.ToArray());
- var numberOfProducts = dataParser.DataIds.First(i => i.Item1 == 0x02).Item2.ToInt32();
- logger.Info("PumpInitializer, node " + ifsfRecipientNode + " CaculatorDbRequest_Read_FuelPoint_Product_FuelMode_Meter_Info Acked,\r\n" +
- "Read caculatorDbOverallInfo, No_Products: " + numberOfProducts
- + ", No_Fuelling_Modes: " + dataParser.DataIds.First(i => i.Item1 == 0x03).Item2.ToInt32()
- + ", No_Meters: " + dataParser.DataIds.First(i => i.Item1 == 0x04).Item2.ToInt32()
- + ", No_FP: " + dataParser.DataIds.First(i => i.Item1 == 0x05).Item2.ToInt32()
- + ", Auth_State_Mode: " + dataParser.DataIds.First(i => i.Item1 == 0x0B).Item2.ToInt32());
- if (numberOfProducts != this.thisTqcProductBarcodes.Count)
- {
- logger.Info("!!!!!!PumpInitializer, node " + ifsfRecipientNode + " This TQC MUST config " + numberOfProducts + " products, but now trying to load local config with " + this.thisTqcProductBarcodes.Count + " products");
- }
- logger.Info("PumpInitializer, node " + ifsfRecipientNode + " sending CommunicationServiceDbRequest_Write_RecipientAddressTable...");
- this.pendingForAckMsgToken = this.msgTokenGenerator();
- context.Outgoing.Write(
- new CommunicationServiceDbRequest_Write_RecipientAddressTable(this.ifsfRecipientSubnet,
- this.ifsfRecipientNode,
- this.ifsfSelfSubnet,
- this.ifsfSelfNode,
- this.pendingForAckMsgToken.Value,
- this.ifsfSelfSubnet,
- this.ifsfSelfNode));
- this.CurrentStatus = Status.Wait_ACK_Add_Recipient_Addr;
- }
- break;
- }
- case Status.Wait_ACK_Add_Recipient_Addr:
- {
- if (context.Incoming.Message is IfsfMessage ifsfMsg && ifsfMsg.MessageType == MessageType.IFSF_MESSAGE_TYPE_ACK
- && ifsfMsg.MessageToken == this.pendingForAckMsgToken)
- {
- logger.Info("PumpInitializer, node " + ifsfRecipientNode + " CommunicationServiceDbRequest_Write_RecipientAddressTable Acked.");
- logger.Info("PumpInitializer, node " + ifsfRecipientNode + " Send LogicalNozzleDb_Read_Nozzle_ProductInfo_PhyId for FP: 0x"
- + this.pumpHandlers.ElementAt(next_Fp_Index - 1).PumpPhysicalId.ToHexLogString());
- this.pendingForAckMsgToken = this.msgTokenGenerator();
- context.Outgoing.Write(
- new LogicalNozzleDb_Read_Nozzle_ProductInfo_PhyId(this.ifsfRecipientSubnet,
- this.ifsfRecipientNode,
- this.ifsfSelfSubnet,
- this.ifsfSelfNode,
- this.pendingForAckMsgToken.Value, (byte)(this.pumpHandlers.ElementAt(next_Fp_Index - 1).PumpPhysicalId), 0x10));
- this.CurrentStatus = Status.Wait_Answer_Read_All_Nozzle_ProductInfo_PhyId;
- }
- break;
- }
- case Status.Wait_Answer_Read_All_Nozzle_ProductInfo_PhyId:
- {
- if (context.Incoming.Message is IfsfMessage ifsfMsg && ifsfMsg.MessageType == MessageType.IFSF_MESSAGE_TYPE_ACK
- && ifsfMsg.MessageToken == this.pendingForAckMsgToken.Value)
- {
- var historyIncoming = context.Incoming as HistoryKeepIncoming<IfsfMessageBase>;
- this.logicalNozzleDb_Nozzle_ProductInfo_PhyId_Answers.AddRange(
- historyIncoming.History.Where(h => (h.Item1 is LogicalNozzleDb_Nozzle_ProductInfo_PhyId_Answer im)
- && im.MessageType == MessageType.IFSF_MESSAGE_TYPE_ANSWER
- && im.MessageToken == this.pendingForAckMsgToken)
- .Select(s => s.Item1 as LogicalNozzleDb_Nozzle_ProductInfo_PhyId_Answer).OrderBy(a => a.LogicalNozzleId));
- if (++next_Fp_Index <= this.pumpHandlers.Count())
- {
- logger.Info("PumpInitializer, node " + ifsfRecipientNode + " LogicalNozzleDb_Read_Nozzle_ProductInfo_PhyId Acked");
- logger.Info("PumpInitializer, node " + ifsfRecipientNode + " Send LogicalNozzleDb_Read_Nozzle_ProductInfo_PhyId for FP: 0x"
- + this.pumpHandlers.ElementAt(next_Fp_Index - 1).PumpPhysicalId.ToHexLogString());
- this.pendingForAckMsgToken = this.msgTokenGenerator();
- context.Outgoing.Write(
- new LogicalNozzleDb_Read_Nozzle_ProductInfo_PhyId(this.ifsfRecipientSubnet,
- this.ifsfRecipientNode,
- this.ifsfSelfSubnet,
- this.ifsfSelfNode,
- this.pendingForAckMsgToken.Value, (byte)(this.pumpHandlers.ElementAt(next_Fp_Index - 1).PumpPhysicalId), 0x10));
- this.CurrentStatus = Status.Wait_Answer_Read_All_Nozzle_ProductInfo_PhyId;
- }
- else
- {
- foreach (var answer in this.logicalNozzleDb_Nozzle_ProductInfo_PhyId_Answers)
- logger.Info(" node " + ifsfRecipientNode + " Read nozzles info for FP: 0x" + answer.TargetFuelPointId.ToHexLogString()
- + ", with logicalId: 0x" + answer.LogicalNozzleId.ToHexLogString()
- + ", with physicalId: 0x" + answer.PhyscialNozzleId.ToHexLogString()
- + ", with product slotId: 0x" + answer.LinkedProductSlotId_InProductDbProdcutNoSlot.ToHexLogString());
- next_Fp_Index = 1;
- logger.Info("PumpInitializer, node " + ifsfRecipientNode + " sending ProductDbRequest_Read_ProductNo");
- this.pendingForAckMsgToken = this.msgTokenGenerator();
- // will receive several answers and an ACK messages since this is a query all request.
- context.Outgoing.Write(new ProductDbRequest_Read_ProductNo(this.ifsfRecipientSubnet,
- this.ifsfRecipientNode,
- this.ifsfSelfSubnet,
- this.ifsfSelfNode,
- this.pendingForAckMsgToken.Value, 0));
- this.CurrentStatus = Status.Wait_Answer_Read_All_ProductNumber;
- }
- }
- break;
- }
- case Status.Wait_Answer_Read_All_ProductNumber:
- {
- if (context.Incoming.Message is IfsfMessage ifsfMsg && ifsfMsg.MessageType == MessageType.IFSF_MESSAGE_TYPE_ACK
- && ifsfMsg.MessageToken == this.pendingForAckMsgToken)
- {
- var historyIncoming = context.Incoming as HistoryKeepIncoming<IfsfMessageBase>;
- //logger.Debug("************" + historyIncoming.History.Select(a => a.Item1.GetType().Name).Aggregate((acc, n) => acc + ", " + n));
- //logger.Debug("************historyIncoming.History.Count: " + historyIncoming.History.Count);
- this.productDb_ProductNo_Answers.AddRange(
- historyIncoming.History.Where(h => (h.Item1 is ProductDb_ProductNo_Answer im)
- && im.MessageType == MessageType.IFSF_MESSAGE_TYPE_ANSWER
- && im.MessageToken == this.pendingForAckMsgToken).Select(s => s.Item1 as ProductDb_ProductNo_Answer).OrderBy(a => a.ProductSlotId));
- if (this.productDb_ProductNo_Answers.Any())
- {
- logger.Info(" node " + ifsfRecipientNode + " Read all existed product number in a TQC which are: " + this.productDb_ProductNo_Answers.Select(s => s.ProductNumber + "(in 0x" + s.ProductSlotId.ToHexLogString() + ")").Aggregate((acc, n) => acc + ", " + n));
- string actualProductNumber = this.productDb_ProductNo_Answers.ElementAt(this.next_ActualInPump_ProductNumber_In_ProductDb_ProductNoSlot_Index - 1).ProductNumber;//this.siteProductBarcodes[next_Clear_ProductNumber_In_Caculator_SlotIndex - 1].ToString();
- this.pendingForAckMsgToken = this.msgTokenGenerator();
- // each Product will receive a serial of answers for its differnt FuelMode since we input 0x10 as query all FM.
- context.Outgoing.Write(new ProductPerFuellingModeDbRequest_Read_ProductPrice(this.ifsfRecipientSubnet,
- this.ifsfRecipientNode,
- this.ifsfSelfSubnet,
- this.ifsfSelfNode,
- this.pendingForAckMsgToken.Value, actualProductNumber, 0x10));
- this.CurrentStatus = Status.Wait_Answer_Read_All_ProductPrice;
- }
- else
- {
- /* TQC without any product configed, happened for fresh new TQC pump (get hardware reset or just shipped from factory??), handle here */
- logger.Info(" node " + ifsfRecipientNode + " has no ProductDb_ProductNo_Answer received, seems there're no product configurated in this TQC yet, will directly Clear Set_ProductNumber_In_ProductDb");
- logger.Info("PumpInitializer, node " + ifsfRecipientNode + " sending Clear ProductNumber in ProductDb slot index: " + next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index);
- this.pendingForAckMsgToken = this.msgTokenGenerator();
- context.Outgoing.Write(
- new ProductDbRequest_Write_SetProductNumber(this.ifsfRecipientSubnet,
- this.ifsfRecipientNode,
- this.ifsfSelfSubnet,
- this.ifsfSelfNode,
- this.pendingForAckMsgToken.Value,
- next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index, null));
- this.CurrentStatus = Status.Wait_ACK_Set_ProductNumber_In_ProductDb;
- }
- }
- break;
- }
- case Status.Wait_Answer_Read_All_ProductPrice:
- {
- if (context.Incoming.Message is AcknowledgeMessage ifsfMsg && ifsfMsg.MessageType == MessageType.IFSF_MESSAGE_TYPE_ACK
- && ifsfMsg.MessageToken == this.pendingForAckMsgToken.Value)
- {
- var historyIncoming = context.Incoming as HistoryKeepIncoming<IfsfMessageBase>;
- var resultSetsForOneProduct = historyIncoming.History.Where(h => (h.Item1 is ProductPerFuellingModeDb_ProductPrice_Answer im)
- && im.MessageType == MessageType.IFSF_MESSAGE_TYPE_ANSWER
- && im.MessageToken == this.pendingForAckMsgToken).Select(s => s.Item1 as ProductPerFuellingModeDb_ProductPrice_Answer);
- logger.Info(" node " + ifsfRecipientNode + ", Read one existed product price with product number: "
- + resultSetsForOneProduct.Last().ProductNumber
- + ", price are: " + resultSetsForOneProduct.OrderBy(a => a.FuelModeId).Select(s => s.Price + " in FM:0x" + s.FuelModeId.ToString("X")).Aggregate((acc, n) => acc + ", " + n));
- this.productPerFuellingModeDb_ProductPrice_Answers.AddRange(resultSetsForOneProduct);
- if (this.productDb_ProductNo_Answers.Count() >= ++next_ActualInPump_ProductNumber_In_ProductDb_ProductNoSlot_Index)
- {
- string actualProductNumber = this.productDb_ProductNo_Answers.ElementAt(this.next_ActualInPump_ProductNumber_In_ProductDb_ProductNoSlot_Index - 1).ProductNumber;//this.siteProductBarcodes[next_Clear_ProductNumber_In_Caculator_SlotIndex - 1].ToString();
- this.pendingForAckMsgToken = this.msgTokenGenerator();
- context.Outgoing.Write(new ProductPerFuellingModeDbRequest_Read_ProductPrice(this.ifsfRecipientSubnet,
- this.ifsfRecipientNode,
- this.ifsfSelfSubnet,
- this.ifsfSelfNode,
- this.pendingForAckMsgToken.Value, actualProductNumber, 0x10));
- this.CurrentStatus = Status.Wait_Answer_Read_All_ProductPrice;
- }
- else
- {
- next_ActualInPump_ProductNumber_In_ProductDb_ProductNoSlot_Index = 1;
- logger.Info("PumpInitializer, node " + ifsfRecipientNode + " Read_All_ProductPrice done!");
- var safe = this.OnTqcExistedConfigRead;
- safe?.Invoke(this, null);
- logger.Info("PumpInitializer, node " + ifsfRecipientNode + " sending Clear productNo(1st time) in ProductDb with slot index: " + next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index);
- this.pendingForAckMsgToken = this.msgTokenGenerator();
- context.Outgoing.Write(
- new ProductDbRequest_Write_SetProductNumber(this.ifsfRecipientSubnet,
- this.ifsfRecipientNode,
- this.ifsfSelfSubnet,
- this.ifsfSelfNode,
- this.pendingForAckMsgToken.Value,
- next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index, null));
- this.CurrentStatus = Status.Wait_ACK_Clear_ProductNumber_In_ProductDb;
- }
- }
- break;
- }
- case Status.Wait_ACK_Clear_ProductNumber_In_ProductDb:
- {
- if (context.Incoming.Message is AcknowledgeMessage ifsfMsg && ifsfMsg.MessageType == MessageType.IFSF_MESSAGE_TYPE_ACK
- && ifsfMsg.MessageToken == this.pendingForAckMsgToken.Value)
- {
- if (ifsfMsg.OverallStatus != MessageAcknowledgeStatus.ACK_PositiveAcknowledgeDataReceived)
- logger.Error(" node " + ifsfRecipientNode + ", clear product from ProductDb failed!");
- logger.Info(" PumpInitializer, node " + ifsfRecipientNode + ", clear product no. from ProductDb with msgToken:" + this.pendingForAckMsgToken.Value + " Acked.");
- if (++next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index <= 8)
- {
- logger.Info("PumpInitializer, node " + ifsfRecipientNode + " sending Clear productNo in ProductDb with slot index: " + next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index);
- this.pendingForAckMsgToken = this.msgTokenGenerator();
- context.Outgoing.Write(
- new ProductDbRequest_Write_SetProductNumber(this.ifsfRecipientSubnet,
- this.ifsfRecipientNode,
- this.ifsfSelfSubnet,
- this.ifsfSelfNode,
- this.pendingForAckMsgToken.Value,
- next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index, null));
- this.CurrentStatus = Status.Wait_ACK_Clear_ProductNumber_In_ProductDb;
- }
- else
- {
- logger.Info("PumpInitializer, node " + ifsfRecipientNode + " clear product number on all productDb productNo slots(total:" + (next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index - 1) + ") done!");
- next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index = 1;
- var next_site_nozzle = this.pumpHandlers.SelectMany(p => p.Nozzles)
- .OrderBy(n => n.PumpId).OrderBy(n => n.LogicalId).ElementAt(next_site_nozzle_Index - 1);
- var nozzleProductConfig = this.nozzleProductConfig
- .First(c => c.PumpId == next_site_nozzle.PumpId && c.NozzleLogicalId == next_site_nozzle.LogicalId);
- var ifsfNozzle
- = this.logicalNozzleDb_Nozzle_ProductInfo_PhyId_Answers
- .First(ifsfNzl => ifsfNzl.TargetFuelPointId == this.pumpHandlers.First(p => p.PumpId == next_site_nozzle.PumpId).PumpPhysicalId
- && ifsfNzl.LogicalNozzleId == next_site_nozzle.PhysicalId);
- var nozzleBoundToProductDbProductSlot = ifsfNozzle.LinkedProductSlotId_InProductDbProdcutNoSlot;
- logger.Info("PumpInitializer, node " + ifsfRecipientNode
- + " pump " + next_site_nozzle.PumpId + ", nozzle logicalId " + next_site_nozzle.LogicalId
- + "(ifsf FpId 0x" + ifsfNozzle.TargetFuelPointId.ToHexLogString() + ", ifsf nozzle logicalId 0x" + ifsfNozzle.LogicalNozzleId.ToHexLogString() + ")"
- + " is hardware-bound to productDb product No. slot 0x" + nozzleBoundToProductDbProductSlot.ToHexLogString()
- + ", will(1st time) set 0x" + nozzleBoundToProductDbProductSlot.ToHexLogString() + " to product No.: " + nozzleProductConfig.ProductBarcode);
- this.pendingForAckMsgToken = this.msgTokenGenerator();
- context.Outgoing.Write(
- new ProductDbRequest_Write_SetProductNumber(this.ifsfRecipientSubnet,
- this.ifsfRecipientNode,
- this.ifsfSelfSubnet,
- this.ifsfSelfNode,
- this.pendingForAckMsgToken.Value,
- (byte)(nozzleBoundToProductDbProductSlot - 0x40), nozzleProductConfig.ProductBarcode.ToString()));
- this.CurrentStatus = Status.Wait_ACK_Set_ProductNumber_In_ProductDb;
- }
- }
- break;
- }
- case Status.Wait_ACK_Set_ProductNumber_In_ProductDb:
- {
- if (context.Incoming.Message is AcknowledgeMessage ifsfMsg && ifsfMsg.MessageType == MessageType.IFSF_MESSAGE_TYPE_ACK
- && ifsfMsg.MessageToken == this.pendingForAckMsgToken.Value)
- {
- if (ifsfMsg.OverallStatus != MessageAcknowledgeStatus.ACK_PositiveAcknowledgeDataReceived)
- logger.Error(" node " + ifsfRecipientNode + ", set product to ProductDb failed!");
- logger.Info(" PumpInitializer, node " + ifsfRecipientNode + " ProductDbRequest_Write_SetProductNumber with msgToken:" + this.pendingForAckMsgToken.Value + " Acked.");
- if (++next_site_nozzle_Index <= this.pumpHandlers.SelectMany(p => p.Nozzles).Count())
- {
- var next_site_nozzle = this.pumpHandlers.SelectMany(p => p.Nozzles)
- .OrderBy(n => n.PumpId).OrderBy(n => n.LogicalId).ElementAt(next_site_nozzle_Index - 1);
- var nozzleProductConfig = this.nozzleProductConfig
- .First(c => c.PumpId == next_site_nozzle.PumpId && c.NozzleLogicalId == next_site_nozzle.LogicalId);
- var ifsfNozzle
- = this.logicalNozzleDb_Nozzle_ProductInfo_PhyId_Answers
- .First(ifsfNzl => ifsfNzl.TargetFuelPointId == this.pumpHandlers.First(p => p.PumpId == next_site_nozzle.PumpId).PumpPhysicalId
- && ifsfNzl.LogicalNozzleId == next_site_nozzle.PhysicalId);
- var nozzleBoundToProductDbProductSlot = ifsfNozzle.LinkedProductSlotId_InProductDbProdcutNoSlot;
- logger.Info("PumpInitializer, node " + ifsfRecipientNode
- + " pump " + next_site_nozzle.PumpId + ", nozzle logicalId " + next_site_nozzle.LogicalId
- + "(ifsf FpId 0x" + ifsfNozzle.TargetFuelPointId.ToHexLogString() + ", ifsf nozzle logicalId 0x" + ifsfNozzle.LogicalNozzleId.ToHexLogString() + ")"
- + " is hardware-bound to productDb product No. slot 0x" + nozzleBoundToProductDbProductSlot.ToHexLogString()
- + ", will set 0x" + nozzleBoundToProductDbProductSlot.ToHexLogString() + " to product No.: " + nozzleProductConfig.ProductBarcode);
- this.pendingForAckMsgToken = this.msgTokenGenerator();
- context.Outgoing.Write(
- new ProductDbRequest_Write_SetProductNumber(this.ifsfRecipientSubnet,
- this.ifsfRecipientNode,
- this.ifsfSelfSubnet,
- this.ifsfSelfNode,
- this.pendingForAckMsgToken.Value,
- (byte)(nozzleBoundToProductDbProductSlot - 0x40), nozzleProductConfig.ProductBarcode.ToString()));
- this.CurrentStatus = Status.Wait_ACK_Set_ProductNumber_In_ProductDb;
- }
- else
- {
- next_site_nozzle_Index = 1;
- logger.Info("PumpInitializer, node " + ifsfRecipientNode + " sending CaculatorDbRequest_Write_Set_AuthStateMode_MinFuelingVol_MinDisplayVol");
- this.pendingForAckMsgToken = this.msgTokenGenerator();
- context.Outgoing.Write(
- new CaculatorDbRequest_Write_Set_AuthStateMode_MinFuelingVol_MinDisplayVol(this.ifsfRecipientSubnet,
- this.ifsfRecipientNode,
- this.ifsfSelfSubnet,
- this.ifsfSelfNode,
- this.pendingForAckMsgToken.Value,
- CaculatorDbRequest_Write_Set_AuthStateMode_MinFuelingVol_MinDisplayVol.Caculator_Auth_State_Mode.AUTH_State_Allowed));
- this.CurrentStatus = Status.Wait_ACK_Set_AUTH_MODE;
- }
- //if (++next_Clear_ProductNumber_In_Caculator_SlotIndex <= 8)
- //this.CurrentStatus = Status.Sending_Link_Meter_To_CaculatorSlot;
- //logger.Info("PumpInitializer, node " + ifsfRecipientNode + " sending MeterDbRequest_Write_SetMesureToProduct(first), meterId: "
- // + next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index + ", 2nd arg: " + next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index);
- //this.pendingForAckMsgToken = this.msgTokenGenerator();
- //context.Outgoing.Write(
- // new MeterDbRequest_Write_SetMesureToProduct(this.ifsfRecipientSubnet,
- // this.ifsfRecipientNode,
- // this.ifsfSelfSubnet,
- // this.ifsfSelfNode,
- // this.pendingForAckMsgToken.Value,
- // next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index,
- // next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index));
- //this.CurrentStatus = Status.Wait_ACK_Link_Meter_To_ProductDb_ProductNoSlot;
- }
- break;
- }
- //case Status.Wait_ACK_Link_Meter_To_ProductDb_ProductNoSlot:
- // {
- // if (context.Incoming.Message is AcknowledgeMessage ifsfMsg && ifsfMsg.MessageType == MessageType.IFSF_MESSAGE_TYPE_ACK
- // && ifsfMsg.MessageToken == this.pendingForAckMsgToken.Value)
- // {
- // if (ifsfMsg.OverallStatus != MessageAcknowledgeStatus.ACK_PositiveAcknowledgeDataReceived)
- // logger.Error(" node " + ifsfRecipientNode + ", link meter to ProductDb failed!");
- // logger.Info(" PumpInitializer, MeterDbRequest_Write_SetMesureToProduct with msgToken:" + this.pendingForAckMsgToken.Value + " Acked.");
- // if (this.thisTqcProductBarcodes.Count >= ++next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index)
- // {
- // //this.CurrentStatus = Status.Sending_Set_ProductNumber_In_Caculator;
- // this.pendingForAckMsgToken = this.msgTokenGenerator();
- // // put 91 to 98 to caculator 8 slots.
- // string operatingProductNumber = this.thisTqcProductBarcodes[next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index - 1].ToString();
- // logger.Info("PumpInitializer, node " + ifsfRecipientNode + " sending ProductDbRequest_Write_SetProductNumber, ProductDb ProductNoSlot: "
- // + next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index + ", productNo: " + operatingProductNumber);
- // context.Outgoing.Write(
- // new ProductDbRequest_Write_SetProductNumber(this.ifsfRecipientSubnet,
- // this.ifsfRecipientNode,
- // this.ifsfSelfSubnet,
- // this.ifsfSelfNode,
- // this.pendingForAckMsgToken.Value,
- // next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index, operatingProductNumber));
- // this.CurrentStatus = Status.Wait_ACK_Set_ProductNumber_In_ProductDb;
- // }
- // else
- // {
- // next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index = 1;
- // logger.Info("PumpInitializer, node " + ifsfRecipientNode + " Link_Meter_To_ProductDb_ProductNoSlot done!");
- // //this.CurrentStatus = Status.Sending_Set_AUTH_MODE;
- // }
- // }
- // break;
- // }
- case Status.Wait_ACK_Set_AUTH_MODE:
- {
- if (context.Incoming.Message is IfsfMessage ifsfMsg && ifsfMsg.MessageType == MessageType.IFSF_MESSAGE_TYPE_ACK
- && ifsfMsg.MessageToken == this.pendingForAckMsgToken.Value)
- {
- logger.Info("PumpInitializer, node " + ifsfRecipientNode + " CaculatorDbRequest_Write_Set_AuthStateMode_MinFuelingVol_MinDisplayVol Acked.");
- var targetBarcode = this.thisTqcProductBarcodes[next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index - 1];
- int newInitPriceWithoutDecimalPoints;
- if (this.PriceBook.ContainsKey(targetBarcode))
- newInitPriceWithoutDecimalPoints = this.PriceBook[targetBarcode];
- else
- {
- // try load the existed pre-configed price value which just read from TQC pump.
- var preConfigedPriceOnPump = this.productPerFuellingModeDb_ProductPrice_Answers.FirstOrDefault(p => p.FuelModeId == 0x11 && p.ProductNumber == targetBarcode.ToString().PadLeft(8, '0'))?.Price;
- if (string.IsNullOrEmpty(preConfigedPriceOnPump))
- newInitPriceWithoutDecimalPoints = 1883 + next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index;
- else
- newInitPriceWithoutDecimalPoints = int.Parse(preConfigedPriceOnPump);
- this.PriceBook.Add(targetBarcode, newInitPriceWithoutDecimalPoints);
- }
- logger.Info("PumpInitializer, node " + ifsfRecipientNode + " sending ProductPerFuellingModeDbRequest_Write_SetPrice, productNo: "
- + targetBarcode.ToString()
- + ", new price(without decimalPoints): " + newInitPriceWithoutDecimalPoints.ToString());
- this.pendingForAckMsgToken = this.msgTokenGenerator();
- context.Outgoing.Write(
- new ProductPerFuellingModeDbRequest_Write_SetPrice(this.ifsfRecipientSubnet,
- this.ifsfRecipientNode,
- this.ifsfSelfSubnet,
- this.ifsfSelfNode,
- this.pendingForAckMsgToken.Value,
- targetBarcode.ToString(), newInitPriceWithoutDecimalPoints.ToString()
- , 0x11)
- );
- this.CurrentStatus = Status.Wait_ACK_Set_Price;
- }
- break;
- }
- case Status.Wait_ACK_Set_Price:
- {
- if (context.Incoming.Message is AcknowledgeMessage ifsfMsg && ifsfMsg.MessageType == MessageType.IFSF_MESSAGE_TYPE_ACK
- && ifsfMsg.MessageToken == this.pendingForAckMsgToken.Value)
- {
- if (ifsfMsg.OverallStatus != MessageAcknowledgeStatus.ACK_PositiveAcknowledgeDataReceived)
- logger.Error(" node " + ifsfRecipientNode + ", set price for product failed!");
- if (this.thisTqcProductBarcodes.Count >= ++next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index)
- {
- logger.Info("PumpInitializer, node " + ifsfRecipientNode + " ProductPerFuellingModeDbRequest_Write_SetPrice Acked.");
- var targetBarcode = this.thisTqcProductBarcodes[next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index - 1];
- int newInitPriceWithoutDecimalPoints;
- if (this.PriceBook != null && this.PriceBook.ContainsKey(targetBarcode))
- newInitPriceWithoutDecimalPoints = this.PriceBook[targetBarcode];
- else
- {
- // try load the existed pre-configed price value which just read from TQC pump.
- var preConfigedPriceOnPump = this.productPerFuellingModeDb_ProductPrice_Answers.FirstOrDefault(p => p.FuelModeId == 0x11 && p.ProductNumber == targetBarcode.ToString().PadLeft(8, '0'))?.Price;
- if (string.IsNullOrEmpty(preConfigedPriceOnPump))
- newInitPriceWithoutDecimalPoints = 1883 + next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index;
- else
- newInitPriceWithoutDecimalPoints = int.Parse(preConfigedPriceOnPump);
- this.PriceBook.Add(targetBarcode, newInitPriceWithoutDecimalPoints);
- }
- logger.Info("PumpInitializer, node " + ifsfRecipientNode + " sending ProductPerFuellingModeDbRequest_Write_SetPrice, productNo: "
- + targetBarcode.ToString()
- + ", new price(without decimalPoints): " + newInitPriceWithoutDecimalPoints.ToString());
- this.pendingForAckMsgToken = this.msgTokenGenerator();
- //logger.Info("PumpInitializer, node "+ifsfRecipientNode+" will set product: " + this.siteProductBarcodes[next_Clear_ProductNumber_In_Caculator_SlotIndex - 1].ToString() + " with price " + (1883 + next_Clear_ProductNumber_In_Caculator_SlotIndex).ToString());
- context.Outgoing.Write(
- new ProductPerFuellingModeDbRequest_Write_SetPrice(this.ifsfRecipientSubnet,
- this.ifsfRecipientNode,
- this.ifsfSelfSubnet,
- this.ifsfSelfNode,
- this.pendingForAckMsgToken.Value, targetBarcode.ToString(), newInitPriceWithoutDecimalPoints.ToString(), 0x11)
- );
- this.CurrentStatus = Status.Wait_ACK_Set_Price;
- }
- else
- {
- next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index = 1;
- logger.Info("PumpInitializer, node " + ifsfRecipientNode + " set product Price(8 products) in fuel mode 0x11 done!");
- //this.CurrentStatus = Status.Sending_Set_Nozzle_To_CacalatorSlot;
- // now we only have fuelling mode 0x11.
- logger.Info("PumpInitializer, node " + ifsfRecipientNode + " Send FuellingPointDbRequest_Write_SetDefaultFuellingMode,\r\n" +
- "FP: 0x" + this.pumpHandlers.ElementAt(next_Fp_Index - 1).PumpPhysicalId.ToHexLogString() + " set to fuelling mode 0x11");
- this.pendingForAckMsgToken = this.msgTokenGenerator();
- context.Outgoing.Write(
- new FuellingPointDbRequest_Write_SetDefaultFuellingMode(this.ifsfRecipientSubnet,
- this.ifsfRecipientNode,
- this.ifsfSelfSubnet,
- this.ifsfSelfNode,
- this.pendingForAckMsgToken.Value, (byte)(this.pumpHandlers.ElementAt(next_Fp_Index - 1).PumpPhysicalId), 1));
- this.CurrentStatus = Status.Wait_ACK_Set_FP_Default_FuellingMode;
- }
- }
- break;
- }
- //case Status.Wait_ACK_Set_Nozzle_To_ProductDb_ProductNoSlot:
- // {
- // if (context.Incoming.Message is AcknowledgeMessage ifsfMsg && ifsfMsg.MessageType == MessageType.IFSF_MESSAGE_TYPE_ACK
- // && ifsfMsg.MessageToken == this.pendingForAckMsgToken.Value)
- // {
- // if (ifsfMsg.OverallStatus != MessageAcknowledgeStatus.ACK_PositiveAcknowledgeDataReceived)
- // logger.Error(" node " + ifsfRecipientNode + ", set nozzle to ProductDb failed:\r\n " + ifsfMsg.ToLogString());
- // if (++next_site_nozzle_Index <= this.pumpHandlers.SelectMany(p => p.Nozzles).Count())
- // {
- // logger.Info("PumpInitializer, node " + ifsfRecipientNode + " LogicalNozzleDb_Write_SetNozzleProductAndMeter Acked.");
- // var next_site_nozzle = this.pumpHandlers.SelectMany(p => p.Nozzles).ElementAt(next_site_nozzle_Index - 1);
- // var productOnThisNozzleSitsInWhichCaculatorSlot =
- // thisTqcProductBarcodes.IndexOf(nozzleProductConfig.First(p => p.NozzleLogicalId == next_site_nozzle.LogicalId && p.PumpId == next_site_nozzle.PumpId).ProductBarcode) + 1;
- // this.pendingForAckMsgToken = this.msgTokenGenerator();
- // byte targetIfsfFpId = this.pumpHandlers.First(p => p.PumpId == next_site_nozzle.PumpId).ifsfFuelPointId;
- // byte targetIfsfNozzleId = ((byte)(0x11 + next_site_nozzle.LogicalId - 1));
- // logger.Info("PumpInitializer, node " + ifsfRecipientNode + " sending LogicalNozzleDb_Write_SetNozzleProductAndMeter,\r\n" +
- // "set product to nozzle, FP: 0x" + targetIfsfFpId.ToHexLogString()
- // + ", nozzle: 0x" + targetIfsfNozzleId.ToHexLogString()
- // + ", PumpId: " + next_site_nozzle.PumpId + " map to ProductDb ProductNo Slot: " + productOnThisNozzleSitsInWhichCaculatorSlot);
- // context.Outgoing.Write(
- // new LogicalNozzleDb_Write_SetNozzleProductAndMeter(this.ifsfRecipientSubnet,
- // this.ifsfRecipientNode,
- // this.ifsfSelfSubnet,
- // this.ifsfSelfNode,
- // this.pendingForAckMsgToken.Value,
- // targetIfsfFpId
- // //assume logical id is 1 based.
- // , targetIfsfNozzleId,
- // (byte)productOnThisNozzleSitsInWhichCaculatorSlot, 1)
- // );
- // this.CurrentStatus = Status.Wait_ACK_Set_Nozzle_To_ProductDb_ProductNoSlot;
- // }
- // else
- // {
- // next_site_nozzle_Index = 1;
- // logger.Info("PumpInitializer, node " + ifsfRecipientNode + " set fp nozzles to ProductDb ProductNo Slot done!");
- // }
- // }
- // break;
- // }
- case Status.Wait_ACK_Set_FP_Default_FuellingMode:
- {
- if (context.Incoming.Message is IfsfMessage ifsfMsg && ifsfMsg.MessageType == MessageType.IFSF_MESSAGE_TYPE_ACK
- && ifsfMsg.MessageToken == this.pendingForAckMsgToken.Value)
- {
- if (++next_Fp_Index <= this.pumpHandlers.Count())
- {
- logger.Info("PumpInitializer, node " + ifsfRecipientNode + " FuellingPointDbRequest_Write_SetDefaultFuellingMode Acked");
- // now we only have fuelling mode 0x11.
- logger.Info("PumpInitializer, node " + ifsfRecipientNode + " Send FuellingPointDbRequest_Write_SetDefaultFuellingMode,\r\n" +
- "FP Default fuelling mode, FP: 0x" + this.pumpHandlers.ElementAt(next_Fp_Index - 1).PumpPhysicalId.ToHexLogString());
- this.pendingForAckMsgToken = this.msgTokenGenerator();
- context.Outgoing.Write(
- new FuellingPointDbRequest_Write_SetDefaultFuellingMode(this.ifsfRecipientSubnet,
- this.ifsfRecipientNode,
- this.ifsfSelfSubnet,
- this.ifsfSelfNode,
- this.pendingForAckMsgToken.Value, (byte)(this.pumpHandlers.ElementAt(next_Fp_Index - 1).PumpPhysicalId), 1));
- this.CurrentStatus = Status.Wait_ACK_Set_FP_Default_FuellingMode;
- }
- else
- {
- next_Fp_Index = 1;
- logger.Info("PumpInitializer, node " + ifsfRecipientNode + " set fp default fuelling mode all done!");
- logger.Info("PumpInitializer, node " + ifsfRecipientNode + " DONE!!!");
- this.CurrentStatus = Status.Done;
- var safe = this.OnInitDone;
- safe?.Invoke(this, null);
- }
- }
- break;
- }
- }
- return true;
- }
- public bool IsInitDone => this.CurrentStatus == Status.Done;
- public void Reset()
- {
- this.CurrentStatus = Status.UnInit;
- this.initTimeoutTimer.Stop();
- this.logicalNozzleDb_Nozzle_ProductInfo_PhyId_Answers.Clear();
- this.productDb_ProductNo_Answers.Clear();
- this.productPerFuellingModeDb_ProductPrice_Answers.Clear();
- }
- }
- #region IDisposable Support
- private bool disposedValue = false; // To detect redundant calls
- protected virtual void Dispose(bool disposing)
- {
- if (!disposedValue)
- {
- if (disposing)
- {
- // TODO: dispose managed state (managed objects).
- }
- // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
- // TODO: set large fields to null.
- disposedValue = true;
- }
- }
- // TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
- // ~PumpHandler() {
- // // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
- // Dispose(false);
- // }
- // This code added to correctly implement the disposable pattern.
- public void Dispose()
- {
- // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
- Dispose(true);
- // TODO: uncomment the following line if the finalizer is overridden above.
- // GC.SuppressFinalize(this);
- }
- IEnumerator<IFdcPumpController> IEnumerable<IFdcPumpController>.GetEnumerator()
- {
- return this.pumpHandlers.GetEnumerator();
- }
- #endregion
- }
- }
|