using Edge.Core.Parser; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Wayne.FDCPOSLibrary; namespace Edge.Core.IndustryStandardInterface.Pump { /// <summary> /// Implements this interface indicates the class have the ability to control the physical /// pump and expose the controller interface by following Fdc pattern. /// </summary> public interface IFdcPumpController //: IDeviceController { event EventHandler<FdcPumpControllerOnStateChangeEventArg> OnStateChange; event EventHandler<FdcTransactionDoneEventArg> OnCurrentFuellingStatusChange; /// <summary> /// will be called once Fdc server starting. /// Fdc server will pass in necessary parameters via this function to each FdcPumpController. /// </summary> /// <param name="parameters"></param> void OnFdcServerInit(Dictionary<string, object> parameters); string Name { get; } /// <summary> /// Gets the Identification of the pump for the system. Is the logical number of the pump. /// e.g.: A site may have 4 physical pumps, each physical pump have 2 sides(fuelling point), then it's the /// pump id from 1 to 8. /// Then may have the model of physical pump with 6 nozzels, 3 for each side, but each side may grouped into 2 fuelling points, /// the first fuelling point in one side contains 1 nozzel, while the second contains 2 nozzels, so in this case, /// this physical pump actually have 4 fuelling points, also means this physical pump should have 4 pump ids. /// </summary> int PumpId { get; } /// <summary> /// Gets the internal identification of the fuelling position. /// Most likely it'll be only used in binary protocol parsing level. /// At least for Wayne pump, it can configed an internal address for each fuelling position via physical pump main board, /// this Id is critical for the case of multiple Pumps connected into one ComPort. /// If a device didn't have to check binary message with this id, then put any value for it. /// </summary> int PumpPhysicalId { get; } IEnumerable<LogicalNozzle> Nozzles { get; } /// <summary> /// Gets the money/amount digits. /// the Money/amount value read from pump is always an int value, need convert with this digits settings to readable format. /// </summary> int AmountDecimalDigits { get; } /// <summary> /// Gets the volume digits /// </summary> int VolumeDecimalDigits { get; } /// <summary> /// price digits typically not the same with Amount digits /// </summary> int PriceDecimalDigits { get; } int VolumeTotalizerDecimalDigits { get; } Task<LogicalDeviceState> QueryStatusAsync(); /// <summary> /// /// </summary> /// <returns>MoneyTotalizer:VolumnTotalizer</returns> Task<Tuple<int, int>> QueryTotalizerAsync(byte logicalNozzleId); //string QueryConfiguration(); Task<bool> SuspendFuellingAsync(); Task<bool> ResumeFuellingAsync(); Task<bool> ChangeFuelPriceAsync(int newPriceWithoutDecimalPoint, byte logicalNozzleId); Task<bool> AuthorizeAsync(byte logicalNozzleId); Task<bool> UnAuthorizeAsync(byte logicalNozzleId); Task<bool> AuthorizeWithAmountAsync(int moneyAmountWithoutDecimalPoint, byte logicalNozzleId); Task<bool> AuthorizeWithVolumeAsync(int volumnWithoutDecimalPoint, byte logicalNozzleId); /// <summary> /// 凑整 /// </summary> /// <param name="amount">expecting fueling to this amount, value is without decimal point</param> /// <returns></returns> Task<bool> FuelingRoundUpByAmountAsync(int amount); /// <summary> /// 凑整 /// </summary> /// <param name="amount">expecting fueling to this volum, value is without decimal point</param> /// <returns></returns> Task<bool> FuelingRoundUpByVolumeAsync(int volume); /// <summary> /// lock a nozzle for not allow it for fueling /// </summary> /// <param name="logicalNozzleId"></param> /// <returns></returns> Task<bool> LockNozzleAsync(byte logicalNozzleId); /// <summary> /// unlock a locked nozzle /// </summary> /// <param name="logicalNozzleId"></param> /// <returns></returns> Task<bool> UnlockNozzleAsync(byte logicalNozzleId); } /// <summary> /// 每把逻辑枪代表着能加出某个油品的虚拟枪。 /// 大多数情况下逻辑枪数==物理枪数。 /// 存在一把物理枪可以加出三种油的情况,这种情况下,即为三把逻辑枪,但共用一个Physical Id. /// </summary> public class LogicalNozzle { private LogicalNozzle() { } /// <summary> /// /// </summary> /// <param name="pumpId">the pump(FuelPoint) id of this nozzle is hosted</param> /// <param name="physicalId"></param> /// <param name="logicalId">must >=1</param> /// <param name="realPriceOnPhysicalPump"></param> public LogicalNozzle(int pumpId, byte physicalId, byte logicalId, int? realPriceOnPhysicalPump) { if (logicalId < 1) throw new ArgumentException("Nozzle logical id must be >=1"); this.PumpId = pumpId; this.RealPriceOnPhysicalPump = realPriceOnPhysicalPump; this.PhysicalId = physicalId; this.LogicalId = logicalId; } public int PumpId { get; } /// <summary> /// nozzle PhysicalId should be assgined at hardware level for a physical pump. /// so it's device dependent, can be confirmed in Pump comm protocol doc. /// like in Ifsf protocol, physical id for a nozzle is from 0x11 - 0x18. /// like in Wayne dart protocol, physical id for na nozzle is from 1 - 8. /// a physical nozzle may have multiple fuel products assgined(blending). /// most likely it will repeat in each individual pump. /// </summary> public byte PhysicalId { get; } /// <summary> /// Gets or sets the logical id for a nozzle, value must range from 1 to N. /// in LiteFcc, we follow the rule of, that you face to a FuelPoint, /// the most left side nozzle is always logicalId 1, /// and the nozzle right to it, it's 2, and then 3... /// </summary> public byte LogicalId { get; } /// <summary> /// Gets or sets the real price which read from physical pump, without decimal points. /// some pumps can get price when first time FC connected to it, but some are not. /// So it may null though the physical pump side price is set (have not read by FC). /// So it may diff from the FC side value(by a failure in price change request, and that value will be saved into db) /// /// </summary> public int? RealPriceOnPhysicalPump { get; set; } /// <summary> /// Gets or sets the expecting price which set from FC side, without decimal points. /// FC side could change the pump price (via price change request), this value will send to physical /// pump and finally saved into FC db. /// but this does NOT gurantee the consistent since the comm between the FC and pump may fail. /// </summary> public int? ExpectingPriceOnFcSide { get; set; } /// <summary> /// Gets or sets the vol totalizer value for this nozzle, without decimal points. /// </summary> public int? VolumeTotalizer { get; set; } public LogicalDeviceState? LogicalState { get; set; } } public class FdcTransactionDoneEventArg : System.EventArgs { public FdcTransactionDoneEventArg(FdcTransaction transaction) { this.Transaction = transaction; } public FdcTransaction Transaction { get; private set; } } public class FdcTransaction { public LogicalNozzle Nozzle { get; set; } /// <summary> /// without decimal points /// </summary> public int Amount { get; set; } /// <summary> /// without decimal points /// </summary> public int Volumn { get; set; } /// <summary> /// without decimal points /// </summary> public int Price { get; set; } public int Barcode { get; set; } /// <summary> /// Gets or set the seq number which typically generated on phsyical pump side for /// unique a trx, for most pumps, the number will be rotate and reused after a period of time, /// this is fine since FDC server side check the duplication only by a short time period range, /// not the full range scan. /// for some pumps, it didn't have this value at all, then need generate one in FC pump handler side, /// an unique value is requried. /// </summary> public int SequenceNumberGeneratedOnPhysicalPump { get; set; } /// <summary> /// the money amount totalizer value after this new trx done, without decimal points. /// the trx from a pump may not carry on amount totalizer value, it device dependent. /// </summary> public int? AmountTotalizer { get; set; } /// <summary> /// the volume amount totalizer value after this new trx done, without decimal points. /// the trx from a pump may not carry on volume totalizer value, it device dependent. /// </summary> public int? VolumeTotalizer { get; set; } /// <summary> /// Gets or sets if the fueling transaction still on going. /// True for transaction is done, False for on going. /// </summary> public bool Finished { get; set; } /// <summary> /// Gets or sets the start time of this fuel trx. /// leave it null will set it to: (SaleEndTime - x minutues), the default x is 3 and could be changed in future in FdcServerApp. /// </summary> public DateTime? SaleStartTime { get; set; } /// <summary> /// Gets or sets the end time of this fuel trx. /// leave it null will set it to DateTime.Now in FdcServerApp. /// </summary> public DateTime? SaleEndTime { get; set; } } }