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 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 list = new List(); 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 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); } } } /// /// 扩展方法 byte[] /// 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; } } }