Prechádzať zdrojové kódy

feat(HengshanPaymentTerminal):发送信息到油机改为使用Context.Outgoing.WriteAsyncAndCheckIsConnect发送,支持超时时间,检测是否断开连接

Zhenghanjv 4 mesiacov pred
rodič
commit
179fa85e99

+ 9 - 9
Edge.Core/Processor/Communicator/TcpServerCommunicator.cs

@@ -19,7 +19,7 @@ namespace Edge.Core.Processor.Communicator
     [MetaPartsDescriptor(
         "lang-zh-cn:Tcp(本程序为服务器端)通讯器lang-en-us:Tcp(as server) communicator",
         "lang-zh-cn:基于TCP/IP技术的通讯器, FC作为服务器端等待客户端连接lang-en-us:TCP/IP based communicator, FC as the server and wait for connections")]
-    public class TcpServerCommunicator<T> : IClinet, ICommunicator<byte[], T> where T : MessageTemplateBase
+    public class TcpServerCommunicator<T> : ICommunicator<byte[], T> where T : MessageTemplateBase
     {
         private CancellationTokenSource readAsyncCancellationTokenSource;
         private DateTime? lastReceiveMsgDataFromTcpClientDateTime;
@@ -352,14 +352,14 @@ namespace Edge.Core.Processor.Communicator
         }
 
 
-        public TcpClient? GetTcpClient()
-        {
-            return this.exclusiveTcpClient;
-        }
+        //public TcpClient? GetTcpClient()
+        //{
+        //    return this.exclusiveTcpClient;
+        //}
 
-        public int GetServerPort()
-        {
-            return this.localTcpServerListeningPort;
-        }
+        //public int GetServerPort()
+        //{
+        //    return this.localTcpServerListeningPort;
+        //}
     }
 }

+ 12 - 8
Edge.Core/Processor/GenericDeviceProcessor.cs

@@ -94,7 +94,8 @@ namespace Edge.Core.Processor
 
             this.Communicator = communicator;
             var incoming = new HistoryKeepIncoming<TMessage>(10);
-            this.Context = new Context<TRaw, TMessage>(this, handler, communicator, incoming, new Outgoing<TRaw, TMessage>(incoming, services));
+            Outgoing<TRaw, TMessage> outgoing = new Outgoing<TRaw, TMessage>(incoming, services);
+            this.Context = new Context<TRaw, TMessage>(this, handler, communicator, incoming, outgoing);
             this.Context.Outgoing.OnWriting += (s, a) =>
             {
                 if (a.ExtraControlParameter != null)
@@ -104,16 +105,19 @@ namespace Edge.Core.Processor
             };
             this.Communicator.OnConnected += (communicator, a) =>
             {
-                if(communicator is IClinet)
-                {
-                    IClinet clinet = (IClinet)communicator;
-                    handler.SetTcpClient(clinet?.GetTcpClient(),clinet?.GetServerPort());
-                    handler.SendQRCodeAsync();
-                }
+                outgoing.OnConnect();
+                handler.SendQRCodeAsync();
+                //if (communicator is IClinet)
+                //{
+                //    IClinet clinet = (IClinet)communicator;
+                //    handler.SetTcpClient(clinet?.GetTcpClient(), clinet?.GetServerPort());
+                //    handler.SendQRCodeAsync();
+                //}
             };
             this.Communicator.OnDisconnected += (communicator, a) =>
             {
-                handler.OnTcpDisconnect();
+                outgoing.OnDisconnect();
+                //handler.OnTcpDisconnect();
             };
             this.Communicator.OnDataReceived += (s, a) =>
             {

+ 9 - 0
Edge.Core/Processor/Outgoing/IOutgoing.cs

@@ -33,6 +33,15 @@ namespace Edge.Core.Processor
         /// <returns>a response from remote device</returns>
         Task<TMessage> WriteAsync(TMessage request, Func<TMessage, TMessage, bool> responseCapture, int timeout);
 
+        /// <summary>
+        /// 加上检查是否连接正常的发送及回复
+        /// </summary>
+        /// <param name="request"></param>
+        /// <param name="responseCapture"></param>
+        /// <param name="timeout"></param>
+        /// <returns></returns>
+        Task<WriteRepsonse> WriteAsyncAndCheckIsConnect(TMessage request, Func<TMessage, TMessage, bool> responseCapture, int timeout);
+
         void Write(TMessage message);
 
         /// <summary>

+ 57 - 0
Edge.Core/Processor/Outgoing/Outgoing.cs

@@ -17,6 +17,10 @@ namespace Edge.Core.Processor
         static ILogger logger = NullLogger.Instance;
         protected IIncoming<TMessage> incoming;
         public event EventHandler<OutgoingEventArg<TMessage>> OnWriting;
+
+        //接收当前连接是否正常
+        private TaskCompletionSource<bool> isConnectTask;
+
         public Outgoing(IIncoming<TMessage> incoming)
         {
             this.incoming = incoming;
@@ -32,6 +36,22 @@ namespace Edge.Core.Processor
             }
         }
 
