⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 winstream.cs

📁 C#串口通讯开发实例一个基于C#开发的串口通讯实例
💻 CS
字号:
using System;
using System.IO;
using System.Collections;
using System.Runtime.InteropServices;
using OpenNETCF.IO.Ports;

namespace OpenNETCF.IO.Ports.Streams
{
	public class WinStream : Stream, ISerialStreamCtrl
	{
		internal OpenNETCF.IO.Serial.Port _port;

		public class Consts
		{
			public const int Win32Err_ERROR_INSUFFICIENT_BUFFER = 122;
			public const uint PortEnum_InitBufSize				= 8 * 1024;
			public const uint PortEnum_MaxBufSize				= 100 * 1024;
		}

		#region Construction and Disposing
		internal WinStream(
			int			baudRate,
			int			dataBits,
			bool		discardNull,
			bool		dtrEnable,
			Handshake	handshake,
			Parity		parity,
			byte		parityReplace,
			string		portName,
			int			readBufferSize,
			int			readTimeout,
			int			receivedBytesThreshold,
			bool		rtsEnable,
			StopBits	stopBits,
			int			writeBufferSize,
			int			writeTimeout )
		{
			_port = new OpenNETCF.IO.Serial.Port( portName, readBufferSize, writeBufferSize );
			
			BaudRate				= baudRate;
			DataBits				= dataBits;
			DiscardNull				= discardNull;
			DtrEnable				= dtrEnable;
			Handshake				= handshake;
			Parity					= parity;
			ParityReplace			= parityReplace;
// TODO:	ReadTimeout				= readTimeout;
			ReceivedBytesThreshold	= receivedBytesThreshold;
			RtsEnable				= rtsEnable;
			StopBits				= stopBits;
// TODO:	WriteTimeout			= writeTimeout;

			_port.DataReceived		+= new OpenNETCF.IO.Serial.Port.CommEvent(_port_DataReceived);
			_port.OnError			+= new OpenNETCF.IO.Serial.Port.CommErrorEvent(_port_OnError);
			_port.RingChange		+= new OpenNETCF.IO.Serial.Port.CommChangeEvent(_port_RingChange);
			_port.RLSDChange		+= new OpenNETCF.IO.Serial.Port.CommChangeEvent(_port_RLSDChange);

			if( !_port.Open() )
				throw new UnauthorizedAccessException();
		}

		protected void AssertOpenPort()
		{
			if( !_port.IsOpen )
				throw new InvalidOperationException("Serial Port is not open");
		}

		protected bool GetCommStatusFlag( OpenNETCF.IO.Serial.CommModemStatusFlags statusFlag )
		{
			AssertOpenPort();

			uint modemStatus = 0;
			_port.m_CommAPI.GetCommModemStatus( _port.hPort, ref modemStatus );
			
			return ( (uint)statusFlag & modemStatus ) != 0;
		}

		public void Dispose()
		{
			_port.Dispose();
		}

		#endregion

		#region Stream Implementation

		public override bool CanRead	{ get { return _port.IsOpen; }}
		public override bool CanWrite	{ get { return _port.IsOpen; }}
		public override bool CanSeek	{ get { return false; }}
		public override long Length		{ get { throw new NotSupportedException(); }}

		public override long Position
		{
			get { throw new NotSupportedException(); }
			set { throw new NotSupportedException(); }
		}


		public override void Close()
		{
			base.Close ();
			Dispose();
		}

		public override void Flush()
		{
			AssertOpenPort();

			if( _port.OutBufferCount > 0 )
			{
				int oldSThreshold = _port.SThreshold;
				_port.SThreshold = -1; // force even empty buffer to be written out
				_port.Output = new byte[0];
				_port.SThreshold = oldSThreshold;
			}

			// Flush OS buffer
			if( !_port.m_CommAPI.FlushFileBuffers(_port.hPort) )
				throw new InvalidOperationException( string.Format( "Error flushing buffer: {0}", Marshal.GetLastWin32Error() ));
		}

