PumpGroupHandler.cs 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  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;
  12. using Edge.Core.IndustryStandardInterface.Pump;
  13. using Wayne.FDCPOSLibrary;
  14. using System.Xml;
  15. using Edge.Core.Database.Models;
  16. using System.Threading.Tasks;
  17. using Edge.Core.Processor.Communicator;
  18. using Edge.Core.Processor.Dispatcher.Attributes;
  19. using Microsoft.Extensions.Logging;
  20. using Microsoft.Extensions.Logging.Abstractions;
  21. using Stateless;
  22. using Edge.Core.Configuration;
  23. using Microsoft.Extensions.DependencyInjection;
  24. namespace ZhongSheng_NonIC_Pump
  25. {
  26. #region Ctor parameters
  27. public class PumpGroupConfig
  28. {
  29. /// <summary>
  30. /// 数据发送端的地址编号
  31. /// 一般是指FCC? 则应该是一个全局共享值,放0xE0
  32. /// </summary>
  33. public byte FccCommAddress { get; set; } = 0xE0;
  34. /// <summary>
  35. /// 数据接收端的地址编号
  36. /// 指油机端的配置值,应该是每个通讯链路都不一样,一个链路上可能有1个或者多个加油点
  37. /// </summary>
  38. public byte DispenserCommBoardAddress { get; set; }
  39. public List<PumpConfig> PumpConfigs { get; set; }
  40. }
  41. public class PumpConfig
  42. {
  43. /// <summary>
  44. /// used by Fcc inside, the classic pump id concept.
  45. /// </summary>
  46. public byte PumpId { get; set; }
  47. /// <summary>
  48. /// 枪号为以整个加油站为基础的油枪顺序编号
  49. /// 就是全站枪号?
  50. /// </summary>
  51. public byte DispenserSideNozzleId { get; set; }
  52. }
  53. #endregion
  54. /// <summary>
  55. /// 协议支持9600bps,8 位数据位,1 位起始位,1 位停止位,无校验位
  56. /// </summary>
  57. [MetaPartsRequired(typeof(HalfDuplexActivePollingDeviceProcessor<,>))]
  58. [MetaPartsRequired(typeof(ComPortCommunicator<>))]
  59. [MetaPartsRequired(typeof(TcpClientCommunicator<>))]
  60. [MetaPartsDescriptor(
  61. "lang-zh-cn:中升非IC卡加油机lang-en-us:ZhongSheng Non-IC card dispenser",
  62. "用于驱动 中升非IC卡 加油机, 它每把枪就是一个Pump即一个加油点,且油机上配置的枪号等同于全站枪号。此油机可以配置提枪直接出油,也可以配置成需要后台授权,请在加油机上配置(菜单IC卡支付方式中选择第4项即开启后台授权模式)。根据油机方的技术人员说明,我们中控这边对接的油机,都会是单枪单显,或者是2枪2显,不会有单面双单价的型号。 原生支持 8位数据位,1位起始位,1位停止位,无校验位RS422。",
  63. new[] { "lang-zh-cn:加油机lang-en-us:Pump" })]
  64. public class PumpGroupHandler : IEnumerable<IFdcPumpController>, IDeviceHandler<byte[], MessageTemplateBase>
  65. {
  66. private IServiceProvider services;
  67. private ILogger logger = NullLogger.Instance;
  68. public PumpGroupConfig pumpGroupConfig;
  69. protected IEnumerable<NozzleExtraInfo> nozzleExtraInfos;
  70. protected IContext<byte[], MessageTemplateBase> context;
  71. protected IEnumerable<StatePumpHandler> pumpHandlers;
  72. private object rotateFrameNo_Guard = new object();
  73. /// <summary>
  74. /// </summary>
  75. private byte rotateFrameNo = 0;
  76. /// <summary>
  77. /// get a valid FrameNo which from >=1 and <= 0x3F.
  78. /// </summary>
  79. /// <returns></returns>
  80. public byte GenerateNewFrameNo()
  81. {
  82. lock (this.rotateFrameNo_Guard)
  83. {
  84. //return 0;
  85. if (this.rotateFrameNo > 0x3E)
  86. this.rotateFrameNo = 0;
  87. return (byte)(++this.rotateFrameNo);
  88. }
  89. }
  90. [ParamsJsonSchemas("PumpGroupHandlerCtorParamsJsonSchemas")]
  91. public PumpGroupHandler(PumpGroupConfig pumpGroupConfig, IServiceProvider services)
  92. {
  93. this.pumpGroupConfig = pumpGroupConfig;
  94. this.services = services;
  95. var loggerFactory = services.GetRequiredService<ILoggerFactory>();
  96. this.logger = loggerFactory.CreateLogger("PumpHandler");
  97. this.pumpHandlers =
  98. pumpGroupConfig.PumpConfigs.Select(pc =>
  99. new StatePumpHandler(this, pc.PumpId, pc.DispenserSideNozzleId, services)).ToList();
  100. }
  101. public void OnFdcServerInit(Dictionary<string, object> parameters)
  102. {
  103. if (parameters != null && parameters.TryGetValue("NozzleProductMapping", out object param))
  104. {
  105. this.nozzleExtraInfos = param as IEnumerable<NozzleExtraInfo>;
  106. }
  107. }
  108. public void Init(IContext<byte[], MessageTemplateBase> context)
  109. {
  110. this.context = context;
  111. var timeWindowWithActivePollingOutgoing =
  112. this.context.Outgoing as TimeWindowWithActivePollingOutgoing<byte[], MessageTemplateBase>;
  113. //this.pollingInterval = timeWindowWithActivePollingOutgoing.PollingInterval;
  114. timeWindowWithActivePollingOutgoing.PollingMsgProducer =
  115. () =>
  116. {
  117. //if (!this.isCommConnected) return null;
  118. return new GenericInquiryRequest()
  119. {
  120. SourceAddress = this.pumpGroupConfig.FccCommAddress,
  121. TargetAddress = this.pumpGroupConfig.DispenserCommBoardAddress,
  122. FrameSeqNo = this.GenerateNewFrameNo(),
  123. };// this.GetNewMessageToken(target.PumpId));
  124. };
  125. this.pumpHandlers.ToList().ForEach(p => p.Init(this.context));
  126. this.context.Incoming.OnLongTimeNoSeeMessage += (_, __) =>
  127. {
  128. this.pumpHandlers.ToList().ForEach(p => p.TriggerPumpOffline());
  129. };
  130. this.context.Incoming.LongTimeNoSeeMessageTimeout = 6000;
  131. }
  132. public async Task Process(IContext<byte[], MessageTemplateBase> context)
  133. {
  134. this.context = context;
  135. //var ph = this.pumpHandlers.FirstOrDefault(p => (byte)(p.PumpPhysicalId) == context.Incoming.Message.SourceAddress);
  136. //if (ph == null)
  137. //{
  138. // logger.LogInformation("PumpGroupHandler does not contain pumpHandler with physcialId: "
  139. // + context.Incoming.Message.SourceAddress.ToString("X2"));
  140. // return Task.CompletedTask;
  141. //}
  142. //有可能是设备端是2枪2显,但将区别的逻辑放入到pumpHandler里面去处理
  143. foreach (var ph in this.pumpHandlers)
  144. await ph.Process(context);
  145. }
  146. public IEnumerator<IFdcPumpController> GetEnumerator()
  147. {
  148. return this.pumpHandlers.GetEnumerator();
  149. }
  150. IEnumerator IEnumerable.GetEnumerator()
  151. {
  152. return this.pumpHandlers.GetEnumerator();
  153. }
  154. }
  155. }