+        /// <summary>
+        /// 通知当前链接已连接
+        /// </summary>
+        public void OnConnect()
+        {
+            isConnectTask = new TaskCompletionSource<bool>();
+        }
+
+        /// <summary>
+        /// 通知当前链接已断开
+        /// </summary>
+        public void OnDisconnect()
+        {
+            isConnectTask.SetResult(false);
+        }
+
         /// <summary>
         /// 
         /// </summary>
@@ -90,6 +110,29 @@ namespace Edge.Core.Processor
             return tcs.Task;
         }
 
+        public virtual async Task<WriteRepsonse> WriteAsyncAndCheckIsConnect(TMessage request, Func<TMessage, TMessage, bool> responseCapture, int timeout)
+        {
+            Task<TMessage> sendTask = WriteAsync(request, responseCapture, timeout);
+            Task responseTask = await Task.WhenAny(sendTask, isConnectTask.Task);
+            var type = WriteResponseType.TIME_OUT;
+            object? result = null;
+            if (responseTask == sendTask)
+            {
+                result = await sendTask;
+                if (result != null) type = WriteResponseType.OK;
+            }
+            if(responseTask == isConnectTask.Task)
+            {
+                result = await isConnectTask.Task;
+                type = WriteResponseType.DISCONNECT;
+            }
+
+            return new WriteRepsonse()
+            {
+                ResponseType = type,
+                Data = result,
+            };
+        }
 
         public virtual void Write(TMessage message)
         {
@@ -108,4 +151,18 @@ namespace Edge.Core.Processor
             safe?.Invoke(this, new OutgoingEventArg<TMessage>() { Message = message, ExtraControlParameter = extraControlParameter });
         }
     }
+
+    public class WriteRepsonse
+    {
+        public WriteResponseType ResponseType { get; set; }
+
+        public object? Data { get; set; }
+    }
+
+    public enum WriteResponseType
+    {
+        TIME_OUT,
+        DISCONNECT,
+        OK
+    }
 }

+ 2 - 2
FccLite.sln

@@ -9,11 +9,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FccLite.Device", "src\FccLi
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FccLite.Web", "src\FccLife.Web\FccLite.Web.csproj", "{6D8BA5A6-16A3-40DE-9EB3-BD2985F04BDE}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HengshanPaymentTerminal", "HengshanPaymentTerminal\HengshanPaymentTerminal.csproj", "{4F13588F-3A60-4FE7-98D3-811D76924A92}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HengshanPaymentTerminal", "HengshanPaymentTerminal\HengshanPaymentTerminal.csproj", "{4F13588F-3A60-4FE7-98D3-811D76924A92}"
 EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Frameword", "Frameword", "{610364EC-E9E0-4864-887E-2DFBEA7B92BF}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Edge.Core", "Edge.Core\Edge.Core.csproj", "{CF30BD39-AB3C-4B9B-A3C1-79D64C35D1F6}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Edge.Core", "Edge.Core\Edge.Core.csproj", "{CF30BD39-AB3C-4B9B-A3C1-79D64C35D1F6}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution

+ 461 - 238
HengshanPaymentTerminal/HengshanPayTermHandler.cs

@@ -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;

+ 1 - 0
HengshanPaymentTerminal/HengshanPaymentTerminal.csproj

@@ -19,6 +19,7 @@
 
   <ItemGroup>
     <ProjectReference Include="..\Edge.Core\Edge.Core.csproj" />
+    <ProjectReference Include="..\Web\Web.csproj" />
   </ItemGroup>
 
   <ItemGroup>

+ 63 - 4
HengshanPaymentTerminal/MessageEntity/CommonMessage.cs

@@ -73,17 +73,17 @@ namespace HengshanPaymentTerminal.MessageEntity
         /// <summary>
         /// 包头 0xFA
         /// </summary>