		public override int  Read( byte[] buffer, int offset, int count )
		{
			AssertOpenPort();

			if( buffer == null )
				throw new ArgumentException( "null", "buffer" );

			if( offset < 0 )
				throw new ArgumentException( "<0", "offset" );

			if( count < 0 )
				throw new ArgumentException( "<0", "count" );
			else if( count == 0 )
				return 0;

			//
			// modified from original Port.Input
			//
			// lock the rx FIFO while reading
			_port.rxBufferBusy.WaitOne();

			// how much data are we *actually* going to return from the call?
			int dequeueLength = (count < _port.rxFIFO.Count) ? count : _port.rxFIFO.Count;

			// dequeue the data
			for(int p = offset ; p < offset + dequeueLength ; p++)
				buffer[p] = (byte)_port.rxFIFO.Dequeue();

			// release the mutex so the Rx thread can continue
			_port.rxBufferBusy.ReleaseMutex();

			return dequeueLength;
		}

		public override long Seek( long offset, SeekOrigin origin )
		{
			throw new NotSupportedException();
		}

		public override void SetLength( long value )
		{
			throw new NotSupportedException();
		}

		public override void Write( byte[] buffer, int offset, int count )
		{
			AssertOpenPort();

			if( buffer == null )
				throw new ArgumentException( "null", "buffer" );

			if( offset < 0 )
				throw new ArgumentException( "<0", "offset" );

			if( count < 0 )
				throw new ArgumentException( "<0", "count" );
			else if( count == 0 )
				return;

			byte[] buf = new byte[ count ];
			Buffer.BlockCopy( buffer, offset, buf, 0, count );

			_port.Output = buf;
		}
		#endregion

		#region	  ISerialStreamCtrl Members
		public int			BaudRate
		{
			get { return (int) _port.Settings.BaudRate; }
			set { _port.Settings.BaudRate = (OpenNETCF.IO.Serial.BaudRates) value; }
		}

		public bool			BreakState
		{
			get { return _port.Break; }
			set { _port.Break = value; }
		}

		public int			BytesToRead
		{
			get { return _port.InBufferCount; }
		}

		public int			BytesToWrite
		{
			get { return _port.OutBufferCount; }
		}

		public bool			CDHolding
		{
			get { return GetCommStatusFlag( OpenNETCF.IO.Serial.CommModemStatusFlags.MS_RLSD_ON ); }
		}

		public bool			CtsHolding
		{
			get { return GetCommStatusFlag( OpenNETCF.IO.Serial.CommModemStatusFlags.MS_CTS_ON ); }
		}

		public int			DataBits
		{
			get { return _port.Settings.ByteSize; }
			set { _port.Settings.ByteSize = (byte)value; }
		}

		public bool			DiscardNull
		{
			get { return _port.DetailedSettings.DiscardNulls; }
			set { _port.DetailedSettings.DiscardNulls = value; }
		}

		public bool			DsrHolding
		{
			get { return GetCommStatusFlag( OpenNETCF.IO.Serial.CommModemStatusFlags.MS_DSR_ON ); }
		}

		public bool			DtrEnable
		{
			get { return _port.DTREnable; }
			set { _port.DTREnable = value; }
		}


