StatePumpHandler.cs 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539
  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 Microsoft.Extensions.DependencyInjection;
  23. namespace ZhongSheng_NonIC_Pump
  24. {
  25. public class StatePumpHandler : IFdcPumpController//, IDeviceHandler<byte[], MessageTemplateBase>
  26. {
  27. private IServiceProvider services;
  28. private IContext<byte[], MessageTemplateBase> context;
  29. private ILogger logger = NullLogger.Instance;
  30. private PumpGroupHandler parent;
  31. private LogicalDeviceState currentState = LogicalDeviceState.FDC_OFFLINE;
  32. public event EventHandler<FdcPumpControllerOnStateChangeEventArg> OnStateChange;
  33. /// <summary>
  34. /// fired on fueling process is on going, the fuel amount should keep changing.
  35. /// </summary>
  36. public event EventHandler<FdcTransactionDoneEventArg> OnCurrentFuellingStatusChange;
  37. StateMachine<LogicalDeviceState, Trigger> stateless
  38. = new StateMachine<LogicalDeviceState, Trigger>(LogicalDeviceState.FDC_OFFLINE);
  39. protected List<LogicalNozzle> nozzles;
  40. public IEnumerable<LogicalNozzle> Nozzles => this.nozzles;
  41. protected enum Trigger
  42. {
  43. //AnyPumpMsgReceived,
  44. AnyPumpMsgHaveNotReceivedForWhile,
  45. NozzleLifted_And_开机,
  46. NozzleLifted_And_停机,
  47. NozzleReplaced_And_开机,
  48. NozzleReplaced_And_停机,
  49. NozzleFuelNumbersIsRunning,
  50. //PumpAuthorizedByFC,
  51. }
  52. public int AmountDecimalDigits => 2;
  53. public int VolumeDecimalDigits => 2;
  54. public int PriceDecimalDigits => 2;
  55. public int VolumeTotalizerDecimalDigits => 2;
  56. /// <summary>
  57. /// </summary>
  58. public int PumpId { get; private set; }
  59. /// <summary>
  60. /// will set it to 油机端的配置值,枪号为以整个加油站为基础的油枪顺序编号, 就是全站枪号
  61. /// </summary>
  62. public int PumpPhysicalId { get; private set; }
  63. public string Name => "ZhongSheng_NonIC_Pump";
  64. /// <summary>
  65. /// 每把枪就是一个Pump即一个加油点
  66. /// </summary>
  67. /// <param name="pumpId"></param>
  68. /// <param name="dispenserSideNozzleId">油机端的配置值,枪号为以整个加油站为基础的油枪顺序编号, 就是全站枪号?</param>
  69. public StatePumpHandler(PumpGroupHandler parent, byte pumpId,
  70. byte dispenserSideNozzleId, IServiceProvider services)
  71. {
  72. this.parent = parent;
  73. this.services = services;
  74. var loggerFactory = services.GetRequiredService<ILoggerFactory>();
  75. this.logger = loggerFactory.CreateLogger("PumpHandler");
  76. this.PumpId = pumpId;
  77. this.PumpPhysicalId = dispenserSideNozzleId;
  78. //每把枪就是一个Pump即一个加油点
  79. this.nozzles = new List<LogicalNozzle>() { new LogicalNozzle(pumpId, dispenserSideNozzleId, 1, null) };
  80. }
  81. internal void TriggerPumpOffline()
  82. {
  83. if (this.currentState != LogicalDeviceState.FDC_OFFLINE)
  84. {
  85. this.currentState = LogicalDeviceState.FDC_OFFLINE;
  86. this.OnStateChange?.Invoke(this, new FdcPumpControllerOnStateChangeEventArg(LogicalDeviceState.FDC_OFFLINE));
  87. }
  88. }
  89. public void Init(IContext<byte[], MessageTemplateBase> context)
  90. {
  91. this.context = context;
  92. }
  93. public async Task Process(IContext<byte[], MessageTemplateBase> context)
  94. {
  95. this.context = context;
  96. if (context.Incoming.Message is PumpInIdleResponse)
  97. {
  98. if (this.currentState != LogicalDeviceState.FDC_READY)
  99. {
  100. logger.LogDebug("Pump: " + this.PumpId + ", Switched to FDC_READY from " + this.currentState + " by received a PumpInIdleResponse");
  101. this.currentState = LogicalDeviceState.FDC_READY;
  102. this.OnStateChange?.Invoke(this, new FdcPumpControllerOnStateChangeEventArg(LogicalDeviceState.FDC_READY));
  103. }
  104. }
  105. else if (context.Incoming.Message is PumpInOperationResponse pumpInOperation)
  106. {
  107. if (pumpInOperation.PumpStateBlocks?.Any(s => s.NozzleNumber == this.PumpPhysicalId) ?? false)
  108. {
  109. var pumpStateBlock = pumpInOperation.PumpStateBlocks.First(s => s.NozzleNumber == this.PumpPhysicalId);
  110. if (pumpStateBlock.NozzleLiftState == NozzleLiftStateEnum.未提)
  111. {
  112. if (this.currentState != LogicalDeviceState.FDC_READY)
  113. {
  114. logger.LogDebug("Pump: " + this.PumpId + ", Switched to FDC_READY from " + this.currentState + " by PumpState-> " + pumpStateBlock.ToString());
  115. //if (this.currentState == LogicalDeviceState.FDC_OFFLINE)
  116. // logger.LogInformation("Pump: " + this.PumpId + ", Pump side 加油机状态信息配置: " + pumpStateBlock.ToString());
  117. //if (this.currentState == LogicalDeviceState.FDC_FUELLING)
  118. // logger.LogDebug("Pump: " + this.PumpId + ", Pump side 加油机状态信息配置: " + pumpStateBlock.ToString());
  119. this.currentState = LogicalDeviceState.FDC_READY;
  120. this.OnStateChange?.Invoke(this, new FdcPumpControllerOnStateChangeEventArg(LogicalDeviceState.FDC_READY));
  121. }
  122. }
  123. else if (pumpStateBlock.NozzleLiftState == NozzleLiftStateEnum.已提)
  124. {
  125. if (pumpStateBlock.AuthMode == PumpAuthModeEnum.自授权模式)
  126. {
  127. /*in this mode, pump will auth itself and directly go into Athorized state, and then fuelling state.
  128. */
  129. if (this.currentState != LogicalDeviceState.FDC_AUTHORISED)
  130. {
  131. //simulate the Calling state by request from vendor for a temp solution, this will let the FdcServer trigger a authorize calling, but later he said this is not necessary.
  132. //logger.LogDebug("Pump: " + this.PumpId + ", Switched to simulated FDC_CALLING from " + this.currentState + " by PumpState-> " + pumpStateBlock.ToString());
  133. //this.currentState = LogicalDeviceState.FDC_CALLING;
  134. //this.OnStateChange?.Invoke(this, new FdcPumpControllerOnStateChangeEventArg(LogicalDeviceState.FDC_CALLING, this.nozzles.First()));
  135. logger.LogDebug("Pump: " + this.PumpId + ", Switched to FDC_AUTHORISED from " + this.currentState + " by PumpState-> " + pumpStateBlock.ToString());
  136. this.currentState = LogicalDeviceState.FDC_AUTHORISED;
  137. this.OnStateChange?.Invoke(this, new FdcPumpControllerOnStateChangeEventArg(LogicalDeviceState.FDC_AUTHORISED, this.nozzles.First()));
  138. }
  139. }
  140. else
  141. {
  142. if (pumpStateBlock.PumpAuthorizeState == PumpAuthorizeStateEnum.未授权
  143. && this.currentState != LogicalDeviceState.FDC_CALLING)
  144. {
  145. logger.LogDebug("Pump: " + this.PumpId + ", Switched to FDC_CALLING from " + this.currentState + " by PumpState-> " + pumpStateBlock.ToString());
  146. this.currentState = LogicalDeviceState.FDC_CALLING;
  147. this.OnStateChange?.Invoke(this, new FdcPumpControllerOnStateChangeEventArg(LogicalDeviceState.FDC_CALLING, this.nozzles.First()));
  148. }
  149. else if (pumpStateBlock.PumpAuthorizeState == PumpAuthorizeStateEnum.授权成功
  150. && this.currentState != LogicalDeviceState.FDC_AUTHORISED)
  151. {
  152. logger.LogDebug("Pump: " + this.PumpId + ", Switched to FDC_AUTHORISED from " + this.currentState + " by PumpState-> " + pumpStateBlock.ToString());
  153. this.currentState = LogicalDeviceState.FDC_AUTHORISED;
  154. this.OnStateChange?.Invoke(this, new FdcPumpControllerOnStateChangeEventArg(LogicalDeviceState.FDC_AUTHORISED, this.nozzles.First()));
  155. }
  156. }
  157. }
  158. else if (pumpStateBlock.NozzleLiftState == NozzleLiftStateEnum.第二条枪提起)
  159. {
  160. this.logger.LogCritical("根据油机方的技术人员说明,对于此项目,我们中控这边对接的油机,都会是单枪单显,或者是2枪2显,不会有单面双单价(2枪共一个加油点)的型号,但是为什么现在收到这样的数据?");
  161. //if (this.currentState != LogicalDeviceState.FDC_CALLING)
  162. //{
  163. // this.currentState = LogicalDeviceState.FDC_CALLING;
  164. // this.OnStateChange?.Invoke(this, new FdcPumpControllerOnStateChangeEventArg(LogicalDeviceState.FDC_CALLING, this.nozzles.First()));
  165. //}
  166. }
  167. }
  168. if (pumpInOperation.FuellingDataBlocks?.Any(s => s.NozzleNumber == this.PumpPhysicalId) ?? false)
  169. {
  170. var fuellingDataBlock = pumpInOperation.FuellingDataBlocks.First(s => s.NozzleNumber == this.PumpPhysicalId);
  171. if (this.currentState != LogicalDeviceState.FDC_FUELLING)
  172. {
  173. //sometimes the pump will not report authorized state and directly go into fuelling, so here add one from air for process completion.
  174. if (this.currentState != LogicalDeviceState.FDC_AUTHORISED)
  175. {
  176. logger.LogDebug("Pump: " + this.PumpId + ", Switched to FDC_AUTHORISED from " + this.currentState + " by manual inserting");
  177. this.currentState = LogicalDeviceState.FDC_AUTHORISED;
  178. this.OnStateChange?.Invoke(this, new FdcPumpControllerOnStateChangeEventArg(LogicalDeviceState.FDC_AUTHORISED, this.nozzles.First()));
  179. }
  180. logger.LogDebug("Pump: " + this.PumpId + ", Switched to FDC_FUELLING from " + this.currentState + " by received a FuellingDataBlock-> " + fuellingDataBlock.ToString());
  181. this.currentState = LogicalDeviceState.FDC_FUELLING;
  182. this.OnStateChange?.Invoke(this, new FdcPumpControllerOnStateChangeEventArg(LogicalDeviceState.FDC_FUELLING, this.nozzles.First()));
  183. }
  184. if (this.logger.IsEnabled(LogLevel.Trace))
  185. this.logger.LogTrace("Pump " + this.PumpId + ": Reporting Fuelling in progress: " + fuellingDataBlock.ToString());
  186. this.nozzles.First().RealPriceOnPhysicalPump = fuellingDataBlock.Price;
  187. this.OnCurrentFuellingStatusChange?.Invoke(this, new FdcTransactionDoneEventArg(new FdcTransaction()
  188. {
  189. Amount = fuellingDataBlock.Amount,
  190. Volumn = fuellingDataBlock.Volume,
  191. Finished = false,
  192. Nozzle = this.nozzles.First(),
  193. Price = fuellingDataBlock.Price,
  194. }));
  195. }
  196. }
  197. else if (context.Incoming.Message is PumpNotifyTransactionDoneEvent trxDoneEvent
  198. && trxDoneEvent.交易枪号 == this.PumpPhysicalId)
  199. {
  200. logger.LogDebug("Pump " + this.PumpId + ": " + "Report a trx done, 交易金额: " + trxDoneEvent.交易金额 +
  201. ", 油量总量: " + trxDoneEvent.油量总量 +
  202. ", 交易单价: " + trxDoneEvent.交易单价);
  203. this.context.Outgoing.Write(new AckPumpTransactionRequest(trxDoneEvent.FrameSeqNo)
  204. {
  205. SourceAddress = this.parent.pumpGroupConfig.FccCommAddress,
  206. TargetAddress = this.parent.pumpGroupConfig.DispenserCommBoardAddress,
  207. });
  208. // at least within 62 years, exception will not throw here
  209. int newTrxSeqNumber = (int)(DateTime.Now.Subtract(new DateTime(2020, 1, 1)).TotalSeconds);
  210. this.OnCurrentFuellingStatusChange?.Invoke(this, new FdcTransactionDoneEventArg(new FdcTransaction()
  211. {
  212. Amount = trxDoneEvent.交易金额,
  213. Volumn = trxDoneEvent.交易油量,
  214. AmountTotalizer = trxDoneEvent.金额总量,
  215. VolumeTotalizer = trxDoneEvent.油量总量,
  216. Finished = true,
  217. Nozzle = this.nozzles.First(),
  218. Price = trxDoneEvent.交易单价,
  219. SequenceNumberGeneratedOnPhysicalPump = newTrxSeqNumber,
  220. }));
  221. }
  222. }
  223. public virtual async Task<LogicalDeviceState> QueryStatusAsync()
  224. {
  225. return this.currentState;
  226. }
  227. /// <summary>
  228. ///
  229. /// </summary>
  230. /// <returns>MoneyTotalizer:VolumnTotalizer</returns>
  231. public async Task<Tuple<int, int>> QueryTotalizerAsync(byte logicalNozzleId)
  232. {
  233. var result = new System.Tuple<int, int>(-1, -1);
  234. logger.LogDebug("Pump: " + this.PumpId + ", " + "Start QueryTotalizer pump with logical nozzle: " + logicalNozzleId);
  235. var nozzlePhysicalId = this.nozzles.FirstOrDefault(n => n.LogicalId == logicalNozzleId)?.PhysicalId;
  236. if (nozzlePhysicalId == null)
  237. {
  238. logger.LogDebug("Pump: " + this.PumpId + ", " + " Nozzle with logicalId: " + logicalNozzleId + " does not exists, totalizer will return -1, -1");
  239. return new System.Tuple<int, int>(-1, -1);
  240. }
  241. var frameSeqNo = this.parent.GenerateNewFrameNo();
  242. var response = await this.context.Outgoing.WriteAsync(
  243. new ReadPumpAccumulatorRequest()
  244. {
  245. SourceAddress = this.parent.pumpGroupConfig.FccCommAddress,
  246. TargetAddress = this.parent.pumpGroupConfig.DispenserCommBoardAddress,
  247. FrameSeqNo = frameSeqNo
  248. },
  249. (request, testResponse) =>
  250. testResponse is ReadPumpAccumulatorResponse r
  251. && (r.NozzleAndAccumulators?.Exists(d => d.枪号 == this.PumpPhysicalId) ?? false),
  252. 3000) as ReadPumpAccumulatorResponse;
  253. if (response != null)
  254. {
  255. logger.LogDebug("Pump: " + this.PumpId + ", " + " Queried Totalizer for logical nozzle: " + logicalNozzleId +
  256. ", response detail-> 油量累计: " + (response.NozzleAndAccumulators?.FirstOrDefault(n => n.枪号 == this.PumpPhysicalId)?.油量累计 ?? -1) +
  257. ", 金额累计: " + (response.NozzleAndAccumulators?.FirstOrDefault(n => n.枪号 == this.PumpPhysicalId)?.金额累计 ?? -1));
  258. var t = response.NozzleAndAccumulators.First(d => d.枪号 == this.PumpPhysicalId);
  259. result = new System.Tuple<int, int>((int)t.金额累计, t.油量累计);
  260. }
  261. else
  262. {
  263. logger.LogError("Pump: " + this.PumpId + ", " + "QueryTotalizer timed out");
  264. }
  265. return result;
  266. }
  267. public virtual async Task<bool> ChangeFuelPriceAsync(int newPriceWithoutDecimalPoint, byte logicalNozzleId)
  268. {
  269. logger.LogDebug("Pump: " + this.PumpId + ", " + "start ChangeFuelPriceAsync pump with nozzle: " + logicalNozzleId);
  270. var nozzlePhysicalId = this.nozzles.FirstOrDefault(n => n.LogicalId == logicalNozzleId)?.PhysicalId;
  271. if (nozzlePhysicalId == null)
  272. {
  273. logger.LogDebug("Pump: " + this.PumpId + ", " + " Nozzle with logicalId: " + logicalNozzleId + " does not exists, ChangeFuelPriceAsync failed");
  274. return false;
  275. }
  276. var frameSeqNo = this.parent.GenerateNewFrameNo();
  277. var response = await this.context.Outgoing.WriteAsync(
  278. new ChangePumpPriceRequest((byte)this.PumpPhysicalId, newPriceWithoutDecimalPoint)
  279. {
  280. SourceAddress = this.parent.pumpGroupConfig.FccCommAddress,
  281. TargetAddress = this.parent.pumpGroupConfig.DispenserCommBoardAddress,
  282. FrameSeqNo = frameSeqNo
  283. },
  284. (request, testResponse) =>
  285. testResponse is AckChangePumpPriceResponse r && r.FrameSeqNo == frameSeqNo, 3000) as AckChangePumpPriceResponse;
  286. if (response != null)
  287. {
  288. if (response.参数 == 0x00)
  289. {
  290. logger.LogDebug("Pump: " + this.PumpId + ", " + " ChangeFuelPrice is Acked.");
  291. return true;
  292. }
  293. else
  294. {
  295. logger.LogDebug("Pump: " + this.PumpId + ", " + " Nozzle with logicalId: " + logicalNozzleId + " change price response received with an error code: " + response.参数 + ", ChangeFuelPriceAsync failed");
  296. return false;
  297. }
  298. }
  299. return false;
  300. }
  301. /// <summary>
  302. ///
  303. /// </summary>
  304. /// <param name="logicalNozzleId">useless for this type of pump, it always one pump one nozzle</param>
  305. /// <returns></returns>
  306. public virtual async Task<bool> AuthorizeAsync(byte logicalNozzleId)
  307. {
  308. logger.LogDebug("Pump: " + this.PumpId + ", " + "start AuthorizeAsync pump with nozzle: " + logicalNozzleId);
  309. var nozzlePhysicalId = this.nozzles.FirstOrDefault(n => n.LogicalId == logicalNozzleId)?.PhysicalId;
  310. if (nozzlePhysicalId == null)
  311. {
  312. logger.LogDebug("Pump: " + this.PumpId + ", " + " Nozzle with logicalId: " + logicalNozzleId + " does not exists, AuthorizeAsync failed");
  313. return false;
  314. }
  315. var frameSeqNo = this.parent.GenerateNewFrameNo();
  316. var response = await this.context.Outgoing.WriteAsync(
  317. new StartPumpRequest((byte)this.PumpPhysicalId, StartPumpRequest.PresetType.随意加油, 987699)
  318. {
  319. SourceAddress = this.parent.pumpGroupConfig.FccCommAddress,
  320. TargetAddress = this.parent.pumpGroupConfig.DispenserCommBoardAddress,
  321. FrameSeqNo = frameSeqNo
  322. },
  323. (request, testResponse) =>
  324. testResponse is AckStartPumpResponse r, 3000) as AckStartPumpResponse;
  325. if (response != null)
  326. {
  327. if (response.参数 == 0x00)
  328. return true;
  329. else
  330. {
  331. logger.LogDebug("Pump: " + this.PumpId + ", " + " Nozzle with logicalId: " + logicalNozzleId + " auth response received with an error code: " + response.参数 + ", AuthorizeAsync failed");
  332. return false;
  333. }
  334. }
  335. return false;
  336. }
  337. /// <summary>
  338. ///
  339. /// </summary>
  340. /// <param name="moneyAmount"></param>
  341. /// <param name="logicalNozzleId">useless for this type of pump, it always one pump one nozzle</param>
  342. /// <returns></returns>
  343. public virtual async Task<bool> AuthorizeWithAmountAsync(int moneyAmountWithoutDecimalPoint, byte logicalNozzleId)
  344. {
  345. logger.LogDebug("Pump: " + this.PumpId + ", " + "start AuthorizeWithAmountAsync pump with amount: " + moneyAmountWithoutDecimalPoint + ", nozzle: " + logicalNozzleId);
  346. var nozzlePhysicalId = this.nozzles.FirstOrDefault(n => n.LogicalId == logicalNozzleId)?.PhysicalId;
  347. if (nozzlePhysicalId == null)
  348. {
  349. logger.LogDebug("Pump: " + this.PumpId + ", " + " Nozzle with logicalId: " + logicalNozzleId + " does not exists, AuthorizeWithAmountAsync failed");
  350. return false;
  351. }
  352. var frameSeqNo = this.parent.GenerateNewFrameNo();
  353. var response = await this.context.Outgoing.WriteAsync(
  354. new StartPumpRequest((byte)this.PumpPhysicalId, StartPumpRequest.PresetType.定金额加油, moneyAmountWithoutDecimalPoint)
  355. {
  356. SourceAddress = this.parent.pumpGroupConfig.FccCommAddress,
  357. TargetAddress = this.parent.pumpGroupConfig.DispenserCommBoardAddress,
  358. FrameSeqNo = frameSeqNo
  359. },
  360. (request, testResponse) =>
  361. testResponse is AckStartPumpResponse r, 3000) as AckStartPumpResponse;
  362. if (response != null)
  363. {
  364. if (response.参数 == 0x00)
  365. return true;
  366. else
  367. {
  368. logger.LogDebug("Pump: " + this.PumpId + ", " + " Nozzle with logicalId: " + logicalNozzleId + " auth response received with an error code: " + response.参数 + ", AuthorizeAsync failed");
  369. return false;
  370. }
  371. }
  372. return false;
  373. }
  374. /// <summary>
  375. ///
  376. /// </summary>
  377. /// <param name="volumnWithoutDecimalPoint"></param>
  378. /// <param name="logicalNozzleId">useless for this type of pump, it always one pump one nozzle</param>
  379. /// <returns></returns>
  380. public virtual async Task<bool> AuthorizeWithVolumeAsync(int volumnWithoutDecimalPoint, byte logicalNozzleId)
  381. {
  382. logger.LogDebug("Pump: " + this.PumpId + ", " + "start AuthorizeWithVolumeAsync pump with volume: " + volumnWithoutDecimalPoint + ", nozzle: " + logicalNozzleId);
  383. var nozzlePhysicalId = this.nozzles.FirstOrDefault(n => n.LogicalId == logicalNozzleId)?.PhysicalId;
  384. if (nozzlePhysicalId == null)
  385. {
  386. logger.LogDebug("Pump: " + this.PumpId + ", " + " Nozzle with logicalId: " + logicalNozzleId + " does not exists, AuthorizeWithVolumeAsync failed");
  387. return false;
  388. }
  389. var frameSeqNo = this.parent.GenerateNewFrameNo();
  390. var response = await this.context.Outgoing.WriteAsync(
  391. new StartPumpRequest((byte)this.PumpPhysicalId, StartPumpRequest.PresetType.定油量体积加油, volumnWithoutDecimalPoint)
  392. {
  393. SourceAddress = this.parent.pumpGroupConfig.FccCommAddress,
  394. TargetAddress = this.parent.pumpGroupConfig.DispenserCommBoardAddress,
  395. FrameSeqNo = frameSeqNo
  396. },
  397. (request, testResponse) =>
  398. testResponse is AckStartPumpResponse r, 3000) as AckStartPumpResponse;
  399. if (response != null)
  400. {
  401. if (response.参数 == 0x00)
  402. return true;
  403. else
  404. {
  405. logger.LogDebug("Pump: " + this.PumpId + ", " + " Nozzle with logicalId: " + logicalNozzleId + " auth response received with an error code: " + response.参数 + ", AuthorizeAsync failed");
  406. return false;
  407. }
  408. }
  409. return false;
  410. }
  411. public virtual async Task<bool> FuelingRoundUpByAmountAsync(int amount)
  412. {
  413. throw new NotImplementedException();
  414. }
  415. #region not implemented
  416. public async Task<bool> UnAuthorizeAsync(byte logicalNozzleId)
  417. {
  418. logger.LogDebug("Pump: " + this.PumpId + ", " + "start UnAuthorizeAsync pump with nozzle: " + logicalNozzleId);
  419. var nozzlePhysicalId = this.nozzles.FirstOrDefault(n => n.LogicalId == logicalNozzleId)?.PhysicalId;
  420. if (nozzlePhysicalId == null)
  421. {
  422. logger.LogDebug("Pump: " + this.PumpId + ", " + " Nozzle with logicalId: " + logicalNozzleId + " does not exists, UnAuthorizeAsync failed");
  423. return false;
  424. }
  425. var frameSeqNo = this.parent.GenerateNewFrameNo();
  426. var response = await this.context.Outgoing.WriteAsync(
  427. new StopPumpRequest((byte)this.PumpPhysicalId)
  428. {
  429. SourceAddress = this.parent.pumpGroupConfig.FccCommAddress,
  430. TargetAddress = this.parent.pumpGroupConfig.DispenserCommBoardAddress,
  431. FrameSeqNo = frameSeqNo
  432. },
  433. (request, testResponse) =>
  434. testResponse is AckStopPumpResponse r, 3000) as AckStopPumpResponse;
  435. if (response != null)
  436. {
  437. if (response.参数 == 0x00)
  438. return true;
  439. else
  440. {
  441. logger.LogDebug("Pump: " + this.PumpId + ", " + " Nozzle with logicalId: " + logicalNozzleId + " auth response received with an error code: " + response.参数 + ", UnAuthorizeAsync failed");
  442. return false;
  443. }
  444. }
  445. return false;
  446. }
  447. public async Task<bool> SuspendFuellingAsync()
  448. {
  449. throw new NotImplementedException();
  450. }
  451. public async Task<bool> ResumeFuellingAsync()
  452. {
  453. throw new NotImplementedException();
  454. }
  455. public async Task<bool> FuelingRoundUpByVolumeAsync(int volume)
  456. { throw new NotImplementedException(); }
  457. #endregion
  458. /// <summary>
  459. /// </summary>
  460. protected Dictionary<byte, FuelSaleTransaction> logicalNozzleIdToLastFuelSaleTrxMapping = new Dictionary<byte, FuelSaleTransaction>();
  461. public void OnFdcServerInit(Dictionary<string, object> parameters)
  462. {
  463. if (parameters.ContainsKey("LastPriceChange"))
  464. {
  465. }
  466. /* Load Last sale(from db) for void the case of FC accidently disconnect from Pump in fueling,
  467. and may cause a fueling trx gone from FC control */
  468. if (parameters.ContainsKey("LastFuelSaleTrx"))
  469. {
  470. // nozzle logical id:lastSale
  471. //var lastFuelSaleTrxes = parameters["LastFuelSaleTrx"] as Dictionary<byte, FuelSaleTransaction>;
  472. //foreach (var lastFuelSaleTrx in lastFuelSaleTrxes)
  473. //{
  474. // logger.Info("Pump: " + this.pumpId + ", OnFdcServerInit, load last fuel sale " +
  475. // "on logical nozzle: " + lastFuelSaleTrx.Key + " with value: " + lastFuelSaleTrx.Value);
  476. // this.logicalNozzleIdToLastFuelSaleTrxMapping.Remove(lastFuelSaleTrx.Key);
  477. // this.logicalNozzleIdToLastFuelSaleTrxMapping.Add(lastFuelSaleTrx.Key, lastFuelSaleTrx.Value);
  478. //}
  479. }
  480. }
  481. public async Task<bool> LockNozzleAsync(byte logicalNozzleId)
  482. {
  483. return false;
  484. }
  485. public async Task<bool> UnlockNozzleAsync(byte logicalNozzleId)
  486. {
  487. return false;
  488. }
  489. }
  490. }