/// <summary>
/// 串口通讯辅助类
/// </summary>
public class serialHelper : SerialResult
{
/*
:LF(换行)、CR(回车)、FF(换页)、DEL(删除)、BS(退格)、BEL(响铃)等;
通信专用字符:SOH(文头)、EOT(文尾)、ACK(确认)等;
ASCII值为8、9、10 和13 分别转换为退格、制表、换行和回车字符。它们并没有特定的图形显示,
但会依不同的应用程序,而对文本显示有不同的影响。
\0 空字符
\a 警报符
\b 退格
\f 换页
\n 换行
\r 回车
\t 水平制表
\v 垂直制表
BEL 7 \a
BS 8 \b
HT 9 \t
LF 0A \n
VT 0B \v
FF 0C \f
CR 0D \r
*/
/// <summary>
/// 唯一标识
/// </summary>
public string IDStr { get; set; }
/// <summary>
/// 结束符枚举
/// </summary>
public enum eofStrEnum
{
/// <summary>
/// 枚举名:BEL ASCII值:7 转义:\a 解释:警报符(响铃)
/// </summary>
BEL,
/// <summary>
/// 枚举名:BS ASCII值:8 转义:\b 解释:退格
/// </summary>
BS,
/// <summary>
/// 枚举名:HT ASCII值:9 转义:\t 解释:水平制表符
/// </summary>
HT,
/// <summary>
/// 枚举名:LF ASCII值:0A 转义:\n 解释:换行符
/// </summary>
LF,
/// <summary>
/// 枚举名:VT ASCII值:0B 转义:\v 解释:垂直制表符
/// </summary>
VT,
/// <summary>
/// 枚举名:FF ASCII值:0C 转义:\f 解释:换页
/// </summary>
FF,
/// <summary>
/// 枚举名:CR ASCII值:0D 转义:\r 解释:回车
/// </summary>
CR
};
/// <summary>
/// 波特率列表
/// </summary>
public static int[] PortBaudRateList = new int[] {2400,4800,9600,19200,38400,43000,56000,57600,115200 };
/// <summary>
/// 校验位名称列表
/// </summary>
public static string[] ParityList = new string[] {
Parity.Even.ToString(),
Parity.Mark.ToString(),
Parity.None.ToString(),
Parity.Odd.ToString(),
Parity.Space.ToString()
};
/// <summary>
/// 停止位名称列表
/// </summary>
public static string[] StopBitsList = new string[]{
StopBits.One.ToString(),
StopBits.Two.ToString(),
StopBits.OnePointFive.ToString(),
StopBits.None.ToString()
};
/// <summary>
/// 数据位值列表
/// </summary>
public static int[] DataBitsList = new int[] { 5, 6, 7, 8 };
public event EventHandler<ReceivedDataEventArgs> RecDataInfo;
/// <summary>
/// 由字符N,1,1.5,2转为对应的停止位StopBits
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static StopBits cToStopBits(string str)
{
StopBits p = StopBits.One;
switch (str)
{
case "N":
p = StopBits.None;
break;
case "1":
p = StopBits.One;
break;
case "1.5":
p = StopBits.OnePointFive;
break;
case "2":
p = StopBits.Two;
break;
}
return p;
}
/// <summary>
/// 由字符E,M,N,O,S转为对应的校验位Parity
/// </summary>
/// <param name="pstr"></param>
/// <returns></returns>
public static Parity cToParity(string pstr)
{
Parity p=Parity.Even;
switch (pstr)
{
case "E":
p = Parity.Even;
break;
case "M":
p = Parity.Mark;
break;
case "N":
p = Parity.None;
break;
case "O":
p = Parity.Odd;
break;
case "S":
p = Parity.Space;
break;
}
return p;
}
private struct PortWriteHistory
{
public byte[] writeBytes;
public DateTime writeDate;
}
private struct PortRecHistory
{
public IList<byte> recBytes;
public DateTime recTime;
}
//public static List<string> chuankoulist = new List<string>();
//
private object _lock = new object();
public event SerialPortEventHandler ComReceiveDataEvent = null;
public delegate void SerialPortEventHandler(object sender, SerialPortEventArgs e);
public class SerialPortEventArgs : EventArgs
{
public bool IsOpened = false;
public byte[] ReceivedBytes = null;
}
#region Protery
internal SerialPort serialPort = new SerialPort();
/// <summary>
/// 串口说明字符串
/// </summary>
public string PortExpainString { get; private set; }
/// <summary>
/// 串口名,例如:COM1
/// </summary>
public string PortName { get; private set; }
/// <summary>
/// 波特率
/// </summary>
public int PortBaudRate { get; private set; }
/// <summary>
/// 数据位
/// </summary>
public int PortDataBits { get; private set; }
/// <summary>
/// 检验位
/// </summary>
public Parity PortParity { get; private set; }
/// <summary>
/// 停止位
/// </summary>
public StopBits PortStopBits { get; private set; }
/// <summary>
/// 结束字符
/// </summary>
public byte[] EndByte { get; set; }
/// <summary>
/// 获取一个值,该值指示BaseSerialPort对象的打开或关闭状态。
/// </summary>
public bool IsOpen
{
get
{
return this.serialPort.IsOpen;
}
}
/// <summary>
/// 获取或设置读取操作未完成时发生超时之前的毫秒数
/// </summary>
public int ReadTimeOut
{
get
{
return this.serialPort.ReadTimeout;
}
set
{
this.serialPort.ReadTimeout = value;
}
}
#endregion
private const int historySum = 5;
//private Queue<PortWriteHistory> writeHistory = new Queue<PortWriteHistory>(historySum);
//private Queue<PortRecHistory> recHistory = new Queue<PortRecHistory>(historySum);
//private IList<byte> alreadyReadbytes;
private static Object objectWrite = false;
private Object m_ObjLock = new Object();
/// <summary>
/// 串口初始化成功
/// </summary>
public bool isInitOK=false;
/// <summary>
/// 串口参数类型
/// </summary>
public struct SerialParamType
{
/// <summary>
/// 串口名,例如:COM1
/// </summary>
public string PortName;
/// <summary>
/// 波特率,例如:115200
/// </summary>
public int PortBaudRate;
/// <summary>
/// 数据位,例如: 8
/// </summary>
public int PortDataBits;
/// <summary>
/// 验证位,例如:Parity.Even
/// </summary>
public Parity PortParity;
/// <summary>
/// 停止位,例如: StopBits.One
/// </summary>
public StopBits PortStopBits;
}
/// <summary>
/// 构造方法
/// </summary>
public serialHelper()
: base()
{
}
/// <summary>
/// 构造
/// <para>异常:Exception</para>
/// </summary>
/// <param name="serialno"></param>
/// <param name="portExpaintStr"></param>
/// <param name="param"></param>
public serialHelper(int serialno,string portExpaintStr, SerialParamType param)
{
if (serialno<0 || portExpaintStr.Length < 1 || param.PortName == null)
throw new ArgumentException("SerialFun");
try
{
SerialPortsInit(param);
isInitOK = true;
RecDataInfo += recDataOperation;
}
catch (System.IO.IOException ex)
{
throw ex;
}
this.PortExpainString = portExpaintStr;
//alreadyReadbytes = new List<byte>();
}
/// <summary>
/// 字符串转Parity
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static Parity strToParity(string str)
{
try
{
return new enumHelper<Parity>().stringToEnum(str);
}
catch
{
return Parity.None;
}
}
/// <summary>
/// 字符串转StopBits
/// <para>异常:Exception</para>
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static StopBits strToStopBits(string str)
{
try
{
return new enumHelper<StopBits>().stringToEnum(str);
}
catch
{
return StopBits.One;
}
}
//public string GetHistory(ReceivedDataEventArgs.IFormattableType type)
//{
// StringBuilder sb1 = new StringBuilder();
// sb1.Append("Write History:\n");
// (from r in writeHistory
// select new
// {
// writeStr = string.Format("[{0:" + type.ToString() + "}],{1}",
// new ReceivedDataEventArgs(r.writeBytes.ToList()), r.writeDate.ToString())
// }).ToList().ForEach(s => sb1.Append(s + "\n"));
// sb1.Append("\nRecevide History:\n");
// StringBuilder sb2 = new StringBuilder();
// (from r in recHistory
// select new
// {
// recStr1 = string.Format("[{0:" + type.ToString() + "}],{1}",
// new ReceivedDataEventArgs(r.recBytes), r.recTime.ToString())
// }).ToList().ForEach(s => sb2.Append(s + "\n"));
// return sb1.ToString() + sb2.ToString();
//}
/// <summary>
/// 打开串口
/// <para>异常:Exception</para>
/// </summary>
/// <param name="Portparameter"></param>
private void SerialPortsInit(SerialParamType Portparameter)
{
Debug.Assert(serialPort != null);
//try
//{
this.PortName= serialPort.PortName = Portparameter.PortName;
this.PortBaudRate= serialPort.BaudRate = Portparameter.PortBaudRate;
this.PortDataBits= serialPort.DataBits = Portparameter.PortDataBits;
this.PortParity=serialPort.Parity = Portparameter.PortParity;
// serialPort.PortName = Portparameter.PortName;
this.PortStopBits= serialPort.StopBits = Portparameter.PortStopBits;
serialPort.ReceivedBytesThreshold = 1;
//注意下面这几个字段,在日系的仪表设备中,由于不光使用到TXD,RXD传送数据
//还用到了DTR,RTS等控制信号,所以也需要初始化状态。
serialPort.DiscardNull = false;
serialPort.DtrEnable = true;
serialPort.Handshake = Handshake.None;
serialPort.RtsEnable = true;
//serialPort.Open();
//
serialPort.DataReceived -= new SerialDataReceivedEventHandler(sport_DataReceived);
serialPort.DataReceived += new SerialDataReceivedEventHandler(sport_DataReceived);
//}
//catch (System.IO.IOException ex)
//{
// throw ex;
//}
}
/// <summary>
/// 打开串口
/// </summary>
public void Open()
{
serialPort.Open();
}
/// <summary>
/// 关闭串口
/// <para>异常:Exception</para>
/// </summary>
public void Close()
{
try
{
if (serialPort != null && serialPort.IsOpen)
serialPort.Close();
}
catch(Exception ex)
{
throw ex;
}
}
/// <summary>
/// 发送内容,字符串
/// <para>异常:Exception</para>
/// </summary>
/// <param name="content"></param>
public void Write(string content)
{
try
{
lock (objectWrite)
{
//alreadyReadbytes.Clear();
//writeHistory.Enqueue(new PortWriteHistory
//{
// writeBytes = System.Text.Encoding.Default.GetBytes(content)
// ,
// writeDate = DateTime.Now
//});
base.isWrite = true;
base.isReceived = false;
serialPort.Write(content);
}
}
catch (TimeoutException ex)
{
throw ex;
}
catch (InvalidOperationException ex)
{
throw ex;
}
}
/// <summary>
/// 标记是否接受到信号
/// </summary>
public static bool isReciveP = false;
/// <summary>
/// 发送内容,按byte[]
/// <para>异常:Exception</para>
/// </summary>
/// <param name="content"></param>
/// <param name="offset"></param>
/// <param name="count"></param>
public void Write(byte[] content, int offset = 0, int count = 0)
{
try
{
lock (objectWrite)
{
count = count == 0 ? content.Length - 1 : count;
serialPort.Write(content, offset, count);
Stopwatch sw = new Stopwatch();
while (!isReciveP)
{
sw.Start();
Thread.Sleep(5);
sw.Stop();
if (sw.ElapsedMilliseconds > 100)
{
break;
}
}
isReciveP = false;
}
}
catch (TimeoutException ex)
{
throw ex;
}
catch (InvalidOperationException ex)
{
throw ex;
}
}
/// <summary>
/// 读串口内容,按字节
/// <para>异常:Exception</para>
/// </summary>
/// <param name="nCount"></param>
/// <returns></returns>
public byte[] Read(int nCount)
{
byte[] buf = new byte[nCount];
try
{
serialPort.Read(buf, 0, nCount);
}
catch (ArgumentOutOfRangeException ex)
{
throw ex;
}
catch (TimeoutException ex)
{
throw ex;
}
catch (InvalidOperationException ex)
{
throw ex;
}
return buf;
}
/// <summary>
/// 读取串口接收缓冲区里的全部字符,
/// 若串口未打开、接收缓冲区字符数为0、存在异常皆返回false
/// <para>异常:Exception</para>
/// </summary>
public bool Read(out string rtnString)
{
lock (m_ObjLock)
{
rtnString = string.Empty;
try
{
if (!IsOpen) return false;
if (this.serialPort.BytesToRead <= 0) return false;
byte[] buffer = new byte[this.serialPort.BytesToRead];
this.serialPort.Read(buffer, 0, buffer.Length);
rtnString = Encoding.ASCII.GetString(buffer);
return true;
}
catch (Exception ex)
{
//ShowInfo.OnNotifyEX(ex, this.m_Name);
return false;
}
}
}
/// <summary>
/// 读取串口接收缓冲区里的全部字节,
/// 若串口未打开、接收缓冲区字节数为0、存在异常皆返回false
/// <para>异常:Exception</para>
/// </summary>
public bool Read(out byte[] rtnByteArray)
{
lock (m_ObjLock)
{
rtnByteArray = new byte[1];
try
{
if (!this.IsOpen) return false;
if (this.serialPort.BytesToRead <= 0) return false;
byte[] buffer = new byte[this.serialPort.BytesToRead];
this.serialPort.Read(buffer, 0, buffer.Length);
rtnByteArray = buffer;
return true;
}
catch (Exception ex)
{
//ShowInfo.OnNotifyEX(ex, this.m_Name);
return false;
}
}
}
/// <summary>
/// 读取串口接收缓冲区里的一行字符,
/// 若串口未打开、接收缓冲区字符数为0、存在异常皆返回false
/// <para>异常:Exception</para>
/// </summary>
public bool ReadLine(out string rtnString)
{
lock (m_ObjLock)
{
rtnString = string.Empty;
try
{
if (!IsOpen) return false;
rtnString = this.serialPort.ReadLine();
return true;
}
catch (Exception ex)
{
//ShowInfo.OnNotifyEX(ex, this.m_Name);
return false;
}
}
}
/// <summary>
/// 读取 System.IO.Ports.SerialPort 对象的流和输入缓冲区中所有立即可用的字节,
/// 若串口未打开、接收缓冲区字符数为0、存在异常皆返回false
/// <para>异常:Exception</para>
/// </summary>
public bool ReadExisting(out string rtnString)
{
lock (m_ObjLock)
{
rtnString = string.Empty;
try
{
if (!IsOpen) return false;
rtnString = this.serialPort.ReadExisting();
return true;
}
catch (Exception ex)
{
//ShowInfo.OnNotifyEX(ex, this.m_Name);
return false;
}
}
}
/*
BEL 7 \a
BS 8 \b
HT 9 \t
LF 0A \n
VT 0B \v
FF 0C \f
CR 0D \r
*/
/// <summary>
/// 返回结束符枚举代表的转义符串,例如结束符CR,返回转义符\r
/// </summary>
/// <param name="eof">枚举数组。BEL=\a,BS=\b,HT=\t,LF=\n,VT=\v,FF=\f,CR=\r</param>
/// <returns></returns>
public string getEofStr(eofStrEnum[] eof)
{
var sb = new StringBuilder();
foreach (var m in eof)
{
sb.Append(reszyf(m));
}
return sb.ToString();
}
/// <summary>
/// 清除串口缓存
/// </summary>
public void clearComBuffer()
{
serialPort.DiscardInBuffer();
serialPort.DiscardOutBuffer();
}
/// <summary>
/// 返回结束符枚举代表的转义符串,例如结束符CR,返回转义符\r
/// </summary>
/// <param name="eof">BEL=\a,BS=\b,HT=\t,LF=\n,VT=\v,FF=\f,CR=\r</param>
/// <returns></returns>
public string getEofStr(eofStrEnum eof)
{
return reszyf(eof);
}
/// <summary>
/// 按结束符枚举返回转义符
/// </summary>
/// <param name="v"></param>
/// <returns></returns>
private string reszyf(eofStrEnum v)
{
var sb = string.Empty;
switch (v.ToString())
{
case "BEL":
sb = "\a";
break;
case "BS":
sb = "\b";
break;
case "HT":
sb = "\t";
break;
case "LF":
sb = "\n";
break;
case "VT":
sb = "\v";
break;
case "FF":
sb = "\f";
break;
case "CR":
sb = "\r";
break;
}
return sb;
}
/// <summary>
/// 在指定的时间内一直读取到输入缓冲区中的指定 value 的字符串,
/// 若串口未打开、接收缓冲区字符数为0、存在异常皆返回string.Empty
/// <para>异常:Exception</para>
/// </summary>
public bool ReadTo(out string rtnString, string terminator = "\r\n", int readTimeOut = 1000)
{
rtnString = string.Empty;
System.Diagnostics.Stopwatch StartRead = new System.Diagnostics.Stopwatch();
StartRead.Restart();
List<byte> iList = new List<byte>();
try
{
if (!this.IsOpen) return false;
while (this.serialPort.BytesToRead != 0 || StartRead.ElapsedMilliseconds < readTimeOut)
{
if (this.serialPort.BytesToRead == 0)
{
Utility.Delay(2);
continue;
}
iList.Add((byte)this.serialPort.ReadByte());
ASCIIEncoding.Unicode.GetString(iList.ToArray<byte>());
rtnString = UnicodeEncoding.Default.GetString(iList.ToArray());
if (rtnString.Length > terminator.Length)
{
if (rtnString.Substring(rtnString.Length - terminator.Length, terminator.Length) == terminator)
{
rtnString = rtnString.Replace(terminator, "");
return true;
}
}
}
//rtnString = string.Format("-{0}-读串口{1}_超时:结果为_{2}", this.PortName, this.serialPort.PortName, rtnString);
return false;
}
catch (Exception ex)
{
return false;
}
finally
{
this.serialPort.DiscardInBuffer();
this.serialPort.DiscardOutBuffer();
}
}
/// <summary>
/// 取本机可用串口列表
/// </summary>
/// <returns></returns>
public static List<string> GetMacPortList()
{
List<string> PortList = new List<string>();
foreach (var m in SerialPort.GetPortNames())
{
PortList.Add(m);
}
return PortList;
}
/// <summary>
/// 数据接收事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void sport_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
if (serialPort.BytesToRead <= 0)
{
return;
}
lock (_lock)
{
var len = serialPort.BytesToRead;
var data = new byte[len];
try
{
serialPort.Read(data, 0, len);
}
catch (System.Exception)
{
//catch read exception
}
var args = new SerialPortEventArgs
{
ReceivedBytes = data
};
ComReceiveDataEvent?.Invoke(this, args);
}
}
private void recDataOperation(Object sender, ReceivedDataEventArgs e)
{
}
/// <summary>
/// 阻塞方式接收串口内容
/// </summary>
/// <returns></returns>
public byte[] WaitReceivedData()
{
//while (true)
//{
// if (base.isReceived)
// {
// return base.ReceivedData.ToArray<byte>();
// }
// Thread.Sleep(20);
//}
return new byte[] { 0 };
}
}
/// <summary>
/// 自定义异常SerialFunException
/// </summary>
public class SerialFunException : ApplicationException
{
public SerialFunException(string message)
: base(message)
{
}
public SerialFunException(string message, Exception innerException)
: base(message, innerException)
{
}
}
/// <summary>
/// 自定义异常SerialFunPortOpenFail
/// </summary>
public class SerialFunPortOpenFail : SerialFunException
{
public SerialFunPortOpenFail(string message)
: base(message)
{
}
public SerialFunPortOpenFail(string message, Exception innerExcepton)
: base(message, innerExcepton)
{
}
private void appendParam()
{
this.Data["ErrorDate"] = DateTime.Now;
this.Source = "SerialFun类";
this.Data.Add("Excepton", "这个异常表示,端口打开失败!");
}
}
/// <summary>
/// 接收事件定义类
/// </summary>
public class ReceivedDataEventArgs : EventArgs, IFormattable
{
public IList<byte> RecData { get; private set; }
/// <summary>
/// 接收事件
/// </summary>
/// <param name="data"></param>
public ReceivedDataEventArgs(IList<byte> data)
{
this.RecData = data;
}
/// <summary>
/// 进制枚举
/// </summary>
public enum IFormattableType
{
hex, str, dec
}
/// <summary>
/// 不同进制转换字符串
/// </summary>
/// <param name="format"></param>
/// <param name="provider"></param>
/// <returns></returns>
public string ToString(string format, IFormatProvider provider)
{
StringBuilder sb1 = new StringBuilder();
if (format.Equals(IFormattableType.hex.ToString()))
{
(from r in RecData.ToArray<byte>()
select new
{
hexStr = Convert.ToString(r, 16)
}).ToList().ForEach(s => sb1.Append(s.hexStr + " "));
return sb1.ToString();
}
else if (format.Equals(IFormattableType.str.ToString()))
{
(from r in RecData.ToArray<byte>()
select new
{
Str = (char)r
}).ToList().ForEach(s => sb1.Append(s.Str));
return sb1.ToString();
}
else if (format.Equals(IFormattableType.dec.ToString()))
{
(from r in RecData.ToArray<byte>()
select new
{
Str = Convert.ToString(r, 10)
}).ToList().ForEach(s => sb1.Append(s.Str + " "));
return sb1.ToString();
}
else
throw new ArgumentException("ToString");
}
}
public class SerialResult
{
/// <summary>
/// 读状态
/// </summary>
public bool isRead { get; internal set; }
/// <summary>
/// 写状态
/// </summary>
public bool isWrite { get; internal set; }
/// <summary>
/// 写的内容,字节列表
/// </summary>
public IList<byte> WriteValue { get; internal set; }
/// <summary>
/// 读的数量
/// </summary>
public int ReadSum { get; internal set; }
/// <summary>
/// 接收的数据,字节列表
/// </summary>
public IList<byte> ReceivedData { get; internal set; }
/// <summary>
/// 接收到数据的标记
/// </summary>
public bool isReceived { get; internal set; }
/// <summary>
/// 构造
/// </summary>
public SerialResult()
{
this.isRead = false;
this.isWrite = false;
this.WriteValue = new byte[] { };
this.ReadSum = 0;
this.isReceived = false;
this.ReceivedData = new byte[] { };
}
}