		public static string[] GetPortNames()
		{
			string	buffer;
			uint	bufferSize = Consts.PortEnum_InitBufSize;
			uint	res;
			int		error;
			
			ArrayList comPorts = new ArrayList();
	
			do 
			{
				buffer = new String( '\0', (int) bufferSize );

				// TODO: two strange bugs (features?):
				//	 GetLastError() does not reset once err# 122 occurs - fixed with SetLastError
				//   if initial buffer has enough space, err# 127 occurs.

				SetLastError(0);
				res = QueryDosDevice( null, buffer, (uint) buffer.Length );
				error = Marshal.GetLastWin32Error();

				if( res == 0 )
				{
					// QueryDosDevice failed
					if( error == Consts.Win32Err_ERROR_INSUFFICIENT_BUFFER )
					{
						// no clue how much we need, double the buffer size
						bufferSize *= 2;
					}
					else
						throw new InvalidOperationException("QueryDosDevice error #" + error.ToString());
				}
				else if( res > bufferSize )
				{
					// TODO: specs are vague for Win2000 & WinNT - needs testing

					// QueryDosDevice failed with non-zero res
					if( error == Consts.Win32Err_ERROR_INSUFFICIENT_BUFFER )
					{
						// this platform knows what it needs
						bufferSize = res;
					}
					else
						throw new InvalidOperationException("QueryDosDevice error #" + error.ToString());
				}
				else if( error == 0 && res == 0 )
				{
					// sanity check
					throw new InvalidOperationException("Internal error");
				}
				else
					break;

			} while( bufferSize <= Consts.PortEnum_MaxBufSize );

			if( bufferSize > Consts.PortEnum_MaxBufSize )
				throw new InvalidOperationException("Maximum buffer size exceeded");

			buffer = buffer.Substring( 0, (int)res );
			foreach( string device in buffer.Split( '\0' ))
			{
				// Assumptions: serial port must be a string that begins with "COM#",
				// where # is a 1 to 3 digit number

				if( device.Length >= 4 && device.Length <= 6 &&
					device.StartsWith("COM") && 
					Char.IsDigit( device, 3 ) && 
					(device.Length < 5 || Char.IsDigit( device, 4 )) &&
					(device.Length < 6 || Char.IsDigit( device, 5 )) )
				{
					comPorts.Add( string.Copy( device ));	// avoid locking the original buffer string
				}
			}
			
			return (string[]) comPorts.ToArray( typeof(string) );
		}
		

		public Handshake	Handshake
		{
			get
			{
				if( _port.DetailedSettings is OpenNETCF.IO.Serial.HandshakeNone )
					return Handshake.None;
				else if( _port.DetailedSettings is OpenNETCF.IO.Serial.HandshakeCtsRts )
					return Handshake.RequestToSend;
				else if( _port.DetailedSettings is OpenNETCF.IO.Serial.HandshakeXonXoff )
					return Handshake.XOnXOff;
				else if( _port.DetailedSettings is OpenNETCF.IO.Serial.HandshakeDsrDtr )
					return Handshake.RequestToSendXOnXOff;
				else
					throw new NotImplementedException();
			}
			set
			{
				// Creating a new Handshaking object resets BasicSettings parameters.
				OpenNETCF.IO.Serial.BasicPortSettings tempPortSettings = _port.DetailedSettings.BasicSettings;

				switch( value )
				{
					case OpenNETCF.IO.Ports.Handshake.None:
						_port.DetailedSettings = new OpenNETCF.IO.Serial.HandshakeNone();
						break;
					case OpenNETCF.IO.Ports.Handshake.RequestToSend:
						_port.DetailedSettings = new OpenNETCF.IO.Serial.HandshakeCtsRts();
						break;
					case OpenNETCF.IO.Ports.Handshake.XOnXOff:
						_port.DetailedSettings = new OpenNETCF.IO.Serial.HandshakeXonXoff();
						break;
					case OpenNETCF.IO.Ports.Handshake.RequestToSendXOnXOff:
						_port.DetailedSettings = new OpenNETCF.IO.Serial.HandshakeDsrDtr();
						break;
					default:
						throw new NotImplementedException();
				}

				_port.DetailedSettings.BasicSettings = tempPortSettings;
			}
		}

		public bool			IsOpen
		{
			get { return _port.IsOpen; }
		}

		public Parity		Parity
		{
			get { return (Parity) Convert.ToInt32(_port.Settings.Parity); }
			set { _port.Settings.Parity = (OpenNETCF.IO.Serial.Parity) Convert.ToInt32(value); }
		}

		public byte			ParityReplace
		{
			get
			{
				return _port.DetailedSettings.ReplaceErrorChar ? (byte)_port.DetailedSettings.ErrorChar : (byte)0;
			}
			set
			{
				if( value == 0 )
					_port.DetailedSettings.ReplaceErrorChar = false;
				else
				{
					_port.DetailedSettings.ErrorChar		= (char) value;
					_port.DetailedSettings.ReplaceErrorChar	= true;
				}
			}
		}

		public int			ReadBufferSize
		{
			get { return _port.rxBufferSize; }
			set { throw new InvalidOperationException("Only available during port initialization"); }
		}

