334 lines
11 KiB
C#
334 lines
11 KiB
C#
|
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.Siemens.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
|
|||
|
}
|
|||
|
}
|