182 lines
7.5 KiB
C#
182 lines
7.5 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO.Ports;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using FundamentalLib;
|
|
using Medulla;
|
|
|
|
namespace MedullaAdapter
|
|
{
|
|
public class EmbeddedCommunication
|
|
{
|
|
private SerialPort _port;
|
|
|
|
private byte[] _receiveBytes;
|
|
|
|
private byte[] _receiveData;
|
|
|
|
private const int BufferThreshold = 300; // 缓冲区大小阈值
|
|
|
|
private List<byte> _buffer = new List<byte>(); // 缓存接收到的数据
|
|
|
|
public bool CommunicationError = false;
|
|
|
|
private DateTime _lastTime = DateTime.Now;
|
|
|
|
private MCUInterface<DiverCartDefinition> _interface;
|
|
|
|
public EmbeddedCommunication(string name, int baudRate)
|
|
{
|
|
_interface = new MCUInterface<DiverCartDefinition>();
|
|
_port = new SerialPort();
|
|
_port.PortName = name; // 根据你的实际串口名称修改
|
|
_port.BaudRate = baudRate;
|
|
_port.Parity = Parity.None;
|
|
_port.DataBits = 8;
|
|
_port.StopBits = StopBits.One;
|
|
_port.Handshake = Handshake.None;
|
|
_port.Open();
|
|
_port.DataReceived += OnDataReceived;
|
|
}
|
|
|
|
public void SendMessage(byte[] data)
|
|
{
|
|
Hedingben.ToastText($"send to mcu:{BitConverter.ToString(data)}","DiverSend");
|
|
_port.Write(data, 0, data.Length);
|
|
}
|
|
|
|
public byte[] GetMessage()
|
|
{
|
|
return _receiveBytes;
|
|
}
|
|
|
|
private void OnDataReceived(object sender, SerialDataReceivedEventArgs e)
|
|
{
|
|
try
|
|
{
|
|
int bytesToRead = _port.BytesToRead;
|
|
byte[] buffer = new byte[bytesToRead];
|
|
var startRead = DateTime.Now;
|
|
_port.Read(buffer, 0, bytesToRead);
|
|
var time = DateTime.Now - startRead;
|
|
// 将新接收到的数据添加到缓冲区
|
|
startRead = DateTime.Now;
|
|
_buffer.AddRange(buffer);
|
|
var time2 = DateTime.Now - startRead;
|
|
Hedingben.ToastText($"buffer length:{_buffer.Count}","bufferDebug");
|
|
DLog.Log($"buffer length:{_buffer.Count}");
|
|
//if (_buffer.Count > BufferThreshold)
|
|
//{
|
|
// _buffer.Clear();
|
|
// return;
|
|
//}
|
|
|
|
// 尝试解析缓冲区中的报文
|
|
var parseTime = DateTime.Now;
|
|
ParseBuffer();
|
|
var time3 = DateTime.Now - parseTime;
|
|
Hedingben.ToastText(
|
|
$"读取报文时间:{time.TotalMilliseconds},增加到缓存区:{time2.TotalMilliseconds},处理时间:{time3.TotalMilliseconds}",
|
|
"timeDebug1");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"读取串口数据时发生错误: {ex.Message}"+ex.StackTrace);
|
|
}
|
|
}
|
|
private void ParseBuffer()
|
|
{
|
|
while (_buffer.Count >= 7) // 报文的最小长度是 7
|
|
{
|
|
// 查找报文头部
|
|
var findTime = DateTime.Now;
|
|
int startIndex = _buffer.FindIndex(0, b => b == 0xBB);
|
|
var time1 = DateTime.Now - findTime;
|
|
if (startIndex == -1)
|
|
{
|
|
// 如果没有找到头部或剩余长度不足最小报文长度,结束解析
|
|
_buffer.Clear();
|
|
return;
|
|
}
|
|
|
|
// 确保头部后还有至少 6 个字节
|
|
if (startIndex + 1 >= _buffer.Count || _buffer[startIndex + 1] != 0xAA)
|
|
{
|
|
// 如果第二字节不是 0xAA,丢弃无效字节
|
|
_buffer.RemoveAt(startIndex);
|
|
continue;
|
|
}
|
|
|
|
// 检查数据段长度
|
|
if (startIndex + 4 >= _buffer.Count) break; // 数据不足,等待下次接收
|
|
int dataLength = _buffer[startIndex + 2] | (_buffer[startIndex + 3] << 8);
|
|
|
|
// 计算报文总长度
|
|
int totalLength = dataLength + 7;
|
|
|
|
// 检查总长度是否足够
|
|
if (startIndex + totalLength > _buffer.Count) break; // 数据不足,等待下次接收
|
|
|
|
// 检查尾部是否是 0xCC 0xEE
|
|
if (_buffer[startIndex + totalLength - 2] == 0xCC && _buffer[startIndex + totalLength - 1] == 0xEE)
|
|
{
|
|
var time2 = DateTime.Now - findTime;
|
|
var copyTime = DateTime.Now;
|
|
// 提取完整报文
|
|
_receiveBytes = _buffer.Skip(startIndex).Take(totalLength).ToArray();
|
|
var time3 = DateTime.Now - copyTime;
|
|
if (_receiveBytes[5] == 0xA0)
|
|
{
|
|
var dataLength1 = BitConverter.ToUInt32(_receiveBytes, 6);
|
|
var data1 = new byte[dataLength1];
|
|
Array.Copy(_receiveBytes, 14, data1, 0, dataLength1);
|
|
var notifyTime = DateTime.Now;
|
|
MCUInterface<DiverCartDefinition>.NotifyLowerData("default", data1);
|
|
var time4 = DateTime.Now - notifyTime;
|
|
var logBytes = new byte[BitConverter.ToInt32(_receiveBytes, 10)];
|
|
var memorySize = BitConverter.ToInt32(_receiveBytes, 6);
|
|
if (logBytes.Length > 0)
|
|
{
|
|
Array.Copy(_receiveBytes, 14 + memorySize, logBytes, 0, logBytes.Length);
|
|
string log = System.Text.Encoding.ASCII.GetString(logBytes);
|
|
string[] result = log.Split(new[] { "\r\n", "\n" }, StringSplitOptions.None);
|
|
for (int i = 0; i < result.Length; i++)
|
|
{
|
|
Hedingben.ToastText(result[i], $"mcuLog" + i);
|
|
}
|
|
}
|
|
|
|
Hedingben.ToastText(
|
|
$"find head time:{time1.TotalMilliseconds},find total time:{time2.TotalMilliseconds},copy time:{time3.TotalMilliseconds},notify time:{time4.TotalMilliseconds}","timeDebug2");
|
|
}
|
|
|
|
Hedingben.ToastText(
|
|
$"receive from mcu:{BitConverter.ToString(_receiveBytes)},time:{(DateTime.Now - _lastTime).TotalMilliseconds}",
|
|
"DiverReceive");
|
|
if ((DateTime.Now - _lastTime).TotalMilliseconds > 200)
|
|
{
|
|
Hedingben.ToastText($"{(DateTime.Now - _lastTime).TotalMilliseconds}ms no message from diver","DiverTimeout");
|
|
}
|
|
_lastTime = DateTime.Now;
|
|
// 从缓冲区中移除已解析的报文
|
|
_buffer.RemoveRange(0, startIndex + totalLength);
|
|
return; // 成功解析一条报文后退出本轮解析
|
|
|
|
}
|
|
else
|
|
{
|
|
// 如果尾部无效,丢弃头部并继续解析
|
|
DLog.Log("DIVER报文无效");
|
|
Console.WriteLine("DIVER报文无效");
|
|
var errorBytes = _buffer.Skip(startIndex).Take(totalLength).ToArray();
|
|
DLog.Log("错误报文"+string.Join(" ",errorBytes.Select(p=>$"{p:X2}")));
|
|
_buffer.RemoveAt(startIndex);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|