-        public Byte Head { get; set; }
+        public Byte Head { get; set; } = 0xFA;
 
         /// <summary>
         /// 目标地址
         /// </summary>
-        public Byte DestinationAddr { get; set; }
+        public Byte DestinationAddr { get; set; } = 0xFF;
 
         /// <summary>
         /// 源地址
         /// </summary>
-        public Byte SourceAddr { get; set; }
+        public Byte SourceAddr { get; set; } = 0xE0;
 
         /// <summary>
         /// 帧号
@@ -121,7 +121,7 @@ namespace HengshanPaymentTerminal.MessageEntity
 
         public CommonMessage getBaseData(byte[] data)
         {
-            this.Handle = data[0];
+            this.Head = data[0];
             this.DestinationAddr = data[1];
             this.SourceAddr = data[2];
             this.FrameNum = data[3];
@@ -253,5 +253,64 @@ namespace HengshanPaymentTerminal.MessageEntity
             bool success = DateTime.TryParseExact(timeStr, formate, null, System.Globalization.DateTimeStyles.None, out parsedDateTime);
             return success ? parsedDateTime : DateTime.Now;
         }
+
+        /// <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.");
+            }
+
+            // 创建一个指定长度的字节数组
+            byte[] paddedBytes = new byte[length];
+
+            // 确保是大端序
+            for (int i = 0; i < length && i < 4; i++)
+            {
+                paddedBytes[length - 1 - i] = (byte)(value >> (i * 8));
+            }
+
+            return paddedBytes;
+        }
+
+        /// <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;
+        }
+
+        public static byte[] FormatDecimal(decimal value)
+        {
+            // 四舍五入到两位小数
+            decimal roundedValue = Math.Round(value, 2, MidpointRounding.AwayFromZero);
+            int valueInt = (int)(roundedValue * 100m);
+            return NumberToByteArrayWithPadding(valueInt, 3); ;
+        }
     }
 }

+ 63 - 0
HengshanPaymentTerminal/MessageEntity/Outgoing/SendActuallyPaid.cs

@@ -0,0 +1,63 @@
+using Edge.Core.Domain.FccOrderInfo.Output;
+using Edge.Core.Parser.BinaryParser.MessageEntity;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace HengshanPaymentTerminal.MessageEntity.Outgoing
+{
+    /// <summary>
+    /// 发送实际支付金额给油机数据对象
+    /// </summary>
+    public class SendActuallyPaid : CommonMessage
+    {
+        /// <summary>
+        /// 油枪号
+        /// </summary>
+        public int NozzleNum { get; set; }
+
+        /// <summary>
+        /// 流水号
+        /// </summary>
+        public int TTC {  get; set; }
+
+        /// <summary>
+        /// 实付金额
+        /// </summary>
+        public decimal Amount { get; set; }
+
+        public SendActuallyPaid(int nozzleNum, int tTC, decimal amount,byte frame)
+        {
+            this.Handle = (byte)Command.SEND_NEED_AMOUNT;
+            NozzleNum = nozzleNum;
+            TTC = tTC;
+            Amount = amount;
+            this.FrameNum = frame;
+        }
+
+        public override byte[] ToCommonByteArray()
+        {
+            List<Byte> list = new List<Byte>();
+            byte[] commandAndNozzle = { this.Handle, (byte)this.NozzleNum };
+            byte[] ttcBytes = NumberToByteArrayWithPadding(this.TTC, 4);
+
+            byte[] amountPayableBytes = FormatDecimal(this.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());
+
+            return sendBytes;
+        }
+
+        public override CommonMessage ToObject(byte[] datas)
+        {
+            return this;
+        }
+    }
+}

+ 68 - 0
HengshanPaymentTerminal/MessageEntity/Outgoing/SendAuthorization.cs

