using HengshanPaymentTerminal.MessageEntity.Incoming;
using HengshanPaymentTerminal.MessageEntity;
using HengshanPaymentTerminal.Support;
using HengshanPaymentTerminal;
using System;
using System.Collections.Concurrent;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Edge.Core.Processor.Dispatcher.Attributes;
using Edge.Core.IndustryStandardInterface.Pump;
using Edge.Core.IndustryStandardInterface.Pump.Fdc;
using Edge.Core.Processor;
using Edge.Core.Core.database;
using Edge.Core.Domain.FccStationInfo.Output;
using Edge.Core.Domain.FccNozzleInfo;
using Edge.Core.Domain.FccNozzleInfo.Output;
using System.Net.Sockets;
using Edge.Core.Domain.FccOrderInfo;
using Microsoft.EntityFrameworkCore;
using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities;
using static Microsoft.AspNetCore.Hosting.Internal.HostingApplication;
namespace HengshanPaymentTerminal
{
///
/// Handler that communicates directly with the Hengshan Payment Terminal for card handling and pump handling via serial port.
///
[MetaPartsDescriptor(
"lang-zh-cn:恒山IC卡终端(UI板) App lang-en-us:Hengshan IC card terminal (UI Board)",
"lang-zh-cn:用于与UI板通讯控制加油机" +
"lang-en-us:Used for terminal communication to control pumps",
new[]
{
"lang-zh-cn:恒山IC卡终端lang-en-us:HengshanICTerminal"
})]
public class HengshanPayTermHandler : IEnumerable, IDeviceHandler
{
#region Fields
private string pumpIds;
private string pumpSubAddresses;
private string pumpNozzles;
private string pumpSiteNozzleNos;
private string nozzleLogicIds;
private IContext _context;
private List pumpHandlers = new List();
public Queue queue = new Queue();
public Queue commonQueue = new Queue();
private object syncObj = new object();
private ConcurrentDictionary statusDict = new ConcurrentDictionary();
public ConcurrentDictionary PumpStatusDict => statusDict;
private Dictionary pumpIdSubAddressDict;
public Dictionary> PumpNozzlesDict { get; private set; }
public Dictionary NozzleLogicIdDict { get; private set; }
public Dictionary> PumpSiteNozzleNoDict { get; private set; }
public MysqlDbContext MysqlDbContext { get; private set; }
public StationInfo stationInfo { get; set; }
public List nozzleInfoList { get; private set; }
public TcpClient? client { get; set; }
#endregion
#region Logger
private static NLog.Logger logger = NLog.LogManager.LoadConfiguration("NLog.config").GetLogger("IPosPlusApp");
#endregion
#region Constructor
//private static List ResolveCtorMetaPartsConfigCompatibility(string incompatibleCtorParamsJsonStr)
//{
// var jsonParams = JsonDocument.Parse(incompatibleCtorParamsJsonStr).RootElement.EnumerateArray().ToArray();
// //sample: "UITemplateVersion":"1.0"
// string uiTemplateVersionRegex = @"(?<=""UITemplateVersion""\:\"").+?(?="")";
// var match = Regex.Match(jsonParams.First().GetRawText(), uiTemplateVersionRegex, RegexOptions.IgnoreCase | RegexOptions.Multiline);
// if (match.Success)
// {
// var curVersion = match.Value;
// if (curVersion == "1.0")
// {
// var existsAppConfigV1 = JsonSerializer.Deserialize(jsonParams.First().GetRawText(), typeof(HengshanPayTerminalHanlderGroupConfigV1));
// }
// else
// {
// }
// }
// return null;
//}
[ParamsJsonSchemas("TermHandlerGroupCtorParamsJsonSchemas")]
public HengshanPayTermHandler(HengshanPayTerminalHanlderGroupConfigV2 config)
: this(config.PumpIds,
string.Join(";", config.PumpSubAddresses.Select(m => $"{m.PumpId}={m.SubAddress}")),
string.Join(";", config.PumpNozzleLogicIds.Select(m => $"{m.PumpId}={m.LogicIds}")),
string.Join(";", config.PumpSiteNozzleNos.Select(m => $"{m.PumpId}={m.SiteNozzleNos}")),
string.Join(";", config.NozzleLogicIds.Select(m => $"{m.NozzleNo}={m.LogicId}")))
{
}
public HengshanPayTermHandler(
string pumpIds,
string pumpSubAddresses,
string pumpNozzles,
string pumpSiteNozzleNos,
string nozzleLogicIds)
{
this.pumpIds = pumpIds;
this.pumpSubAddresses = pumpSubAddresses;
this.pumpNozzles = pumpNozzles;
this.pumpSiteNozzleNos = pumpSiteNozzleNos;
this.nozzleLogicIds = nozzleLogicIds;
this.MysqlDbContext = new MysqlDbContext();
GetInfo();
AssociatedPumpIds = GetPumpIdList(pumpIds);
pumpIdSubAddressDict = InitializePumpSubAddressMapping();
PumpNozzlesDict = ParsePumpNozzlesList(pumpNozzles);
PumpSiteNozzleNoDict = ParsePumpSiteNozzleNoList(pumpSiteNozzleNos);
NozzleLogicIdDict = InitializeNozzleLogicIdMapping(nozzleLogicIds);
InitializePumpHandlers();
}
#endregion
public void OnFdcServerInit(Dictionary parameters)
{
logger.Info("OnFdcServerInit called");
if (parameters.ContainsKey("LastPriceChange"))
{
// nozzle logical id:rawPrice
var lastPriceChanges = parameters["LastPriceChange"] as Dictionary;
foreach (var priceChange in lastPriceChanges)
{
}
}
}
#region Event handler
public event EventHandler OnTerminalMessageReceived;
public event EventHandler OnTotalizerReceived;
public event EventHandler OnFuelPriceChangeRequested;
public event EventHandler OnTerminalFuelPriceDownloadRequested;
public event EventHandler OnCheckCommandReceived;
public event EventHandler OnLockUnlockCompleted;
#endregion
#region Properties
public List AssociatedPumpIds { get; private set; }
public IContext Context
{
get { return _context; }
}
public string PumpIdList => pumpIds;
//public LockUnlockOperation LockUnlockOperationType { get; set; } = LockUnlockOperation.Undefined;
#endregion
#region Methods
public int GetSubAddressForPump(int pumpId)
{
return pumpIdSubAddressDict.First(d => d.Key == pumpId).Value;
}
private List GetPumpIdList(string pumpIds)
{
var pumpIdList = new List();
if (!string.IsNullOrEmpty(pumpIds) && pumpIds.Contains(',')) //multiple pumps per serial port, Hengshan TQC pump
{
var arr = pumpIds.Split(',');
foreach (var item in arr)
{
pumpIdList.Add(int.Parse(item));
}
return pumpIdList;
}
else if (!string.IsNullOrEmpty(pumpIds) && pumpIds.Length == 1 || pumpIds.Length == 2) //only 1 pump per serial port, Hengshan pump
{
return new List { int.Parse(pumpIds) };
}
else
{
throw new ArgumentException("Pump id list not specified!");
}
}
private Dictionary InitializePumpSubAddressMapping()
{
var dict = new Dictionary();
if (!string.IsNullOrEmpty(pumpSubAddresses))
{
var sequence = pumpSubAddresses.Split(';')
.Select(s => s.Split('='))
.Select(a => new { PumpId = int.Parse(a[0]), SubAddress = int.Parse(a[1]) });
foreach (var pair in sequence)
{
if (!dict.ContainsKey(pair.PumpId))
{
dict.Add(pair.PumpId, pair.SubAddress);
}
}
return dict;
}
else
{
throw new ArgumentException("Pump id and sub address mapping does not exist");
}
}
private Dictionary> ParsePumpNozzlesList(string pumpNozzles)
{
Dictionary> pumpNozzlesDict = new Dictionary>();
if (!string.IsNullOrEmpty(pumpNozzles) && pumpNozzles.Contains(';'))
{
var arr = pumpNozzles.Split(';');
foreach (var subMapping in arr)
{
var pair = new KeyValuePair(int.Parse(subMapping.Split('=')[0]), int.Parse(subMapping.Split('=')[1]));
Console.WriteLine($"{pair.Key}, {pair.Value}");
if (!pumpNozzlesDict.ContainsKey(pair.Key))
{
pumpNozzlesDict.Add(pair.Key, new List { pair.Value });
}
else
{
List nozzlesForThisPump;
pumpNozzlesDict.TryGetValue(pair.Key, out nozzlesForThisPump);
if (nozzlesForThisPump != null && !nozzlesForThisPump.Contains(pair.Value))
{
nozzlesForThisPump.Add(pair.Value);
}
}
}
}
else if (!string.IsNullOrEmpty(pumpNozzles) && pumpNozzles.Count(c => c == '=') == 1) // only one pump per serial port
{
try
{
pumpNozzlesDict.Add(
int.Parse(pumpNozzles.Split('=')[0]),
new List { int.Parse(pumpNozzles.Split('=')[1]) });
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
else
{
throw new ArgumentException("Wrong mapping between pump and its associated nozzles!");
}
return pumpNozzlesDict;
}
static Dictionary> ParsePumpSiteNozzleNoList(string pumpSiteNozzleNos)
{
Dictionary> pumpSiteNozzleNoDict = new Dictionary>();
if (!string.IsNullOrEmpty(pumpSiteNozzleNos) && pumpSiteNozzleNos.Contains(';'))
{
var arr = pumpSiteNozzleNos.Split(';');
foreach (var subMapping in arr)
{
var pair = new KeyValuePair>(
int.Parse(subMapping.Split('=')[0]), subMapping.Split('=')[1].Split(',').Select(a => int.Parse(a)).ToList());
Console.WriteLine($"{pair.Key}, {pair.Value}");
if (!pumpSiteNozzleNoDict.ContainsKey(pair.Key))
{
pumpSiteNozzleNoDict.Add(pair.Key, pair.Value);
}
}
}
else if (!string.IsNullOrEmpty(pumpSiteNozzleNos) && pumpSiteNozzleNos.Count(c => c == '=') == 1)
{
try
{
string[] strArr = pumpSiteNozzleNos.Split('=');
pumpSiteNozzleNoDict.Add(
int.Parse(strArr[0]), new List { int.Parse(strArr[1]) });
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
else
{
throw new ArgumentException("Wrong mapping between pump and its associated nozzles!");
}
return pumpSiteNozzleNoDict;
}
private Dictionary InitializeNozzleLogicIdMapping(string nozzleLogicIds)
{
var dict = new Dictionary();
if (!string.IsNullOrEmpty(nozzleLogicIds))
{
var sequence = nozzleLogicIds.Split(';')
.Select(s => s.Split('='))
.Select(a => new { NozzleNo = int.Parse(a[0]), LogicId = int.Parse(a[1]) });
foreach (var pair in sequence)
{
if (!dict.ContainsKey(pair.NozzleNo))
{
Console.WriteLine($"nozzle, logic id: {pair.NozzleNo} - {pair.LogicId}");
dict.Add(pair.NozzleNo, pair.LogicId);
}
}
return dict;
}
else if (!string.IsNullOrEmpty(nozzleLogicIds) && nozzleLogicIds.Count(c => c == '=') == 1)
{
try
{
string[] sequence = nozzleLogicIds.Split('=');
dict.Add(int.Parse(sequence[0]), int.Parse(sequence[1]));
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
return dict;
}
else
{
throw new ArgumentException("Pump id and sub address mapping does not exist");
}
}
private void InitializePumpHandlers()
{
var pumpIdList = GetPumpIdList(pumpIds);
foreach (var item in pumpIdList)
{
var nozzleList = GetNozzleListForPump(item);
var siteNozzleNoList = PumpSiteNozzleNoDict[item];
HengshanPumpHandler pumpHandler = new HengshanPumpHandler(this, $"Pump_{item}", item, nozzleList, siteNozzleNoList);
pumpHandler.OnFuelPriceChangeRequested += PumpHandler_OnFuelPriceChangeRequested;
pumpHandlers.Add(pumpHandler);
}
}
private List GetNozzleListForPump(int pumpId)
{
List nozzles;
PumpNozzlesDict.TryGetValue(pumpId, out nozzles);
return nozzles;
}
private void PumpHandler_OnFuelPriceChangeRequested(object sender, FuelPriceChangeRequestEventArgs e)
{
InfoLog($"Change price, Pump {e.PumpId}, Nozzle {e.NozzleId}, Price {e.Price}");
OnFuelPriceChangeRequested?.Invoke(sender, e);
}
IEnumerator IEnumerable.GetEnumerator()
{
return pumpHandlers.GetEnumerator();
}
#endregion
#region IHandler implementation
public void Init(IContext context)
{
CommIdentity = context.Processor.Communicator.Identity;
_context = context;
}
public string CommIdentity { get; private set; }
public async Task Process(IContext context)
{
switch(context.Incoming.Message.Handle)
{
//订单
case 0x18:
//添加或修改数据库订单
OrderFromMachine message = (OrderFromMachine)context.Incoming.Message;
int row = UpLoadOrder(message);
logger.Info($"receive order from machine,database had ${row} count change");
break;
}
context.Outgoing.Write(context.Incoming.Message);
}
private void CheckStatus(CheckCmdRequest request)
{
if (!statusDict.ContainsKey(request.FuelingPoint.PumpNo))
{
var result = statusDict.TryAdd(request.FuelingPoint.PumpNo,
new PumpStateHolder
{
PumpNo = request.FuelingPoint.PumpNo,
NozzleNo = 1,
State = request,
OperationType = LockUnlockOperation.None
});
logger.Info($"Adding FuelingPoint {request.FuelingPoint.PumpNo} to dict");
if (!result)
{
statusDict.TryAdd(request.FuelingPoint.PumpNo, null);
}
}
else
{
PumpStateHolder stateHolder = null;
statusDict.TryGetValue(request.FuelingPoint.PumpNo, out stateHolder);
if (stateHolder != null)
{
logger.Debug($"State holder, PumpNo: {stateHolder.PumpNo}, dispenser state: {stateHolder.State.DispenserState}, " +
$"operation: {stateHolder.OperationType}");
}
if (stateHolder != null && stateHolder.OperationType != LockUnlockOperation.None)
{
logger.Debug($"PumpNo: {request.FuelingPoint.PumpNo}, Last Dispenser State: {stateHolder.State.DispenserState}, " +
$"Current Dispenser State: {request.DispenserState}");
if (stateHolder.State.DispenserState == 3 && request.DispenserState == 2)
{
//Pump is locked due to lock operation
if (stateHolder.OperationType != LockUnlockOperation.None)
{
logger.Info("Locking done!");
stateHolder.State = request; //Update the state
OnLockUnlockCompleted?.Invoke(this, new LockUnlockEventArgs(stateHolder.OperationType, true));
}
}
else if (stateHolder.State.DispenserState == 2 && request.DispenserState == 3)
{
//Pump is unlocked due to unlock operation
if (stateHolder.OperationType != LockUnlockOperation.None)
{
logger.Info($"Unlocking done!");
stateHolder.State = request; //Update the state
OnLockUnlockCompleted?.Invoke(this, new LockUnlockEventArgs(stateHolder.OperationType, true));
}
}
}
else if (stateHolder != null && stateHolder.OperationType == LockUnlockOperation.None)
{
if (stateHolder.State.DispenserState != request.DispenserState)
{
logger.Warn($"Observed a pump state change, {stateHolder.State.DispenserState} -> {request.DispenserState}");
stateHolder.State = request; //Update the state.
}
}
}
}
public void Write(CommonMessage cardMessage)
{
_context.Outgoing.Write(cardMessage);
}
public async Task WriteAsync(CommonMessage request, Func responseCapture,
int timeout)
{
var resp = await _context.Outgoing.WriteAsync(request, responseCapture, timeout);
return resp;
}
#endregion
#region IEnumerable implementation
public IEnumerator GetEnumerator()
{
return pumpHandlers.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return pumpHandlers.GetEnumerator();
}
#endregion
public void PendMessage(CardMessageBase message)
{
lock (syncObj)
{
queue.Enqueue(message);
}
}
public bool TrySendNextMessage()
{
lock (syncObj)
{
if (queue.Count > 0)
{
DebugLog($"queue count: {queue.Count}");
var message = commonQueue.Dequeue();
Write(message);
return true;
}
}
return false;
}
public void StoreLatestFrameSqNo(int pumpId, byte frameSqNo)
{
var pump = GetPump(pumpId);
if (pump != null)
{
pump.FrameSqNo = frameSqNo;
}
}
public void UpdatePumpState(int pumpId, int logicId, LogicalDeviceState state)
{
var currentPump = GetPump(pumpId);
currentPump?.FirePumpStateChange(state, Convert.ToByte(logicId));
}
public void UpdateFuelingStatus(int pumpId, FdcTransaction fuelingTransaction)
{
var currentPump = GetPump(pumpId);
currentPump?.FireFuelingStatusChange(fuelingTransaction);
}
private HengshanPumpHandler GetPump(int pumpId)
{
return pumpHandlers.FirstOrDefault(p => p.PumpId == pumpId);
}
public void SetRealPrice(int pumpId, int price)
{
var currentPump = GetPump(pumpId);
var nozzle = currentPump?.Nozzles.FirstOrDefault();
if (nozzle != null)
nozzle.RealPriceOnPhysicalPump = price;
}
#region Log methods
private void InfoLog(string info)
{
logger.Info("PayTermHdlr " + info);
}
private void DebugLog(string debugMsg)
{
logger.Debug("PayTermHdlr " + debugMsg);
}
#endregion
#region 二维码加油机相关方法
///
/// 获取站点信息
///
private void GetInfo()
{
Edge.Core.Domain.FccStationInfo.FccStationInfo? fccStationInfo = MysqlDbContext.FccStationInfos.FirstOrDefault();
if(fccStationInfo != null) stationInfo = new StationInfo(fccStationInfo);
nozzleInfoList = MysqlDbContext.NozzleInfos.ToList().Select(n => new DetailsNozzleInfoOutput(n)).ToList();
}
///
/// 发送二维码信息给油机
///
///
public void SendQRCode()
{
string? smallProgram = stationInfo?.SmallProgram;
if (smallProgram == null)
{
logger.Info($"can not get smallProgram link");
return;
}
System.Net.EndPoint? remoteEndPoint = this.client?.Client.RemoteEndPoint;
if (remoteEndPoint == null)
{
logger.Info($"can not get client");
return;
}
string[] remoteAddr = remoteEndPoint.ToString().Split(":");
string ip = remoteAddr[0];
List nozzles = nozzleInfoList.FindAll(nozzle => nozzle.Ip == ip);
foreach (var item in nozzles)
{
List list = new List();
byte[] commandAndNozzle = { 0x63, (byte)item.NozzleNum };
string qrCode = smallProgram + "/" + item.NozzleNum;
byte[] qrCodeBytes = Encoding.ASCII.GetBytes(qrCode);
list.AddRange(commandAndNozzle);
list.Add((byte)qrCodeBytes.Length);
list.AddRange(qrCodeBytes);
byte[] sendBytes = content2data(list.ToArray());
this.client?.Client.Send(sendBytes);
}
}
///
/// 发送实付金额给油机
///
///
public void SendActuallyPaid(FccOrderInfo orderInfo)
{
List list = new List();
byte[] commandAndNozzle = { 0x19, (byte)orderInfo.NozzleNum };
byte[] ttcBytes = NumberToByteArrayWithPadding(orderInfo.Ttc, 4);
byte[] amountPayableBytes = FormatDecimal(orderInfo.AmountPayable);
list.AddRange(commandAndNozzle); //添加命令字和枪号
list.AddRange(ttcBytes); //添加流水号
list.Add(0x21); //由fcc推送实付金额表示该订单是二维码小程序支付的
list.AddRange(amountPayableBytes); //添加实付金额
//添加3位交易金额1,3位交易金额2,2位优惠规则代码,10位卡应用号,4位消息鉴别码
list.AddRange(new byte[] { 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00 });
byte[] sendBytes = content2data(list.ToArray());
this.client?.Client.Send(sendBytes);
}
public void SetTcpClinet(TcpClient? tcpClient)
{
this.client = tcpClient;
}
///
/// 添加或修改订单
///
/// 接收到油机的订单信息
///
public int UpLoadOrder(OrderFromMachine order)
{
FccOrderInfo orderByMessage = order.ToComponent();
FccOrderInfo? fccOrderInfo = MysqlDbContext.fccOrderInfos.FirstOrDefault(fccOrder =>
fccOrder.NozzleNum == order.nozzleNum && fccOrder.Ttc == order.ttc);
if (fccOrderInfo == null)
{
logger.Info($"receive order from machine,find order from database is null");
MysqlDbContext.fccOrderInfos.Add(orderByMessage);
}
else
{
logger.Info($"receive order from machine,padding data right now");
order.PaddingAuthorizationOrderData(fccOrderInfo);
}
return MysqlDbContext.SaveChanges();
}
///
/// 传入有效数据,拼接为要发送给油机包
///
///
///
public byte[] content2data(byte[] content)
{
List list = new List();
//目标地址,源地址,帧号
byte[] head = new byte[] { 0xFF, 0xE0, 0x01 };
byte[] length = Int2BCD(content.Length);
list.AddRange(head);
list.AddRange(length);
list.AddRange(content);
byte[] crc = HengshanCRC16.ComputeChecksumToBytes(list.ToArray());
list.AddRange(crc);
List addFAList = addFA(list);
addFAList.Insert(0, 0xFA);
return addFAList.ToArray();
}
public int Bcd2Int(byte byte1, byte byte2)
{
// 提取第一个字节的高四位和低四位
int digit1 = (byte1 >> 4) & 0x0F; // 高四位
int digit2 = byte1 & 0x0F; // 低四位
// 提取第二个字节的高四位和低四位
int digit3 = (byte2 >> 4) & 0x0F; // 高四位
int digit4 = byte2 & 0x0F; // 低四位
// 组合成一个整数
int result = digit1 * 1000 + digit2 * 100 + digit3 * 10 + digit4;
return result;
}
public byte[] Int2BCD(int number)
{
// 提取千位、百位、十位和个位
int thousands = number / 1000;
int hundreds = (number / 100) % 10;
int tens = (number / 10) % 10;
int units = number % 10;
// 将千位和百位组合成一个字节(千位在高四位,百位在低四位)
byte firstByte = (byte)((thousands * 16) + hundreds); // 乘以16相当于左移4位
// 将十位和个位组合成一个字节(十位在高四位,个位在低四位)
byte secondByte = (byte)((tens * 16) + units);
// 返回结果数组
return new byte[] { firstByte, secondByte };
}
public List addFA(List list)
{
List result = new List();
foreach (byte b in list)
{
if (b == 0xFA)
{
result.Add(0xFA);
result.Add(0xFA);
}
else
{
result.Add(b);
}
}
return result;
}
///
/// 将数值转为byte[]
///
/// 数值
/// 数组长度,不够高位补0
///
///
public static byte[] NumberToByteArrayWithPadding(int value, int length)
{
if (length < 0)
{
throw new ArgumentException("Length must be non-negative.");
}
// 创建一个指定长度的字节数组
byte[] paddedBytes = new byte[length];
// 确保是大端序
for (int i = 0; i < length && i < 4; i++)
{
paddedBytes[length - 1 - i] = (byte)(value >> (i * 8));
}
return paddedBytes;
}
public static byte[] FormatDecimal(decimal value)
{
// 四舍五入到两位小数
decimal roundedValue = Math.Round(value, 2, MidpointRounding.AwayFromZero);
int valueInt = (int)(roundedValue * 100m);
return NumberToByteArrayWithPadding(valueInt, 3); ;
}
// CRC16 constants
const ushort CRC_ORDER16 = 16;
const ushort CRC_POLYNOM16 = 0x1021;
const ushort CRC_CRCINIT16 = 0xFFFF;
const ushort CRC_CRCXOR16 = 0x0000;
const ushort CRC_MASK = 0xFFFF;
const ushort CRC_HIGHEST_BIT = (ushort)(1 << (CRC_ORDER16 - 1));
const ushort TGT_CRC_DEFAULT_INIT = 0xFFFF;
public static ushort Crc16(byte[] buffer, ushort length)
{
ushort crc_rc = TGT_CRC_DEFAULT_INIT;
for (int i = 0; i < length; i++)
{
byte c = buffer[i];
for (ushort j = 0x80; j != 0; j >>= 1)
{
ushort crc_bit = (ushort)((crc_rc & CRC_HIGHEST_BIT) != 0 ? 1 : 0);
crc_rc <<= 1;
if ((c & j) != 0)
{
crc_bit = (ushort)((crc_bit == 0) ? 1 : 0);
}
if (crc_bit != 0)
{
crc_rc ^= CRC_POLYNOM16;
}
}
}
return (ushort)((crc_rc ^ CRC_CRCXOR16) & CRC_MASK);
}
#endregion
}
public class HengshanPayTerminalHanlderGroupConfigV1
{
public string PumpIds { get; set; }
public List PumpSubAddresses { get; set; }
}
public class HengshanPayTerminalHanlderGroupConfigV2
{
public string PumpIds { get; set; }
public List PumpSubAddresses { get; set; }
public List PumpNozzleLogicIds { get; set; }
public List PumpSiteNozzleNos { get; set; }
public List NozzleLogicIds { get; set; }
}
public class PumpSubAddress
{
public byte PumpId { get; set; }
public byte SubAddress { get; set; }
}
public class PumpNozzleLogicId
{
public byte PumpId { get; set; }
public string LogicIds { get; set; }
}
public class PumpSiteNozzleNo
{
public byte PumpId { get; set; }
public string SiteNozzleNos { get; set; }
}
public class NozzleLogicId
{
public byte NozzleNo { get; set; }
public byte LogicId { get; set; }
}
}