123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334 |
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.IO.Ports;
- using System.Threading;
- using MECF.Framework.RT.Core.ThreadLock;
- using log4net.Core;
- namespace MECF.Framework.RT.Core.IoProviders.Common.Serial
- {
- /// <summary>
- /// 所有串行通信类的基类,提供了一些基础的服务
- /// </summary>
- public class SerialBase
- {
- #region Constructor
- /// <summary>
- /// 实例化一个无参的构造方法
- /// </summary>
- public SerialBase( )
- {
- SP_ReadData = new SerialPort( );
- hybirdLock = new SimpleHybirdLock( );
- }
- #endregion
- #region Public Method
- /// <summary>
- /// 初始化串口信息,9600波特率,8位数据位,1位停止位,无奇偶校验
- /// </summary>
- /// <param name="portName">端口号信息,例如"COM3"</param>
- public void SerialPortInni( string portName )
- {
- SerialPortInni( portName, 9600 );
- }
- /// <summary>
- /// 初始化串口信息,波特率,8位数据位,1位停止位,无奇偶校验
- /// </summary>
- /// <param name="portName">端口号信息,例如"COM3"</param>
- /// <param name="baudRate">波特率</param>
- public void SerialPortInni( string portName, int baudRate )
- {
- SerialPortInni( portName, baudRate, 8, StopBits.One, Parity.None );
- }
- /// <summary>
- /// 初始化串口信息,波特率,数据位,停止位,奇偶校验需要全部自己来指定
- /// </summary>
- /// <param name="portName">端口号信息,例如"COM3"</param>
- /// <param name="baudRate">波特率</param>
- /// <param name="dataBits">数据位</param>
- /// <param name="stopBits">停止位</param>
- /// <param name="parity">奇偶校验</param>
- public void SerialPortInni( string portName, int baudRate, int dataBits, StopBits stopBits, Parity parity )
- {
- if (SP_ReadData.IsOpen)
- {
- return;
- }
- SP_ReadData.PortName = portName; // 串口
- SP_ReadData.BaudRate = baudRate; // 波特率
- SP_ReadData.DataBits = dataBits; // 数据位
- SP_ReadData.StopBits = stopBits; // 停止位
- SP_ReadData.Parity = parity; // 奇偶校验
- }
- /// <summary>
- /// 根据自定义初始化方法进行初始化串口信息
- /// </summary>
- /// <param name="initi">初始化的委托方法</param>
- public void SerialPortInni( Action<SerialPort> initi )
- {
- if (SP_ReadData.IsOpen)
- {
- return;
- }
- SP_ReadData.PortName = "COM5";
- SP_ReadData.BaudRate = 9600;
- SP_ReadData.DataBits = 8;
- SP_ReadData.StopBits = StopBits.One;
- SP_ReadData.Parity = Parity.None;
- initi.Invoke( SP_ReadData );
- }
- /// <summary>
- /// 打开一个新的串行端口连接
- /// </summary>
- public void Open( )
- {
- if (!SP_ReadData.IsOpen)
- {
- SP_ReadData.Open( );
- InitializationOnOpen( );
- }
- }
- /// <summary>
- /// 获取一个值,指示串口是否处于打开状态
- /// </summary>
- /// <returns>是或否</returns>
- public bool IsOpen( )
- {
- return SP_ReadData.IsOpen;
- }
- /// <summary>
- /// 关闭端口连接
- /// </summary>
- public void Close( )
- {
- if(SP_ReadData.IsOpen)
- {
- ExtraOnClose( );
- SP_ReadData.Close( );
- }
- }
- /// <summary>
- /// 读取串口的数据
- /// </summary>
- /// <param name="send">发送的原始字节数据</param>
- /// <returns>带接收字节的结果对象</returns>
- public OperateResult<byte[]> ReadBase(byte[] send)
- {
- hybirdLock.Enter( );
- if (IsClearCacheBeforeRead) ClearSerialCache( );
- OperateResult sendResult = SPSend( SP_ReadData, send );
- if (!sendResult.IsSuccess)
- {
- hybirdLock.Leave( );
- return OperateResult.CreateFailedResult<byte[]>( sendResult );
- }
- OperateResult<byte[]> receiveResult = SPReceived( SP_ReadData, true );
- hybirdLock.Leave( );
- return receiveResult;
- }
- /// <summary>
- /// 清除串口缓冲区的数据,并返回该数据,如果缓冲区没有数据,返回的字节数组长度为0
- /// </summary>
- /// <returns>是否操作成功的方法</returns>
- public OperateResult<byte[]> ClearSerialCache( )
- {
- return SPReceived( SP_ReadData, false );
- }
- #endregion
- #region virtual Method
- /// <summary>
- /// 检查当前接收的字节数据是否正确的
- /// </summary>
- /// <param name="rBytes">输入字节</param>
- /// <returns>检查是否正确</returns>
- protected virtual bool CheckReceiveBytes(byte[] rBytes )
- {
- return true;
- }
- #endregion
- #region Initialization And Extra
- /// <summary>
- /// 在打开端口时的初始化方法,按照协议的需求进行必要的重写
- /// </summary>
- /// <returns>是否初始化成功</returns>
- protected virtual OperateResult InitializationOnOpen( )
- {
- return OperateResult.CreateSuccessResult( );
- }
- /// <summary>
- /// 在将要和服务器进行断开的情况下额外的操作,需要根据对应协议进行重写
- /// </summary>
- /// <returns>当断开连接时额外的操作结果</returns>
- protected virtual OperateResult ExtraOnClose( )
- {
- return OperateResult.CreateSuccessResult( );
- }
- #endregion
- #region Private Method
-
- /// <summary>
- /// 发送数据到串口里去
- /// </summary>
- /// <param name="serialPort">串口对象</param>
- /// <param name="data">字节数据</param>
- /// <returns>是否发送成功</returns>
- protected virtual OperateResult SPSend( SerialPort serialPort, byte[] data )
- {
- if (data != null && data.Length > 0)
- {
- try
- {
- serialPort.Write( data, 0, data.Length );
- return OperateResult.CreateSuccessResult( );
- }
- catch(Exception ex)
- {
- return new OperateResult( ex.Message );
- }
- }
- else
- {
- return OperateResult.CreateSuccessResult( );
- }
- }
- /// <summary>
- /// 从串口接收一串数据信息,可以指定是否一定要接收到数据
- /// </summary>
- /// <param name="serialPort">串口对象</param>
- /// <param name="awaitData">是否必须要等待数据返回</param>
- /// <returns>结果数据对象</returns>
- protected virtual OperateResult<byte[]> SPReceived( SerialPort serialPort, bool awaitData )
- {
- byte[] buffer = new byte[1024];
- System.IO.MemoryStream ms = new System.IO.MemoryStream( );
- DateTime start = DateTime.Now; // 开始时间,用于确认是否超时的信息
- while (true)
- {
- System.Threading.Thread.Sleep( sleepTime );
- try
- {
- if (serialPort.BytesToRead < 1)
- {
- if ((DateTime.Now - start).TotalMilliseconds > ReceiveTimeout)
- {
- ms.Dispose( );
- return new OperateResult<byte[]>( $"Time out: {ReceiveTimeout}" );
- }
- else if (ms.Length > 0)
- {
- break;
- }
- else if (awaitData)
- {
- continue;
- }
- else
- {
- break;
- }
- }
- // 继续接收数据
- int sp_receive = serialPort.Read( buffer, 0, buffer.Length );
- ms.Write( buffer, 0, sp_receive );
- }
- catch (Exception ex)
- {
- ms.Dispose( );
- return new OperateResult<byte[]>( ex.Message );
- }
- }
- // resetEvent.Set( );
- byte[] result = ms.ToArray( );
- ms.Dispose( );
- return OperateResult.CreateSuccessResult( result );
- }
-
- #endregion
- #region Object Override
- /// <summary>
- /// 返回表示当前对象的字符串
- /// </summary>
- /// <returns>字符串</returns>
- public override string ToString()
- {
- return "SerialBase";
- }
- #endregion
- #region Public Properties
- /// <summary>
- /// 接收数据的超时时间,默认5000ms
- /// </summary>
- public int ReceiveTimeout
- {
- get { return receiveTimeout; }
- set { receiveTimeout = value; }
- }
- /// <summary>
- /// 连续串口缓冲数据检测的间隔时间,默认20ms
- /// </summary>
- public int SleepTime
- {
- get { return sleepTime; }
- set { if (value > 0) sleepTime = value; }
- }
- /// <summary>
- /// 是否在发送数据前清空缓冲数据,默认是false
- /// </summary>
- public bool IsClearCacheBeforeRead
- {
- get { return isClearCacheBeforeRead; }
- set { isClearCacheBeforeRead = value; }
- }
- #endregion
- #region Private Member
-
- private SerialPort SP_ReadData = null; // 串口交互的核心
- private SimpleHybirdLock hybirdLock; // 数据交互的锁
- private int receiveTimeout = 5000; // 接收数据的超时时间
- private int sleepTime = 20; // 睡眠的时间
- private bool isClearCacheBeforeRead = false; // 是否在发送前清除缓冲
- #endregion
- }
- }
|