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

📄 serialstream.cs

📁 SerialPort 串口通讯用
💻 CS
📖 第 1 页 / 共 5 页
字号:
// ==++==
// 
//   Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// ==--==
/*=============================================================================
**
** Class: SerialStream
**
** Purpose: Class for enabling low-level sync and async control over a serial 
**		  : communications resource.
**
** Date: August, 2002
**
=============================================================================*/

using System;
using System.IO;
using System.Text;
using System.ComponentModel;
using System.Resources;
using System.Runtime;
using System.Security;
using System.Security.Permissions;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Collections;
using System.Data;
using Microsoft.Win32;
using System.Threading;
using System.Runtime.Remoting.Messaging;
using System.Runtime.CompilerServices;



// Notes about the SerialStream:
//	* The stream is always opened via the SerialStream constructor.
//	* The handleProtector guarantees ownership of the file handle, so that it may not be 
//	* unnaturally closed by another process or thread.  Thus, since all properties are available
//	* only when the object exists, the object's properties can be queried only when the SerialStream
//  * object is instantiated (i.e. "open").  
//	* Handles to serial communications resources here always: 
//	* 1) own the handle
//  * 2) are opened for asynchronous operation
//  * 3) set access at the level of FileAccess.ReadWrite
//  * 4) Allow for reading AND writing
//  * 5) Disallow seeking, since they encapsulate a file of type FILE_TYPE_CHAR
	
namespace System.IO.Ports
{
	
	public delegate void SerialEventHandler(object source, SerialEventArgs e);
	internal delegate int WaitEventCallback();
	internal class SerialStream : Stream 
	{

		// members supporting properties exposed to SerialPort
		private string portName;
		private byte parityReplace = (byte) '?';
		private bool dtrEnable;
		private bool rtsEnable;
		private bool inBreak = false;				// port is initially in non-break state
		private Handshake handshake;
		
		// The internal C# representations of Win32 structures necessary for communication
		// hold most of the internal "fields" maintaining information about the port.  
		private UnsafeNativeMethods.DCB dcb;
		private UnsafeNativeMethods.COMMTIMEOUTS commTimeouts;
		private UnsafeNativeMethods.COMSTAT comStat;
		private UnsafeNativeMethods.COMMPROP commProp;
		
		// internal-use members
		private const long dsrTimeout = 0L;
		private const int maxDataBits = 8;
		private const int minDataBits = 5;
		private HandleProtector _handleProtector;  // See the HandleProtector class.
		internal bool lastOpTimedOut = false;	// Read returns without error on timeout, so this is internally required to determine timeout.
		private byte[] tempBuf;					// used to avoid multiple array allocations in ReadByte() 
		
		// callback-related members, following MSDN's Asyncrhonous Programming Design Pattern.
		private WaitEventCallback myWaitCommCallback;
		private AsyncCallback myAsyncCallback;
		private Object state;
	
		// called whenever any async i/o operation completes.
		private unsafe static readonly IOCompletionCallback IOCallback = new IOCompletionCallback(SerialStream.AsyncFSCallback);
			
		// three different events, also wrapped by SerialPort.
		internal event SerialEventHandler ReceivedEvent;	// called when one character is received.
		internal event SerialEventHandler PinChangedEvent; // called when any of the pin/ring-related triggers occurs
		internal event SerialEventHandler ErrorEvent;		// called when any runtime error occurs on the port (frame, overrun, parity, etc.)


		// ----SECTION: inherited properties from Stream class ------------* 
		
		// These six properites are required for SerialStream to inherit from the abstract Stream class.
		// Note four of them are always true or false, and two of them throw exceptions, so these 
		// are not usefully queried by applications which know they have a SerialStream, etc...
		public override bool CanRead
		{
			get { return (!_handleProtector.IsClosed); }
		}
		
		public override bool CanSeek
		{	
			get { return false; }
		}

		
		public override bool CanWrite
		{	
			get { return (!_handleProtector.IsClosed); }
		}

		public override long Length
		{
			get { throw new NotSupportedException(InternalResources.GetResourceString("NotSupported_UnseekableStream")); }
		}
		
		
		public override long Position
		{
			get { throw new NotSupportedException(InternalResources.GetResourceString("NotSupported_UnseekableStream")); }
			set { throw new NotSupportedException(InternalResources.GetResourceString("NotSupported_UnseekableStream")); }		
		}

		// ----- new get-set properties -----------------*
		
		// Standard port properties, also called from SerialPort
		// BaudRate may not be settable to an arbitrary integer between dwMinBaud and dwMaxBaud,
		// and is limited only by the serial driver.  Typically about twelve values such
		// as Winbase.h's CBR_110 through CBR_256000 are used.
		internal int BaudRate 
		{ 
			get { return (int) dcb.BaudRate; }
			set 
			{
				if (value <= 0 || (value > commProp.dwMaxBaud && commProp.dwMaxBaud > 0)) 
				{
					// if no upper bound on baud rate imposed by serial driver, note that argument must be positive
					if (commProp.dwMaxBaud == 0) 
					{
						throw new ArgumentOutOfRangeException("baudRate", 
							InternalResources.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
					} 
					else 
					{
						// otherwise, we can present the bounds on the baud rate for this driver
						throw new ArgumentOutOfRangeException("baudRate", 
							InternalResources.GetResourceString("ArgumentOutOfRange_Bounds_Lower_Upper", 0, commProp.dwMaxBaud));
					}
				}
				// Set only if it's different.  Rollback to previous values if setting fails.
				//  This pattern occurs through most of the other properties in this class.
				if(value != dcb.BaudRate) 
				{
					int baudRateOld = (int) dcb.BaudRate;
					dcb.BaudRate = (uint) value;	
					
					if (UnsafeNativeMethods.SetCommState(_handleProtector.Handle, ref dcb) == false) 
					{
						dcb.BaudRate = (uint) baudRateOld;
						InternalResources.WinIOError();
					}
				}
			}
		}

		internal int DataBits 
		{ 
			get  { return (int) dcb.ByteSize; } 
			set 
			{	
				if(value < minDataBits || value > maxDataBits) 
				{
					throw new ArgumentOutOfRangeException("dataBits", 
						InternalResources.GetResourceString("ArgumentOutOfRange_Bounds_Lower_Upper", minDataBits, maxDataBits));			
				}
				if (value != dcb.ByteSize) 
				{
					byte byteSizeOld = dcb.ByteSize;
					dcb.ByteSize = (byte) value;	
					
					if (UnsafeNativeMethods.SetCommState(_handleProtector.Handle, ref dcb) == false) 
					{
						dcb.ByteSize = byteSizeOld;
						InternalResources.WinIOError();
					}		
				}	
			}
		}

		
		internal bool DiscardNull
		{ 
			get {	return (GetDcbFlag(NativeMethods.FNULL) == 1);}
			set 
			{
				int fNullFlag = GetDcbFlag(NativeMethods.FNULL);
				if(value == true && fNullFlag == 0 || value == false && fNullFlag == 1) 
				{
					int fNullOld = fNullFlag;
					SetDcbFlag(NativeMethods.FNULL, value ? 1 : 0);
			
					if (UnsafeNativeMethods.SetCommState(_handleProtector.Handle, ref dcb) == false) 
					{
						SetDcbFlag(NativeMethods.FNULL, fNullOld);
						InternalResources.WinIOError();
					} 								
				}
			}
		}
		
		internal bool DtrEnable 
		{ 
			get	{	return dtrEnable; } 
			set 
			{  
				if(value != dtrEnable) 
				{
					bool dtrEnableOld = dtrEnable;
					int fDtrControlOld = GetDcbFlag(NativeMethods.FDTRCONTROL);

					dtrEnable = value;	
					SetDcbFlag(NativeMethods.FDTRCONTROL, dtrEnable ? 1 : 0);

					if (UnsafeNativeMethods.SetCommState(_handleProtector.Handle, ref dcb) == false) 
					{
						dtrEnable = dtrEnableOld;
						SetDcbFlag(NativeMethods.FDTRCONTROL, fDtrControlOld);
						InternalResources.WinIOError();
					} 							
				}
			} 
		}

		internal Handshake Handshake 
		{
			get  { return handshake; } 
			set  
			{ 
			
				if (value < Handshake.None || value > Handshake.RequestToSendXOnXOff) 
					throw new ArgumentOutOfRangeException("handshake", InternalResources.GetResourceString("ArgumentOutOfRange_Enum"));
				
				if(value != handshake) 
				{
					// in the DCB, handshake affects the fRtsControl, fOutxCtsFlow, and fInX, fOutX fields,
					// so we must save everything in that closure before making any changes.
					Handshake handshakeOld = handshake;
					int fInOutXOld = GetDcbFlag(NativeMethods.FINX);
					int fOutxCtsFlowOld = GetDcbFlag(NativeMethods.FOUTXCTSFLOW);
					int fRtsControlOld = GetDcbFlag(NativeMethods.FRTSCONTROL);
					
					handshake = value;
					int fInXOutXFlag = (handshake == Handshake.XOnXOff || handshake == Handshake.RequestToSendXOnXOff) ? 1 : 0;					
					SetDcbFlag(NativeMethods.FINX, fInXOutXFlag);
					SetDcbFlag(NativeMethods.FOUTX, fInXOutXFlag);

					SetDcbFlag(NativeMethods.FOUTXCTSFLOW, (handshake == Handshake.RequestToSend ||
						handshake == Handshake.RequestToSendXOnXOff) ? 1 : 0);

					// handshake and rtsEnable properties are necessary and sufficient to determining 
					// the fRtsControl field of the DCB.
					if ((handshake == Handshake.RequestToSend ||
						handshake == Handshake.RequestToSendXOnXOff)) 
					{
						SetDcbFlag(NativeMethods.FRTSCONTROL, NativeMethods.RTS_CONTROL_HANDSHAKE);
					}
					else if(rtsEnable)
					{
						SetDcbFlag(NativeMethods.FRTSCONTROL, NativeMethods.RTS_CONTROL_ENABLE);
					}
					else
					{
						SetDcbFlag(NativeMethods.FRTSCONTROL, NativeMethods.RTS_CONTROL_DISABLE);
					}

					if (UnsafeNativeMethods.SetCommState(_handleProtector.Handle, ref dcb) == false) 
					{
						handshake = handshakeOld;
						SetDcbFlag(NativeMethods.FINX, fInOutXOld);
						SetDcbFlag(NativeMethods.FOUTX, fInOutXOld);
						SetDcbFlag(NativeMethods.FOUTXCTSFLOW, fOutxCtsFlowOld);
						SetDcbFlag(NativeMethods.FRTSCONTROL, fRtsControlOld);
						InternalResources.WinIOError();
					}
					
				}	
			}		
		}
	
		internal Parity Parity 
		{ 
			get 	{	return (Parity) dcb.Parity; 	} 
			set 
			{ 
				if(value < Parity.None || value > Parity.Space)
					throw new ArgumentOutOfRangeException("parity", InternalResources.GetResourceString("ArgumentOutOfRange_Enum"));;
				
				if((byte) value != dcb.Parity) 
				{
					byte parityOld = dcb.Parity;
					
					// in the DCB structure, the parity setting also potentially effects:
					// fParity, fErrorChar, ErrorChar
					// so these must be saved as well.
					int fParityOld = GetDcbFlag(NativeMethods.FPARITY);
					byte ErrorCharOld = dcb.ErrorChar;
					int fErrorCharOld = GetDcbFlag(NativeMethods.FPARITY);
					dcb.Parity = (byte) value;	

					int parityFlag = (dcb.Parity == (byte) Parity.None) ? 1 : 0;
					SetDcbFlag(NativeMethods.FPARITY, parityFlag);
					if (parityFlag == 1) 
					{
						SetDcbFlag(NativeMethods.FERRORCHAR, (parityReplace != '\0') ? 1 : 0);
						dcb.ErrorChar = parityReplace;
					} 
					else 
					{
						SetDcbFlag(NativeMethods.FERRORCHAR, 0);
						dcb.ErrorChar = (byte) '\0';
					}
					if (UnsafeNativeMethods.SetCommState(_handleProtector.Handle, ref dcb) == false) 
					{
						dcb.Parity = parityOld;
						SetDcbFlag(NativeMethods.FPARITY, fParityOld);
				
						dcb.ErrorChar = ErrorCharOld;
						SetDcbFlag(NativeMethods.FERRORCHAR, fErrorCharOld);
				
						InternalResources.WinIOError();
					}								
				}	
			}
		} 

		// ParityReplace is the eight-bit character which replaces any bytes which 
		// ParityReplace affects the equivalent field in the DCB structure: ErrorChar, and 
		// the DCB flag fErrorChar.
		internal byte ParityReplace 
		{ 
			get {	return parityReplace; } 
			set 

⌨️ 快捷键说明

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