| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408 |
-
- using System;
- using System.IO.Ports;
- using System.Text;
- using System.Threading;
- using System.Threading.Tasks;
- using Microsoft.AspNetCore.Components;
- using Microsoft.Extensions.Hosting;
- using Microsoft.Extensions.Logging;
- namespace EasyTemplate.Service
- {
- public class SerialPortBackgroundService : BackgroundService
- {
- private readonly ILogger<SerialPortBackgroundService> _logger;
- private SerialPort _serialPort;
- private readonly string _portName;
- private readonly int _baudRate;
- private bool _isRunning = false;
- public event EventHandler<string> OnDataReceived;
- public event EventHandler<string> OnError;
- public event EventHandler<string> OnStatusChanged;
- private const int VRC_BUF_SIZE = 5120;
- private byte[] m_buf = new byte[VRC_BUF_SIZE];
- private int m_buflen = 0;
- private bool isLastFa = false;
- public SerialPortBackgroundService(ILogger<SerialPortBackgroundService> logger)
- {
- _logger = logger;
- _portName = "COM11"; // 可从配置文件读取
- _baudRate = 9600; // 可从配置文件读取
- }
- public override Task StartAsync(CancellationToken cancellationToken)
- {
- _logger.LogInformation("串口后台服务开始启动");
- return base.StartAsync(cancellationToken);
- }
- protected override async Task ExecuteAsync(CancellationToken stoppingToken)
- {
- _logger.LogInformation("串口后台服务执行中...");
- while (!stoppingToken.IsCancellationRequested)
- {
- if (!_isRunning)
- {
- await InitializeSerialPort();
- }
- await Task.Delay(1000, stoppingToken); // 避免过度占用CPU
- }
- }
- private async Task InitializeSerialPort()
- {
- try
- {
- if (_serialPort != null)
- {
- _serialPort.DataReceived -= SerialPort_DataReceived;
- _serialPort.ErrorReceived -= SerialPort_ErrorReceived;
- _serialPort.Dispose();
- }
- _serialPort = new SerialPort(_portName, _baudRate);
- _serialPort.DataReceived += SerialPort_DataReceived;
- _serialPort.ErrorReceived += SerialPort_ErrorReceived;
- _serialPort.Open();
- _isRunning = true;
- OnStatusChanged?.Invoke(this, "串口服务已启动");
- _logger.LogInformation($"串口 {_portName} 已打开,波特率 {_baudRate}");
- }
- catch (Exception ex)
- {
- _isRunning = false;
- _logger.LogError(ex, $"初始化串口 {_portName} 失败");
- OnError?.Invoke(this, $"串口初始化失败: {ex.Message}");
- await Task.Delay(5000); // 等待5秒后重试
- }
- }
- public async Task<bool> SendDataAsync(string data)
- {
- try
- {
- if (_serialPort == null || !_serialPort.IsOpen)
- {
- _logger.LogWarning("串口未就绪,无法发送数据");
- return false;
- }
- byte[] buffer = Encoding.UTF8.GetBytes(data);
- _serialPort.Write(buffer, 0, buffer.Length);
- _logger.LogInformation($"发送数据: {data}");
- return true;
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "发送数据时发生错误");
- OnError?.Invoke(this, $"发送失败: {ex.Message}");
- return false;
- }
- }
- private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
- {
- try
- {
- if (_serialPort != null && _serialPort.IsOpen)
- {
- //string data = _serialPort.ReadExisting();
- var s = _serialPort.BytesToRead;
- byte[] buffer = new byte[s];
- var ss = _serialPort.Read(buffer, 0, s);
- ProcessComData(buffer, (uint)buffer.Length);
- // OnDataReceived?.Invoke(this, data);
- // _logger.LogInformation($"接收到串口数据: {data}");
- }
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "读取串口数据时发生错误");
- OnError?.Invoke(this, $"读取数据失败: {ex.Message}");
- }
- }
- public bool ProcessComData(byte[] buf, uint bufLen)
- {
- if (bufLen > VRC_BUF_SIZE / 2)
- {
- GlobalTool.vr_log("收到数据长度过长,本次弃用");
- GlobalTool.vr_log_error("收到数据长度过长,本次弃用");
- return false;
- }
- // 记录收到的数据
- StringBuilder s = new StringBuilder();
- for (int i = 0; i < bufLen; i++)
- {
- s.Append($"{buf[i]:X2} ");
- }
- string chlog = $"收到串口{_portName}的数据:{s}";
- GlobalTool.vr_log(chlog);
- // 拆包组包 转义处理 CRC校验
- int len = (int)bufLen;
- byte[] tmpbuf = new byte[VRC_BUF_SIZE];
- Array.Copy(buf, tmpbuf, len);
- int minlen = 10;
- while (len > 0)
- {
- if (m_buflen == 0) // 1.1
- {
- // 定位第一个单独fa
- int pos = -1;
- for (int i = 0; i < len; i++)
- {
- if (tmpbuf[i] == 0xfa)
- {
- if (i == len - 1)
- {
- pos = i;
- }
- else
- {
- if (tmpbuf[i + 1] != 0xfa)
- {
- pos = i;
- break;
- }
- else
- {
- i++;
- }
- }
- }
- }
- // 处理上次可能遗留的fa
- if (isLastFa && len >= 2 && tmpbuf[0] == 0xfa && tmpbuf[1] == 0xfa)
- {
- pos = 1;
- isLastFa = false;
- }
- if (pos != -1)
- {
- if (pos != 0)
- {
- byte[] tmpbuf2 = new byte[VRC_BUF_SIZE];
- Array.Copy(tmpbuf, pos, tmpbuf2, 0, len - pos);
- Array.Copy(tmpbuf2, tmpbuf, len - pos);
- len = len - pos;
- }
- }
- else
- {
- GlobalTool.vr_log("没找到单独fa,弃用");
- GlobalTool.vr_log_error("没找到单独fa,弃用");
- return false;
- }
- // 2.1
- if (len < minlen)
- {
- Array.Copy(tmpbuf, m_buf, len);
- m_buflen = len;
- return false;
- }
- else
- {
- // 2.2 获取数据包长度
- byte[] lenBytes = new byte[2] { tmpbuf[6], tmpbuf[7] };
- ushort nLen = (ushort)GlobalTool.BCDtoDec(lenBytes, 2);
- if (nLen > 1000)
- {
- byte[] tmpbuf2 = new byte[VRC_BUF_SIZE];
- Array.Copy(tmpbuf, 1, tmpbuf2, 0, len - 1);
- Array.Copy(tmpbuf2, tmpbuf, len - 1);
- len = len - 1;
- GlobalTool.vr_log("数据包长度不能超过1000,tmpbuf扔掉包头,重新进入循环判断");
- GlobalTool.vr_log_error("数据包长度不能超过1000,tmpbuf扔掉包头,重新进入循环判断");
- continue;
- }
- // 定位下一个单独fa
- int sepos = -1;
- for (int i = 2; i < len - 1; i++)
- {
- if (tmpbuf[i] == 0xfa)
- {
- if (i == len - 1)
- {
- sepos = i;
- }
- else
- {
- if (tmpbuf[i + 1] != 0xfa)
- {
- sepos = i;
- break;
- }
- else
- {
- i++;
- }
- }
- }
- }
- if (sepos != -1)
- {
- if (sepos < nLen + minlen) // 如果下个独立fa在该数据包的涵盖范围内
- {
- byte[] tmpbuf2 = new byte[VRC_BUF_SIZE];
- Array.Copy(tmpbuf, sepos, tmpbuf2, 0, len - sepos);
- Array.Copy(tmpbuf2, tmpbuf, len - sepos);
- len = len - sepos;
- GlobalTool.vr_log("该数据包不完整,弃用");
- GlobalTool.vr_log_error("该数据包不完整,弃用");
- continue;
- }
- }
- // 检查最后一个字符是否为单独的fa
- if (tmpbuf[len - 1] == 0xfa && len > 1 && tmpbuf[len - 2] != 0xfa)
- {
- isLastFa = true;
- }
- // 2.3 计算非转义长度
- int calclen = len;
- GlobalTool.calcEscapeLength(tmpbuf, ref calclen, 0xfa);
- // 2.4
- if (calclen < (nLen + minlen)) // 数据包没有全部接收
- {
- Array.Copy(tmpbuf, m_buf, len);
- m_buflen = len;
- return false;
- }
- // 处理转义
- GlobalTool.checkEscapeCharacter(ref tmpbuf, ref len, 0xfa);
- byte[] destinationBuffer = new byte[nLen + minlen - 1];
- Buffer.BlockCopy(tmpbuf, 1, destinationBuffer, 0, nLen + minlen - 1);
- // 计算CRC
- ushort nSum = GlobalTool.chkcrc(destinationBuffer, (ushort)(nLen + 7), 0xA001);
- // 字节序转换
- ushort newSum = (ushort)((nSum >> 8) | (nSum << 8));
- ushort oldSum = BitConverter.ToUInt16(tmpbuf, nLen + 8);
- if (oldSum == newSum)
- {
- // 处理交易计数等业务逻辑
- if (tmpbuf[8] == 0x04 || tmpbuf[8] == 0x0D)
- {
- int fip = tmpbuf[4];
- // 这里需要实现singleton<GData>的对应功能
- GlobalTool.vr_log($"(a)主板{fip}收到交易数量");
- }
- if ((tmpbuf[5] & 0x80) == 0x80) // 收到结束帧
- {
- // 这里需要实现singleton<GData>的对应功能
- long currentTick = Environment.TickCount;
- GlobalTool.vr_log($"收到结束帧, 耗时:{currentTick - /*vrceachtick*/0}毫秒");
- }
- byte[] bdbuf = new byte[nLen + minlen];
- Buffer.BlockCopy(tmpbuf, 0, bdbuf, 0, nLen + minlen);
- BufferData bd = new BufferData();
- bd.type = 1;
- bd.buffer = bdbuf;
- bd.serialPort = _serialPort;
- GlobalTool.g_dataQueue.Enqueue(bd);
- }
- else
- {
- GlobalTool.vr_log("crc校验失败");
- GlobalTool.vr_log_error("crc校验失败");
- }
- // 继续处理剩余数据
- if (len > (nLen + minlen))
- {
- byte[] tmpbuf2 = new byte[VRC_BUF_SIZE];
- Array.Copy(tmpbuf, nLen + minlen, tmpbuf2, 0, len - (nLen + minlen));
- Array.Copy(tmpbuf2, tmpbuf, len - (nLen + minlen));
- len = len - (nLen + minlen);
- }
- else
- {
- return true;
- }
- }
- }
- else // 1.2 有缓存数据
- {
- if (m_buflen + len <= VRC_BUF_SIZE)
- {
- Array.Copy(m_buf, 0, tmpbuf, 0, m_buflen);
- Array.Copy(buf, 0, tmpbuf, m_buflen, len);
- len += m_buflen;
- }
- Array.Clear(m_buf, 0, m_buf.Length);
- m_buflen = 0;
- }
- }
- return true;
- }
- private void SerialPort_ErrorReceived(object sender, SerialErrorReceivedEventArgs e)
- {
- string errorMessage = $"串口错误: {e.EventType}";
- _logger.LogError(errorMessage);
- OnError?.Invoke(this, errorMessage);
- }
- public override async Task StopAsync(CancellationToken cancellationToken)
- {
- _logger.LogInformation("串口后台服务正在停止");
- _isRunning = false;
- if (_serialPort != null && _serialPort.IsOpen)
- {
- _serialPort.Close();
- _serialPort.DataReceived -= SerialPort_DataReceived;
- _serialPort.ErrorReceived -= SerialPort_ErrorReceived;
- _serialPort.Dispose();
- }
- await base.StopAsync(cancellationToken);
- }
- public bool IsConnected() => _serialPort?.IsOpen ?? false;
- public string[] GetAvailablePorts() => SerialPort.GetPortNames();
- }
- }
|