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

📄 serialstream.cs

📁 SerialPort 串口通讯用
💻 CS
📖 第 1 页 / 共 5 页
字号:
		}
			
		public override void SetLength(long value) 
		{
			throw new NotSupportedException(InternalResources.GetResourceString("NotSupported_UnseekableStream")); 
		}


		public override void Write(byte[] array, int offset, int count) 
		{
			Write(array, offset, count, WriteTimeout);
		}
		internal void Write(byte[] array, int offset, int count, int timeout)
		{
			
			if (inBreak)
				throw new InvalidOperationException("Write in break");
			if (array==null)
				throw new ArgumentNullException("write buffer", InternalResources.GetResourceString("ArgumentNull_Array"));
			if (offset < 0)
				throw new ArgumentOutOfRangeException("write offset", InternalResources.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
			if (count < 0)
				throw new ArgumentOutOfRangeException("write count", InternalResources.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
			if (count == 0) return;	// no need to expend overhead in creating asyncResult, etc.				
			if (array.Length - offset < count)
				throw new ArgumentException("write count",InternalResources.GetResourceString("ArgumentOutOfRange_OffsetOut"));
			Debug.Assert(timeout == SerialPort.InfiniteTimeout || timeout >= 0, "Serial Stream Write - write timeout is " + timeout);
			
			// check for open handle, though the port is always supposed to be open
			if (_handleProtector.IsClosed) InternalResources.FileNotOpen();
			
			IAsyncResult result = BeginWriteCore(array, offset, count, null, null, timeout);
			EndWrite(result);
	
			return;
	
		}

		// use default timeout as argument to WriteByte override with timeout arg
		public override void WriteByte(byte value) 
		{
			WriteByte(value, WriteTimeout);
		}
		
		internal void WriteByte(byte value, int timeout) 
		{
			if (inBreak)
				throw new InvalidOperationException("WriteByte in break");
			
			if (_handleProtector.IsClosed) InternalResources.FileNotOpen();
			tempBuf[0] = value;
			IAsyncResult ar = BeginWriteCore(tempBuf, 0, 1, null, null, timeout);
			EndWrite(ar);
		
			return;
		}

		

		// --------SUBSECTION: internal-use methods ----------------------*
		// ------ internal DCB-supporting methods ------- * 
			
		// Initializes unmananged DCB struct, to be called after opening communications resource. 
		// assumes we have already: baudRate, parity, dataBits, stopBits
		// should only be called in SerialStream(...) 
		private void InitializeDCB(int baudRate, Parity parity, int dataBits, StopBits stopBits, bool discardNull)
		{
		
			// first get the current dcb structure setup
			if (UnsafeNativeMethods.GetCommState(_handleProtector.Handle, ref dcb) == false) 
			{
				InternalResources.WinIOError();
			}			
			dcb.DCBlength = (uint) System.Runtime.InteropServices.Marshal.SizeOf(dcb);
			
			// set parameterized properties
			dcb.BaudRate = (uint) baudRate;
			dcb.ByteSize = (byte) dataBits;			
	

			switch (stopBits) 
			{
				case StopBits.One:
					dcb.StopBits = NativeMethods.ONESTOPBIT;
					break;
				case StopBits.OnePointFive:
					dcb.StopBits = NativeMethods.ONE5STOPBITS;
					break;
				case StopBits.Two:
					dcb.StopBits = NativeMethods.TWOSTOPBITS;
					break;
				default:
					Debug.Assert(true, "TBD");
					break;
			}
			
			dcb.Parity = (byte) parity;
			// SetDcbFlag, GetDcbFlag expose access to each of the relevant bits of the 32-bit integer 
			// storing all flags of the DCB.  C# provides no direct means of manipulating bit fields, so
			// this is the solution.
			SetDcbFlag(NativeMethods.FPARITY, ((parity == Parity.None)  ?  0  :  1));
		
			SetDcbFlag(NativeMethods.FBINARY, 1);	// always true for communications resources
			
			// set DCB fields implied by default and the arguments given.
			// Boolean fields in C# must become 1, 0 to properly set the bit flags in the unmanaged DCB struct	

			SetDcbFlag(NativeMethods.FOUTXCTSFLOW, ((handshake == Handshake.RequestToSend ||
				handshake == Handshake.RequestToSendXOnXOff) ? 1 : 0));
			SetDcbFlag(NativeMethods.FOUTXDSRFLOW, (dsrTimeout != 0L) ? 1 : 0);
			SetDcbFlag(NativeMethods.FDTRCONTROL, (dtrEnable) ? NativeMethods.DTR_CONTROL_ENABLE : NativeMethods.DTR_CONTROL_DISABLE);
			SetDcbFlag(NativeMethods.FDSRSENSITIVITY, 0); // this should remain off 
			SetDcbFlag(NativeMethods.FINX, (handshake == Handshake.XOnXOff || handshake == Handshake.RequestToSendXOnXOff) ? 1 : 0);
			SetDcbFlag(NativeMethods.FOUTX,(handshake == Handshake.XOnXOff || handshake == Handshake.RequestToSendXOnXOff) ? 1 : 0);
			
			// if no parity, we have no error character (i.e. ErrorChar = '\0' or null character)
			if (parity != Parity.None)
			{
				SetDcbFlag(NativeMethods.FERRORCHAR, (parityReplace != '\0') ? 1 : 0);
				dcb.ErrorChar = parityReplace;
			}
			else
			{
				SetDcbFlag(NativeMethods.FERRORCHAR, 0);
				dcb.ErrorChar = (byte) '\0';
			}
			
			// this method only runs once in the constructor, so we only have the default value to use.
			// Later the user may change this via the NullDiscard property.
			SetDcbFlag(NativeMethods.FNULL, discardNull ? 1 : 0); 
			
					
			// Setting RTS control, which is RTS_CONTROL_HANDSHAKE if RTS / RTS-XOnXOff handshaking
			// used, RTS_ENABLE (RTS pin used during operation) if rtsEnable true but XOnXoff / No handshaking
			// used, and disabled otherwise.
			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);
			}
			
			dcb.XonChar = NativeMethods.DEFAULTXONCHAR;				// may be exposed later but for now, constant
			dcb.XoffChar = NativeMethods.DEFAULTXOFFCHAR;
			
			// minimum number of bytes allowed in each buffer before flow control activated
			// heuristically, this has been set at 1/4 of the buffer size
			dcb.XonLim = dcb.XoffLim = (ushort) (commProp.dwCurrentRxQueue / 4);  
				
			dcb.EofChar = NativeMethods.EOFCHAR;	
			
			//OLD MSCOMM: dcb.EvtChar = (byte) 0;
			// now changed to make use of RxFlag WaitCommEvent event => EofReceived WaitForCommEvent event
			dcb.EvtChar = NativeMethods.EOFCHAR;
			
			// set DCB structure
			if (UnsafeNativeMethods.SetCommState(_handleProtector.Handle, ref dcb) == false) 
			{
				InternalResources.WinIOError();
			}
		}

		// Here we provide a method for getting the flags of the Device Control Block structure dcb
		// associated with each instance of SerialStream, i.e. this method gets myStream.dcb.Flags
		// Flags are any of the constants in NativeMethods such as FBINARY, FDTRCONTROL, etc.
		internal int GetDcbFlag(int whichFlag) 
		{
			uint mask;
			
			Debug.Assert(whichFlag >= NativeMethods.FBINARY && whichFlag <= NativeMethods.FDUMMY2, "GetDcbFlag needs to fit into enum!");
			
			if (whichFlag == NativeMethods.FDTRCONTROL || whichFlag == NativeMethods.FRTSCONTROL) 
			{
				mask = 0x3;
			} 
			else if (whichFlag == NativeMethods.FDUMMY2) 
			{
				mask = 0x1FFFF;
			} 
			else 
			{
				mask = 0x1;
			} 
			uint result = dcb.Flags & (mask << whichFlag);
			return (int) (result >> whichFlag);
		}

		// Since C# applications have to provide a workaround for accessing and setting bitfields in unmanaged code,
		// here we provide methods for getting and setting the Flags field of the Device Control Block structure dcb
		// associated with each instance of SerialStream, i.e. this method sets myStream.dcb.Flags
		// Flags are any of the constants in NativeMethods such as FBINARY, FDTRCONTROL, etc.
		internal void SetDcbFlag(int whichFlag, int setting) 
		{
			uint mask;
			setting = setting << whichFlag; 
			
			Debug.Assert(whichFlag >= NativeMethods.FBINARY && whichFlag <= NativeMethods.FDUMMY2, "SetDcbFlag needs to fit into enum!");
			
			if (whichFlag == NativeMethods.FDTRCONTROL || whichFlag == NativeMethods.FRTSCONTROL) 
			{
				mask = 0x3;
			} 
			else if (whichFlag == NativeMethods.FDUMMY2) 
			{
				mask = 0x1FFFF;
			} 
			else 
			{
				mask = 0x1;
			}

			// clear the region
			dcb.Flags &= ~(mask << whichFlag);
			
			// set the region
			dcb.Flags |= ((uint) setting);
		}
		
		// ----SUBSECTION: internal methods supporting public read/write methods-------*
		
		unsafe private AsyncSerialStream_AsyncResult BeginReadCore(byte[] array, int offset, int numBytes, AsyncCallback userCallback, Object stateObject, int numBufferedBytesRead, int timeout)
		{

			// Create and store async stream class library specific data in the 
			// async result
			AsyncSerialStream_AsyncResult asyncResult = new AsyncSerialStream_AsyncResult();
			asyncResult._userCallback = userCallback;
			asyncResult._userStateObject = stateObject;
			asyncResult._isWrite = false;
			
			asyncResult._oldTimeout = ReadTimeout; // store "old" timeout
			ReadTimeout = timeout;	// enforce timeouts in COMMTIMEOUTS structure
			
			// Must set this here to ensure all the state on the IAsyncResult 
			// object is set before we call ReadFile, which gives the OS an
			// opportunity to run our callback (including the user callback &
			// the call to EndRead) before ReadFile has returned.  
			asyncResult._numBufferedBytes = numBufferedBytesRead;

			// For Synchronous IO, I could go with either a callback and using
			// the managed Monitor class, or I could create a handle and wait on it.
			ManualResetEvent waitHandle = new ManualResetEvent(false);
			asyncResult._waitHandle = waitHandle;

			// Create a managed overlapped class
			// We will set the file offsets later
			Overlapped overlapped = new Overlapped(0, 0, 0, asyncResult);

			// Pack the Overlapped class, and store it in the async result
			NativeOverlapped* intOverlapped = overlapped.Pack(IOCallback);
			asyncResult._overlapped = intOverlapped;
			
			// Keep the array in one location in memory until the OS writes the
			// relevant data into the array.  Free GCHandle later.
			asyncResult.PinBuffer(array);

			// queue an async ReadFile operation and pass in a packed overlapped
			//int r = ReadFile(_handle, array, numBytes, null, intOverlapped);
			int hr = 0;
			int r = ReadFileNative(_handleProtector, array, offset, numBytes,
			 intOverlapped, out hr);
			
			// ReadFile, the OS version, will return 0 on failure.  But
			// my ReadFileNative wrapper returns -1.  My wrapper will return
			// the following:
			// On error, r==-1.
			// On async requests that are still pending, r==-1 w/ hr==ERROR_IO_PENDING
			// on async requests that completed sequentially, r==0
			// Note that you will NEVER RELIABLY be able to get the number of bytes
			// read back from this call when using overlapped structures!  You must
			// not pass in a non-null lpNumBytesRead to ReadFile when using 
			// overlapped structures! 
			if (r==-1) 
			{
				if (hr != NativeMethods.ERROR_IO_PENDING) 
				{
					if (hr == NativeMethods.ERROR_HANDLE_EOF)
						InternalResources.EndOfFile();
					else
						InternalResources.WinIOError(hr, String.Empty);
				}
			}

			return asyncResult;
		}

		unsafe private AsyncSerialStream_AsyncResult BeginWriteCore(byte[] array, int offset, int numBytes, AsyncCallback userCallback, Object stateObject, int timeout) 
		{
			
			// Create and store async stream class library specific data in the 
			// async result
			AsyncSerialStream_AsyncResult asyncResult = new AsyncSerialStream_AsyncResult();
			asyncResult._userCallback = userCallback;
			asyncResult._userStateObject = stateObject;
			asyncResult._isWrite = true;
			
			asyncResult._oldTimeout = WriteTimeout;		// set "old" timeout
			WriteTimeout = timeout;
			
			// For Synchronous IO, I could go with either a callback and using
			// the managed Monitor class, or I could create a handle and wait on it.
			ManualResetEvent waitHandle = new ManualResetEvent(false); 
			asyncResult._waitHandle = waitHandle;

			// Create a managed overlapped class
			// We will set the file offsets later
			Overlapped overlapped = new Overlapped(0, 0, 0, asyncResult);

			// Pack the Overlapped class, and store it in the async result
			NativeOverlapped* intOverlapped = overlapped.Pack(IOCallback);
			asyncResult._overlapped = intOverlapped;
            
			
			// Keep the array in one location in memory until the OS reads the
			// relevant data from the array.  Free GCHandle later.
			asyncResult.PinBuffer(array);

			int hr = 0;
			// queue an async WriteFile operation and pass in a packed overlapped
			int r = WriteFileNative(_handleProtector, array, offset, numBytes, intOverlapped, out hr);

			// WriteFile, the OS version, will return 0 on failure.  But
			// my WriteFileNative wrapper returns -1.  My wrapper will return
			// the following:
			// On error, r==-1.
			// On async requests that are still pending, r==-1 w/ hr==ERROR_IO_PENDING
			// On async requests that completed sequentially, r==0
			// Note that you will NEVER RELIABLY be able to get the number of bytes
			// written back from this call when using overlapped IO!  You must
			// not pass in a non-null lpNumBytesWritten to WriteFile when using 
			// overlapped structures! 
			if (r==-1) 
			{
				if (hr != NativeMethods.ERROR_IO_PENDING) 
				{
				
					if (hr == NativeMethods.ERROR_HANDLE_EOF)
						InternalResources.EndOfFile();

⌨️ 快捷键说明

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