		public int			ReadTimeout
		{
			get { throw new NotImplementedException(); }
			set { throw new NotImplementedException(); }
		}

		public int			ReceivedBytesThreshold
		{
			get { return _port.RThreshold; }
			set { _port.RThreshold = value; }
		}

		public bool			RtsEnable
		{
			get { return _port.RTSEnable; }
			set { _port.RTSEnable = value; }
		}

		public StopBits		StopBits
		{
			get
			{
				switch( _port.Settings.StopBits )
				{
					default:
						throw new InvalidOperationException();
					case OpenNETCF.IO.Serial.StopBits.one:
						return StopBits.One;
					case OpenNETCF.IO.Serial.StopBits.onePointFive:
						return StopBits.OnePointFive;
					case OpenNETCF.IO.Serial.StopBits.two:
						return StopBits.Two;
				}
			}
			set
			{
				switch( value )
				{
					case StopBits.One:
						_port.Settings.StopBits = OpenNETCF.IO.Serial.StopBits.one;
						break;
					case StopBits.OnePointFive:
						_port.Settings.StopBits = OpenNETCF.IO.Serial.StopBits.onePointFive;
						break;
					case StopBits.Two:
						_port.Settings.StopBits = OpenNETCF.IO.Serial.StopBits.two;
						break;
				}
			}
		}

		public int			WriteBufferSize
		{
			get { return _port.txBufferSize; }
			set { throw new InvalidOperationException("Only available during port initialization"); }
		}

		public int			WriteTimeout
		{
			get { throw new NotImplementedException(); }
			set { throw new NotImplementedException(); }
		}


		public event SerialErrorEventHandler		ErrorEvent;
		public event SerialReceivedEventHandler		ReceivedEvent;
		public event SerialPinChangedEventHandler	PinChangedEvent;

		public void DiscardInBuffer()
		{
			// lock the rx FIFO while reading
			_port.rxBufferBusy.WaitOne();

			// Empty buffer
			_port.rxFIFO.Clear();

			// release the mutex so the Rx thread can continue
			_port.rxBufferBusy.ReleaseMutex();
		}

		public void DiscardOutBuffer()
		{
			_port.ptxBuffer = 0;
		}

		#endregion

		#region Internal Events Forwarding
		private void _port_DataReceived()
		{
			if( ReceivedEvent != null )
				ReceivedEvent(this, new SerialReceivedEventArgs(SerialReceived.ReceivedChars));
		}

		private void _port_OnError(string Description)
		{
			if( ErrorEvent != null )
			{
				SerialErrors err = (SerialErrors) 0;

				if( Description.IndexOf("Framing") >= 0 )
					err |= SerialErrors.Frame;
				if( Description.IndexOf("Overrun") >= 0 )
					err |= SerialErrors.Overrun;
				if( Description.IndexOf("Receive Overflow") >= 0 )
					err |= SerialErrors.RxOver;
				if( Description.IndexOf("Parity") >= 0 )
					err |= SerialErrors.RxParity;
				if( Description.IndexOf("Transmit Overflow") >= 0 )
					err |= SerialErrors.TxFull;

				ErrorEvent( this, new SerialErrorEventArgs(err) );
			}
		}

		private void _port_RingChange(bool NewState)
		{
			if( PinChangedEvent != null )
				PinChangedEvent(this, new SerialPinChangedEventArgs(SerialPinChanges.Ring));
		}

		private void _port_RLSDChange(bool NewState)
		{
			if( PinChangedEvent != null )
				PinChangedEvent(this, new SerialPinChangedEventArgs(SerialPinChanges.CDChanged));
		}

		#endregion

		#region Extern code declarations
		
		[DllImport("kernel32.dll")]
		static extern void SetLastError(uint dwErrCode);

		[DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)]
		private extern static uint QueryDosDevice(
			[MarshalAs(UnmanagedType.LPTStr)]
			string lpDeviceName,
			[MarshalAs(UnmanagedType.LPTStr)]
			string lpTargetPath,
			uint ucchMax);
		
		#endregion
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -