using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Configuration;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using Timer = System.Timers.Timer;
using System.Collections;
using Edge.Core.Processor;
using Edge.Core.IndustryStandardInterface.Pump;
using Wayne.FDCPOSLibrary;
using System.Xml;
using Edge.Core.Database.Models;
using System.Threading.Tasks;
using Edge.Core.Processor.Communicator;
using Edge.Core.Processor.Dispatcher.Attributes;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Stateless;
using Edge.Core.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace ZhongSheng_NonIC_Pump
{
#region Ctor parameters
public class PumpGroupConfig
{
///
/// 数据发送端的地址编号
/// 一般是指FCC? 则应该是一个全局共享值,放0xE0
///
public byte FccCommAddress { get; set; } = 0xE0;
///
/// 数据接收端的地址编号
/// 指油机端的配置值,应该是每个通讯链路都不一样,一个链路上可能有1个或者多个加油点
///
public byte DispenserCommBoardAddress { get; set; }
public List PumpConfigs { get; set; }
}
public class PumpConfig
{
///
/// used by Fcc inside, the classic pump id concept.
///
public byte PumpId { get; set; }
///
/// 枪号为以整个加油站为基础的油枪顺序编号
/// 就是全站枪号?
///
public byte DispenserSideNozzleId { get; set; }
}
#endregion
///
/// 协议支持9600bps,8 位数据位,1 位起始位,1 位停止位,无校验位
///
[MetaPartsRequired(typeof(HalfDuplexActivePollingDeviceProcessor<,>))]
[MetaPartsRequired(typeof(ComPortCommunicator<>))]
[MetaPartsRequired(typeof(TcpClientCommunicator<>))]
[MetaPartsDescriptor(
"lang-zh-cn:中升非IC卡加油机lang-en-us:ZhongSheng Non-IC card dispenser",
"用于驱动 中升非IC卡 加油机, 它每把枪就是一个Pump即一个加油点,且油机上配置的枪号等同于全站枪号。此油机可以配置提枪直接出油,也可以配置成需要后台授权,请在加油机上配置(菜单IC卡支付方式中选择第4项即开启后台授权模式)。根据油机方的技术人员说明,我们中控这边对接的油机,都会是单枪单显,或者是2枪2显,不会有单面双单价的型号。 原生支持 8位数据位,1位起始位,1位停止位,无校验位RS422。",
new[] { "lang-zh-cn:加油机lang-en-us:Pump" })]
public class PumpGroupHandler : IEnumerable, IDeviceHandler
{
private IServiceProvider services;
private ILogger logger = NullLogger.Instance;
public PumpGroupConfig pumpGroupConfig;
protected IEnumerable nozzleExtraInfos;
protected IContext context;
protected IEnumerable pumpHandlers;
private object rotateFrameNo_Guard = new object();
///
///
private byte rotateFrameNo = 0;
///
/// get a valid FrameNo which from >=1 and <= 0x3F.
///
///
public byte GenerateNewFrameNo()
{
lock (this.rotateFrameNo_Guard)
{
//return 0;
if (this.rotateFrameNo > 0x3E)
this.rotateFrameNo = 0;
return (byte)(++this.rotateFrameNo);
}
}
[ParamsJsonSchemas("PumpGroupHandlerCtorParamsJsonSchemas")]
public PumpGroupHandler(PumpGroupConfig pumpGroupConfig, IServiceProvider services)
{
this.pumpGroupConfig = pumpGroupConfig;
this.services = services;
var loggerFactory = services.GetRequiredService();
this.logger = loggerFactory.CreateLogger("PumpHandler");
this.pumpHandlers =
pumpGroupConfig.PumpConfigs.Select(pc =>
new StatePumpHandler(this, pc.PumpId, pc.DispenserSideNozzleId, services)).ToList();
}
public void OnFdcServerInit(Dictionary parameters)
{
if (parameters != null && parameters.TryGetValue("NozzleProductMapping", out object param))
{
this.nozzleExtraInfos = param as IEnumerable;
}
}
public void Init(IContext context)
{
this.context = context;
var timeWindowWithActivePollingOutgoing =
this.context.Outgoing as TimeWindowWithActivePollingOutgoing;
//this.pollingInterval = timeWindowWithActivePollingOutgoing.PollingInterval;
timeWindowWithActivePollingOutgoing.PollingMsgProducer =
() =>
{
//if (!this.isCommConnected) return null;
return new GenericInquiryRequest()
{
SourceAddress = this.pumpGroupConfig.FccCommAddress,
TargetAddress = this.pumpGroupConfig.DispenserCommBoardAddress,
FrameSeqNo = this.GenerateNewFrameNo(),
};// this.GetNewMessageToken(target.PumpId));
};
this.pumpHandlers.ToList().ForEach(p => p.Init(this.context));
this.context.Incoming.OnLongTimeNoSeeMessage += (_, __) =>
{
this.pumpHandlers.ToList().ForEach(p => p.TriggerPumpOffline());
};
this.context.Incoming.LongTimeNoSeeMessageTimeout = 6000;
}
public async Task Process(IContext context)
{
this.context = context;
//var ph = this.pumpHandlers.FirstOrDefault(p => (byte)(p.PumpPhysicalId) == context.Incoming.Message.SourceAddress);
//if (ph == null)
//{
// logger.LogInformation("PumpGroupHandler does not contain pumpHandler with physcialId: "
// + context.Incoming.Message.SourceAddress.ToString("X2"));
// return Task.CompletedTask;
//}
//有可能是设备端是2枪2显,但将区别的逻辑放入到pumpHandler里面去处理
foreach (var ph in this.pumpHandlers)
await ph.Process(context);
}
public IEnumerator GetEnumerator()
{
return this.pumpHandlers.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.pumpHandlers.GetEnumerator();
}
}
}