|
|
@@ -1,167 +1,248 @@
|
|
|
-using AntDesign;
|
|
|
-using Microsoft.AspNetCore.Components;
|
|
|
+using Microsoft.Extensions.DependencyInjection;
|
|
|
+using Microsoft.Extensions.Hosting;
|
|
|
+using Microsoft.Extensions.Logging;
|
|
|
using System.Net.Sockets;
|
|
|
using System.Text;
|
|
|
+using EasyTemplate.Tool.Entity;
|
|
|
+using EasyTemplate.Tool.Entity.App;
|
|
|
|
|
|
namespace EasyTemplate.Service
|
|
|
{
|
|
|
-
|
|
|
- public class HandleData
|
|
|
+ /// <summary>
|
|
|
+ /// 数据处理后台服务
|
|
|
+ /// </summary>
|
|
|
+ public class HandleDataService : BackgroundService
|
|
|
{
|
|
|
- private Thread _thread;
|
|
|
- // [Inject] public UdpListenerService udpclient { get; set; }
|
|
|
- //public UdpListenerService udpclient { get; set; } = default!;
|
|
|
-
|
|
|
-
|
|
|
- //private readonly UdpListenerService _udpclient;
|
|
|
+ private readonly IServiceProvider _serviceProvider;
|
|
|
+ private readonly ILogger<HandleDataService> _logger;
|
|
|
|
|
|
-
|
|
|
-
|
|
|
- public HandleData()//UdpListenerService myService)
|
|
|
+ public HandleDataService(IServiceProvider serviceProvider, ILogger<HandleDataService> logger)
|
|
|
{
|
|
|
- //_udpclient = myService;
|
|
|
- // 初始化线程,但不立即启动
|
|
|
- _thread = new Thread(new ThreadStart(Loop));
|
|
|
- _thread.IsBackground = true; // 设置线程为后台线程,程序结束时自动结束
|
|
|
- _thread.Start(); // 启动线程
|
|
|
+ _serviceProvider = serviceProvider;
|
|
|
+ _logger = logger;
|
|
|
}
|
|
|
|
|
|
- private void Loop()
|
|
|
+ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
|
|
{
|
|
|
- while (true) // 无限循环
|
|
|
+ _logger.LogInformation("数据处理服务已启动");
|
|
|
+
|
|
|
+ while (!stoppingToken.IsCancellationRequested)
|
|
|
{
|
|
|
- Console.WriteLine("Looping..."); // 执行一些任务
|
|
|
-
|
|
|
try
|
|
|
{
|
|
|
- BufferData bd = GlobalTool.g_dataQueue.TryDequeue(out BufferData result) ? result : null;
|
|
|
- if(bd==null)
|
|
|
- {
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
+ await ProcessDataAsync();
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ _logger.LogError(ex, "数据处理发生错误");
|
|
|
+ }
|
|
|
+
|
|
|
+ await Task.Delay(50, stoppingToken);
|
|
|
+ }
|
|
|
+
|
|
|
+ _logger.LogInformation("数据处理服务已停止");
|
|
|
+ }
|
|
|
|
|
|
+ private async Task ProcessDataAsync()
|
|
|
+ {
|
|
|
+ BufferData bd = GlobalTool.g_dataQueue.TryDequeue(out BufferData result) ? result : null;
|
|
|
+ if(bd==null)
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- //TQC dest-2;source-2;frame-1;length-2(HEX);cmd-1
|
|
|
- //VRC 包头(0xfa)+ 目标地址2+源地址2+控制/帧号1+数据长度2(BCD)+命令字1+数据 + CRC校验2
|
|
|
+ //TQC dest-2;source-2;frame-1;length-2(HEX);cmd-1
|
|
|
+ //VRC 包头(0xfa)+ 目标地址 2+ 源地址 2+ 控制/帧号 1+ 数据长度 2(BCD)+ 命令字 1+ 数据 + CRC 校验 2
|
|
|
|
|
|
- if(bd.type == 0)
|
|
|
+ if(bd.type == 0)
|
|
|
+ {
|
|
|
+ int datalength = bd.buffer[5] * 256 + bd.buffer[6];
|
|
|
+ if (datalength + 9 == bd.buffer.Length)
|
|
|
+ {
|
|
|
+ // 计算 crc
|
|
|
+ int packlen = bd.buffer.Length;
|
|
|
+ byte[] tmpbuf = bd.buffer;
|
|
|
+ ushort nSum = GlobalTool.chkcrc(tmpbuf, (ushort)(packlen - 2), 0xA001);
|
|
|
+ ushort newSum = nSum;
|
|
|
+ newSum = (ushort)(newSum / 256 + newSum % 256 * 256);
|
|
|
+ ushort oldSum = BitConverter.ToUInt16(tmpbuf, packlen - 2);
|
|
|
+
|
|
|
+ if (oldSum == newSum)
|
|
|
{
|
|
|
- int datalength = bd.buffer[5] * 256 + bd.buffer[6];
|
|
|
- if (datalength + 9 == bd.buffer.Length)
|
|
|
- {
|
|
|
- // 计算crc
|
|
|
- int packlen = bd.buffer.Length;
|
|
|
- byte[] tmpbuf = bd.buffer;
|
|
|
- ushort nSum = GlobalTool.chkcrc(tmpbuf, (ushort)(packlen - 2), 0xA001);
|
|
|
- ushort newSum = nSum;
|
|
|
- newSum = (ushort)(newSum / 256 + newSum % 256 * 256);
|
|
|
- ushort oldSum = BitConverter.ToUInt16(tmpbuf, packlen - 2);
|
|
|
-
|
|
|
- if (oldSum == newSum)
|
|
|
- {
|
|
|
- Console.WriteLine("CRC校验成功");
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- Console.WriteLine("crc校验失败");
|
|
|
- continue;
|
|
|
- }
|
|
|
- }
|
|
|
- else if (datalength + 9 == bd.buffer.Length + 2)
|
|
|
- {
|
|
|
- //旧协议无crc
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- Console.WriteLine("数据长度不对");
|
|
|
- continue;
|
|
|
- }
|
|
|
+ _logger.LogDebug("CRC 校验成功");
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- int datalength = GlobalTool.ConvertBCDToDecimalSingle(bd.buffer[6]) * 100 + GlobalTool.ConvertBCDToDecimalSingle(bd.buffer[7]);
|
|
|
- if (datalength + 10 == bd.buffer.Length)
|
|
|
- {
|
|
|
-
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- Console.WriteLine("数据长度不对");
|
|
|
- continue;
|
|
|
- }
|
|
|
+ _logger.LogWarning("crc 校验失败");
|
|
|
+ return;
|
|
|
}
|
|
|
+ }
|
|
|
+ else if (datalength + 9 == bd.buffer.Length + 2)
|
|
|
+ {
|
|
|
+ //旧协议无 crc
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ _logger.LogWarning("数据长度不对");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ int datalength = GlobalTool.ConvertBCDToDecimalSingle(bd.buffer[6]) * 100 + GlobalTool.ConvertBCDToDecimalSingle(bd.buffer[7]);
|
|
|
+ if (datalength + 10 == bd.buffer.Length)
|
|
|
+ {
|
|
|
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ _logger.LogWarning("数据长度不对");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
+ int cmdtype = bd.buffer[7];
|
|
|
+ int startindex = 8;
|
|
|
+ if (bd.type == 1)
|
|
|
+ {
|
|
|
+ cmdtype = bd.buffer[8];
|
|
|
+ startindex = 9;
|
|
|
+ }
|
|
|
|
|
|
-
|
|
|
- int cmdtype = bd.buffer[7];
|
|
|
- int startindex = 8;
|
|
|
- if (bd.type == 1)
|
|
|
- {
|
|
|
- cmdtype = bd.buffer[8];
|
|
|
- startindex = 9;
|
|
|
- }
|
|
|
-
|
|
|
- switch (cmdtype)
|
|
|
- {
|
|
|
- case 1:
|
|
|
- filling_nozzleup up = GlobalTool.extractFillingNozzleUP(bd.buffer, startindex);
|
|
|
- GlobalTool.g_mNozzleState[up.noz].nozzlestate = GlobalTool.NozzleState_Filling;
|
|
|
- break;
|
|
|
- case 2:
|
|
|
- filling_process process = GlobalTool.extractFillingProcess(bd.buffer, startindex);
|
|
|
- GlobalTool.g_mNozzleState[process.noz].nozzlestate = GlobalTool.NozzleState_Filling;
|
|
|
- GlobalTool.g_mNozzleState[process.noz].VLR = ((double)process.VLR / 1000).ToString("F2");
|
|
|
- break;
|
|
|
- case 3:
|
|
|
- filling_nozzledown down = GlobalTool.extractFillingNozzleDown(bd.buffer, startindex);
|
|
|
- GlobalTool.g_mNozzleState[down.noz].nozzlestate = GlobalTool.NozzleState_Idle;
|
|
|
- break;
|
|
|
- case 4:
|
|
|
- filling_record record = GlobalTool.extractFillingRecord(bd.buffer, startindex);
|
|
|
- GlobalTool.g_mNozzleState[record.noz].nozzlestate = GlobalTool.NozzleState_Idle;
|
|
|
- GlobalTool.g_mNozzleState[record.noz].VLR = ((double)record.VLR / 1000).ToString("F2");
|
|
|
- break;
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- default:
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- if(bd.type == 0)
|
|
|
+ switch (cmdtype)
|
|
|
+ {
|
|
|
+ case 1:
|
|
|
+ filling_nozzleup up = GlobalTool.extractFillingNozzleUP(bd.buffer, startindex);
|
|
|
+ if(GlobalTool.g_mNozzleState.ContainsKey(up.noz))
|
|
|
+ GlobalTool.g_mNozzleState[up.noz].nozzlestate = GlobalTool.NozzleState_Filling;
|
|
|
+ break;
|
|
|
+ case 2:
|
|
|
+ filling_process process = GlobalTool.extractFillingProcess(bd.buffer, startindex);
|
|
|
+ if(GlobalTool.g_mNozzleState.ContainsKey(process.noz))
|
|
|
{
|
|
|
- var message = Encoding.UTF8.GetString(bd.buffer);
|
|
|
- //_logger.LogInformation($"接收到消息: {result.Buffer.ToString()}\r\n");
|
|
|
-
|
|
|
- byte[] responseData = Encoding.UTF8.GetBytes("Echo: " + message);
|
|
|
- bd.udpClient.SendAsync(responseData, responseData.Length, bd.endpoint);
|
|
|
+ GlobalTool.g_mNozzleState[process.noz].nozzlestate = GlobalTool.NozzleState_Filling;
|
|
|
+ GlobalTool.g_mNozzleState[process.noz].VLR = ((double)process.VLR / 1000).ToString("F2");
|
|
|
}
|
|
|
- else
|
|
|
+ break;
|
|
|
+ case 3:
|
|
|
+ filling_nozzledown down = GlobalTool.extractFillingNozzleDown(bd.buffer, startindex);
|
|
|
+ if(GlobalTool.g_mNozzleState.ContainsKey(down.noz))
|
|
|
+ GlobalTool.g_mNozzleState[down.noz].nozzlestate = GlobalTool.NozzleState_Idle;
|
|
|
+ break;
|
|
|
+ case 4:
|
|
|
+ filling_record record = GlobalTool.extractFillingRecord(bd.buffer, startindex);
|
|
|
+ if(GlobalTool.g_mNozzleState.ContainsKey(record.noz))
|
|
|
{
|
|
|
- var message = Encoding.UTF8.GetString(bd.buffer);
|
|
|
- //_logger.LogInformation($"接收到消息: {result.Buffer.ToString()}\r\n");
|
|
|
-
|
|
|
- byte[] responseData = Encoding.UTF8.GetBytes("Echo: " + message);
|
|
|
- bd.serialPort.Write(responseData, 0, responseData.Length);
|
|
|
-
|
|
|
+ GlobalTool.g_mNozzleState[record.noz].nozzlestate = GlobalTool.NozzleState_Idle;
|
|
|
+ GlobalTool.g_mNozzleState[record.noz].VLR = ((double)record.VLR / 1000).ToString("F2");
|
|
|
}
|
|
|
+
|
|
|
+ // 将记录插入到数据库
|
|
|
+ await InsertRecordToDatabaseAsync(record);
|
|
|
+
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
+ if(bd.type == 0)
|
|
|
+ {
|
|
|
+ var message = Encoding.UTF8.GetString(bd.buffer);
|
|
|
+ byte[] responseData = Encoding.UTF8.GetBytes("Echo: " + message);
|
|
|
+ await bd.udpClient.SendAsync(responseData, responseData.Length, bd.endpoint);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ var message = Encoding.UTF8.GetString(bd.buffer);
|
|
|
+ byte[] responseData = Encoding.UTF8.GetBytes("Echo: " + message);
|
|
|
+ bd.serialPort.Write(responseData, 0, responseData.Length);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 异步插入交易记录到数据库
|
|
|
+ /// </summary>
|
|
|
+ private async Task InsertRecordToDatabaseAsync(filling_record record)
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ // 创建作用域以获取 Scoped 服务
|
|
|
+ using var scope = _serviceProvider.CreateScope();
|
|
|
+ var nozzleService = scope.ServiceProvider.GetRequiredService<NozzleService>();
|
|
|
+
|
|
|
+ // 将 filling_record 转换为 TRecord
|
|
|
+ var tRecord = new TRecord
|
|
|
+ {
|
|
|
+ fip = record.fip,
|
|
|
+ board = record.board,
|
|
|
+ noz = record.noz,
|
|
|
+ liquidVl = record.liquidVL,
|
|
|
+ vaporVl = record.vaporVL,
|
|
|
+ liquidFr = record.liquidFR,
|
|
|
+ vaporFr = record.vaporFR,
|
|
|
+ vlr = record.VLR,
|
|
|
+ vaporPa = record.vaporPA,
|
|
|
+ ttc = record.ttc,
|
|
|
+ vlrBefore = record.VLR_BEFORE,
|
|
|
+ vlrOffset = record.VLR_OFFSET,
|
|
|
+ pwm = record.pwm,
|
|
|
+ tmBegin = ParseDateTime(record.tmBegin),
|
|
|
+ tmEnd = ParseDateTime(record.tmEnd),
|
|
|
+ overproof = record.overproof,
|
|
|
+ uploadflag = record.uploadflag,
|
|
|
+ uploadflag2 = record.uploadflag2,
|
|
|
+ uploadflag3 = record.uploadflag3,
|
|
|
+ downloadflag1 = record.downloadflag1,
|
|
|
+ yz = record.yz,
|
|
|
+ tankpressure = record.tankpressure,
|
|
|
+ refuelingseconds = record.refuelingseconds,
|
|
|
+ errorcontrolvalue = record.errorcontrolvalue,
|
|
|
+ errornum = record.errornum,
|
|
|
+ callbackflag = record.callbackflag,
|
|
|
+ vccerrorinfo = record.vccerrorinfo ?? string.Empty
|
|
|
+ };
|
|
|
+
|
|
|
+ // 调用 NozzleService 的插入方法
|
|
|
+ var result = await nozzleService.CreateRecordAsync(tRecord);
|
|
|
+
|
|
|
+ if (result)
|
|
|
+ {
|
|
|
+ _logger.LogInformation($"成功插入交易记录:油枪{record.noz}, 时间={record.tmEnd}");
|
|
|
}
|
|
|
- catch(Exception e)
|
|
|
+ else
|
|
|
{
|
|
|
-
|
|
|
+ _logger.LogWarning($"插入交易记录失败:油枪{record.noz}");
|
|
|
}
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- Thread.Sleep(50);
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ _logger.LogError(ex, $"插入交易记录异常:油枪{record.noz}");
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 解析字符串时间为 DateTime
|
|
|
+ /// </summary>
|
|
|
+ private DateTime ParseDateTime(string timeStr)
|
|
|
+ {
|
|
|
+ if (string.IsNullOrEmpty(timeStr))
|
|
|
+ {
|
|
|
+ return DateTime.Now;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 假设时间格式为 yyyyMMddHHmmss 或类似格式
|
|
|
+ // 根据实际协议格式调整解析逻辑
|
|
|
+ if (timeStr.Length >= 14)
|
|
|
+ {
|
|
|
+ if (DateTime.TryParseExact(timeStr, "yyyyMMddHHmmss", null, System.Globalization.DateTimeStyles.None, out var result))
|
|
|
+ {
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果解析失败,返回当前时间
|
|
|
+ return DateTime.Now;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
-
|