@@ -0,0 +1,68 @@
+using Edge.Core.Parser.BinaryParser.MessageEntity;
+using Org.BouncyCastle.Asn1.Ocsp;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace HengshanPaymentTerminal.MessageEntity.Outgoing
+{
+    /// <summary>
+    /// 发送授权请求给油机数据对象
+    /// </summary>
+    public class SendAuthorization : CommonMessage
+    {
+        /// <summary>
+        /// 请求授权的枪号
+        /// </summary>
+        public int NozzleNum {  get; set; }
+
+        /// <summary>
+        /// 请求授权时间
+        /// </summary>
+        private DateTime AuthorizationTime { get; set; }
+
+        /// <summary>
+        /// 授权类型:01:定金额,02:定升数
+        /// </summary>
+        private int AuthorizationType { get; set; }
+
+        /// <summary>
+        /// 定值量
+        /// </summary>
+        private decimal Value { get; set; }
+
+        public SendAuthorization(int nozzleNum, DateTime authorizationTime, int authorizationType, decimal value,byte frame)
+        {
+            this.Handle = (byte)Command.ACCREDIT;
+            NozzleNum = nozzleNum;
+            AuthorizationTime = authorizationTime;
+            AuthorizationType = authorizationType;
+            Value = value;
+            this.FrameNum = frame;
+        }
+
+        public override byte[] ToCommonByteArray()
+        {
+            List<Byte> list = new List<Byte>();
+            byte[] commandAndNozzle = { this.Handle, (byte)this.NozzleNum };
+            byte[] authorizationTimeBytes = ConvertDateTimeToByteArray(this.AuthorizationTime);
+            //将小数点后移两位,因为油机只支持两位小数点,这边传过去的3位字节转为int后取后两位为十分位和百分位
+            int value = (int)this.Value * 100;
+            byte[] valueBytes = NumberToByteArrayWithPadding(value, 3);
+            list.AddRange(commandAndNozzle);
+            list.AddRange(authorizationTimeBytes);
+            list.Add((byte)this.AuthorizationType);
+            list.AddRange(valueBytes);
+            byte[] sendBytes = content2data(list.ToArray());
+
+            return sendBytes;
+        }
+
+        public override CommonMessage ToObject(byte[] datas)
+        {
+            return this;
+        }
+    }
+}

+ 52 - 0
HengshanPaymentTerminal/MessageEntity/Outgoing/SendQrCode.cs

@@ -0,0 +1,52 @@
+using Edge.Core.Parser.BinaryParser.MessageEntity;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace HengshanPaymentTerminal.MessageEntity.Outgoing
+{
+    /// <summary>
+    /// 发送二维码至油机数据对象
+    /// </summary>
+    public class SendQrCode : CommonMessage
+    {
+        /// <summary>
+        /// 油枪号
+        /// </summary>
+        public int NozzleNum {  get; set; }
+
+        /// <summary>
+        /// 小程序链接
+        /// </summary>
+        private string SmallProgram {  get; set; }
+
+        public SendQrCode(int nozzle,string samllProgram,byte frame)
+        {
+            this.Handle = (byte)Command.SEND_QR_CODE;
+            this.NozzleNum = nozzle;
+            this.SmallProgram = samllProgram;
+            this.FrameNum = frame;
+        }
+
+        public override byte[] ToCommonByteArray()
+        {
+            List<Byte> list = new List<Byte>();
+            byte[] commandAndNozzle = { this.Handle, (byte)this.NozzleNum };
+            string qrCode = this.SmallProgram + "/" + this.NozzleNum;
+            byte[] qrCodeBytes = Encoding.ASCII.GetBytes(qrCode);
+            list.AddRange(commandAndNozzle);
+            list.Add((byte)qrCodeBytes.Length);
+            list.AddRange(qrCodeBytes);
+            byte[] sendBytes = content2data(list.ToArray());
+
+            return sendBytes;
+        }
+
+        public override CommonMessage ToObject(byte[] datas)
+        {
+            return this;
+        }
+    }
+}

+ 59 - 0
HengshanPaymentTerminal/MessageEntity/Outgoing/SendUnAuthorization.cs

@@ -0,0 +1,59 @@
+using Org.BouncyCastle.Asn1.Ocsp;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace HengshanPaymentTerminal.MessageEntity.Outgoing
+{
+    /// <summary>
+    /// 发送取消授权给油机数据对象
+    /// </summary>
+    public class SendUnAuthorization:CommonMessage
+    {
+        /// <summary>
+        /// 请求授权的枪号
+        /// </summary>
+        public int NozzleNum { get; set; }
+
+        /// <summary>
+        /// 请求授权时间
+        /// </summary>
+        private DateTime AuthorizationTime { get; set; }
+
+        /// <summary>
+        /// 授权后分配的流水号
+        /// </summary>
+        private int TTC {  get; set; }
+
+        public SendUnAuthorization(int nozzleNum, DateTime authorizationTime, int tTC,byte frame)
+        {
+            this.Handle = (byte)Command.CANCEL_ACCREDIT;
+            NozzleNum = nozzleNum;
+            AuthorizationTime = authorizationTime;
+            TTC = tTC;
+            this.FrameNum = frame;
+        }
+
+        public override byte[] ToCommonByteArray()
+        {
+            List<Byte> list = new List<Byte>();
+            byte[] commandAndNozzle = { this.Handle, (byte)this.NozzleNum };
+            byte[] authorizationTimeBytes = ConvertDateTimeToByteArray(this.AuthorizationTime);
+
+            byte[] ttcBytes = NumberToByteArrayWithPadding(this.TTC, 4);
+            list.AddRange(commandAndNozzle);
+            list.AddRange(authorizationTimeBytes);
+            list.AddRange(ttcBytes);
+            byte[] sendBytes = content2data(list.ToArray());
+
+            return sendBytes;
+        }
+
+        public override CommonMessage ToObject(byte[] datas)
+        {
+            return this;
+        }
+    }
+}

