PumpGroupHandler.cs 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. using Edge.Core.Processor;using Edge.Core.IndustryStandardInterface.Pump;
  2. using System;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. using System.Text;
  7. using System.Threading.Tasks;
  8. using System.Xml;
  9. using Global_Pump_Fdc.MessageEntity;
  10. using Global_Pump_Fdc.MessageEntity.Outgoing;
  11. using System.Collections.Specialized;
  12. using Edge.Core.Processor;using Edge.Core.IndustryStandardInterface.Pump;
  13. namespace Global_Pump_Fdc
  14. {
  15. public class PumpGroupHandler : IEnumerable<IFdcPumpController>, IDeviceHandler<object, FccMessageBase>
  16. {
  17. static NLog.Logger logger = NLog.LogManager.LoadConfiguration("nlog.config").GetLogger("PumpHandler");
  18. protected IContext<object, FccMessageBase> context;
  19. protected int pollingInterval;
  20. protected List<PumpHandler> pumpHandlers = new List<PumpHandler>();
  21. /// <summary>
  22. /// if the underlying communicator connected to remote device.
  23. /// </summary>
  24. private bool isCommConnected = false;
  25. private int amountDecimalDigits;
  26. private int volumeDecimalDigits;
  27. private int priceDecimalDigits;
  28. private int volumeTotalizerDecimalDigits;
  29. public PumpGroupHandler(int amountDecimalDigits, int volumeDecimalDigits,
  30. int priceDecimalDigits, int volumeTotalizerDecimalDigits,
  31. string pumpGroupXmlConfiguration)
  32. {
  33. this.amountDecimalDigits = amountDecimalDigits;
  34. this.volumeDecimalDigits = volumeDecimalDigits;
  35. this.priceDecimalDigits = priceDecimalDigits;
  36. this.volumeTotalizerDecimalDigits = volumeTotalizerDecimalDigits;
  37. //sample of pumpGroupXmlConfiguration, the address is a config value in physical wayne dart
  38. //pump mother board, 1 - 32 is the acceptable values.
  39. //the reason introduce PumpGroupHandler, because wayne dart pump may run multiple pumps in single
  40. //rs485 com port.
  41. //<PumpGroup>
  42. // <Pump pumpId='1' physicalId='1'>
  43. // <Nozzles>
  44. // <Nozzle logicalId='1' physicalId='1' />
  45. // <Nozzle logicalId='2' physicalId='2' />
  46. // <Nozzle logicalId='3' physicalId='3' />
  47. // </Nozzles>
  48. // </Pump>
  49. // <Pump pumpId='2' physicalId='2'>
  50. // <Nozzles>
  51. // <Nozzle logicalId='1' physicalId='1' />
  52. // <Nozzle logicalId='2' physicalId='2' />
  53. // </Nozzles>
  54. // </Pump>
  55. //</PumpGroup>
  56. XmlDocument xmlDocument = new XmlDocument();
  57. xmlDocument.LoadXml(pumpGroupXmlConfiguration);
  58. ////var rootElement = xmlDocument.GetElementsByTagName("PumpGroup").Cast<XmlElement>().First();
  59. var pumpElements = xmlDocument.GetElementsByTagName("Pump");
  60. logger.Info("Global Fdc pump group, Will create " + pumpElements.Count + " pump handlers for this Global Fdc Group from local config");
  61. this.CreatePumpHandlers(pumpElements);
  62. }
  63. protected virtual void CreatePumpHandlers(XmlNodeList pumpElements)
  64. {
  65. foreach (XmlNode pumpElement in pumpElements)
  66. {
  67. var pumpId =
  68. int.Parse(pumpElement.Attributes["pumpId"].Value);
  69. var pumpHandler = new PumpHandler(this, pumpId,
  70. amountDecimalDigits, volumeDecimalDigits,
  71. priceDecimalDigits, volumeTotalizerDecimalDigits,
  72. pumpElement.OuterXml);
  73. this.pumpHandlers.Add(pumpHandler);
  74. }
  75. this.rotateMsgTokens.AddRange(Enumerable.Repeat(0, this.pumpHandlers.Select(s => s.PumpId).Max()));
  76. }
  77. public IEnumerator<IFdcPumpController> GetEnumerator()
  78. {
  79. return this.pumpHandlers.GetEnumerator();
  80. }
  81. IEnumerator IEnumerable.GetEnumerator()
  82. {
  83. return this.pumpHandlers.GetEnumerator();
  84. }
  85. /// <summary>
  86. /// key:value = pumpId:MsgToken
  87. /// </summary>
  88. private List<int> rotateMsgTokens = new List<int>();
  89. /// <summary>
  90. /// get a valid token which from >=1 and lessOrEqual F.
  91. /// NOTE, if ResetMessageTokenToAlign(pumpId) was called, the next token generated here will be 0, which is
  92. /// a special value used to align the comm with real pump side, and then if the comm eastablished, we
  93. /// should use 1 to F.
  94. /// </summary>
  95. /// <param name="pumpId"></param>
  96. /// <returns></returns>
  97. public byte GetNewMessageToken(int pumpId)
  98. {
  99. lock (rotateMsgTokens)
  100. {
  101. //return 0;
  102. if (rotateMsgTokens[pumpId - 1] > 0x0E)
  103. this.rotateMsgTokens[pumpId - 1] = 0;
  104. //var returnValue = this.rotateMsgTokens[pumpId - 1];
  105. //this.rotateMsgTokens[pumpId - 1] += 1;
  106. return (byte)(++this.rotateMsgTokens[pumpId - 1]);
  107. }
  108. }
  109. /// <summary>
  110. /// typically called after a data request was NAKed by pump side, 0 token used for
  111. /// re-align the comm from FC to real pump.
  112. /// </summary>
  113. /// <param name="pumpId"></param>
  114. public void ResetMessageTokenToAlign(int pumpId)
  115. {
  116. lock (rotateMsgTokens)
  117. this.rotateMsgTokens[pumpId - 1] = -1;
  118. }
  119. public void Init(IContext<object, FccMessageBase> context)
  120. {
  121. this.context = context;
  122. this.context.Communicator.OnConnected += (object sender, EventArgs e) => { this.isCommConnected = true; };
  123. this.context.Communicator.OnDisconnected += (object sender, EventArgs e) => { this.isCommConnected = false; };
  124. this.pumpHandlers.ForEach(p => p.Init(this.context));
  125. }
  126. public Task Process(IContext<object, FccMessageBase> context)
  127. {
  128. var parameters = context.Incoming.Message.Parameters as StringDictionary;
  129. if (parameters == null)
  130. {
  131. logger.Error("Read invalid FCC message" + context.Incoming.Message.Parameters);
  132. return Task.CompletedTask;
  133. }
  134. int pumpId = int.Parse(parameters["PumpID"]);
  135. if (pumpId == -1)
  136. {
  137. foreach (var phr in this.pumpHandlers)
  138. {
  139. phr.Process(context);
  140. }
  141. return Task.CompletedTask;
  142. }
  143. var ph = this.pumpHandlers.FirstOrDefault(p => p.PumpId == pumpId);
  144. if (ph == null)
  145. {
  146. logger.Error("PumpGroupHandler does not contain pumpHandler with physcialId: " + pumpId.ToString("X2"));
  147. return Task.CompletedTask;
  148. }
  149. return ph.Process(context);
  150. }
  151. }
  152. }