SilentPumpHandler.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Collections.ObjectModel;
  4. using System.Configuration;
  5. using System.IO.Ports;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Threading;
  9. using Timer = System.Timers.Timer;
  10. using System.Collections;
  11. using Edge.Core.Processor;using Edge.Core.IndustryStandardInterface.Pump;
  12. using Wayne.FDCPOSLibrary;
  13. using System.Xml;
  14. using Edge.Core.Database.Models;
  15. using System.Threading.Tasks;
  16. namespace FuRen_Sinopec_IcCardReader
  17. {
  18. /// <summary>
  19. /// This pump handler only listen the ic card reader, will never send message.
  20. /// </summary>
  21. public class SilentPumpHandler : IFdcPumpController, IDeviceHandler<byte[], KaJiLianDongV11MessageTemplateBase>
  22. {
  23. static NLog.Logger logger = NLog.LogManager.LoadConfiguration("nlog.config").GetLogger("PumpHandler");
  24. protected IContext<byte[], KaJiLianDongV11MessageTemplateBase> context;
  25. public event EventHandler<FdcPumpControllerOnStateChangeEventArg> OnStateChange;
  26. /// <summary>
  27. /// fired on fueling process is on going, the fuel amount should keep changing.
  28. /// </summary>
  29. public event EventHandler<FdcTransactionDoneEventArg> OnCurrentFuellingStatusChange;
  30. protected LogicalDeviceState lastLogicalDeviceState = LogicalDeviceState.FDC_CLOSED;
  31. private DateTime lastLogicalDeviceStateReceivedTime;
  32. // by seconds
  33. private const int lastLogicalDeviceStateExpiredTime = 6;
  34. private Guid uniqueId = Guid.NewGuid();
  35. private int pumpId = -1;
  36. protected List<LogicalNozzle> nozzles = new List<LogicalNozzle>();
  37. public IEnumerable<LogicalNozzle> Nozzles => this.nozzles;
  38. /// <summary>
  39. /// </summary>
  40. /// <param name="pumpId"></param>
  41. /// <param name="nozzlesXmlConfiguration"></param>
  42. public SilentPumpHandler(int pumpId)
  43. {
  44. this.pumpId = pumpId;
  45. //this.nozzles.Add(new LogicalNozzle(pumpId, 1, 1, null));
  46. }
  47. public void Init(IContext<byte[], KaJiLianDongV11MessageTemplateBase> context)
  48. {
  49. this.context = context;
  50. }
  51. public virtual async Task Process(IContext<byte[], KaJiLianDongV11MessageTemplateBase> context)
  52. {
  53. this.context = context;
  54. this.lastLogicalDeviceStateReceivedTime = DateTime.Now;
  55. //PumpStateChangeCommand -- it's also the PC polling message response from pump.
  56. //PumpNotifyTransactionDoneCommand
  57. if (this.lastLogicalDeviceState == LogicalDeviceState.FDC_OFFLINE)
  58. {
  59. logger.Info("Pump: " + this.pumpId + ", " + "Recevied an IcCard Msg in FDC_OFFLINE state, " +
  60. "indicates the underlying connection is established, switch to FDC_READY");
  61. this.lastLogicalDeviceState = LogicalDeviceState.FDC_READY;
  62. var safe = this.OnStateChange;
  63. safe?.Invoke(this, new FdcPumpControllerOnStateChangeEventArg(LogicalDeviceState.FDC_READY));
  64. }
  65. if (context.Incoming.Message is PumpStateChangeCommand PumpStateChangeCommand)
  66. {
  67. if (PumpStateChangeCommand.StateNozzleOperatingSubMessages == null
  68. && PumpStateChangeCommand.StateNozzleOperatingSubMessages == null)
  69. {
  70. if (this.lastLogicalDeviceState != LogicalDeviceState.FDC_READY)
  71. {
  72. this.lastLogicalDeviceState = LogicalDeviceState.FDC_READY;
  73. var safe2 = this.OnStateChange;
  74. safe2?.Invoke(this, new FdcPumpControllerOnStateChangeEventArg(
  75. LogicalDeviceState.FDC_READY,
  76. this.nozzles.FirstOrDefault()));
  77. }
  78. }
  79. if (PumpStateChangeCommand.StateNozzleOperatingSubMessages != null
  80. && PumpStateChangeCommand.StateNozzleOperatingSubMessages.Any(n =>
  81. n.St状态字 == PumpStateChangeNozzleOperatingSubState.PumpStateChangeCode.抬枪或加油中))
  82. {
  83. if (!this.nozzles.Any())
  84. this.nozzles.Add(new LogicalNozzle(this.pumpId, 0,
  85. PumpStateChangeCommand.StateNozzleOperatingSubMessages.First().MZN枪号,
  86. PumpStateChangeCommand.StateNozzleOperatingSubMessages.First().PRC价格));
  87. if (this.lastLogicalDeviceState != LogicalDeviceState.FDC_FUELLING)
  88. {
  89. this.lastLogicalDeviceState = LogicalDeviceState.FDC_FUELLING;
  90. var safe = this.OnCurrentFuellingStatusChange;
  91. safe?.Invoke(this, new FdcTransactionDoneEventArg(new FdcTransaction()
  92. {
  93. Nozzle = this.nozzles.First(),
  94. Amount = PumpStateChangeCommand.StateNozzleOperatingSubMessages.First().AMN数额,
  95. Volumn = PumpStateChangeCommand.StateNozzleOperatingSubMessages.First().VOL升数,
  96. Price = PumpStateChangeCommand.StateNozzleOperatingSubMessages.First().PRC价格,
  97. Finished = false,
  98. }));
  99. }
  100. }
  101. }
  102. else if (context.Incoming.Message is PumpNotifyTransactionDoneCommand PumpNotifyTransactionDoneCommand)
  103. {
  104. if (!this.nozzles.Any())
  105. this.nozzles.Add(new LogicalNozzle(this.pumpId, 0,
  106. PumpNotifyTransactionDoneCommand.NZN_枪号,
  107. PumpNotifyTransactionDoneCommand.PRC_成交价格));
  108. var safe1 = this.OnCurrentFuellingStatusChange;
  109. safe1?.Invoke(this, new FdcTransactionDoneEventArg(new FdcTransaction()
  110. {
  111. // 恒山油机 一个加油点只有一把枪
  112. Nozzle = this.nozzles.First(),
  113. Amount = PumpNotifyTransactionDoneCommand.AMN数额,
  114. Volumn = PumpNotifyTransactionDoneCommand.VOL_升数,
  115. Price = PumpNotifyTransactionDoneCommand.PRC_成交价格,
  116. SequenceNumberGeneratedOnPhysicalPump = PumpNotifyTransactionDoneCommand.POS_TTC,
  117. //AmountTotalizer = ,
  118. VolumeTotalizer = PumpNotifyTransactionDoneCommand.V_TOT_升累计,
  119. Finished = true,
  120. }));
  121. }
  122. else
  123. {
  124. if (logger.IsDebugEnabled)
  125. logger.Debug("Incoming an unknown message, will do nothing and ignore.");
  126. }
  127. }
  128. public string Name => this.GetType().FullName;
  129. public Guid Id => this.uniqueId;
  130. /// <summary>
  131. /// Gets the Identification of the pump for the system. Is the logical number of the pump
  132. /// </summary>
  133. public int PumpId => this.pumpId;
  134. /// <summary>
  135. /// this pump have no way to share same comport since this HengShan protocol content does not contains
  136. /// any id info, so always static 0 here.
  137. /// 地址面地址
  138. /// </summary>
  139. public int PumpPhysicalId => 0;
  140. public int AmountDecimalDigits => 2;
  141. public int VolumeDecimalDigits => 2;
  142. public int PriceDecimalDigits => 2;
  143. public int VolumeTotalizerDecimalDigits => 2;
  144. public virtual async Task<LogicalDeviceState> QueryStatusAsync()
  145. {
  146. // if last state is expired, we return a OFFLINE here to FdcClient.
  147. if (DateTime.Now.Subtract(this.lastLogicalDeviceStateReceivedTime).TotalSeconds > lastLogicalDeviceStateExpiredTime)
  148. {
  149. if (this.lastLogicalDeviceState != LogicalDeviceState.FDC_OFFLINE)
  150. {
  151. this.lastLogicalDeviceState = LogicalDeviceState.FDC_OFFLINE;
  152. logger.Info("Pump: " + this.pumpId + ", " + " State switched to FDC_OFFLINE due to cached state expired");
  153. var safe0 = this.OnStateChange;
  154. safe0?.Invoke(this, new FdcPumpControllerOnStateChangeEventArg(LogicalDeviceState.FDC_OFFLINE, null));
  155. }
  156. return LogicalDeviceState.FDC_OFFLINE;
  157. }
  158. return this.lastLogicalDeviceState;
  159. }
  160. /// <summary>
  161. ///
  162. /// </summary>
  163. /// <returns>MoneyTotalizer:VolumnTotalizer</returns>
  164. public async Task<Tuple<int, int>> QueryTotalizerAsync(byte logicalNozzleId)
  165. {
  166. throw new NotImplementedException();
  167. }
  168. public virtual async Task<bool> ChangeFuelPriceAsync(int newPriceWithoutDecimalPoint, byte logicalNozzleId)
  169. {
  170. throw new NotImplementedException();
  171. }
  172. /// <summary>
  173. ///
  174. /// </summary>
  175. /// <param name="logicalNozzleId">useless for this type of pump, it always one pump one nozzle</param>
  176. /// <returns></returns>
  177. public virtual async Task<bool> AuthorizeAsync(byte logicalNozzleId)
  178. {
  179. throw new NotImplementedException();
  180. }
  181. /// <summary>
  182. ///
  183. /// </summary>
  184. /// <param name="moneyAmount"></param>
  185. /// <param name="logicalNozzleId">useless for this type of pump, it always one pump one nozzle</param>
  186. /// <returns></returns>
  187. public virtual async Task<bool> AuthorizeWithAmountAsync(int moneyAmountWithoutDecimalPoint, byte logicalNozzleId)
  188. {
  189. throw new NotImplementedException();
  190. }
  191. /// <summary>
  192. ///
  193. /// </summary>
  194. /// <param name="volumn"></param>
  195. /// <param name="logicalNozzleId">useless for this type of pump, it always one pump one nozzle</param>
  196. /// <returns></returns>
  197. public virtual async Task<bool> AuthorizeWithVolumeAsync(int volumnWithoutDecimalPoint, byte logicalNozzleId)
  198. {
  199. throw new NotImplementedException();
  200. }
  201. public virtual async Task<bool> FuelingRoundUpByAmountAsync(int amount)
  202. {
  203. throw new NotImplementedException();
  204. }
  205. #region not implemented
  206. public async Task<bool> UnAuthorizeAsync(byte logicalNozzleId)
  207. {
  208. throw new NotImplementedException();
  209. }
  210. public async Task<bool> SuspendFuellingAsync()
  211. {
  212. throw new NotImplementedException();
  213. }
  214. public async Task<bool> ResumeFuellingAsync()
  215. {
  216. throw new NotImplementedException();
  217. }
  218. public async Task<bool> FuelingRoundUpByVolumeAsync(int volume)
  219. { throw new NotImplementedException(); }
  220. #endregion
  221. /// <summary>
  222. /// </summary>
  223. protected Dictionary<byte, FuelSaleTransaction> logicalNozzleIdToLastFuelSaleTrxMapping = new Dictionary<byte, FuelSaleTransaction>();
  224. public void OnFdcServerInit(Dictionary<string, object> parameters)
  225. {
  226. if (parameters.ContainsKey("LastPriceChange"))
  227. {
  228. }
  229. /* Load Last sale(from db) for void the case of FC accidently disconnect from Pump in fueling,
  230. and may cause a fueling trx gone from FC control */
  231. if (parameters.ContainsKey("LastFuelSaleTrx"))
  232. {
  233. // nozzle logical id:lastSale
  234. //var lastFuelSaleTrxes = parameters["LastFuelSaleTrx"] as Dictionary<byte, FuelSaleTransaction>;
  235. //foreach (var lastFuelSaleTrx in lastFuelSaleTrxes)
  236. //{
  237. // logger.Info("Pump: " + this.pumpId + ", OnFdcServerInit, load last fuel sale " +
  238. // "on logical nozzle: " + lastFuelSaleTrx.Key + " with value: " + lastFuelSaleTrx.Value);
  239. // this.logicalNozzleIdToLastFuelSaleTrxMapping.Remove(lastFuelSaleTrx.Key);
  240. // this.logicalNozzleIdToLastFuelSaleTrxMapping.Add(lastFuelSaleTrx.Key, lastFuelSaleTrx.Value);
  241. //}
  242. }
  243. }
  244. public async Task<bool> LockNozzleAsync(byte logicalNozzleId)
  245. {
  246. return false;
  247. }
  248. public async Task<bool> UnlockNozzleAsync(byte logicalNozzleId)
  249. {
  250. return false;
  251. }
  252. }
  253. }