PumpGroupHandler.cs 77 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189
  1. using Edge.Core.Database;
  2. using Edge.Core.Processor;
  3. using Edge.Core.IndustryStandardInterface.Pump;
  4. using HengShan_Pump_TQC_IFSF.MessageEntity;
  5. using HengShan_Pump_TQC_IFSF.MessageEntity.Incoming;
  6. using HengShan_Pump_TQC_IFSF.MessageEntity.Outgoing;
  7. using Edge.Core.Parser.BinaryParser.Util;
  8. using System;
  9. using System.Collections;
  10. using System.Collections.Generic;
  11. using System.Globalization;
  12. using System.Linq;
  13. using System.Text;
  14. using System.Threading;
  15. using System.Threading.Tasks;
  16. using System.Xml;
  17. using Wayne.FDCPOSLibrary;
  18. using Timer = System.Timers.Timer;
  19. using Edge.Core.Processor.Dispatcher.Attributes;
  20. using Edge.Core.Processor.Communicator;
  21. using Edge.Core.Configuration;
  22. namespace HengShan_Pump_TQC_IFSF
  23. {
  24. #region Ctor parameters
  25. public class PumpGroupConfiguration
  26. {
  27. //public byte AmountDecimalDigits { get; set; }
  28. //public byte VolumeDecimalDigits { get; set; }
  29. //public byte PriceDecimalDigits { get; set; }
  30. //public byte VolumeTotalizerDecimalDigits { get; set; }
  31. public byte FccIfsfSubnetValue { get; set; }
  32. public byte FccIfsfNodeValue { get; set; }
  33. public byte PumpIfsfSubnetValue { get; set; }
  34. public byte PumpIfsfNodeValue { get; set; }
  35. public List<PumpConfiguration> PumpConfigurations { get; set; }
  36. }
  37. public class PumpConfiguration
  38. {
  39. public byte PumpId { get; set; }
  40. /// <summary>
  41. /// 0x21 - 0x24
  42. /// </summary>
  43. public byte PhysicalId { get; set; }
  44. public List<NozzleConfiguration> NozzleConfigurations { get; set; }
  45. }
  46. public class NozzleConfiguration
  47. {
  48. public byte LogicalId { get; set; }
  49. /// <summary>
  50. /// 0x11 - 0x18
  51. /// </summary>
  52. public byte PhysicalId { get; set; }
  53. }
  54. #endregion
  55. /// <summary>
  56. /// one TQC connection controls a full physical pump, typically 2 sides.
  57. /// </summary>
  58. [MetaPartsRequired(typeof(GenericDeviceProcessor<,>))]
  59. [MetaPartsRequired(typeof(HengShan_TQC_IFsfMessageTcpIpCommunicator<>))]
  60. [MetaPartsRequired(typeof(IfsfMessageBase))]
  61. [MetaPartsDescriptor(
  62. "lang-zh-cn:HS TQC加油机lang-en-us:HS TQC Pump",
  63. "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",
  64. new[] { "lang-zh-cn:加油机lang-en-us:Pump" })]
  65. public class PumpGroupHandler : IEnumerable<IFdcPumpController>, IDeviceHandler<byte[], IfsfMessageBase>
  66. {
  67. private object syncObject = new object();
  68. protected IEnumerable<NozzleExtraInfo> nozzleProductMappings;
  69. //private System.Timers.Timer heartBeatUdpPolling;
  70. //protected int heartBeatUdpPollingInterval = 6000;
  71. //private System.Timers.Timer queryTqcAllPumpStatePolling;
  72. //private long queryTqcAllPumpStatePollingInterval = 60 * 1000;
  73. private Guid uniqueId = Guid.NewGuid();
  74. internal TqcPumpGroupInitializer tqcPumpGroupInitializer;
  75. //protected static ILog logger = log4net.LogManager.GetLogger("PumpHandler");
  76. protected static NLog.Logger logger = NLog.LogManager.LoadConfiguration("nlog.config").GetLogger("PumpHandler");
  77. protected IContext<byte[], IfsfMessageBase> context;
  78. protected List<PumpHandler> pumpHandlers = new List<PumpHandler>();
  79. // for test, the tqc configured as subnet 1, node 1.
  80. protected byte recipientSubnet = 1;
  81. protected byte recipientNode = 1;
  82. // originator, it's the FC self.
  83. public static byte originatorSubnet = 2;
  84. public static byte originatorNode = 1;
  85. [ParamsJsonSchemas("PumpGroupHandlerCtorParamsJsonSchemas")]
  86. public PumpGroupHandler(PumpGroupConfiguration pumpGroupConfiguration, IServiceProvider services)
  87. {
  88. originatorSubnet = pumpGroupConfiguration.FccIfsfSubnetValue;
  89. originatorNode = pumpGroupConfiguration.FccIfsfNodeValue;
  90. this.recipientSubnet = pumpGroupConfiguration.PumpIfsfSubnetValue;
  91. this.recipientNode = pumpGroupConfiguration.PumpIfsfNodeValue;
  92. logger.Info("node " + this.recipientNode + ", Will create " +
  93. pumpGroupConfiguration.PumpConfigurations.Count + " pump handlers for this TQC connection according from config");
  94. this.CreatePumpHandlers(pumpGroupConfiguration.PumpConfigurations.Select(pc =>
  95. {
  96. XmlDocument doc = new XmlDocument();
  97. var xml =
  98. "<Pump pumpId='" + pc.PumpId + "' physicalId='" + pc.PhysicalId + "'>" +
  99. "<Nozzles>" +
  100. pc.NozzleConfigurations.Select(nc =>
  101. "<Nozzle logicalId='" + nc.LogicalId + "' physicalId='" + nc.PhysicalId + "' />")
  102. .Aggregate((acc, n) => acc + n) +
  103. "</Nozzles>" +
  104. "</Pump>";
  105. doc.LoadXml(xml);
  106. return doc.FirstChild;
  107. }));
  108. this.SetupTqcPumpGroupInitializer();
  109. }
  110. /// <summary>
  111. ///
  112. /// </summary>
  113. /// <param name="fccIfsfSubnetValue">fcc as a node in a ifsf subnet, has its subnet value</param>
  114. /// <param name="fccIfsfNodeValue">fcc as a node in a ifsf subnet, has its node value</param>
  115. /// <param name="pumpsXmlConfiguration"></param>
  116. public PumpGroupHandler(int fccIfsfSubnetValue, int fccIfsfNodeValue, string pumpsXmlConfiguration)
  117. {
  118. originatorSubnet = (byte)fccIfsfSubnetValue;
  119. originatorNode = (byte)fccIfsfNodeValue;
  120. // sample
  121. //<PumpGroup ifsfSubNet='2' ifsfNode='1'>
  122. // <Pump pumpId='1' physicalId='0x21'>
  123. // <Nozzles>
  124. // <Nozzle logicalId='1' physicalId='0x11' />
  125. // <Nozzle logicalId='2' physicalId='0x12' />
  126. // </Nozzles>
  127. // </Pump>
  128. // <Pump pumpId='2' physicalId='0x22'>
  129. // <Nozzles>
  130. // <Nozzle logicalId='1' physicalId='0x11' />
  131. // <Nozzle logicalId='2' physicalId='0x12' "/>
  132. // </Nozzles>
  133. // </Pump>
  134. // <Pump pumpId='3' physicalId='0x23'>
  135. // <Nozzles>
  136. // <Nozzle logicalId='1' physicalId='0x13' />
  137. // <Nozzle logicalId='2' physicalId='0x14' />
  138. // </Nozzles>
  139. // </Pump>
  140. // <Pump pumpId='4' physicalId='0x24'>
  141. // <Nozzles>
  142. // <Nozzle logicalId='1' physicalId='0x15' />
  143. // <Nozzle logicalId='2' physicalId='0x16' />
  144. // </Nozzles>
  145. // </Pump>
  146. //</PumpGroup>
  147. XmlDocument xmlDocument = new XmlDocument();
  148. xmlDocument.LoadXml(pumpsXmlConfiguration);
  149. var rootElement = xmlDocument.GetElementsByTagName("PumpGroup").Cast<XmlElement>().First();
  150. this.recipientSubnet = byte.Parse(rootElement.Attributes["ifsfSubNet"].Value);
  151. this.recipientNode = byte.Parse(rootElement.Attributes["ifsfNode"].Value);
  152. var pumpElements = xmlDocument.GetElementsByTagName("Pump").Cast<XmlNode>();
  153. logger.Info("node " + recipientNode + ", Will create " + pumpElements.Count() + " pump handlers for this TQC connection according from local config");
  154. this.CreatePumpHandlers(pumpElements);
  155. this.SetupTqcPumpGroupInitializer();
  156. }
  157. protected virtual void SetupTqcPumpGroupInitializer()
  158. {
  159. this.tqcPumpGroupInitializer = new TqcPumpGroupInitializer(originatorSubnet, originatorNode, this.recipientSubnet, this.recipientNode, this.pumpHandlers, this.GetNewMessageToken);
  160. this.tqcPumpGroupInitializer.OnInitTimeout += (cc, dd) =>
  161. {
  162. logger.Info("TqcPumpGroupInitializer, node " + this.tqcPumpGroupInitializer.ifsfRecipientNode + ", init timed out, will start it over...");
  163. this.tqcPumpGroupInitializer.Reset();
  164. this.tqcPumpGroupInitializer.FeedIn(this.context);
  165. };
  166. this.tqcPumpGroupInitializer.OnInitDone += (ee, ff) =>
  167. {
  168. logger.Info("TqcPumpGroupInitializer, node " + this.tqcPumpGroupInitializer.ifsfRecipientNode + ", init done, will query all FP status and routed following msg to PumpHandlers");
  169. // query all FP status, answer will be routed to each PumpHandler to handle.
  170. this.context.Outgoing.Write(
  171. new FuellingPointDbRequest_Read_FuelPointState(this.recipientSubnet,
  172. this.recipientNode,
  173. originatorSubnet,
  174. originatorNode,
  175. this.GetNewMessageToken(),
  176. 0x20));
  177. this.pumpHandlers.SelectMany(p => p.Nozzles).ToList().ForEach(n =>
  178. {
  179. var boundProductNo = this.nozzleProductMappings.First(c => c.PumpId == n.PumpId && c.NozzleLogicalId == n.LogicalId).ProductBarcode;
  180. logger.Info("TqcPumpGroupInitializer, node " + this.tqcPumpGroupInitializer.ifsfRecipientNode
  181. + ", will write back price to nozzle on pump " + n.PumpId + ", logicalNozzleId: " + n.LogicalId + ", boundProductNo: " + boundProductNo
  182. + " to new Init Price(without decimal points): " + this.tqcPumpGroupInitializer.PriceBook[boundProductNo]);
  183. n.RealPriceOnPhysicalPump = this.tqcPumpGroupInitializer.PriceBook[boundProductNo];
  184. });
  185. };
  186. }
  187. protected virtual void CreatePumpHandlers(IEnumerable<XmlNode> pumpElements)
  188. {
  189. foreach (XmlNode pumpElement in pumpElements)
  190. {
  191. byte pumpPhysicalIdValue;
  192. var rawPumpPhysicalId = pumpElement.Attributes["physicalId"].Value;//.Substring(2);
  193. if (rawPumpPhysicalId.StartsWith("0x") || rawPumpPhysicalId.StartsWith("0X"))
  194. pumpPhysicalIdValue = byte.Parse(pumpElement.Attributes["physicalId"].Value.Substring(2), NumberStyles.HexNumber);
  195. else
  196. pumpPhysicalIdValue = byte.Parse(pumpElement.Attributes["physicalId"].Value);
  197. if (pumpPhysicalIdValue < 0x21 || pumpPhysicalIdValue > 0x24)
  198. throw new ArgumentException("ifsf fuel point id must be range from 0x21 to 0x24, while the configuration passed in " + rawPumpPhysicalId);
  199. PumpHandler pumpHandler = new PumpHandler(this, int.Parse(pumpElement.Attributes["pumpId"].Value),
  200. pumpPhysicalIdValue,
  201. this.recipientSubnet, this.recipientNode,
  202. pumpElement.InnerXml, GetNewMessageToken);
  203. this.pumpHandlers.Add(pumpHandler);
  204. }
  205. }
  206. /// <summary>
  207. /// will be called at the Init stage of FdcServerApp, that means before the calling the Start() for all the Processors.
  208. /// </summary>
  209. /// <param name="parameters"></param>
  210. public void OnFdcServerInit(Dictionary<string, object> parameters)
  211. {
  212. if (parameters != null && parameters.TryGetValue("NozzleProductMapping", out object param))
  213. {
  214. this.nozzleProductMappings = param as IEnumerable<NozzleExtraInfo>;
  215. this.tqcPumpGroupInitializer.NozzleProductConfig = this.nozzleProductMappings;
  216. }
  217. this.pumpHandlers.ForEach(ph => ph.OnFdcServerInit(parameters));
  218. }
  219. public virtual void Init(IContext<byte[], IfsfMessageBase> context)
  220. {
  221. this.context = context;
  222. this.context.Communicator.OnConnected += (e, f) =>
  223. {
  224. // each time communicator get disconnect, will trigger a re-init.
  225. logger.Info("TqcPumpGroupInitializer, node " + this.tqcPumpGroupInitializer.ifsfRecipientNode + ", OnCommunicator Connected, will start init...");
  226. this.tqcPumpGroupInitializer.Reset();
  227. this.tqcPumpGroupInitializer.FeedIn(this.context);
  228. };
  229. this.context.Communicator.OnDisconnected += (e, f) =>
  230. {
  231. logger.Info("TqcPumpGroupInitializer, node " + this.tqcPumpGroupInitializer.ifsfRecipientNode + ", OnCommunicator Disconnected...");
  232. this.tqcPumpGroupInitializer.Reset();
  233. this.pumpHandlers.ForEach(p => p.HandleFpStatusChange(FuellingPointStatus.Inoperative, null));
  234. };
  235. this.pumpHandlers.ForEach(p => p.Init(this.context));
  236. }
  237. private byte rotateMsgToken = 0;
  238. public byte GetNewMessageToken()
  239. {
  240. if (rotateMsgToken == (0xFF & 0x01F))
  241. rotateMsgToken = 0;
  242. else
  243. rotateMsgToken++;
  244. return rotateMsgToken;
  245. }
  246. public virtual Task Process(IContext<byte[], IfsfMessageBase> context)
  247. {
  248. this.context = context;
  249. if (!this.tqcPumpGroupInitializer.IsInitDone)
  250. {
  251. this.tqcPumpGroupInitializer.FeedIn(context);
  252. return Task.CompletedTask;
  253. }
  254. this.RouteMessageToHandlers(context);
  255. return Task.CompletedTask;
  256. }
  257. protected virtual void RouteMessageToHandlers(IContext<byte[], IfsfMessageBase> context)
  258. {
  259. switch (context.Incoming.Message)
  260. {
  261. case FuellingPointDb_FpStatus_Event fpStatusEvent:
  262. this.pumpHandlers.Where(h => h.PumpPhysicalId == fpStatusEvent.TargetFuelPointId).ToList().ForEach(p => p.Process(context));
  263. break;
  264. case FuellingPointDb_FpStatus_Answer fpStatusAnswer:
  265. this.pumpHandlers.Where(h => h.PumpPhysicalId == fpStatusAnswer.TargetFuelPointId).ToList().ForEach(p => p.Process(context));
  266. break;
  267. case FuellingPointDb_FpRunningTransaction_Event fpRunningTrxEvent:
  268. this.pumpHandlers.Where(h => h.PumpPhysicalId == fpRunningTrxEvent.TargetFuelPointId).ToList().ForEach(p => p.Process(context));
  269. break;
  270. case FuellingPointDb_FpRunningTransaction_Event_ACK fpRunningTrxEvent:
  271. this.pumpHandlers.Where(h => h.PumpPhysicalId == fpRunningTrxEvent.TargetFuelPointId).ToList().ForEach(p => p.Process(context));
  272. break;
  273. case FuellingTrxDb_TransactionBufferStatus_Event trxBufferStatusEvent:
  274. this.pumpHandlers.Where(h => h.PumpPhysicalId == trxBufferStatusEvent.TargetFuelPointId).ToList().ForEach(p => p.Process(context));
  275. break;
  276. case FuellingTrxDb_TransactionBufferStatus_Event_ACK trxBufferStatusEvent:
  277. this.pumpHandlers.Where(h => h.PumpPhysicalId == trxBufferStatusEvent.TargetFuelPointId).ToList().ForEach(p => p.Process(context));
  278. break;
  279. case FuellingTrxDb_TransactionBufferStatus_Answer trxBufferStatusAnswer:
  280. this.pumpHandlers.Where(h => h.PumpPhysicalId == trxBufferStatusAnswer.TargetFuelPointId).ToList().ForEach(p => p.Process(context));
  281. break;
  282. //default: this.pumpHandlers.ForEach(p => p.Process(context)); break;
  283. }
  284. }
  285. public IEnumerator<IFdcPumpController> GetEnumerator()
  286. {
  287. return this.pumpHandlers.GetEnumerator();
  288. }
  289. IEnumerator IEnumerable.GetEnumerator()
  290. {
  291. return this.pumpHandlers.GetEnumerator();
  292. }
  293. public Guid Id => this.uniqueId;
  294. /// <summary>
  295. /// Initalizer for init default values into TQC pump.
  296. /// especially for default product price: it will read pre-config values for each product in pump first,
  297. /// </summary>
  298. internal class TqcPumpGroupInitializer
  299. {
  300. System.Timers.Timer initTimeoutTimer = new Timer(initTimeout);
  301. const int initTimeout = 10000;
  302. /// <summary>
  303. /// will fire when reached timed out time, and state is still not Done.
  304. /// </summary>
  305. public event EventHandler OnInitTimeout;
  306. public event EventHandler OnInitDone;
  307. public event EventHandler OnInitError;
  308. /// <summary>
  309. /// init process will firstly read all necessary config values in TQC, and then execute the write operations.
  310. /// this event will be fired once those config values were read, and write operation is still not perform.
  311. /// </summary>
  312. public event EventHandler OnTqcExistedConfigRead;
  313. private List<FuellingPointDb_FpStatus_Answer> fpStatus_Answers
  314. = new List<FuellingPointDb_FpStatus_Answer>();
  315. private List<LogicalNozzleDb_Nozzle_ProductInfo_PhyId_Answer> logicalNozzleDb_Nozzle_ProductInfo_PhyId_Answers
  316. = new List<LogicalNozzleDb_Nozzle_ProductInfo_PhyId_Answer>();
  317. /// <summary>
  318. /// Gets pre-config value in TQC pump.
  319. /// </summary>
  320. public IEnumerable<LogicalNozzleDb_Nozzle_ProductInfo_PhyId_Answer> LogicalNozzleDb_Nozzle_ProductInfo_PhyId_Answers => this.logicalNozzleDb_Nozzle_ProductInfo_PhyId_Answers;
  321. private List<ProductDb_ProductNo_Answer> productDb_ProductNo_Answers
  322. = new List<ProductDb_ProductNo_Answer>();
  323. /// <summary>
  324. /// Gets pre-config value in TQC pump.
  325. /// </summary>
  326. public IEnumerable<ProductDb_ProductNo_Answer> ProductDb_ProductNo_Answers => this.productDb_ProductNo_Answers;
  327. private List<ProductPerFuellingModeDb_ProductPrice_Answer> productPerFuellingModeDb_ProductPrice_Answers
  328. = new List<ProductPerFuellingModeDb_ProductPrice_Answer>();
  329. /// <summary>
  330. /// Gets pre-config value in TQC pump.
  331. /// </summary>
  332. public IEnumerable<ProductPerFuellingModeDb_ProductPrice_Answer> ProductPerFuellingModeDb_ProductPrice_Answers => this.productPerFuellingModeDb_ProductPrice_Answers;
  333. private Dictionary<int, int> priceBook = new Dictionary<int, int>();
  334. /// <summary>
  335. /// Gets or set the init price for each product.
  336. /// default price init policy is read from pricebook, if found then apply, otherwise use pre-config value read from pump.
  337. /// should follow-> barcode:rawFormatPriceWithoutDecimalPoints
  338. /// </summary>
  339. public Dictionary<int, int> PriceBook => this.priceBook;
  340. private IEnumerable<NozzleExtraInfo> nozzleProductConfig;
  341. public IEnumerable<NozzleExtraInfo> NozzleProductConfig
  342. {
  343. get
  344. {
  345. return this.nozzleProductConfig;
  346. }
  347. set
  348. {
  349. this.nozzleProductConfig = value;
  350. this.thisTqcProductBarcodes = this.nozzleProductConfig.Where(n => this.pumpHandlers.Select(p => p.PumpId).Contains(n.PumpId)).Select(s => s.ProductBarcode).Distinct().OrderBy(o => o).ToList();
  351. //this.thisTqcProductBarcodes = nozzleProductConfig.Select(s => s.ProductBarcode).Distinct().OrderBy(o => o).ToList();
  352. logger.Info("PumpInitializer, node " + ifsfRecipientNode + " current TQC local configuration indicates total have "
  353. + this.thisTqcProductBarcodes.Count + " product barcodes: " + this.thisTqcProductBarcodes.Select(s => s.ToString()).Aggregate((acc, n) => acc + ", " + n));
  354. }
  355. }
  356. //= Configurator.Default.NozzleProductConfiguration.Mapping;
  357. private byte ifsfSelfSubnet;
  358. private byte ifsfSelfNode;
  359. private byte ifsfRecipientSubnet;
  360. public byte ifsfRecipientNode;
  361. IEnumerable<PumpHandler> pumpHandlers;
  362. Func<byte> msgTokenGenerator;
  363. private List<int> thisTqcProductBarcodes;
  364. private Status currentStatus;
  365. private Status CurrentStatus
  366. {
  367. get { return this.currentStatus; }
  368. set
  369. {
  370. //logger.Debug("PumpInitializer, node " + ifsfRecipientNode + ", Status switched from " + this.currentStatus + " to " + value);
  371. this.currentStatus = value;
  372. }
  373. }
  374. //private DateTime previousRequestingTime;
  375. private byte? pendingForAckMsgToken;
  376. private enum Status
  377. {
  378. UnInit = 0,
  379. Wait_Answer_Query_All_FuelPointState,
  380. Wait_Answer_Close_All_FuelPoint,
  381. Wait_Answer_Query_Caculator_Overall_Info,
  382. Wait_Answer_Read_All_Nozzle_ProductInfo_PhyId,
  383. Wait_Answer_Read_All_ProductNumber,
  384. Wait_Answer_Read_All_ProductPrice,
  385. //Sending_Add_Recipient_Addr,
  386. Wait_ACK_Add_Recipient_Addr,
  387. //Sending_Clear_ProductNumber_In_Caculator,
  388. Wait_ACK_Clear_ProductNumber_In_ProductDb,
  389. //Sending_Set_ProductNumber_In_Caculator,
  390. Wait_ACK_Set_ProductNumber_In_ProductDb,
  391. //Sending_Link_Meter_To_CaculatorSlot,
  392. Wait_ACK_Link_Meter_To_ProductDb_ProductNoSlot,
  393. //Sending_Set_AUTH_MODE,
  394. Wait_ACK_Set_AUTH_MODE,
  395. //Sending_Set_Price,
  396. Wait_ACK_Set_Price,
  397. //Sending_Set_Nozzle_To_CacalatorSlot,
  398. Wait_ACK_Set_Nozzle_To_ProductDb_ProductNoSlot,
  399. //Sending_Set_FP_Default_FuellingMode,
  400. Wait_ACK_Set_FP_Default_FuellingMode,
  401. //Send_Open_FP,
  402. //Wait_ACK_Open_FP,
  403. Done
  404. }
  405. /// <summary>
  406. ///
  407. /// </summary>
  408. /// <param name="selfSubnet">fc ifsf subnet value</param>
  409. /// <param name="selfNode">fc ifsf node value</param>
  410. /// <param name="ifsfRecipientSubnet">remote ifsf recipient subnet value</param>
  411. /// <param name="ifsfRecipientNode">remote ifsf recipient node value</param>
  412. /// <param name="pumpHandlers">pump handlers created from the pump Group handler</param>
  413. /// <param name="msgTokenGenerator"></param>
  414. public TqcPumpGroupInitializer(byte selfSubnet, byte selfNode, byte ifsfRecipientSubnet, byte ifsfRecipientNode,
  415. IEnumerable<PumpHandler> pumpHandlers, Func<byte> msgTokenGenerator)
  416. {
  417. this.ifsfSelfSubnet = selfSubnet;
  418. this.ifsfSelfNode = selfNode;
  419. this.ifsfRecipientSubnet = ifsfRecipientSubnet;
  420. this.ifsfRecipientNode = ifsfRecipientNode;
  421. this.pumpHandlers = pumpHandlers;
  422. this.msgTokenGenerator = msgTokenGenerator;
  423. this.initTimeoutTimer.Elapsed += (a, b) =>
  424. {
  425. this.initTimeoutTimer.Stop();
  426. if (!this.IsInitDone)
  427. {
  428. var safe = this.OnInitTimeout;
  429. safe(this, null);
  430. }
  431. };
  432. }
  433. private byte next_ActualInPump_ProductNumber_In_ProductDb_ProductNoSlot_Index = 1;
  434. private byte next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index = 1;
  435. //private byte next_Link_Meter_to_ProductNumber_Index = 1;
  436. private byte next_site_nozzle_Index = 1;
  437. private byte next_Fp_Index = 1;
  438. /// <summary>
  439. /// if it was Done, return false. otherwise, the init is kicking off, return true.
  440. /// </summary>
  441. /// <param name="context"></param>
  442. /// <returns></returns>
  443. public bool FeedIn(IContext<byte[], IfsfMessageBase> context)
  444. {
  445. if (!this.initTimeoutTimer.Enabled) this.initTimeoutTimer.Start();
  446. if (IsInitDone) return false;
  447. switch (this.CurrentStatus)
  448. {
  449. case Status.UnInit:
  450. {
  451. logger.Info("PumpInitializer, node " + ifsfRecipientNode + " start Init, firstly Query&Close all FuelPoints...");
  452. logger.Info("PumpInitializer, node " + ifsfRecipientNode + " Send QueryAllFp state(first time)");
  453. this.pendingForAckMsgToken = this.msgTokenGenerator();
  454. context.Outgoing.Write(
  455. new FuellingPointDbRequest_Read_FuelPointState(this.ifsfRecipientSubnet,
  456. this.ifsfRecipientNode,
  457. this.ifsfSelfSubnet,
  458. this.ifsfSelfNode,
  459. this.pendingForAckMsgToken.Value, 0x20
  460. ));
  461. this.CurrentStatus = Status.Wait_Answer_Query_All_FuelPointState;
  462. break;
  463. }
  464. case Status.Wait_Answer_Query_All_FuelPointState:
  465. {
  466. if (context.Incoming.Message is IfsfMessage ifsfMsg && ifsfMsg.MessageType == MessageType.IFSF_MESSAGE_TYPE_ACK
  467. && ifsfMsg.MessageToken == this.pendingForAckMsgToken.Value)
  468. {
  469. var historyIncoming = context.Incoming as HistoryKeepIncoming<IfsfMessageBase>;
  470. this.fpStatus_Answers = historyIncoming.History.Where(h => (h.Item1 is FuellingPointDb_FpStatus_Answer im)
  471. && im.MessageType == MessageType.IFSF_MESSAGE_TYPE_ANSWER
  472. && im.MessageToken == this.pendingForAckMsgToken)
  473. .Select(s => (FuellingPointDb_FpStatus_Answer)s.Item1).ToList();
  474. logger.Info("PumpInitializer, node " + ifsfRecipientNode + ", read total " + fpStatus_Answers.Count
  475. + " Fp status, they're " + this.fpStatus_Answers.Select(s => "Fp 0x" + s.TargetFuelPointId.ToHexLogString() + " is " + s.FuelPointState)
  476. .Aggregate((n, acc) => n + ", " + acc));
  477. this.pendingForAckMsgToken = this.msgTokenGenerator();
  478. logger.Info("PumpInitializer, node " + ifsfRecipientNode + " Send CloseFuelPoint(first time) for FP: 0x"
  479. + this.pumpHandlers.ElementAt(next_Fp_Index - 1).PumpPhysicalId.ToHexLogString());
  480. this.pendingForAckMsgToken = this.msgTokenGenerator();
  481. context.Outgoing.Write(
  482. new FuellingPointDbRequest_Write_CloseFuelPoint(this.ifsfRecipientSubnet,
  483. this.ifsfRecipientNode,
  484. this.ifsfSelfSubnet,
  485. this.ifsfSelfNode,
  486. this.pendingForAckMsgToken.Value, (byte)(this.pumpHandlers.ElementAt(next_Fp_Index - 1).PumpPhysicalId)
  487. ));
  488. this.CurrentStatus = Status.Wait_Answer_Close_All_FuelPoint;
  489. }
  490. break;
  491. }
  492. case Status.Wait_Answer_Close_All_FuelPoint:
  493. {
  494. if (context.Incoming.Message is IfsfMessage ifsfMsg && ifsfMsg.MessageType == MessageType.IFSF_MESSAGE_TYPE_ACK
  495. && ifsfMsg.MessageToken == this.pendingForAckMsgToken)
  496. {
  497. if (++next_Fp_Index <= this.pumpHandlers.Count())
  498. {
  499. logger.Info("PumpInitializer, node " + ifsfRecipientNode + " CloseFuelPoint Acked");
  500. logger.Info("PumpInitializer, node " + ifsfRecipientNode + " Send CloseFuelPoint for FP: 0x"
  501. + this.pumpHandlers.ElementAt(next_Fp_Index - 1).PumpPhysicalId.ToHexLogString());
  502. this.pendingForAckMsgToken = this.msgTokenGenerator();
  503. context.Outgoing.Write(
  504. new FuellingPointDbRequest_Write_CloseFuelPoint(this.ifsfRecipientSubnet,
  505. this.ifsfRecipientNode,
  506. this.ifsfSelfSubnet,
  507. this.ifsfSelfNode,
  508. this.pendingForAckMsgToken.Value, (byte)(this.pumpHandlers.ElementAt(next_Fp_Index - 1).PumpPhysicalId)
  509. ));
  510. this.CurrentStatus = Status.Wait_Answer_Close_All_FuelPoint;
  511. }
  512. else
  513. {
  514. this.next_Fp_Index = 1;
  515. logger.Info("PumpInitializer, node " + ifsfRecipientNode + " sending CaculatorDbRequest_Read_FuelPoint_Product_FuelMode_Meter_Info...");
  516. this.pendingForAckMsgToken = this.msgTokenGenerator();
  517. context.Outgoing.Write(
  518. new CaculatorDbRequest_Read_FuelPoint_Product_FuelMode_Meter_Info(this.ifsfRecipientSubnet,
  519. this.ifsfRecipientNode,
  520. this.ifsfSelfSubnet,
  521. this.ifsfSelfNode,
  522. this.pendingForAckMsgToken.Value
  523. ));
  524. this.CurrentStatus = Status.Wait_Answer_Query_Caculator_Overall_Info;
  525. }
  526. }
  527. break;
  528. }
  529. case Status.Wait_Answer_Query_Caculator_Overall_Info:
  530. {
  531. if (context.Incoming.Message is IfsfMessage ifsfMsg && ifsfMsg.MessageType == MessageType.IFSF_MESSAGE_TYPE_ANSWER
  532. && ifsfMsg.MessageToken == this.pendingForAckMsgToken)
  533. {
  534. var dataParser = DatabaseDataParser.New().Convert(ifsfMsg.RawDatabaseData.ToArray());
  535. var numberOfProducts = dataParser.DataIds.First(i => i.Item1 == 0x02).Item2.ToInt32();
  536. logger.Info("PumpInitializer, node " + ifsfRecipientNode + " CaculatorDbRequest_Read_FuelPoint_Product_FuelMode_Meter_Info Acked,\r\n" +
  537. "Read caculatorDbOverallInfo, No_Products: " + numberOfProducts
  538. + ", No_Fuelling_Modes: " + dataParser.DataIds.First(i => i.Item1 == 0x03).Item2.ToInt32()
  539. + ", No_Meters: " + dataParser.DataIds.First(i => i.Item1 == 0x04).Item2.ToInt32()
  540. + ", No_FP: " + dataParser.DataIds.First(i => i.Item1 == 0x05).Item2.ToInt32()
  541. + ", Auth_State_Mode: " + dataParser.DataIds.First(i => i.Item1 == 0x0B).Item2.ToInt32());
  542. if (numberOfProducts != this.thisTqcProductBarcodes.Count)
  543. {
  544. logger.Info("!!!!!!PumpInitializer, node " + ifsfRecipientNode + " This TQC MUST config " + numberOfProducts + " products, but now trying to load local config with " + this.thisTqcProductBarcodes.Count + " products");
  545. }
  546. logger.Info("PumpInitializer, node " + ifsfRecipientNode + " sending CommunicationServiceDbRequest_Write_RecipientAddressTable...");
  547. this.pendingForAckMsgToken = this.msgTokenGenerator();
  548. context.Outgoing.Write(
  549. new CommunicationServiceDbRequest_Write_RecipientAddressTable(this.ifsfRecipientSubnet,
  550. this.ifsfRecipientNode,
  551. this.ifsfSelfSubnet,
  552. this.ifsfSelfNode,
  553. this.pendingForAckMsgToken.Value,
  554. this.ifsfSelfSubnet,
  555. this.ifsfSelfNode));
  556. this.CurrentStatus = Status.Wait_ACK_Add_Recipient_Addr;
  557. }
  558. break;
  559. }
  560. case Status.Wait_ACK_Add_Recipient_Addr:
  561. {
  562. if (context.Incoming.Message is IfsfMessage ifsfMsg && ifsfMsg.MessageType == MessageType.IFSF_MESSAGE_TYPE_ACK
  563. && ifsfMsg.MessageToken == this.pendingForAckMsgToken)
  564. {
  565. logger.Info("PumpInitializer, node " + ifsfRecipientNode + " CommunicationServiceDbRequest_Write_RecipientAddressTable Acked.");
  566. logger.Info("PumpInitializer, node " + ifsfRecipientNode + " Send LogicalNozzleDb_Read_Nozzle_ProductInfo_PhyId for FP: 0x"
  567. + this.pumpHandlers.ElementAt(next_Fp_Index - 1).PumpPhysicalId.ToHexLogString());
  568. this.pendingForAckMsgToken = this.msgTokenGenerator();
  569. context.Outgoing.Write(
  570. new LogicalNozzleDb_Read_Nozzle_ProductInfo_PhyId(this.ifsfRecipientSubnet,
  571. this.ifsfRecipientNode,
  572. this.ifsfSelfSubnet,
  573. this.ifsfSelfNode,
  574. this.pendingForAckMsgToken.Value, (byte)(this.pumpHandlers.ElementAt(next_Fp_Index - 1).PumpPhysicalId), 0x10));
  575. this.CurrentStatus = Status.Wait_Answer_Read_All_Nozzle_ProductInfo_PhyId;
  576. }
  577. break;
  578. }
  579. case Status.Wait_Answer_Read_All_Nozzle_ProductInfo_PhyId:
  580. {
  581. if (context.Incoming.Message is IfsfMessage ifsfMsg && ifsfMsg.MessageType == MessageType.IFSF_MESSAGE_TYPE_ACK
  582. && ifsfMsg.MessageToken == this.pendingForAckMsgToken.Value)
  583. {
  584. var historyIncoming = context.Incoming as HistoryKeepIncoming<IfsfMessageBase>;
  585. this.logicalNozzleDb_Nozzle_ProductInfo_PhyId_Answers.AddRange(
  586. historyIncoming.History.Where(h => (h.Item1 is LogicalNozzleDb_Nozzle_ProductInfo_PhyId_Answer im)
  587. && im.MessageType == MessageType.IFSF_MESSAGE_TYPE_ANSWER
  588. && im.MessageToken == this.pendingForAckMsgToken)
  589. .Select(s => s.Item1 as LogicalNozzleDb_Nozzle_ProductInfo_PhyId_Answer).OrderBy(a => a.LogicalNozzleId));
  590. if (++next_Fp_Index <= this.pumpHandlers.Count())
  591. {
  592. logger.Info("PumpInitializer, node " + ifsfRecipientNode + " LogicalNozzleDb_Read_Nozzle_ProductInfo_PhyId Acked");
  593. logger.Info("PumpInitializer, node " + ifsfRecipientNode + " Send LogicalNozzleDb_Read_Nozzle_ProductInfo_PhyId for FP: 0x"
  594. + this.pumpHandlers.ElementAt(next_Fp_Index - 1).PumpPhysicalId.ToHexLogString());
  595. this.pendingForAckMsgToken = this.msgTokenGenerator();
  596. context.Outgoing.Write(
  597. new LogicalNozzleDb_Read_Nozzle_ProductInfo_PhyId(this.ifsfRecipientSubnet,
  598. this.ifsfRecipientNode,
  599. this.ifsfSelfSubnet,
  600. this.ifsfSelfNode,
  601. this.pendingForAckMsgToken.Value, (byte)(this.pumpHandlers.ElementAt(next_Fp_Index - 1).PumpPhysicalId), 0x10));
  602. this.CurrentStatus = Status.Wait_Answer_Read_All_Nozzle_ProductInfo_PhyId;
  603. }
  604. else
  605. {
  606. foreach (var answer in this.logicalNozzleDb_Nozzle_ProductInfo_PhyId_Answers)
  607. logger.Info(" node " + ifsfRecipientNode + " Read nozzles info for FP: 0x" + answer.TargetFuelPointId.ToHexLogString()
  608. + ", with logicalId: 0x" + answer.LogicalNozzleId.ToHexLogString()
  609. + ", with physicalId: 0x" + answer.PhyscialNozzleId.ToHexLogString()
  610. + ", with product slotId: 0x" + answer.LinkedProductSlotId_InProductDbProdcutNoSlot.ToHexLogString());
  611. next_Fp_Index = 1;
  612. logger.Info("PumpInitializer, node " + ifsfRecipientNode + " sending ProductDbRequest_Read_ProductNo");
  613. this.pendingForAckMsgToken = this.msgTokenGenerator();
  614. // will receive several answers and an ACK messages since this is a query all request.
  615. context.Outgoing.Write(new ProductDbRequest_Read_ProductNo(this.ifsfRecipientSubnet,
  616. this.ifsfRecipientNode,
  617. this.ifsfSelfSubnet,
  618. this.ifsfSelfNode,
  619. this.pendingForAckMsgToken.Value, 0));
  620. this.CurrentStatus = Status.Wait_Answer_Read_All_ProductNumber;
  621. }
  622. }
  623. break;
  624. }
  625. case Status.Wait_Answer_Read_All_ProductNumber:
  626. {
  627. if (context.Incoming.Message is IfsfMessage ifsfMsg && ifsfMsg.MessageType == MessageType.IFSF_MESSAGE_TYPE_ACK
  628. && ifsfMsg.MessageToken == this.pendingForAckMsgToken)
  629. {
  630. var historyIncoming = context.Incoming as HistoryKeepIncoming<IfsfMessageBase>;
  631. //logger.Debug("************" + historyIncoming.History.Select(a => a.Item1.GetType().Name).Aggregate((acc, n) => acc + ", " + n));
  632. //logger.Debug("************historyIncoming.History.Count: " + historyIncoming.History.Count);
  633. this.productDb_ProductNo_Answers.AddRange(
  634. historyIncoming.History.Where(h => (h.Item1 is ProductDb_ProductNo_Answer im)
  635. && im.MessageType == MessageType.IFSF_MESSAGE_TYPE_ANSWER
  636. && im.MessageToken == this.pendingForAckMsgToken).Select(s => s.Item1 as ProductDb_ProductNo_Answer).OrderBy(a => a.ProductSlotId));
  637. if (this.productDb_ProductNo_Answers.Any())
  638. {
  639. 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));
  640. 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();
  641. this.pendingForAckMsgToken = this.msgTokenGenerator();
  642. // each Product will receive a serial of answers for its differnt FuelMode since we input 0x10 as query all FM.
  643. context.Outgoing.Write(new ProductPerFuellingModeDbRequest_Read_ProductPrice(this.ifsfRecipientSubnet,
  644. this.ifsfRecipientNode,
  645. this.ifsfSelfSubnet,
  646. this.ifsfSelfNode,
  647. this.pendingForAckMsgToken.Value, actualProductNumber, 0x10));
  648. this.CurrentStatus = Status.Wait_Answer_Read_All_ProductPrice;
  649. }
  650. else
  651. {
  652. /* TQC without any product configed, happened for fresh new TQC pump (get hardware reset or just shipped from factory??), handle here */
  653. 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");
  654. logger.Info("PumpInitializer, node " + ifsfRecipientNode + " sending Clear ProductNumber in ProductDb slot index: " + next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index);
  655. this.pendingForAckMsgToken = this.msgTokenGenerator();
  656. context.Outgoing.Write(
  657. new ProductDbRequest_Write_SetProductNumber(this.ifsfRecipientSubnet,
  658. this.ifsfRecipientNode,
  659. this.ifsfSelfSubnet,
  660. this.ifsfSelfNode,
  661. this.pendingForAckMsgToken.Value,
  662. next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index, null));
  663. this.CurrentStatus = Status.Wait_ACK_Set_ProductNumber_In_ProductDb;
  664. }
  665. }
  666. break;
  667. }
  668. case Status.Wait_Answer_Read_All_ProductPrice:
  669. {
  670. if (context.Incoming.Message is AcknowledgeMessage ifsfMsg && ifsfMsg.MessageType == MessageType.IFSF_MESSAGE_TYPE_ACK
  671. && ifsfMsg.MessageToken == this.pendingForAckMsgToken.Value)
  672. {
  673. var historyIncoming = context.Incoming as HistoryKeepIncoming<IfsfMessageBase>;
  674. var resultSetsForOneProduct = historyIncoming.History.Where(h => (h.Item1 is ProductPerFuellingModeDb_ProductPrice_Answer im)
  675. && im.MessageType == MessageType.IFSF_MESSAGE_TYPE_ANSWER
  676. && im.MessageToken == this.pendingForAckMsgToken).Select(s => s.Item1 as ProductPerFuellingModeDb_ProductPrice_Answer);
  677. logger.Info(" node " + ifsfRecipientNode + ", Read one existed product price with product number: "
  678. + resultSetsForOneProduct.Last().ProductNumber
  679. + ", price are: " + resultSetsForOneProduct.OrderBy(a => a.FuelModeId).Select(s => s.Price + " in FM:0x" + s.FuelModeId.ToString("X")).Aggregate((acc, n) => acc + ", " + n));
  680. this.productPerFuellingModeDb_ProductPrice_Answers.AddRange(resultSetsForOneProduct);
  681. if (this.productDb_ProductNo_Answers.Count() >= ++next_ActualInPump_ProductNumber_In_ProductDb_ProductNoSlot_Index)
  682. {
  683. 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();
  684. this.pendingForAckMsgToken = this.msgTokenGenerator();
  685. context.Outgoing.Write(new ProductPerFuellingModeDbRequest_Read_ProductPrice(this.ifsfRecipientSubnet,
  686. this.ifsfRecipientNode,
  687. this.ifsfSelfSubnet,
  688. this.ifsfSelfNode,
  689. this.pendingForAckMsgToken.Value, actualProductNumber, 0x10));
  690. this.CurrentStatus = Status.Wait_Answer_Read_All_ProductPrice;
  691. }
  692. else
  693. {
  694. next_ActualInPump_ProductNumber_In_ProductDb_ProductNoSlot_Index = 1;
  695. logger.Info("PumpInitializer, node " + ifsfRecipientNode + " Read_All_ProductPrice done!");
  696. var safe = this.OnTqcExistedConfigRead;
  697. safe?.Invoke(this, null);
  698. logger.Info("PumpInitializer, node " + ifsfRecipientNode + " sending Clear productNo(1st time) in ProductDb with slot index: " + next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index);
  699. this.pendingForAckMsgToken = this.msgTokenGenerator();
  700. context.Outgoing.Write(
  701. new ProductDbRequest_Write_SetProductNumber(this.ifsfRecipientSubnet,
  702. this.ifsfRecipientNode,
  703. this.ifsfSelfSubnet,
  704. this.ifsfSelfNode,
  705. this.pendingForAckMsgToken.Value,
  706. next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index, null));
  707. this.CurrentStatus = Status.Wait_ACK_Clear_ProductNumber_In_ProductDb;
  708. }
  709. }
  710. break;
  711. }
  712. case Status.Wait_ACK_Clear_ProductNumber_In_ProductDb:
  713. {
  714. if (context.Incoming.Message is AcknowledgeMessage ifsfMsg && ifsfMsg.MessageType == MessageType.IFSF_MESSAGE_TYPE_ACK
  715. && ifsfMsg.MessageToken == this.pendingForAckMsgToken.Value)
  716. {
  717. if (ifsfMsg.OverallStatus != MessageAcknowledgeStatus.ACK_PositiveAcknowledgeDataReceived)
  718. logger.Error(" node " + ifsfRecipientNode + ", clear product from ProductDb failed!");
  719. logger.Info(" PumpInitializer, node " + ifsfRecipientNode + ", clear product no. from ProductDb with msgToken:" + this.pendingForAckMsgToken.Value + " Acked.");
  720. if (++next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index <= 8)
  721. {
  722. logger.Info("PumpInitializer, node " + ifsfRecipientNode + " sending Clear productNo in ProductDb with slot index: " + next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index);
  723. this.pendingForAckMsgToken = this.msgTokenGenerator();
  724. context.Outgoing.Write(
  725. new ProductDbRequest_Write_SetProductNumber(this.ifsfRecipientSubnet,
  726. this.ifsfRecipientNode,
  727. this.ifsfSelfSubnet,
  728. this.ifsfSelfNode,
  729. this.pendingForAckMsgToken.Value,
  730. next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index, null));
  731. this.CurrentStatus = Status.Wait_ACK_Clear_ProductNumber_In_ProductDb;
  732. }
  733. else
  734. {
  735. logger.Info("PumpInitializer, node " + ifsfRecipientNode + " clear product number on all productDb productNo slots(total:" + (next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index - 1) + ") done!");
  736. next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index = 1;
  737. var next_site_nozzle = this.pumpHandlers.SelectMany(p => p.Nozzles)
  738. .OrderBy(n => n.PumpId).OrderBy(n => n.LogicalId).ElementAt(next_site_nozzle_Index - 1);
  739. var nozzleProductConfig = this.nozzleProductConfig
  740. .First(c => c.PumpId == next_site_nozzle.PumpId && c.NozzleLogicalId == next_site_nozzle.LogicalId);
  741. var ifsfNozzle
  742. = this.logicalNozzleDb_Nozzle_ProductInfo_PhyId_Answers
  743. .First(ifsfNzl => ifsfNzl.TargetFuelPointId == this.pumpHandlers.First(p => p.PumpId == next_site_nozzle.PumpId).PumpPhysicalId
  744. && ifsfNzl.LogicalNozzleId == next_site_nozzle.PhysicalId);
  745. var nozzleBoundToProductDbProductSlot = ifsfNozzle.LinkedProductSlotId_InProductDbProdcutNoSlot;
  746. logger.Info("PumpInitializer, node " + ifsfRecipientNode
  747. + " pump " + next_site_nozzle.PumpId + ", nozzle logicalId " + next_site_nozzle.LogicalId
  748. + "(ifsf FpId 0x" + ifsfNozzle.TargetFuelPointId.ToHexLogString() + ", ifsf nozzle logicalId 0x" + ifsfNozzle.LogicalNozzleId.ToHexLogString() + ")"
  749. + " is hardware-bound to productDb product No. slot 0x" + nozzleBoundToProductDbProductSlot.ToHexLogString()
  750. + ", will(1st time) set 0x" + nozzleBoundToProductDbProductSlot.ToHexLogString() + " to product No.: " + nozzleProductConfig.ProductBarcode);
  751. this.pendingForAckMsgToken = this.msgTokenGenerator();
  752. context.Outgoing.Write(
  753. new ProductDbRequest_Write_SetProductNumber(this.ifsfRecipientSubnet,
  754. this.ifsfRecipientNode,
  755. this.ifsfSelfSubnet,
  756. this.ifsfSelfNode,
  757. this.pendingForAckMsgToken.Value,
  758. (byte)(nozzleBoundToProductDbProductSlot - 0x40), nozzleProductConfig.ProductBarcode.ToString()));
  759. this.CurrentStatus = Status.Wait_ACK_Set_ProductNumber_In_ProductDb;
  760. }
  761. }
  762. break;
  763. }
  764. case Status.Wait_ACK_Set_ProductNumber_In_ProductDb:
  765. {
  766. if (context.Incoming.Message is AcknowledgeMessage ifsfMsg && ifsfMsg.MessageType == MessageType.IFSF_MESSAGE_TYPE_ACK
  767. && ifsfMsg.MessageToken == this.pendingForAckMsgToken.Value)
  768. {
  769. if (ifsfMsg.OverallStatus != MessageAcknowledgeStatus.ACK_PositiveAcknowledgeDataReceived)
  770. logger.Error(" node " + ifsfRecipientNode + ", set product to ProductDb failed!");
  771. logger.Info(" PumpInitializer, node " + ifsfRecipientNode + " ProductDbRequest_Write_SetProductNumber with msgToken:" + this.pendingForAckMsgToken.Value + " Acked.");
  772. if (++next_site_nozzle_Index <= this.pumpHandlers.SelectMany(p => p.Nozzles).Count())
  773. {
  774. var next_site_nozzle = this.pumpHandlers.SelectMany(p => p.Nozzles)
  775. .OrderBy(n => n.PumpId).OrderBy(n => n.LogicalId).ElementAt(next_site_nozzle_Index - 1);
  776. var nozzleProductConfig = this.nozzleProductConfig
  777. .First(c => c.PumpId == next_site_nozzle.PumpId && c.NozzleLogicalId == next_site_nozzle.LogicalId);
  778. var ifsfNozzle
  779. = this.logicalNozzleDb_Nozzle_ProductInfo_PhyId_Answers
  780. .First(ifsfNzl => ifsfNzl.TargetFuelPointId == this.pumpHandlers.First(p => p.PumpId == next_site_nozzle.PumpId).PumpPhysicalId
  781. && ifsfNzl.LogicalNozzleId == next_site_nozzle.PhysicalId);
  782. var nozzleBoundToProductDbProductSlot = ifsfNozzle.LinkedProductSlotId_InProductDbProdcutNoSlot;
  783. logger.Info("PumpInitializer, node " + ifsfRecipientNode
  784. + " pump " + next_site_nozzle.PumpId + ", nozzle logicalId " + next_site_nozzle.LogicalId
  785. + "(ifsf FpId 0x" + ifsfNozzle.TargetFuelPointId.ToHexLogString() + ", ifsf nozzle logicalId 0x" + ifsfNozzle.LogicalNozzleId.ToHexLogString() + ")"
  786. + " is hardware-bound to productDb product No. slot 0x" + nozzleBoundToProductDbProductSlot.ToHexLogString()
  787. + ", will set 0x" + nozzleBoundToProductDbProductSlot.ToHexLogString() + " to product No.: " + nozzleProductConfig.ProductBarcode);
  788. this.pendingForAckMsgToken = this.msgTokenGenerator();
  789. context.Outgoing.Write(
  790. new ProductDbRequest_Write_SetProductNumber(this.ifsfRecipientSubnet,
  791. this.ifsfRecipientNode,
  792. this.ifsfSelfSubnet,
  793. this.ifsfSelfNode,
  794. this.pendingForAckMsgToken.Value,
  795. (byte)(nozzleBoundToProductDbProductSlot - 0x40), nozzleProductConfig.ProductBarcode.ToString()));
  796. this.CurrentStatus = Status.Wait_ACK_Set_ProductNumber_In_ProductDb;
  797. }
  798. else
  799. {
  800. next_site_nozzle_Index = 1;
  801. logger.Info("PumpInitializer, node " + ifsfRecipientNode + " sending CaculatorDbRequest_Write_Set_AuthStateMode_MinFuelingVol_MinDisplayVol");
  802. this.pendingForAckMsgToken = this.msgTokenGenerator();
  803. context.Outgoing.Write(
  804. new CaculatorDbRequest_Write_Set_AuthStateMode_MinFuelingVol_MinDisplayVol(this.ifsfRecipientSubnet,
  805. this.ifsfRecipientNode,
  806. this.ifsfSelfSubnet,
  807. this.ifsfSelfNode,
  808. this.pendingForAckMsgToken.Value,
  809. CaculatorDbRequest_Write_Set_AuthStateMode_MinFuelingVol_MinDisplayVol.Caculator_Auth_State_Mode.AUTH_State_Allowed));
  810. this.CurrentStatus = Status.Wait_ACK_Set_AUTH_MODE;
  811. }
  812. //if (++next_Clear_ProductNumber_In_Caculator_SlotIndex <= 8)
  813. //this.CurrentStatus = Status.Sending_Link_Meter_To_CaculatorSlot;
  814. //logger.Info("PumpInitializer, node " + ifsfRecipientNode + " sending MeterDbRequest_Write_SetMesureToProduct(first), meterId: "
  815. // + next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index + ", 2nd arg: " + next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index);
  816. //this.pendingForAckMsgToken = this.msgTokenGenerator();
  817. //context.Outgoing.Write(
  818. // new MeterDbRequest_Write_SetMesureToProduct(this.ifsfRecipientSubnet,
  819. // this.ifsfRecipientNode,
  820. // this.ifsfSelfSubnet,
  821. // this.ifsfSelfNode,
  822. // this.pendingForAckMsgToken.Value,
  823. // next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index,
  824. // next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index));
  825. //this.CurrentStatus = Status.Wait_ACK_Link_Meter_To_ProductDb_ProductNoSlot;
  826. }
  827. break;
  828. }
  829. //case Status.Wait_ACK_Link_Meter_To_ProductDb_ProductNoSlot:
  830. // {
  831. // if (context.Incoming.Message is AcknowledgeMessage ifsfMsg && ifsfMsg.MessageType == MessageType.IFSF_MESSAGE_TYPE_ACK
  832. // && ifsfMsg.MessageToken == this.pendingForAckMsgToken.Value)
  833. // {
  834. // if (ifsfMsg.OverallStatus != MessageAcknowledgeStatus.ACK_PositiveAcknowledgeDataReceived)
  835. // logger.Error(" node " + ifsfRecipientNode + ", link meter to ProductDb failed!");
  836. // logger.Info(" PumpInitializer, MeterDbRequest_Write_SetMesureToProduct with msgToken:" + this.pendingForAckMsgToken.Value + " Acked.");
  837. // if (this.thisTqcProductBarcodes.Count >= ++next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index)
  838. // {
  839. // //this.CurrentStatus = Status.Sending_Set_ProductNumber_In_Caculator;
  840. // this.pendingForAckMsgToken = this.msgTokenGenerator();
  841. // // put 91 to 98 to caculator 8 slots.
  842. // string operatingProductNumber = this.thisTqcProductBarcodes[next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index - 1].ToString();
  843. // logger.Info("PumpInitializer, node " + ifsfRecipientNode + " sending ProductDbRequest_Write_SetProductNumber, ProductDb ProductNoSlot: "
  844. // + next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index + ", productNo: " + operatingProductNumber);
  845. // context.Outgoing.Write(
  846. // new ProductDbRequest_Write_SetProductNumber(this.ifsfRecipientSubnet,
  847. // this.ifsfRecipientNode,
  848. // this.ifsfSelfSubnet,
  849. // this.ifsfSelfNode,
  850. // this.pendingForAckMsgToken.Value,
  851. // next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index, operatingProductNumber));
  852. // this.CurrentStatus = Status.Wait_ACK_Set_ProductNumber_In_ProductDb;
  853. // }
  854. // else
  855. // {
  856. // next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index = 1;
  857. // logger.Info("PumpInitializer, node " + ifsfRecipientNode + " Link_Meter_To_ProductDb_ProductNoSlot done!");
  858. // //this.CurrentStatus = Status.Sending_Set_AUTH_MODE;
  859. // }
  860. // }
  861. // break;
  862. // }
  863. case Status.Wait_ACK_Set_AUTH_MODE:
  864. {
  865. if (context.Incoming.Message is IfsfMessage ifsfMsg && ifsfMsg.MessageType == MessageType.IFSF_MESSAGE_TYPE_ACK
  866. && ifsfMsg.MessageToken == this.pendingForAckMsgToken.Value)
  867. {
  868. logger.Info("PumpInitializer, node " + ifsfRecipientNode + " CaculatorDbRequest_Write_Set_AuthStateMode_MinFuelingVol_MinDisplayVol Acked.");
  869. var targetBarcode = this.thisTqcProductBarcodes[next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index - 1];
  870. int newInitPriceWithoutDecimalPoints;
  871. if (this.PriceBook.ContainsKey(targetBarcode))
  872. newInitPriceWithoutDecimalPoints = this.PriceBook[targetBarcode];
  873. else
  874. {
  875. // try load the existed pre-configed price value which just read from TQC pump.
  876. var preConfigedPriceOnPump = this.productPerFuellingModeDb_ProductPrice_Answers.FirstOrDefault(p => p.FuelModeId == 0x11 && p.ProductNumber == targetBarcode.ToString().PadLeft(8, '0'))?.Price;
  877. if (string.IsNullOrEmpty(preConfigedPriceOnPump))
  878. newInitPriceWithoutDecimalPoints = 1883 + next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index;
  879. else
  880. newInitPriceWithoutDecimalPoints = int.Parse(preConfigedPriceOnPump);
  881. this.PriceBook.Add(targetBarcode, newInitPriceWithoutDecimalPoints);
  882. }
  883. logger.Info("PumpInitializer, node " + ifsfRecipientNode + " sending ProductPerFuellingModeDbRequest_Write_SetPrice, productNo: "
  884. + targetBarcode.ToString()
  885. + ", new price(without decimalPoints): " + newInitPriceWithoutDecimalPoints.ToString());
  886. this.pendingForAckMsgToken = this.msgTokenGenerator();
  887. context.Outgoing.Write(
  888. new ProductPerFuellingModeDbRequest_Write_SetPrice(this.ifsfRecipientSubnet,
  889. this.ifsfRecipientNode,
  890. this.ifsfSelfSubnet,
  891. this.ifsfSelfNode,
  892. this.pendingForAckMsgToken.Value,
  893. targetBarcode.ToString(), newInitPriceWithoutDecimalPoints.ToString()
  894. , 0x11)
  895. );
  896. this.CurrentStatus = Status.Wait_ACK_Set_Price;
  897. }
  898. break;
  899. }
  900. case Status.Wait_ACK_Set_Price:
  901. {
  902. if (context.Incoming.Message is AcknowledgeMessage ifsfMsg && ifsfMsg.MessageType == MessageType.IFSF_MESSAGE_TYPE_ACK
  903. && ifsfMsg.MessageToken == this.pendingForAckMsgToken.Value)
  904. {
  905. if (ifsfMsg.OverallStatus != MessageAcknowledgeStatus.ACK_PositiveAcknowledgeDataReceived)
  906. logger.Error(" node " + ifsfRecipientNode + ", set price for product failed!");
  907. if (this.thisTqcProductBarcodes.Count >= ++next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index)
  908. {
  909. logger.Info("PumpInitializer, node " + ifsfRecipientNode + " ProductPerFuellingModeDbRequest_Write_SetPrice Acked.");
  910. var targetBarcode = this.thisTqcProductBarcodes[next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index - 1];
  911. int newInitPriceWithoutDecimalPoints;
  912. if (this.PriceBook != null && this.PriceBook.ContainsKey(targetBarcode))
  913. newInitPriceWithoutDecimalPoints = this.PriceBook[targetBarcode];
  914. else
  915. {
  916. // try load the existed pre-configed price value which just read from TQC pump.
  917. var preConfigedPriceOnPump = this.productPerFuellingModeDb_ProductPrice_Answers.FirstOrDefault(p => p.FuelModeId == 0x11 && p.ProductNumber == targetBarcode.ToString().PadLeft(8, '0'))?.Price;
  918. if (string.IsNullOrEmpty(preConfigedPriceOnPump))
  919. newInitPriceWithoutDecimalPoints = 1883 + next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index;
  920. else
  921. newInitPriceWithoutDecimalPoints = int.Parse(preConfigedPriceOnPump);
  922. this.PriceBook.Add(targetBarcode, newInitPriceWithoutDecimalPoints);
  923. }
  924. logger.Info("PumpInitializer, node " + ifsfRecipientNode + " sending ProductPerFuellingModeDbRequest_Write_SetPrice, productNo: "
  925. + targetBarcode.ToString()
  926. + ", new price(without decimalPoints): " + newInitPriceWithoutDecimalPoints.ToString());
  927. this.pendingForAckMsgToken = this.msgTokenGenerator();
  928. //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());
  929. context.Outgoing.Write(
  930. new ProductPerFuellingModeDbRequest_Write_SetPrice(this.ifsfRecipientSubnet,
  931. this.ifsfRecipientNode,
  932. this.ifsfSelfSubnet,
  933. this.ifsfSelfNode,
  934. this.pendingForAckMsgToken.Value, targetBarcode.ToString(), newInitPriceWithoutDecimalPoints.ToString(), 0x11)
  935. );
  936. this.CurrentStatus = Status.Wait_ACK_Set_Price;
  937. }
  938. else
  939. {
  940. next_Clear_ProductNumber_In_ProductDb_ProductNoSlot_Index = 1;
  941. logger.Info("PumpInitializer, node " + ifsfRecipientNode + " set product Price(8 products) in fuel mode 0x11 done!");
  942. //this.CurrentStatus = Status.Sending_Set_Nozzle_To_CacalatorSlot;
  943. // now we only have fuelling mode 0x11.
  944. logger.Info("PumpInitializer, node " + ifsfRecipientNode + " Send FuellingPointDbRequest_Write_SetDefaultFuellingMode,\r\n" +
  945. "FP: 0x" + this.pumpHandlers.ElementAt(next_Fp_Index - 1).PumpPhysicalId.ToHexLogString() + " set to fuelling mode 0x11");
  946. this.pendingForAckMsgToken = this.msgTokenGenerator();
  947. context.Outgoing.Write(
  948. new FuellingPointDbRequest_Write_SetDefaultFuellingMode(this.ifsfRecipientSubnet,
  949. this.ifsfRecipientNode,
  950. this.ifsfSelfSubnet,
  951. this.ifsfSelfNode,
  952. this.pendingForAckMsgToken.Value, (byte)(this.pumpHandlers.ElementAt(next_Fp_Index - 1).PumpPhysicalId), 1));
  953. this.CurrentStatus = Status.Wait_ACK_Set_FP_Default_FuellingMode;
  954. }
  955. }
  956. break;
  957. }
  958. //case Status.Wait_ACK_Set_Nozzle_To_ProductDb_ProductNoSlot:
  959. // {
  960. // if (context.Incoming.Message is AcknowledgeMessage ifsfMsg && ifsfMsg.MessageType == MessageType.IFSF_MESSAGE_TYPE_ACK
  961. // && ifsfMsg.MessageToken == this.pendingForAckMsgToken.Value)
  962. // {
  963. // if (ifsfMsg.OverallStatus != MessageAcknowledgeStatus.ACK_PositiveAcknowledgeDataReceived)
  964. // logger.Error(" node " + ifsfRecipientNode + ", set nozzle to ProductDb failed:\r\n " + ifsfMsg.ToLogString());
  965. // if (++next_site_nozzle_Index <= this.pumpHandlers.SelectMany(p => p.Nozzles).Count())
  966. // {
  967. // logger.Info("PumpInitializer, node " + ifsfRecipientNode + " LogicalNozzleDb_Write_SetNozzleProductAndMeter Acked.");
  968. // var next_site_nozzle = this.pumpHandlers.SelectMany(p => p.Nozzles).ElementAt(next_site_nozzle_Index - 1);
  969. // var productOnThisNozzleSitsInWhichCaculatorSlot =
  970. // thisTqcProductBarcodes.IndexOf(nozzleProductConfig.First(p => p.NozzleLogicalId == next_site_nozzle.LogicalId && p.PumpId == next_site_nozzle.PumpId).ProductBarcode) + 1;
  971. // this.pendingForAckMsgToken = this.msgTokenGenerator();
  972. // byte targetIfsfFpId = this.pumpHandlers.First(p => p.PumpId == next_site_nozzle.PumpId).ifsfFuelPointId;
  973. // byte targetIfsfNozzleId = ((byte)(0x11 + next_site_nozzle.LogicalId - 1));
  974. // logger.Info("PumpInitializer, node " + ifsfRecipientNode + " sending LogicalNozzleDb_Write_SetNozzleProductAndMeter,\r\n" +
  975. // "set product to nozzle, FP: 0x" + targetIfsfFpId.ToHexLogString()
  976. // + ", nozzle: 0x" + targetIfsfNozzleId.ToHexLogString()
  977. // + ", PumpId: " + next_site_nozzle.PumpId + " map to ProductDb ProductNo Slot: " + productOnThisNozzleSitsInWhichCaculatorSlot);
  978. // context.Outgoing.Write(
  979. // new LogicalNozzleDb_Write_SetNozzleProductAndMeter(this.ifsfRecipientSubnet,
  980. // this.ifsfRecipientNode,
  981. // this.ifsfSelfSubnet,
  982. // this.ifsfSelfNode,
  983. // this.pendingForAckMsgToken.Value,
  984. // targetIfsfFpId
  985. // //assume logical id is 1 based.
  986. // , targetIfsfNozzleId,
  987. // (byte)productOnThisNozzleSitsInWhichCaculatorSlot, 1)
  988. // );
  989. // this.CurrentStatus = Status.Wait_ACK_Set_Nozzle_To_ProductDb_ProductNoSlot;
  990. // }
  991. // else
  992. // {
  993. // next_site_nozzle_Index = 1;
  994. // logger.Info("PumpInitializer, node " + ifsfRecipientNode + " set fp nozzles to ProductDb ProductNo Slot done!");
  995. // }
  996. // }
  997. // break;
  998. // }
  999. case Status.Wait_ACK_Set_FP_Default_FuellingMode:
  1000. {
  1001. if (context.Incoming.Message is IfsfMessage ifsfMsg && ifsfMsg.MessageType == MessageType.IFSF_MESSAGE_TYPE_ACK
  1002. && ifsfMsg.MessageToken == this.pendingForAckMsgToken.Value)
  1003. {
  1004. if (++next_Fp_Index <= this.pumpHandlers.Count())
  1005. {
  1006. logger.Info("PumpInitializer, node " + ifsfRecipientNode + " FuellingPointDbRequest_Write_SetDefaultFuellingMode Acked");
  1007. // now we only have fuelling mode 0x11.
  1008. logger.Info("PumpInitializer, node " + ifsfRecipientNode + " Send FuellingPointDbRequest_Write_SetDefaultFuellingMode,\r\n" +
  1009. "FP Default fuelling mode, FP: 0x" + this.pumpHandlers.ElementAt(next_Fp_Index - 1).PumpPhysicalId.ToHexLogString());
  1010. this.pendingForAckMsgToken = this.msgTokenGenerator();
  1011. context.Outgoing.Write(
  1012. new FuellingPointDbRequest_Write_SetDefaultFuellingMode(this.ifsfRecipientSubnet,
  1013. this.ifsfRecipientNode,
  1014. this.ifsfSelfSubnet,
  1015. this.ifsfSelfNode,
  1016. this.pendingForAckMsgToken.Value, (byte)(this.pumpHandlers.ElementAt(next_Fp_Index - 1).PumpPhysicalId), 1));
  1017. this.CurrentStatus = Status.Wait_ACK_Set_FP_Default_FuellingMode;
  1018. }
  1019. else
  1020. {
  1021. next_Fp_Index = 1;
  1022. logger.Info("PumpInitializer, node " + ifsfRecipientNode + " set fp default fuelling mode all done!");
  1023. logger.Info("PumpInitializer, node " + ifsfRecipientNode + " DONE!!!");
  1024. this.CurrentStatus = Status.Done;
  1025. var safe = this.OnInitDone;
  1026. safe?.Invoke(this, null);
  1027. }
  1028. }
  1029. break;
  1030. }
  1031. }
  1032. return true;
  1033. }
  1034. public bool IsInitDone => this.CurrentStatus == Status.Done;
  1035. public void Reset()
  1036. {
  1037. this.CurrentStatus = Status.UnInit;
  1038. this.initTimeoutTimer.Stop();
  1039. this.logicalNozzleDb_Nozzle_ProductInfo_PhyId_Answers.Clear();
  1040. this.productDb_ProductNo_Answers.Clear();
  1041. this.productPerFuellingModeDb_ProductPrice_Answers.Clear();
  1042. }
  1043. }
  1044. #region IDisposable Support
  1045. private bool disposedValue = false; // To detect redundant calls
  1046. protected virtual void Dispose(bool disposing)
  1047. {
  1048. if (!disposedValue)
  1049. {
  1050. if (disposing)
  1051. {
  1052. // TODO: dispose managed state (managed objects).
  1053. }
  1054. // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
  1055. // TODO: set large fields to null.
  1056. disposedValue = true;
  1057. }
  1058. }
  1059. // TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
  1060. // ~PumpHandler() {
  1061. // // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
  1062. // Dispose(false);
  1063. // }
  1064. // This code added to correctly implement the disposable pattern.
  1065. public void Dispose()
  1066. {
  1067. // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
  1068. Dispose(true);
  1069. // TODO: uncomment the following line if the finalizer is overridden above.
  1070. // GC.SuppressFinalize(this);
  1071. }
  1072. IEnumerator<IFdcPumpController> IEnumerable<IFdcPumpController>.GetEnumerator()
  1073. {
  1074. return this.pumpHandlers.GetEnumerator();
  1075. }
  1076. #endregion
  1077. }
  1078. }