C00225155-02/C00225155/MegaRobo.C00225155/MegaRobo.C00225155.ControlD.../SerialPortService.cs

799 lines
20 KiB
C#
Raw Normal View History

2026-04-13 09:12:49 +00:00
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO.Ports;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
namespace MegaRobo.C00225155.ControlDevices
{
public enum SerialPortDataFormat
{
Char,
Hex
}
public class SerialPortService : IDisposable
{
private SerialPort serialPort;
private bool isCloseing = false;
private int tryReadNumber = 3;
public SerialConfigOptions SerialConfigOptions => new SerialConfigOptions
{
BaudRate = BaudRate,
DataBits = DataBits,
Handshake = Handshake,
Parity = Parity,
PortName = PortName,
StopBits = StopBits
};
public Stream BaseStream => serialPort.BaseStream;
public int BaudRate
{
get
{
return serialPort.BaudRate;
}
set
{
serialPort.BaudRate = value;
}
}
public bool BreakState
{
get
{
return serialPort.BreakState;
}
set
{
serialPort.BreakState = value;
}
}
public int BytesToRead => serialPort.BytesToRead;
public int BytesToWrite => serialPort.BytesToWrite;
public bool CDHolding => serialPort.CDHolding;
public bool CtsHolding => serialPort.CtsHolding;
public int DataBits
{
get
{
return serialPort.DataBits;
}
set
{
serialPort.DataBits = value;
}
}
public bool DiscardNull
{
get
{
return serialPort.DiscardNull;
}
set
{
serialPort.DiscardNull = value;
}
}
public bool DsrHolding => serialPort.DsrHolding;
public bool DtrEnable
{
get
{
return serialPort.DtrEnable;
}
set
{
serialPort.DtrEnable = value;
}
}
public Encoding Encoding
{
get
{
return serialPort.Encoding;
}
set
{
serialPort.Encoding = value;
}
}
public Handshake Handshake
{
get
{
return serialPort.Handshake;
}
set
{
serialPort.Handshake = value;
}
}
public bool IsOpen => serialPort?.IsOpen ?? false;
public string NewLine
{
get
{
return serialPort.NewLine;
}
set
{
serialPort.NewLine = value;
}
}
public Parity Parity
{
get
{
return serialPort.Parity;
}
set
{
serialPort.Parity = value;
}
}
public byte ParityReplace
{
get
{
return serialPort.ParityReplace;
}
set
{
serialPort.ParityReplace = value;
}
}
public string PortName
{
get
{
return serialPort.PortName;
}
set
{
serialPort.PortName = value;
}
}
public int ReadBufferSize
{
get
{
return serialPort.ReadBufferSize;
}
set
{
serialPort.ReadBufferSize = value;
}
}
public int ReadTimeout
{
get
{
return serialPort.ReadTimeout;
}
set
{
serialPort.ReadTimeout = value;
}
}
public int ReceivedBytesThreshold
{
get
{
return serialPort.ReceivedBytesThreshold;
}
set
{
serialPort.ReceivedBytesThreshold = value;
}
}
public bool RtsEnable
{
get
{
return serialPort.RtsEnable;
}
set
{
serialPort.RtsEnable = value;
}
}
public StopBits StopBits
{
get
{
return serialPort.StopBits;
}
set
{
serialPort.StopBits = value;
}
}
public int WriteBufferSize
{
get
{
return serialPort.WriteBufferSize;
}
set
{
serialPort.WriteBufferSize = value;
}
}
public int WriteTimeout
{
get
{
return serialPort.WriteTimeout;
}
set
{
serialPort.WriteTimeout = value;
}
}
public int TryReadSpanTime { get; set; } = 10;
public string Terminator { get; set; } = null;
public SerialPortDataFormat DataFormat { get; set; } = SerialPortDataFormat.Char;
public int TryReadNumber
{
get
{
return tryReadNumber;
}
set
{
if (value < 1)
{
throw new ArgumentOutOfRangeException("TryReadNumber", "TryReadNumber must be equal or greater than 1.");
}
tryReadNumber = value;
}
}
public event EventHandler<Message> DataReceived;
public static string[] GetPortNames()
{
return SerialPort.GetPortNames();
}
public SerialPortService()
{
}
public SerialPortService(string portName)
: this(portName, 9600, 8, StopBits.One, Parity.None, Handshake.None)
{
}
public SerialPortService(string portName, int baudRate)
: this(portName, baudRate, 8, StopBits.One, Parity.None, Handshake.None)
{
}
public SerialPortService(string portName, int baudRate = 9600, int dataBits = 8, StopBits stopBits = StopBits.One, Parity parity = Parity.None, Handshake handshake = Handshake.None)
{
if (portName == null)
{
throw new ArgumentNullException("portName");
}
if (dataBits < 7 || dataBits > 8)
{
throw new ArgumentNullException("dataBits", "only 7,8");
}
serialPort = new SerialPort(portName, baudRate, parity, dataBits, stopBits)
{
Handshake = handshake,
WriteTimeout = 3000,
ReadTimeout = 4000
};
}
public SerialPortService(SerialConfigOptions options)
: this(options.PortName, options.BaudRate, options.DataBits, options.StopBits, options.Parity, options.Handshake)
{
if (options == null)
{
throw new ArgumentNullException("options");
}
}
public void Open()
{
if (serialPort == null)
{
throw new InvalidOperationException("Not initialized");
}
if (!serialPort.IsOpen)
{
serialPort.Open();
serialPort.DataReceived += SerialPort_DataReceived;
}
}
public void Close()
{
if (IsOpen)
{
isCloseing = true;
Thread.Sleep(TryReadSpanTime + 5);
serialPort.DataReceived -= SerialPort_DataReceived;
Thread.Sleep(TryReadSpanTime + 5);
serialPort.Close();
}
}
public void DiscardInBuffer()
{
serialPort.DiscardInBuffer();
}
public void DiscardOutBuffer()
{
serialPort.DiscardOutBuffer();
}
public void Dispose()
{
Close();
serialPort = null;
}
public int ReadByte()
{
return serialPort.ReadByte();
}
public int ReadChar()
{
return serialPort.ReadChar();
}
public string ReadLine()
{
return serialPort.ReadLine();
}
public string ReadExisting()
{
return serialPort.ReadExisting();
}
public string ReadTo(string value)
{
return serialPort.ReadTo(value);
}
public string ReadString()
{
try
{
string result = null;
byte[] array = TryRead();
if (array != null && array.Length != 0)
{
switch (DataFormat)
{
case SerialPortDataFormat.Char:
result = serialPort.Encoding.GetString(array);
break;
case SerialPortDataFormat.Hex:
result = array.ToHexString();
break;
}
}
return result;
}
catch (Exception ex)
{
throw new Exception(ex.Message, ex);
}
}
public byte[] Read()
{
try
{
return TryRead();
}
catch (Exception ex)
{
throw new Exception(ex.Message, ex);
}
}
private byte[] TryRead()
{
int num = 0;
int num2 = 0;
bool flag = false;
List<byte> list = new List<byte>();
byte[] array = null;
if (Terminator != null)
{
array = Terminator.HexToByte();
num2 = array.Length;
}
while ((serialPort.BytesToRead > 0 || !flag) && num < tryReadNumber)
{
int num3 = ((serialPort.BytesToRead < serialPort.ReadBufferSize) ? serialPort.BytesToRead : serialPort.ReadBufferSize);
byte[] array2 = new byte[num3];
serialPort.Read(array2, 0, array2.Length);
list.AddRange(array2);
if (array != null && num2 > 0)
{
byte[] array3 = new byte[num2];
if (array2.Length >= num2)
{
Buffer.BlockCopy(array2, array2.Length - num2, array3, 0, num2);
}
else
{
if (list.ToArray().Length < num2)
{
continue;
}
byte[] array4 = list.ToArray();
Buffer.BlockCopy(array4, array4.Length - num2, array3, 0, num2);
}
flag = array.Length != 0 && array3.SequenceEqual(array);
}
if (TryReadSpanTime > 0)
{
Thread.Sleep(TryReadSpanTime);
}
num++;
}
return (list.Count > 0) ? list.ToArray() : null;
}
public int WriteHexString(string str)
{
try
{
byte[] array = str.HexToByte();
return Write(array, 0, array.Length);
}
catch (Exception ex)
{
throw new Exception(ex.Message, ex);
}
}
public int WriteAsciiString(string str)
{
try
{
byte[] bytes = serialPort.Encoding.GetBytes(str);
return Write(bytes, 0, bytes.Length);
}
catch (Exception ex)
{
throw new Exception(ex.Message, ex);
}
}
public int Write(byte[] bytes)
{
return Write(bytes, 0, bytes.Length);
}
public void Write(string text)
{
serialPort.Write(text);
}
public int Write(byte[] bytes, int offset, int count)
{
try
{
serialPort.DiscardInBuffer();
serialPort.Write(bytes, offset, count);
return count;
}
catch (Exception ex)
{
throw new Exception(ex.Message, ex);
}
}
public void WriteLine(string str)
{
serialPort.WriteLine(str);
}
public byte[] SendAndReceive(IEnumerable<byte> datas, TimeSpan timeout)
{
byte[] mReply = null;
DataReceived += SerialPortDataReceived;
int num = Write(datas.ToArray());
Stopwatch stopwatch = Stopwatch.StartNew();
while (mReply == null && (double)stopwatch.ElapsedMilliseconds < timeout.TotalMilliseconds)
{
Thread.Sleep(50);
}
DataReceived -= SerialPortDataReceived;
return mReply;
void SerialPortDataReceived(object sender, Message msg)
{
mReply = msg.Data;
}
}
private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
if (!isCloseing)
{
byte[] data = TryRead();
Message e2 = new Message(data, Encoding);
this.DataReceived?.Invoke(this, e2);
}
}
}
/// <summary>
/// 扩展方法 byte[]
/// </summary>
public static class Extension
{
public static string ToHexString(this byte[] bytes, string separator = " ")
{
if (bytes == null || bytes.Length < 1)
{
return null;
}
return string.Join(separator, bytes.Select((byte b) => b.ToString("X2")).ToArray());
}
public static byte[] HexToByte(this string hex)
{
hex = hex.Replace(" ", "");
byte[] array = new byte[hex.Length / 2];
for (int i = 0; i < hex.Length; i += 2)
{
array[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
}
return array;
}
}
public class SerialConfigOptions
{
public string PortName { get; set; }
public int BaudRate { get; set; } = 9600;
public int DataBits { get; set; } = 8;
public StopBits StopBits { get; set; } = StopBits.One;
public Parity Parity { get; set; } = Parity.None;
public Handshake Handshake { get; set; } = Handshake.None;
public SerialConfigOptions()
{
}
public SerialConfigOptions(string portName, int baudRate = 9600, int dataBits = 8, StopBits stopBits = StopBits.One, Parity parity = Parity.None, Handshake handshake = Handshake.None)
{
PortName = portName ?? throw new ArgumentNullException("portName");
if (dataBits < 7 || dataBits > 8)
{
throw new ArgumentNullException("dataBits", "only 7,8");
}
BaudRate = baudRate;
DataBits = dataBits;
StopBits = stopBits;
Parity = parity;
Handshake = handshake;
}
public SerialConfigOptions(string portName, int baudRate = 9600, int dataBits = 8, int stopBits = 1, int parity = 0, int handshake = 0)
: this(portName, baudRate, dataBits, GetStopBits(stopBits), GetParity(parity), GetHandshake(handshake))
{
}
public SerialConfigOptions(string portName, int baudRate = 9600, int dataBits = 8, string stopBits = "one", string parity = "none", string handshake = "none")
: this(portName, baudRate, dataBits, GetStopBits(stopBits), GetParity(parity), GetHandshake(handshake))
{
}
public static Parity GetParity(string parityVal)
{
switch (parityVal?.ToLower())
{
case "0":
case "n":
case "none":
return Parity.None;
case "1":
case "o":
case "odd":
return Parity.Odd;
case "2":
case "e":
case "even":
return Parity.Even;
case "3":
case "m":
case "mark":
return Parity.Mark;
case "4":
case "s":
case "space":
return Parity.Space;
default:
return Parity.None;
}
}
public static Parity GetParity(int parityVal)
{
return GetParity(parityVal.ToString());
}
public static StopBits GetStopBits(string stopBitsVal)
{
switch (stopBitsVal?.ToLower())
{
case "0":
case "n":
case "none":
return StopBits.None;
case "1":
case "o":
case "one":
return StopBits.One;
case "2":
case "t":
case "two":
return StopBits.Two;
case "3":
case "1.5":
case "f":
case "of":
case "opf":
case "onepointfive":
return StopBits.OnePointFive;
default:
return StopBits.One;
}
}
public static StopBits GetStopBits(int stopBitsVal)
{
return GetStopBits(stopBitsVal.ToString());
}
public static Handshake GetHandshake(string shake)
{
switch (shake?.ToLower())
{
case "0":
case "n":
case "none":
return Handshake.None;
case "1":
case "x":
case "xoxo":
case "xonxoff":
case "software":
return Handshake.XOnXOff;
case "2":
case "r":
case "rts":
case "requesttosend":
case "hardware":
return Handshake.RequestToSend;
case "3":
case "rx":
case "rtsxx":
case "requesttosendxonxoff":
case "both":
return Handshake.RequestToSendXOnXOff;
default:
return Handshake.None;
}
}
public static Handshake GetHandshake(int shake)
{
return GetHandshake(shake.ToString());
}
}
public class Message
{
private readonly Encoding _encoder = null;
public byte[] Data { get; private set; }
public string MessageString => _encoder.GetString(Data);
public Message(byte[] data, Encoding stringEncoder)
{
Data = data;
_encoder = stringEncoder;
}
public string ReadString(SerialPortDataFormat dataFormat= SerialPortDataFormat.Char)
{
string result = null;
byte[] data = Data;
if (Data != null && Data.Length != 0)
{
switch (dataFormat)
{
case SerialPortDataFormat.Char:
result = _encoder.GetString(data);
break;
case SerialPortDataFormat.Hex:
result = data.ToHexString();
break;
}
}
return result;
}
}
}