|
@@ -28,6 +28,8 @@ using HengshanPaymentTerminal.Http.Request;
|
|
|
using System.Text.Json;
|
|
|
using Newtonsoft.Json;
|
|
|
using HengshanPaymentTerminal.Http.Response;
|
|
|
+using HengshanPaymentTerminal.MessageEntity.Outgoing;
|
|
|
+using Microsoft.IdentityModel.Tokens;
|
|
|
|
|
|
namespace HengshanPaymentTerminal
|
|
|
{
|
|
@@ -81,14 +83,14 @@ namespace HengshanPaymentTerminal
|
|
|
|
|
|
public int? serverPort { get; set; }
|
|
|
|
|
|
- private readonly ConcurrentDictionary<string,TaskCompletionSource<CommonMessage>> _tcsDictionary = new ConcurrentDictionary<string, TaskCompletionSource<CommonMessage>>();
|
|
|
+ //private readonly ConcurrentDictionary<string,TaskCompletionSource<CommonMessage>> _tcsDictionary = new ConcurrentDictionary<string, TaskCompletionSource<CommonMessage>>();
|
|
|
|
|
|
- private TaskCompletionSource<ErrorMessage> checkDisConnectTask = new TaskCompletionSource<ErrorMessage>();
|
|
|
+ //private TaskCompletionSource<ErrorMessage> checkDisConnectTask = new TaskCompletionSource<ErrorMessage>();
|
|
|
|
|
|
private byte frame = 0x00;
|
|
|
private object lockFrame = new object();
|
|
|
|
|
|
- private readonly IHttpClientUtil httpClientUtil;
|
|
|
+ private IHttpClientUtil httpClientUtil;
|
|
|
|
|
|
//记录油枪状态,key-枪号,value:01:离线 02:锁枪 03:空闲 04:提枪 06:开始加油 08:加油中
|
|
|
private ConcurrentDictionary<int, int> nozzleStatusDic = new ConcurrentDictionary<int, int>();
|
|
@@ -150,10 +152,7 @@ namespace HengshanPaymentTerminal
|
|
|
this.pumpNozzles = pumpNozzles;
|
|
|
this.pumpSiteNozzleNos = pumpSiteNozzleNos;
|
|
|
this.nozzleLogicIds = nozzleLogicIds;
|
|
|
- this.MysqlDbContext = new MysqlDbContext();
|
|
|
- this.httpClientUtil = new HttpClientUtils();
|
|
|
-
|
|
|
- GetInfo();
|
|
|
+
|
|
|
AssociatedPumpIds = GetPumpIdList(pumpIds);
|
|
|
pumpIdSubAddressDict = InitializePumpSubAddressMapping();
|
|
|
PumpNozzlesDict = ParsePumpNozzlesList(pumpNozzles);
|
|
@@ -434,6 +433,12 @@ namespace HengshanPaymentTerminal
|
|
|
{
|
|
|
CommIdentity = context.Processor.Communicator.Identity;
|
|
|
_context = context;
|
|
|
+
|
|
|
+ this.MysqlDbContext = new MysqlDbContext();
|
|
|
+ this.httpClientUtil = new HttpClientUtils();
|
|
|
+
|
|
|
+ this.serverPort = CommIdentity.Replace("*:", "").ToInt();
|
|
|
+ GetInfo();
|
|
|
}
|
|
|
|
|
|
public string CommIdentity { get; private set; }
|
|
@@ -461,6 +466,7 @@ namespace HengshanPaymentTerminal
|
|
|
CreateTransaction(fccOrderInfo);
|
|
|
break;
|
|
|
}
|
|
|
+ /**
|
|
|
//普通应答
|
|
|
case 0x55:
|
|
|
{
|
|
@@ -513,6 +519,7 @@ namespace HengshanPaymentTerminal
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
+ */
|
|
|
|
|
|
}
|
|
|
|
|
@@ -590,7 +597,7 @@ namespace HengshanPaymentTerminal
|
|
|
}
|
|
|
|
|
|
public void Write(CommonMessage cardMessage)
|
|
|
- {
|
|
|
+ {
|
|
|
_context.Outgoing.Write(cardMessage);
|
|
|
}
|
|
|
|
|
@@ -707,8 +714,8 @@ namespace HengshanPaymentTerminal
|
|
|
/// <param name="tcpClient"></param>
|
|
|
public async void SendQRCodeAsync()
|
|
|
{
|
|
|
- string? smallProgram = stationInfo?.SmallProgram;
|
|
|
- if (smallProgram == null)
|
|
|
+ string smallProgram = stationInfo?.SmallProgram ?? "";
|
|
|
+ if (string.IsNullOrEmpty(smallProgram))
|
|
|
{
|
|
|
logger.Info($"can not get smallProgram link");
|
|
|
return;
|
|
@@ -717,17 +724,30 @@ namespace HengshanPaymentTerminal
|
|
|
List<DetailsNozzleInfoOutput> nozzles = nozzleInfoList.FindAll(nozzle => nozzle.Port == serverPort);
|
|
|
foreach (var item in nozzles)
|
|
|
{
|
|
|
- List<Byte> list = new List<Byte>();
|
|
|
- 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(), null);
|
|
|
+ //List<Byte> list = new List<Byte>();
|
|
|
+ //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(), null);
|
|
|
+
|
|
|
+ SendQrCode sendQrCode = new SendQrCode(item.NozzleNum, smallProgram, getFrame(null));
|
|
|
+ byte[] commandAndNozzle = { sendQrCode.Handle, (byte)sendQrCode.NozzleNum };
|
|
|
|
|
|
Thread.Sleep(5000);
|
|
|
- CommonMessage commonMessage = await SendRequestToMachine("发送二维码", BitConverter.ToString(commandAndNozzle).Replace("-", ""), sendBytes);
|
|
|
+ CommonMessage commonMessage = await SendMessageToMaichine($"发送{sendQrCode.NozzleNum}号枪二维码",(request,response) =>
|
|
|
+ {
|
|
|
+ if(response.Handle == (byte)CommonMessage.Command.COMMON)
|
|
|
+ {
|
|
|
+ CommonAnswerBack commonAnswerBack = (CommonAnswerBack)response;
|
|
|
+ return commonAnswerBack.Command == (byte)CommonMessage.Command.SEND_QR_CODE && commonAnswerBack.NozzleNum == sendQrCode.NozzleNum;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }, sendQrCode);
|
|
|
+ //CommonMessage commonMessage = await SendMessageToMaichine("发送二维码", BitConverter.ToString(commandAndNozzle).Replace("-", ""), sendQrCode);
|
|
|
+ //CommonMessage commonMessage = await SendRequestToMachine("发送二维码", BitConverter.ToString(commandAndNozzle).Replace("-", ""), sendBytes);
|
|
|
if (commonMessage.IsError && commonMessage.TheErrorType == CommonMessage.ErrorType.DISCONNECT) break;
|
|
|
}
|
|
|
|
|
@@ -755,71 +775,108 @@ namespace HengshanPaymentTerminal
|
|
|
/// <param name="orderInfo"></param>
|
|
|
public async void SendActuallyPaid(FccOrderInfo orderInfo)
|
|
|
{
|
|
|
- List<Byte> list = new List<Byte>();
|
|
|
- byte[] commandAndNozzle = { 0x19, (byte)orderInfo.NozzleNum };
|
|
|
- byte[] ttcBytes = NumberToByteArrayWithPadding(orderInfo.Ttc, 4);
|
|
|
-
|
|
|
- byte[] amountPayableBytes = FormatDecimal(orderInfo.AmountPayable ?? orderInfo.Amount);
|
|
|
- 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(), null);
|
|
|
-
|
|
|
- await SendRequestToMachine("发送实付金额", BitConverter.ToString(commandAndNozzle).Replace("-", ""), sendBytes);
|
|
|
+ //List<Byte> list = new List<Byte>();
|
|
|
+ //byte[] commandAndNozzle = { 0x19, (byte)orderInfo.NozzleNum };
|
|
|
+ //byte[] ttcBytes = NumberToByteArrayWithPadding(orderInfo.Ttc, 4);
|
|
|
+
|
|
|
+ //byte[] amountPayableBytes = FormatDecimal(orderInfo.AmountPayable ?? orderInfo.Amount);
|
|
|
+ //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(), null);
|
|
|
+
|
|
|
+
|
|
|
+ SendActuallyPaid sendActuallyPaid = new SendActuallyPaid(orderInfo.NozzleNum, orderInfo.Ttc, orderInfo.AmountPayable ?? orderInfo.Amount, getFrame(null));
|
|
|
+ byte[] commandAndNozzle = { sendActuallyPaid.Handle, (byte)sendActuallyPaid.NozzleNum };
|
|
|
+ await SendMessageToMaichine("发送实付金额", (request, response) =>
|
|
|
+ {
|
|
|
+ if (response.Handle == (byte)CommonMessage.Command.SEND_NEED_AMOUNT)
|
|
|
+ {
|
|
|
+ CommonAnswerBack commonAnswerBack = (CommonAnswerBack)response;
|
|
|
+ return commonAnswerBack.Command == (byte)CommonMessage.Command.SEND_NEED_AMOUNT && commonAnswerBack.NozzleNum == sendActuallyPaid.NozzleNum;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }, sendActuallyPaid);
|
|
|
+ //await SendMessageToMaichine("发送实付金额", BitConverter.ToString(commandAndNozzle).Replace("-", ""), sendActuallyPaid);
|
|
|
}
|
|
|
|
|
|
public async Task<CommonMessage> SendAuthorization(MqttAuthorizationRequest request)
|
|
|
{
|
|
|
- List<Byte> list = new List<Byte>();
|
|
|
- byte[] commandAndNozzle = { 0x65, (byte)request.NozzleNum };
|
|
|
- byte[] authorizationTimeBytes = ConvertDateTimeToByteArray(request.AuthorizationTime);
|
|
|
- //将小数点后移两位,因为油机只支持两位小数点,这边传过去的3位字节转为int后取后两位为十分位和百分位
|
|
|
- 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);
|
|
|
+ //List<Byte> list = new List<Byte>();
|
|
|
+ //byte[] commandAndNozzle = { 0x65, (byte)request.NozzleNum };
|
|
|
+ //byte[] authorizationTimeBytes = ConvertDateTimeToByteArray(request.AuthorizationTime);
|
|
|
+ ////将小数点后移两位,因为油机只支持两位小数点,这边传过去的3位字节转为int后取后两位为十分位和百分位
|
|
|
+ //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);
|
|
|
+
|
|
|
+ SendAuthorization sendAuthorization = new SendAuthorization(request.NozzleNum, request.AuthorizationTime, request.AuthorizationType,request.Value, getFrame(null));
|
|
|
+ byte[] commandAndNozzle = { sendAuthorization.Handle, (byte)sendAuthorization.NozzleNum };
|
|
|
+ return await SendMessageToMaichine("发送授权请求", (request, response) =>
|
|
|
+ {
|
|
|
+ if (response.Handle == (byte)CommonMessage.Command.ACCREDIT)
|
|
|
+ {
|
|
|
+ AuthorizationResponse authorization = (AuthorizationResponse)response;
|
|
|
+ return authorization.NozzleNum == sendAuthorization.NozzleNum;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }, sendAuthorization);
|
|
|
+ //return await SendMessageToMaichine("发送授权请求", BitConverter.ToString(commandAndNozzle).Replace("-", ""), sendAuthorization);
|
|
|
}
|
|
|
|
|
|
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);
|
|
|
- }
|
|
|
+ //List<Byte> list = new List<Byte>();
|
|
|
+ //byte[] commandAndNozzle = { 0x66, (byte)request.NozzleNum };
|
|
|
+ //byte[] authorizationTimeBytes = ConvertDateTimeToByteArray(request.AuthorizationTime);
|
|
|
|
|
|
- public void SetTcpClient(TcpClient? tcpClient, int? serverPort)
|
|
|
- {
|
|
|
- this.client = tcpClient;
|
|
|
- this.serverPort = serverPort;
|
|
|
- checkDisConnectTask = new TaskCompletionSource<ErrorMessage>();
|
|
|
- }
|
|
|
+ //byte[] ttcBytes = NumberToByteArrayWithPadding(request.Ttc, 4);
|
|
|
+ //list.AddRange(commandAndNozzle);
|
|
|
+ //list.AddRange(authorizationTimeBytes);
|
|
|
+ //list.AddRange(ttcBytes);
|
|
|
+ //byte[] sendBytes = content2data(list.ToArray(), null);
|
|
|
|
|
|
- public void OnTcpDisconnect()
|
|
|
- {
|
|
|
- this.client = null;
|
|
|
- ErrorMessage errorMessage = new ErrorMessage()
|
|
|
+ SendUnAuthorization sendUnAuthorization = new SendUnAuthorization(request.NozzleNum, request.AuthorizationTime, request.Ttc, getFrame(null));
|
|
|
+ byte[] commandAndNozzle = { sendUnAuthorization.Handle, (byte)sendUnAuthorization.NozzleNum };
|
|
|
+
|
|
|
+ return await SendMessageToMaichine("发送取消授权请求", (request, response) =>
|
|
|
{
|
|
|
- IsError = true,
|
|
|
- TheErrorType = CommonMessage.ErrorType.DISCONNECT,
|
|
|
- ErrorMessage = $"the client is disconnet"
|
|
|
- };
|
|
|
- checkDisConnectTask.SetResult(errorMessage);
|
|
|
+ if (response.Handle == (byte)CommonMessage.Command.CANCEL_ACCREDIT)
|
|
|
+ {
|
|
|
+ UnAhorizationResponse unauthorization = (UnAhorizationResponse)response;
|
|
|
+ return unauthorization.NozzleNum == sendUnAuthorization.NozzleNum;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }, sendUnAuthorization);
|
|
|
+ //return await SendMessageToMaichine("发送取消授权请求", BitConverter.ToString(commandAndNozzle).Replace("-", ""), sendUnAuthorization);
|
|
|
}
|
|
|
|
|
|
+ //public void SetTcpClient(TcpClient? tcpClient, int? serverPort)
|
|
|
+ //{
|
|
|
+ // this.client = tcpClient;
|
|
|
+ // this.serverPort = serverPort;
|
|
|
+ // checkDisConnectTask = new TaskCompletionSource<ErrorMessage>();
|
|
|
+ //}
|
|
|
+
|
|
|
+ //public void OnTcpDisconnect()
|
|
|
+ //{
|
|
|
+ // this.client = null;
|
|
|
+ // ErrorMessage errorMessage = new ErrorMessage()
|
|
|
+ // {
|
|
|
+ // IsError = true,
|
|
|
+ // TheErrorType = CommonMessage.ErrorType.DISCONNECT,
|
|
|
+ // ErrorMessage = $"the client is disconnet"
|
|
|
+ // };
|
|
|
+ // checkDisConnectTask.SetResult(errorMessage);
|
|
|
+ //}
|
|
|
+
|
|
|
/// <summary>
|
|
|
/// 发送消息到油机,3秒的超时,重试三次
|
|
|
/// </summary>
|
|
@@ -827,63 +884,50 @@ namespace HengshanPaymentTerminal
|
|
|
/// <param name="sendKey">发送的消息key,用于存储 TaskCompletionSource</param>
|
|
|
/// <param name="requestBytes">实际发送消息</param>
|
|
|
/// <returns></returns>
|
|
|
- /// <exception cref="TimeoutException"></exception>
|
|
|
- private async Task<CommonMessage> SendRequestToMachine(string sendTag,string sendKey, byte[] requestBytes)
|
|
|
+ private async Task<CommonMessage> SendMessageToMaichine(string sendTag, Func<CommonMessage, CommonMessage, bool> responseCapture,CommonMessage sendMessage)
|
|
|
{
|
|
|
int retryCount = 0;
|
|
|
- while(retryCount < 3)
|
|
|
+ while (retryCount < 3)
|
|
|
{
|
|
|
try
|
|
|
{
|
|
|
- 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}");
|
|
|
+ var response = await this.Context.Outgoing.WriteAsyncAndCheckIsConnect(sendMessage, responseCapture, 3000);
|
|
|
+
|
|
|
|
|
|
- if (client != null)
|
|
|
+ //超时重试
|
|
|
+ if (response.ResponseType == WriteResponseType.TIME_OUT || response.Data == null)
|
|
|
{
|
|
|
- client?.Client?.Send(requestBytes);
|
|
|
- } else
|
|
|
+ retryCount++;
|
|
|
+ logger.Info($"{sendTag}: time out,retrying... ({retryCount} / 3)");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ //链接断开不再发送
|
|
|
+ if (response.ResponseType == WriteResponseType.DISCONNECT)
|
|
|
{
|
|
|
- return new ErrorMessage()
|
|
|
+ var isConnect = (bool)(response.Data ?? false);
|
|
|
+ if (!isConnect) return new ErrorMessage()
|
|
|
{
|
|
|
IsError = true,
|
|
|
TheErrorType = CommonMessage.ErrorType.DISCONNECT,
|
|
|
ErrorMessage = $"the client is disconnet"
|
|
|
};
|
|
|
- }
|
|
|
-
|
|
|
- logger.Info($"send request to machine:{BitConverter.ToString(requestBytes).Replace("-", " ")}");
|
|
|
|
|
|
- TaskCompletionSource<CommonMessage>? value;
|
|
|
- TaskCompletionSource<CommonMessage> tcs;
|
|
|
- if(_tcsDictionary.TryGetValue(sendKey, out value))
|
|
|
- {
|
|
|
- tcs = value;
|
|
|
- } else
|
|
|
- {
|
|
|
- tcs = new TaskCompletionSource<CommonMessage>();
|
|
|
- }
|
|
|
- Task checkOutTime = Task.Delay(Timeout.Infinite, cts.Token);
|
|
|
- var response = await Task.WhenAny(tcs.Task, checkOutTime, checkDisConnectTask.Task);
|
|
|
- if(response == checkOutTime)
|
|
|
- {
|
|
|
- retryCount++;
|
|
|
- logger.Info($"{sendTag}-{sendKey}: time out,retrying... ({retryCount} / 3)");
|
|
|
- continue;
|
|
|
}
|
|
|
- //CommonMessage response = await tcs.Task.WaitAsync(cts.Token);
|
|
|
- _tcsDictionary.TryRemove(sendKey, out _);
|
|
|
- return await (Task<CommonMessage>)response;
|
|
|
- } catch (Exception)
|
|
|
+ Console.WriteLine("");
|
|
|
+ //返回信息
|
|
|
+ return (CommonMessage)response.Data;
|
|
|
+ }
|
|
|
+ catch (Exception)
|
|
|
{
|
|
|
retryCount++;
|
|
|
- logger.Info($"{sendTag}-{sendKey}: error,retrying... ({retryCount} / 3)");
|
|
|
- } finally
|
|
|
+ logger.Info($"{sendTag}: error,retrying... ({retryCount} / 3)");
|
|
|
+ }
|
|
|
+ finally
|
|
|
{
|
|
|
- if(retryCount >= 3)
|
|
|
+ if (retryCount >= 3)
|
|
|
{
|
|
|
- logger.Info($"{sendTag}-{sendKey}: is time out add retry 3 time");
|
|
|
- _tcsDictionary.TryRemove(sendKey,out _);
|
|
|
+ logger.Info($"{sendTag}: is time out add retry 3 time");
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -894,6 +938,169 @@ namespace HengshanPaymentTerminal
|
|
|
ErrorMessage = $"{sendTag}: can not receive response after 3 retries"
|
|
|
};
|
|
|
}
|
|
|
+
|
|
|
+ ///// <summary>
|
|
|
+ ///// 发送消息到油机,3秒的超时,重试三次
|
|
|
+ ///// </summary>
|
|
|
+ ///// <param name="sendTag">发送的消息类型,用于日志记录</param>
|
|
|
+ ///// <param name="sendKey">发送的消息key,用于存储 TaskCompletionSource</param>
|
|
|
+ ///// <param name="requestBytes">实际发送消息</param>
|
|
|
+ ///// <returns></returns>
|
|
|
+ //private async Task<CommonMessage> SendMessageToMaichine(string sendTag, string sendKey,CommonMessage sendMessage)
|
|
|
+ //{
|
|
|
+ // int retryCount = 0;
|
|
|
+ // while (retryCount < 3)
|
|
|
+ // {
|
|
|
+ // try
|
|
|
+ // {
|
|
|
+ // 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}");
|
|
|
+
|
|
|
+ // Write(sendMessage);
|
|
|
+
|
|
|
+ // TaskCompletionSource<CommonMessage>? value;
|
|
|
+ // TaskCompletionSource<CommonMessage> tcs;
|
|
|
+ // if (_tcsDictionary.TryGetValue(sendKey, out value))
|
|
|
+ // {
|
|
|
+ // tcs = value;
|
|
|
+ // }
|
|
|
+ // else
|
|
|
+ // {
|
|
|
+ // tcs = new TaskCompletionSource<CommonMessage>();
|
|
|
+ // }
|
|
|
+ // Task checkOutTime = Task.Delay(Timeout.Infinite, cts.Token);
|
|
|
+ // var response = await Task.WhenAny(tcs.Task, checkOutTime, checkDisConnectTask.Task);
|
|
|
+ // //超时重试
|
|
|
+ // if (response == checkOutTime)
|
|
|
+ // {
|
|
|
+ // retryCount++;
|
|
|
+ // logger.Info($"{sendTag}-{sendKey}: time out,retrying... ({retryCount} / 3)");
|
|
|
+ // continue;
|
|
|
+ // }
|
|
|
+ // //CommonMessage response = await tcs.Task.WaitAsync(cts.Token);
|
|
|
+ // _tcsDictionary.TryRemove(sendKey, out _);
|
|
|
+
|
|
|
+ // //链接断开不再发送
|
|
|
+ // if(response == checkDisConnectTask.Task)
|
|
|
+ // {
|
|
|
+ // return new ErrorMessage()
|
|
|
+ // {
|
|
|
+ // IsError = true,
|
|
|
+ // TheErrorType = CommonMessage.ErrorType.DISCONNECT,
|
|
|
+ // ErrorMessage = $"the client is disconnet"
|
|
|
+ // };
|
|
|
+ // }
|
|
|
+
|
|
|
+ // //返回信息
|
|
|
+ // return await (Task<CommonMessage>)response;
|
|
|
+ // }
|
|
|
+ // catch (Exception)
|
|
|
+ // {
|
|
|
+ // retryCount++;
|
|
|
+ // logger.Info($"{sendTag}-{sendKey}: error,retrying... ({retryCount} / 3)");
|
|
|
+ // }
|
|
|
+ // finally
|
|
|
+ // {
|
|
|
+ // if (retryCount >= 3)
|
|
|
+ // {
|
|
|
+ // logger.Info($"{sendTag}-{sendKey}: is time out add retry 3 time");
|
|
|
+ // _tcsDictionary.TryRemove(sendKey, out _);
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ // return new ErrorMessage()
|
|
|
+ // {
|
|
|
+ // IsError = true,
|
|
|
+ // TheErrorType = CommonMessage.ErrorType.TIMEOUT,
|
|
|
+ // ErrorMessage = $"{sendTag}: can not receive response after 3 retries"
|
|
|
+ // };
|
|
|
+ //}
|
|
|
+
|
|
|
+ ///// <summary>
|
|
|
+ ///// 发送消息到油机,3秒的超时,重试三次
|
|
|
+ ///// </summary>
|
|
|
+ ///// <param name="sendTag">发送的消息类型,用于日志记录</param>
|
|
|
+ ///// <param name="sendKey">发送的消息key,用于存储 TaskCompletionSource</param>
|
|
|
+ ///// <param name="requestBytes">实际发送消息</param>
|
|
|
+ ///// <returns></returns>
|
|
|
+ ///// <exception cref="TimeoutException"></exception>
|
|
|
+ //private async Task<CommonMessage> SendRequestToMachine(string sendTag,string sendKey, byte[] requestBytes)
|
|
|
+ //{
|
|
|
+ // int retryCount = 0;
|
|
|
+ // while(retryCount < 3)
|
|
|
+ // {
|
|
|
+ // try
|
|
|
+ // {
|
|
|
+ // 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}");
|
|
|
+
|
|
|
+ // if (client != null)
|
|
|
+ // {
|
|
|
+ // client?.Client?.Send(requestBytes);
|
|
|
+ // } else
|
|
|
+ // {
|
|
|
+ // return new ErrorMessage()
|
|
|
+ // {
|
|
|
+ // IsError = true,
|
|
|
+ // TheErrorType = CommonMessage.ErrorType.DISCONNECT,
|
|
|
+ // ErrorMessage = $"the client is disconnet"
|
|
|
+ // };
|
|
|
+ // }
|
|
|
+
|
|
|
+ // logger.Info($"send request to machine:{BitConverter.ToString(requestBytes).Replace("-", " ")}");
|
|
|
+
|
|
|
+ // TaskCompletionSource<CommonMessage>? value;
|
|
|
+ // TaskCompletionSource<CommonMessage> tcs;
|
|
|
+ // if(_tcsDictionary.TryGetValue(sendKey, out value))
|
|
|
+ // {
|
|
|
+ // tcs = value;
|
|
|
+ // } else
|
|
|
+ // {
|
|
|
+ // tcs = new TaskCompletionSource<CommonMessage>();
|
|
|
+ // }
|
|
|
+ // Task checkOutTime = Task.Delay(Timeout.Infinite, cts.Token);
|
|
|
+ // var response = await Task.WhenAny(tcs.Task, checkOutTime, checkDisConnectTask.Task);
|
|
|
+ // if(response == checkOutTime)
|
|
|
+ // {
|
|
|
+ // retryCount++;
|
|
|
+ // logger.Info($"{sendTag}-{sendKey}: time out,retrying... ({retryCount} / 3)");
|
|
|
+ // continue;
|
|
|
+ // }
|
|
|
+ // //CommonMessage response = await tcs.Task.WaitAsync(cts.Token);
|
|
|
+ // _tcsDictionary.TryRemove(sendKey, out _);
|
|
|
+ // if (response == checkDisConnectTask.Task)
|
|
|
+ // {
|
|
|
+ // return new ErrorMessage()
|
|
|
+ // {
|
|
|
+ // IsError = true,
|
|
|
+ // TheErrorType = CommonMessage.ErrorType.DISCONNECT,
|
|
|
+ // ErrorMessage = $"the client is disconnet"
|
|
|
+ // };
|
|
|
+ // }
|
|
|
+ // return await (Task<CommonMessage>)response;
|
|
|
+ // } catch (Exception)
|
|
|
+ // {
|
|
|
+ // retryCount++;
|
|
|
+ // logger.Info($"{sendTag}-{sendKey}: error,retrying... ({retryCount} / 3)");
|
|
|
+ // } finally
|
|
|
+ // {
|
|
|
+ // if(retryCount >= 3)
|
|
|
+ // {
|
|
|
+ // logger.Info($"{sendTag}-{sendKey}: is time out add retry 3 time");
|
|
|
+ // _tcsDictionary.TryRemove(sendKey,out _);
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ // return new ErrorMessage()
|
|
|
+ // {
|
|
|
+ // IsError = true,
|
|
|
+ // TheErrorType = CommonMessage.ErrorType.TIMEOUT,
|
|
|
+ // ErrorMessage = $"{sendTag}: can not receive response after 3 retries"
|
|
|
+ // };
|
|
|
+ //}
|
|
|
+
|
|
|
/// <summary>
|
|
|
/// 添加或修改订单
|
|
|
/// </summary>
|
|
@@ -947,20 +1154,6 @@ namespace HengshanPaymentTerminal
|
|
|
fccOrderInfo.CloundOrderId = response?.data?.Id;
|
|
|
fccOrderInfo.UploadState = response?.data == null ? 0 : 1;
|
|
|
MysqlDbContext.SaveChanges();
|
|
|
- //// 后支付填充云端id
|
|
|
- //if(response != null && createTransaction.type == 2)
|
|
|
- //{
|
|
|
- // FccOrderInfo? currentOrder = MysqlDbContext.FccOrderInfos
|
|
|
- // .Where(order =>
|
|
|
- // order.NozzleNum == fccOrderInfo.NozzleNum && order.Ttc == fccOrderInfo.Ttc
|
|
|
- // && order.AuthorizationTime == fccOrderInfo.AuthorizationTime)
|
|
|
- // .FirstOrDefault();
|
|
|
- // if(currentOrder != null)
|
|
|
- // {
|
|
|
- // currentOrder.CloundOrderId = response.data;
|
|
|
- // MysqlDbContext.SaveChanges();
|
|
|
- // }
|
|
|
- //}
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
@@ -1009,16 +1202,14 @@ namespace HengshanPaymentTerminal
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
- /// 传入有效数据,拼接为要发送给油机包
|
|
|
+ /// 获取发送帧号
|
|
|
/// </summary>
|
|
|
- /// <param name="content"></param>
|
|
|
+ /// <param name="sendFrame"></param>
|
|
|
/// <returns></returns>
|
|
|
- public byte[] content2data(byte[] content,byte? sendFrame)
|
|
|
+ private byte getFrame(byte? sendFrame)
|
|
|
{
|
|
|
- List<byte> list = new List<byte>();
|
|
|
- //目标地址,源地址,帧号
|
|
|
byte frameNo = 0x00;
|
|
|
- if(sendFrame == null)
|
|
|
+ if (sendFrame == null)
|
|
|
{
|
|
|
lock (lockFrame)
|
|
|
{
|
|
@@ -1028,138 +1219,170 @@ namespace HengshanPaymentTerminal
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- frameNo = (byte)(frame + 1);
|
|
|
+ frameNo = (byte)(frame++);
|
|
|
}
|
|
|
}
|
|
|
- } else
|
|
|
+ }
|
|
|
+ else
|
|
|
{
|
|
|
frameNo = sendFrame.Value;
|
|
|
}
|
|
|
-
|
|
|
- byte[] head = new byte[] { 0xFF, 0xE0, frameNo };
|
|
|
- byte[] length = Int2BCD(content.Length);
|
|
|
- list.AddRange(head);
|
|
|
- list.AddRange(length);
|
|
|
- list.AddRange(content);
|
|
|
- byte[] crc = HengshanCRC16.ComputeChecksumToBytes(list.ToArray());
|
|
|
- list.AddRange(crc);
|
|
|
- List<byte> addFAList = addFA(list);
|
|
|
- addFAList.Insert(0, 0xFA);
|
|
|
- return addFAList.ToArray();
|
|
|
+ return frameNo;
|
|
|
}
|
|
|
|
|
|
- public int Bcd2Int(byte byte1, byte byte2)
|
|
|
- {
|
|
|
- // 提取第一个字节的高四位和低四位
|
|
|
- int digit1 = (byte1 >> 4) & 0x0F; // 高四位
|
|
|
- int digit2 = byte1 & 0x0F; // 低四位
|
|
|
+ ///// <summary>
|
|
|
+ ///// 传入有效数据,拼接为要发送给油机包
|
|
|
+ ///// </summary>
|
|
|
+ ///// <param name="content"></param>
|
|
|
+ ///// <returns></returns>
|
|
|
+ //public byte[] content2data(byte[] content, byte? sendFrame)
|
|
|
+ //{
|
|
|
+ // List<byte> list = new List<byte>();
|
|
|
+ // //目标地址,源地址,帧号
|
|
|
+ // byte frameNo = 0x00;
|
|
|
+ // if (sendFrame == null)
|
|
|
+ // {
|
|
|
+ // lock (lockFrame)
|
|
|
+ // {
|
|
|
+ // if (frame == 0x3f)
|
|
|
+ // {
|
|
|
+ // frameNo = 0x00;
|
|
|
+ // }
|
|
|
+ // else
|
|
|
+ // {
|
|
|
+ // frameNo = (byte)(frame++);
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ // else
|
|
|
+ // {
|
|
|
+ // frameNo = sendFrame.Value;
|
|
|
+ // }
|
|
|
|
|
|
- // 提取第二个字节的高四位和低四位
|
|
|
- int digit3 = (byte2 >> 4) & 0x0F; // 高四位
|
|
|
- int digit4 = byte2 & 0x0F; // 低四位
|
|
|
+ // byte[] head = new byte[] { 0xFF, 0xE0, frameNo };
|
|
|
+ // byte[] length = Int2BCD(content.Length);
|
|
|
+ // list.AddRange(head);
|
|
|
+ // list.AddRange(length);
|
|
|
+ // list.AddRange(content);
|
|
|
+ // byte[] crc = HengshanCRC16.ComputeChecksumToBytes(list.ToArray());
|
|
|
+ // list.AddRange(crc);
|
|
|
+ // List<byte> addFAList = addFA(list);
|
|
|
+ // addFAList.Insert(0, 0xFA);
|
|
|
+ // return addFAList.ToArray();
|
|
|
+ //}
|
|
|
|
|
|
- // 组合成一个整数
|
|
|
- int result = digit1 * 1000 + digit2 * 100 + digit3 * 10 + digit4;
|
|
|
+ //public int Bcd2Int(byte byte1, byte byte2)
|
|
|
+ //{
|
|
|
+ // // 提取第一个字节的高四位和低四位
|
|
|
+ // int digit1 = (byte1 >> 4) & 0x0F; // 高四位
|
|
|
+ // int digit2 = byte1 & 0x0F; // 低四位
|
|
|
|
|
|
- return result;
|
|
|
- }
|
|
|
+ // // 提取第二个字节的高四位和低四位
|
|
|
+ // int digit3 = (byte2 >> 4) & 0x0F; // 高四位
|
|
|
+ // int digit4 = byte2 & 0x0F; // 低四位
|
|
|
|
|
|
- public byte[] Int2BCD(int number)
|
|
|
- {
|
|
|
- // 提取千位、百位、十位和个位
|
|
|
- int thousands = number / 1000;
|
|
|
- int hundreds = (number / 100) % 10;
|
|
|
- int tens = (number / 10) % 10;
|
|
|
- int units = number % 10;
|
|
|
+ // // 组合成一个整数
|
|
|
+ // int result = digit1 * 1000 + digit2 * 100 + digit3 * 10 + digit4;
|
|
|
|
|
|
- // 将千位和百位组合成一个字节(千位在高四位,百位在低四位)
|
|
|
- byte firstByte = (byte)((thousands * 16) + hundreds); // 乘以16相当于左移4位
|
|
|
+ // return result;
|
|
|
+ //}
|
|
|
|
|
|
- // 将十位和个位组合成一个字节(十位在高四位,个位在低四位)
|
|
|
- byte secondByte = (byte)((tens * 16) + units);
|
|
|
+ //public byte[] Int2BCD(int number)
|
|
|
+ //{
|
|
|
+ // // 提取千位、百位、十位和个位
|
|
|
+ // int thousands = number / 1000;
|
|
|
+ // int hundreds = (number / 100) % 10;
|
|
|
+ // int tens = (number / 10) % 10;
|
|
|
+ // int units = number % 10;
|
|
|
|
|
|
- // 返回结果数组
|
|
|
- return new byte[] { firstByte, secondByte };
|
|
|
- }
|
|
|
+ // // 将千位和百位组合成一个字节(千位在高四位,百位在低四位)
|
|
|
+ // byte firstByte = (byte)((thousands * 16) + hundreds); // 乘以16相当于左移4位
|
|
|
|
|
|
- public List<Byte> addFA(List<Byte> list)
|
|
|
- {
|
|
|
- List<byte> result = new List<byte>();
|
|
|
+ // // 将十位和个位组合成一个字节(十位在高四位,个位在低四位)
|
|
|
+ // byte secondByte = (byte)((tens * 16) + units);
|
|
|
|
|
|
- foreach (byte b in list)
|
|
|
- {
|
|
|
- if (b == 0xFA)
|
|
|
- {
|
|
|
- result.Add(0xFA);
|
|
|
- result.Add(0xFA);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- result.Add(b);
|
|
|
- }
|
|
|
- }
|
|
|
+ // // 返回结果数组
|
|
|
+ // return new byte[] { firstByte, secondByte };
|
|
|
+ //}
|
|
|
|
|
|
- return result;
|
|
|
- }
|
|
|
+ //public List<Byte> addFA(List<Byte> list)
|
|
|
+ //{
|
|
|
+ // List<byte> result = new List<byte>();
|
|
|
|
|
|
- /// <summary>
|
|
|
- /// 将数值转为byte[]
|
|
|
- /// </summary>
|
|
|
- /// <param name="value">数值</param>
|
|
|
- /// <param name="length">数组长度,不够高位补0</param>
|
|
|
- /// <returns></returns>
|
|
|
- /// <exception cref="ArgumentException"></exception>
|
|
|
- public static byte[] NumberToByteArrayWithPadding(int value, int length)
|
|
|
- {
|
|
|
- if (length < 0)
|
|
|
- {
|
|
|
- throw new ArgumentException("Length must be non-negative.");
|
|
|
- }
|
|
|
+ // foreach (byte b in list)
|
|
|
+ // {
|
|
|
+ // if (b == 0xFA)
|
|
|
+ // {
|
|
|
+ // result.Add(0xFA);
|
|
|
+ // result.Add(0xFA);
|
|
|
+ // }
|
|
|
+ // else
|
|
|
+ // {
|
|
|
+ // result.Add(b);
|
|
|
+ // }
|
|
|
+ // }
|
|
|
|
|
|
- // 创建一个指定长度的字节数组
|
|
|
- byte[] paddedBytes = new byte[length];
|
|
|
+ // return result;
|
|
|
+ //}
|
|
|
|
|
|
- // 确保是大端序
|
|
|
- for (int i = 0; i < length && i < 4; i++)
|
|
|
- {
|
|
|
- paddedBytes[length - 1 - i] = (byte)(value >> (i * 8));
|
|
|
- }
|
|
|
+ ///// <summary>
|
|
|
+ ///// 将数值转为byte[]
|
|
|
+ ///// </summary>
|
|
|
+ ///// <param name="value">数值</param>
|
|
|
+ ///// <param name="length">数组长度,不够高位补0</param>
|
|
|
+ ///// <returns></returns>
|
|
|
+ ///// <exception cref="ArgumentException"></exception>
|
|
|
+ //public static byte[] NumberToByteArrayWithPadding(int value, int length)
|
|
|
+ //{
|
|
|
+ // if (length < 0)
|
|
|
+ // {
|
|
|
+ // throw new ArgumentException("Length must be non-negative.");
|
|
|
+ // }
|
|
|
|
|
|
- return paddedBytes;
|
|
|
- }
|
|
|
+ // // 创建一个指定长度的字节数组
|
|
|
+ // byte[] paddedBytes = new byte[length];
|
|
|
|
|
|
- public static byte[] FormatDecimal(decimal value)
|
|
|
- {
|
|
|
- // 四舍五入到两位小数
|
|
|
- decimal roundedValue = Math.Round(value, 2, MidpointRounding.AwayFromZero);
|
|
|
- int valueInt = (int)(roundedValue * 100m);
|
|
|
- return NumberToByteArrayWithPadding(valueInt, 3); ;
|
|
|
- }
|
|
|
+ // // 确保是大端序
|
|
|
+ // for (int i = 0; i < length && i < 4; i++)
|
|
|
+ // {
|
|
|
+ // paddedBytes[length - 1 - i] = (byte)(value >> (i * 8));
|
|
|
+ // }
|
|
|
|
|
|
- /// <summary>
|
|
|
- /// 将时间转为 BCD
|
|
|
- /// </summary>
|
|
|
- /// <param name="dateTime"></param>
|
|
|
- /// <returns></returns>
|
|
|
- public static byte[] ConvertDateTimeToByteArray(DateTime dateTime)
|
|
|
- {
|
|
|
- // 创建byte数组
|
|
|
- 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); // 十年和个年
|
|
|
-
|
|
|
- // 月、日、小时、分钟、秒直接转换为BCD
|
|
|
- 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;
|
|
|
- }
|
|
|
+ // 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); ;
|
|
|
+ //}
|
|
|
+
|
|
|
+ ///// <summary>
|
|
|
+ ///// 将时间转为 BCD
|
|
|
+ ///// </summary>
|
|
|
+ ///// <param name="dateTime"></param>
|
|
|
+ ///// <returns></returns>
|
|
|
+ //public static byte[] ConvertDateTimeToByteArray(DateTime dateTime)
|
|
|
+ //{
|
|
|
+ // // 创建byte数组
|
|
|
+ // 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); // 十年和个年
|
|
|
+
|
|
|
+ // // 月、日、小时、分钟、秒直接转换为BCD
|
|
|
+ // 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;
|
|
|
+ //}
|
|
|
|
|
|
// CRC16 constants
|
|
|
const ushort CRC_ORDER16 = 16;
|