|
@@ -22,6 +22,7 @@ using Edge.Core.Domain.FccOrderInfo;
|
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities;
|
|
|
using static Microsoft.AspNetCore.Hosting.Internal.HostingApplication;
|
|
|
+using HengshanPaymentTerminal.Mqtt.Request;
|
|
|
|
|
|
namespace HengshanPaymentTerminal
|
|
|
{
|
|
@@ -72,6 +73,11 @@ namespace HengshanPaymentTerminal
|
|
|
public List<DetailsNozzleInfoOutput> nozzleInfoList { get; private set; }
|
|
|
|
|
|
public TcpClient? client { get; set; }
|
|
|
+
|
|
|
+ private readonly ConcurrentDictionary<string,TaskCompletionSource<CommonMessage>> _tcsDictionary = new ConcurrentDictionary<string, TaskCompletionSource<CommonMessage>>();
|
|
|
+
|
|
|
+ private byte frame = 0x00;
|
|
|
+ private object lockFrame = new object();
|
|
|
#endregion
|
|
|
|
|
|
#region Logger
|
|
@@ -422,11 +428,66 @@ namespace HengshanPaymentTerminal
|
|
|
{
|
|
|
|
|
|
case 0x18:
|
|
|
-
|
|
|
- OrderFromMachine message = (OrderFromMachine)context.Incoming.Message;
|
|
|
- int row = UpLoadOrder(message);
|
|
|
- logger.Info($"receive order from machine,database had ${row} count change");
|
|
|
- break;
|
|
|
+ {
|
|
|
+
|
|
|
+ OrderFromMachine orderFromMachine = (OrderFromMachine)context.Incoming.Message;
|
|
|
+ int row = UpLoadOrder(orderFromMachine);
|
|
|
+ logger.Info($"receive order from machine,database had ${row} count change");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ case 0x55:
|
|
|
+ {
|
|
|
+ CommonAnswerBack commonAnswerBack = (CommonAnswerBack)context.Incoming.Message;
|
|
|
+ if (commonAnswerBack.Command == 0x63)
|
|
|
+ {
|
|
|
+ byte[] keyBytes = { commonAnswerBack.Command, (byte)commonAnswerBack.NozzleNum };
|
|
|
+ var key = BitConverter.ToString(keyBytes).Replace("-", "");
|
|
|
+ if (_tcsDictionary.TryGetValue(key, out var value))
|
|
|
+ {
|
|
|
+ value.SetResult(commonAnswerBack);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ logger.Info($"qrcode response:can not get tcs for dictionary");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ case 0x65:
|
|
|
+ {
|
|
|
+ AuthorizationResponse authorizationResponse = (AuthorizationResponse)context.Incoming.Message;
|
|
|
+ byte[] keyBytes = { authorizationResponse.Handle, (byte)authorizationResponse.NozzleNum };
|
|
|
+ var key = BitConverter.ToString(keyBytes).Replace("-", "");
|
|
|
+ if (_tcsDictionary.TryGetValue(key, out var value))
|
|
|
+ {
|
|
|
+ value.SetResult(authorizationResponse);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ logger.Info($"authorization response:can not get tcs for dictionary");
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ case 0x66:
|
|
|
+ {
|
|
|
+ UnAhorizationResponse unauthorizationResponse = (UnAhorizationResponse)context.Incoming.Message;
|
|
|
+ byte[] keyBytes = { unauthorizationResponse.Handle, (byte)unauthorizationResponse.NozzleNum };
|
|
|
+ var key = BitConverter.ToString(keyBytes).Replace("-", "");
|
|
|
+ if (_tcsDictionary.TryGetValue(key, out var value))
|
|
|
+ {
|
|
|
+ value.SetResult(unauthorizationResponse);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ logger.Info($"unauthorization response:can not get tcs for dictionary");
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
|
|
|
context.Outgoing.Write(context.Incoming.Message);
|
|
@@ -616,7 +677,7 @@ namespace HengshanPaymentTerminal
|
|
|
|
|
|
|
|
|
|
|
|
- public void SendQRCode()
|
|
|
+ public async void SendQRCodeAsync()
|
|
|
{
|
|
|
string? smallProgram = stationInfo?.SmallProgram;
|
|
|
if (smallProgram == null)
|
|
@@ -643,8 +704,9 @@ namespace HengshanPaymentTerminal
|
|
|
list.AddRange(commandAndNozzle);
|
|
|
list.Add((byte)qrCodeBytes.Length);
|
|
|
list.AddRange(qrCodeBytes);
|
|
|
- byte[] sendBytes = content2data(list.ToArray());
|
|
|
- this.client?.Client.Send(sendBytes);
|
|
|
+ byte[] sendBytes = content2data(list.ToArray(),null);
|
|
|
+
|
|
|
+ await SendRequestToMachine("发送二维码", BitConverter.ToString(commandAndNozzle).Replace("-", ""), sendBytes);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -652,7 +714,7 @@ namespace HengshanPaymentTerminal
|
|
|
|
|
|
|
|
|
|
|
|
- public void SendActuallyPaid(FccOrderInfo orderInfo)
|
|
|
+ public async void SendActuallyPaid(FccOrderInfo orderInfo)
|
|
|
{
|
|
|
List<Byte> list = new List<Byte>();
|
|
|
byte[] commandAndNozzle = { 0x19, (byte)orderInfo.NozzleNum };
|
|
@@ -665,8 +727,39 @@ namespace HengshanPaymentTerminal
|
|
|
list.AddRange(amountPayableBytes);
|
|
|
|
|
|
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);
|
|
|
+ byte[] sendBytes = content2data(list.ToArray(), null);
|
|
|
+
|
|
|
+ await SendRequestToMachine("发送实付金额", BitConverter.ToString(commandAndNozzle).Replace("-", ""), sendBytes);
|
|
|
+ }
|
|
|
+
|
|
|
+ public async Task<CommonMessage> SendAuthorization(MqttAuthorizationRequest request)
|
|
|
+ {
|
|
|
+ List<Byte> list = new List<Byte>();
|
|
|
+ byte[] commandAndNozzle = { 0x65, (byte)request.NozzleNum };
|
|
|
+ byte[] authorizationTimeBytes = ConvertDateTimeToByteArray(request.AuthorizationTime);
|
|
|
+
|
|
|
+ int value = (int)request.Value * 100;
|
|
|
+ byte[] valueBytes = NumberToByteArrayWithPadding(value, 3);
|
|
|
+ list.AddRange(commandAndNozzle);
|
|
|
+ list.AddRange(authorizationTimeBytes);
|
|
|
+ list.Add((byte)request.AuthorizationType);
|
|
|
+ list.AddRange(valueBytes);
|
|
|
+ byte[] sendBytes = content2data(list.ToArray(), null);
|
|
|
+ return await SendRequestToMachine("发送授权请求", BitConverter.ToString(commandAndNozzle).Replace("-", ""), sendBytes);
|
|
|
+ }
|
|
|
+
|
|
|
+ public async Task<CommonMessage> SendUnAuthorizartion(MqttUnAhorizationRequest request)
|
|
|
+ {
|
|
|
+ List<Byte> list = new List<Byte>();
|
|
|
+ byte[] commandAndNozzle = { 0x66, (byte)request.NozzleNum };
|
|
|
+ byte[] authorizationTimeBytes = ConvertDateTimeToByteArray(request.AuthorizationTime);
|
|
|
+
|
|
|
+ byte[] ttcBytes = NumberToByteArrayWithPadding(request.Ttc, 4);
|
|
|
+ list.AddRange(commandAndNozzle);
|
|
|
+ list.AddRange(authorizationTimeBytes);
|
|
|
+ list.AddRange(ttcBytes);
|
|
|
+ byte[] sendBytes = content2data(list.ToArray(), null);
|
|
|
+ return await SendRequestToMachine("发送取消授权请求", BitConverter.ToString(commandAndNozzle).Replace("-", ""), sendBytes);
|
|
|
}
|
|
|
|
|
|
public void SetTcpClinet(TcpClient? tcpClient)
|
|
@@ -675,25 +768,83 @@ namespace HengshanPaymentTerminal
|
|
|
}
|
|
|
|
|
|
|
|
|
-
|
|
|
+
|
|
|
|
|
|
-
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
|
|
|
- public int UpLoadOrder(OrderFromMachine order)
|
|
|
+
|
|
|
+ private async Task<CommonMessage> SendRequestToMachine(string sendTag,string sendKey, byte[] requestBytes)
|
|
|
{
|
|
|
- FccOrderInfo orderByMessage = order.ToComponent();
|
|
|
- FccOrderInfo? fccOrderInfo = MysqlDbContext.fccOrderInfos.FirstOrDefault(fccOrder =>
|
|
|
- fccOrder.NozzleNum == order.nozzleNum && fccOrder.Ttc == order.ttc);
|
|
|
- if (fccOrderInfo == null)
|
|
|
+ int retryCount = 0;
|
|
|
+ while(retryCount < 3)
|
|
|
{
|
|
|
- logger.Info($"receive order from machine,find order from database is null");
|
|
|
- MysqlDbContext.fccOrderInfos.Add(orderByMessage);
|
|
|
+ var cts = new CancellationTokenSource(TimeSpan.FromSeconds(3));
|
|
|
+ bool isAdd = _tcsDictionary.TryAdd(sendKey, new TaskCompletionSource<CommonMessage>());
|
|
|
+ logger.Info($"{sendTag}: add request {sendKey} to dic is {isAdd}");
|
|
|
+
|
|
|
+ client?.Client.Send(requestBytes);
|
|
|
+
|
|
|
+ try
|
|
|
+ {
|
|
|
+ TaskCompletionSource<CommonMessage>? value;
|
|
|
+ TaskCompletionSource<CommonMessage> tcs;
|
|
|
+ if(_tcsDictionary.TryGetValue(sendKey, out value))
|
|
|
+ {
|
|
|
+ tcs = value;
|
|
|
+ } else
|
|
|
+ {
|
|
|
+ tcs = new TaskCompletionSource<CommonMessage>();
|
|
|
+ }
|
|
|
+
|
|
|
+ CommonMessage response = await tcs.Task.WaitAsync(cts.Token);
|
|
|
+ return response;
|
|
|
+ } catch (OperationCanceledException)
|
|
|
+ {
|
|
|
+ retryCount++;
|
|
|
+ logger.Info($"{sendTag}: time out,retrying... ({retryCount} / 3)");
|
|
|
+ } finally
|
|
|
+ {
|
|
|
+ if(retryCount >= 3)
|
|
|
+ {
|
|
|
+ logger.Info($"{sendTag}: is time out add retry 3 time");
|
|
|
+ _tcsDictionary.TryRemove(sendKey,out _);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
- else
|
|
|
+ return new ErrorMessage()
|
|
|
{
|
|
|
- logger.Info($"receive order from machine,padding data right now");
|
|
|
- order.PaddingAuthorizationOrderData(fccOrderInfo);
|
|
|
+ IsError = true,
|
|
|
+ ErrorMessage = $"{sendTag}: can not receive response after 3 retries"
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ public int UpLoadOrder(CommonMessage order)
|
|
|
+ {
|
|
|
+
|
|
|
+ if(order is OrderFromMachine)
|
|
|
+ {
|
|
|
+ OrderFromMachine orderFromMachine = (OrderFromMachine)order;
|
|
|
+ FccOrderInfo orderByMessage = orderFromMachine.ToComponent();
|
|
|
+ FccOrderInfo? fccOrderInfo = MysqlDbContext.fccOrderInfos.FirstOrDefault(fccOrder =>
|
|
|
+ fccOrder.NozzleNum == orderFromMachine.nozzleNum && fccOrder.Ttc == orderFromMachine.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");
|
|
|
+ orderFromMachine.PaddingAuthorizationOrderData(fccOrderInfo);
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
return MysqlDbContext.SaveChanges();
|
|
|
}
|
|
|
|
|
@@ -702,11 +853,30 @@ namespace HengshanPaymentTerminal
|
|
|
|
|
|
|
|
|
|
|
|
- public byte[] content2data(byte[] content)
|
|
|
+ public byte[] content2data(byte[] content,byte? sendFrame)
|
|
|
{
|
|
|
List<byte> list = new List<byte>();
|
|
|
|
|
|
- byte[] head = new byte[] { 0xFF, 0xE0, 0x01 };
|
|
|
+ byte frameNo = 0x00;
|
|
|
+ if(sendFrame == null)
|
|
|
+ {
|
|
|
+ lock (lockFrame)
|
|
|
+ {
|
|
|
+ if (frame == 0x3f)
|
|
|
+ {
|
|
|
+ frameNo = 0x00;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ frameNo = (byte)(frame + 1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else
|
|
|
+ {
|
|
|
+ frameNo = sendFrame.Value;
|
|
|
+ }
|
|
|
+
|
|
|
+ byte[] head = new byte[] { 0xFF, 0xE0, frameNo };
|
|
|
byte[] length = Int2BCD(content.Length);
|
|
|
list.AddRange(head);
|
|
|
list.AddRange(length);
|
|
@@ -806,6 +976,31 @@ namespace HengshanPaymentTerminal
|
|
|
return NumberToByteArrayWithPadding(valueInt, 3); ;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ public static byte[] ConvertDateTimeToByteArray(DateTime dateTime)
|
|
|
+ {
|
|
|
+
|
|
|
+ byte[] result = new byte[7];
|
|
|
+
|
|
|
+
|
|
|
+ int year = dateTime.Year;
|
|
|
+ result[0] = (byte)((year / 1000) * 16 + (year / 100) % 10);
|
|
|
+ result[1] = (byte)((year / 10) % 10 * 16 + year % 10);
|
|
|
+
|
|
|
+
|
|
|
+ result[2] = (byte)(dateTime.Month / 10 * 16 + dateTime.Month % 10);
|
|
|
+ result[3] = (byte)(dateTime.Day / 10 * 16 + dateTime.Day % 10);
|
|
|
+ result[4] = (byte)(dateTime.Hour / 10 * 16 + dateTime.Hour % 10);
|
|
|
+ result[5] = (byte)(dateTime.Minute / 10 * 16 + dateTime.Minute % 10);
|
|
|
+ result[6] = (byte)(dateTime.Second / 10 * 16 + dateTime.Second % 10);
|
|
|
+
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
|
|
|
const ushort CRC_ORDER16 = 16;
|
|
|
const ushort CRC_POLYNOM16 = 0x1021;
|