using Edge.Core.Processor;
using Edge.Core.IndustryStandardInterface.Pump;
using HengShan_Pump_TQC_IFSF.MessageEntity;
using HengShan_Pump_TQC_IFSF.MessageEntity.Incoming;
using HengShan_Pump_TQC_IFSF.MessageEntity.Outgoing;
using Edge.Core.Parser.BinaryParser.Util;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using Wayne.FDCPOSLibrary;
using Timer = System.Timers.Timer;
using Edge.Core.Processor.Dispatcher.Attributes;
using Edge.Core.Processor.Communicator;
namespace HengShan_Pump_TQC_IFSF
{
///
/// silent means this pump group handler never actively send data to TQC, this is a solution for
/// a special TQC pump only passthrough sales data to FC, because it's controlled by other party FC.
///
[MetaPartsRequired(typeof(GenericDeviceProcessor<,>))]
[MetaPartsRequired(typeof(HengShan_TQC_IFsfMessageTcpIpCommunicator_Silent<>))]
[MetaPartsDescriptor(
"lang-zh-cn:HS TQC只读模式加油机lang-en-us:HS TQC readonly mode pump",
"lang-zh-cn:用于中石化站中驱动只读模式下的基于TCP连接的IFSF协议的 Wayne-WT30 或者 恒山-TH22 协议的加油机lang-en-us:Used for SinoPec site to driven pumps set in readonly mode, and the model are Wayne-WT30 or HengShan-TH22, which using IFSF protocol on TCP",
new[] { "lang-zh-cn:加油机lang-en-us:Pump" })]
public class SilentPumpGroupHandler : PumpGroupHandler
{
private System.Timers.Timer timelyCheckConnection;
private DateTime lastTimeRecieveHearbeat;
[ParamsJsonSchemas("PumpGroupHandlerCtorParamsJsonSchemas")]
public SilentPumpGroupHandler(PumpGroupConfiguration pumpGroupConfiguration, IServiceProvider services)
: base(pumpGroupConfiguration, services)
{
}
///
///
///
///
public SilentPumpGroupHandler(int fccIfsfSubnetValue, int fccIfsfNodeValue, string pumpsXmlConfiguration)
: base(fccIfsfSubnetValue, fccIfsfNodeValue, pumpsXmlConfiguration)
{
// sample
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
}
public override void Init(IContext context)
{
base.context = context;
this.context.Communicator.OnConnected += (e, f) =>
{
// each time communicator get disconnect, will trigger a re-init.
logger.Info("node " + this.tqcPumpGroupInitializer.ifsfRecipientNode + ", OnCommunicator Connected, will hard set all pumps to Idle state anyway");
this.pumpHandlers.ForEach(p => p.HandleFpStatusChange(FuellingPointStatus.Idle, null));
};
this.context.Communicator.OnDisconnected += (e, f) =>
{
logger.Info("node " + this.tqcPumpGroupInitializer.ifsfRecipientNode + ", OnCommunicator Disconnected, will hard set all pumps to Closed state anyway");
this.pumpHandlers.ForEach(p => p.HandleFpStatusChange(FuellingPointStatus.Closed, null));
};
base.pumpHandlers.ForEach(p => p.Init(this.context));
this.timelyCheckConnection = new Timer(6000);
this.timelyCheckConnection.Elapsed += (_, __) =>
{
if (DateTime.Now.Subtract(this.lastTimeRecieveHearbeat).TotalSeconds >= 6)
{
//logger.Debug("Heartbeat timed out, will turn all pumps("
// + this.pumpHandlers.Select(p => p.QueryStatus().ToString()).Aggregate((acc, n) => acc + "," + n)
// + ") to Closed state");
this.pumpHandlers.ForEach(p => p.HandleFpStatusChange(FuellingPointStatus.Closed, null));
}
};
this.timelyCheckConnection.Start();
}
protected override void CreatePumpHandlers(IEnumerable pumpElements)
{
foreach (XmlNode pumpElement in pumpElements)
{
byte pumpPhysicalIdValue;
var rawPumpPhysicalId = pumpElement.Attributes["physicalId"].Value;
if (rawPumpPhysicalId.StartsWith("0x") || rawPumpPhysicalId.StartsWith("0X"))
pumpPhysicalIdValue = byte.Parse(pumpElement.Attributes["physicalId"].Value.Substring(2), NumberStyles.HexNumber);
else
pumpPhysicalIdValue = byte.Parse(pumpElement.Attributes["physicalId"].Value);
if (pumpPhysicalIdValue < 0x21 || pumpPhysicalIdValue > 0x24)
throw new ArgumentException("ifsf fuel point id must be range from 0x21 to 0x24, while the configuration passed in " + rawPumpPhysicalId);
SilentPumpHandler pumpHandler = new SilentPumpHandler(this, int.Parse(pumpElement.Attributes["pumpId"].Value),
pumpPhysicalIdValue,
base.recipientSubnet, base.recipientNode,
pumpElement.InnerXml, GetNewMessageToken);
base.pumpHandlers.Add(pumpHandler);
}
}
public override Task Process(IContext context)
{
base.context = context;
switch (context.Incoming.Message)
{
case CommunicationDb_Event_ACK usedAsHeartBeat:
this.lastTimeRecieveHearbeat = DateTime.Now;
context.Outgoing.Write(new AcknowledgeMessage(
usedAsHeartBeat.OriginatorSubnet,
usedAsHeartBeat.OriginatorNode,
PumpGroupHandler.originatorSubnet, PumpGroupHandler.originatorNode,
usedAsHeartBeat.MessageToken,
usedAsHeartBeat.DatabaseId,
MessageAcknowledgeStatus.ACK_PositiveAcknowledgeDataReceived
));
break;
//case LogicalNozzleDb_Nozzle_PhyId_Event_ACK nozzlePhyIdEvent:
// this.pumpHandlers.Where(h => h.ifsfFuelPointId == nozzlePhyIdEvent.TargetFuelPointId).ToList().ForEach(p => p.Process(context));
// break;
//case FuellingPointDb_FpStatus_Event fpStatusEvent:
// this.pumpHandlers.Where(h => h.ifsfFuelPointId == fpStatusEvent.TargetFuelPointId).ToList().ForEach(p => p.Process(context));
// break;
//case FuellingPointDb_FpRunningTransaction_Event fpRunningTrxEvent:
// this.pumpHandlers.Where(h => h.ifsfFuelPointId == fpRunningTrxEvent.TargetFuelPointId).ToList().ForEach(p => p.Process(context));
// break;
default: base.RouteMessageToHandlers(context); break;
}
return Task.CompletedTask;
}
}
}