+ 16 - 16
HengshanPaymentTerminal/Test/CalculatorTest.cs

@@ -104,25 +104,25 @@ namespace HengshanPaymentTerminal.Test
         [Fact]
         private void testNumber2Bytes()
         {
-            byte[] bytes = HengshanPayTermHandler.NumberToByteArrayWithPadding(123123, 5);
-            string result = BitConverter.ToString(bytes).Replace("-", "");
-            Console.WriteLine(result);
+            //byte[] bytes = HengshanPayTermHandler.NumberToByteArrayWithPadding(123123, 5);
+            //string result = BitConverter.ToString(bytes).Replace("-", "");
+            //Console.WriteLine(result);
         }
 
         [Fact]
         private void testFormatDecimal()
         {
-            byte[] bytes1 = HengshanPayTermHandler.FormatDecimal(new decimal(12.1));
-            string result1 = BitConverter.ToString(bytes1).Replace("-", "");
-            Console.WriteLine(result1);
+            //byte[] bytes1 = HengshanPayTermHandler.FormatDecimal(new decimal(12.1));
+            //string result1 = BitConverter.ToString(bytes1).Replace("-", "");
+            //Console.WriteLine(result1);
 
-            byte[] bytes2 = HengshanPayTermHandler.FormatDecimal(new decimal(12.10));
-            string result2 = BitConverter.ToString(bytes2).Replace("-", "");
-            Console.WriteLine(result2);
+            //byte[] bytes2 = HengshanPayTermHandler.FormatDecimal(new decimal(12.10));
+            //string result2 = BitConverter.ToString(bytes2).Replace("-", "");
+            //Console.WriteLine(result2);
 
-            byte[] bytes3 = HengshanPayTermHandler.FormatDecimal(new decimal(12.54));
-            string result3 = BitConverter.ToString(bytes3).Replace("-", "");
-            Console.WriteLine(result3);
+            //byte[] bytes3 = HengshanPayTermHandler.FormatDecimal(new decimal(12.54));
+            //string result3 = BitConverter.ToString(bytes3).Replace("-", "");
+            //Console.WriteLine(result3);
 
            
         }
@@ -130,10 +130,10 @@ namespace HengshanPaymentTerminal.Test
         [Fact]
         private void testConverDateTimeToBytes()
         {
-            DateTime dateTime = DateTime.Now;
-            byte[] bytes = HengshanPayTermHandler.ConvertDateTimeToByteArray(dateTime);
-            string result = BitConverter.ToString(bytes).Replace("-", " ");
-            Console.WriteLine(result);
+            //DateTime dateTime = DateTime.Now;
+            //byte[] bytes = HengshanPayTermHandler.ConvertDateTimeToByteArray(dateTime);
+            //string result = BitConverter.ToString(bytes).Replace("-", " ");
+            //Console.WriteLine(result);
         }
     }
 }

+ 2 - 0
src/FccLife.Web/FccLite.Web.csproj

@@ -7,6 +7,7 @@
   </PropertyGroup>
 
   <ItemGroup>
+    <PackageReference Include="Microsoft.AspNetCore" Version="2.3.0" />
     <PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.20" />
     <PackageReference Include="NLog" Version="5.3.4" />
     <PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="7.0.0" />
@@ -16,6 +17,7 @@
   <ItemGroup>
     <ProjectReference Include="..\..\Edge.Core\Edge.Core.csproj" />
     <ProjectReference Include="..\..\HengshanPaymentTerminal\HengshanPaymentTerminal.csproj" />
+    <ProjectReference Include="..\..\Web\Web.csproj" />
   </ItemGroup>
 
   <ItemGroup>