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

📄 serialport.cs

📁 本源码为OpenNETCF源代码
💻 CS
📖 第 1 页 / 共 3 页
字号:
				}
				if (this.BytesToRead == 0) {
					return bytesToRead;
				}
			}
			
			this.mReadPos = 0;
			this.mReadLen = 0;
			int topUpBytes = count - bytesToRead;
			int bytesRead = 0;
			byte[] temp = new byte[topUpBytes];
			if (!m_CommAPI.ReadFile(hPort, temp, topUpBytes, ref bytesRead, this.mRxOverlapped)) {
				throw new ApplicationException("Read failed");
			}
			//			if (bytesRead != topUpBytes){
			//				//assert
			//			}
			Buffer.BlockCopy(temp, 0, buffer, offset + bytesToRead, bytesRead);
			this.mDecoder = null;
			return bytesToRead + bytesRead;
		}
		/// <summary>
		/// Synchronously reads one byte from the OpenNETCF.IO.Ports.SerialPort input buffer.
		/// </summary>
		/// <returns>The byte that was read.</returns>
		public int ReadByte() {
			if (!this.IsOpen) {
				throw new InvalidOperationException("Port is not open");
			}
			if (this.mReadLen != this.mReadPos) {
				return this.mInBuffer[this.mReadPos++];
			}
			mDecoder = null;
			byte[] temp = new byte[1];
			int one = this.Read(temp, 0, 1);
			return temp[0];
		}
		/// <summary>
		/// Reads up to the OpenNETCF.IO.Ports.SerialPort.NewLine value in the input buffer.
		/// </summary>
		/// <returns>A string containing the contents of the input buffer up to the OpenNETCF.IO.Ports.SerialPort.NewLine.</returns>
		public string ReadLine() {
			return this.ReadTo(this.NewLine);
		}
		/// <summary>
		/// Reads a number of bytes from the OpenNETCF.IO.Ports.SerialPort input buffer and writes those bytes into a character array at a given offset.
		/// </summary>
		/// <param name="buffer">The character array to which the input is written.</param>
		/// <param name="offset">The offset in the buffer array where writing should begin.</param>
		/// <param name="count">The number of bytes to be read.</param>
		/// <returns></returns>
		public int Read(char[] buffer, int offset, int count) {
			//TODO Read char[]
			throw new NotSupportedException("not yet");
		}
		/// <summary>
		/// Synchronously reads one character from the OpenNETCF.IO.Ports.SerialPort input buffer.
		/// </summary>
		/// <returns>The character read.</returns>
		public int ReadChar() {
			//TODO Read single char
			throw new NotSupportedException("not yet");
		}
		/// <summary>
		/// Reads a string up to the specified value in the input buffer.
		/// </summary>
		/// <param name="value">String value where the read operation stops.</param>
		/// <returns>A string containing the contents of the input buffer up to the value.</returns>
		public string ReadTo(string value) {
			//TODO read up to given string
			throw new NotSupportedException("not yet");
		}
		/// <summary>
		/// Reads all immediately available characters, based on the encoding, in both the stream and the input buffer of the OpenNETCF.IO.Ports.SerialPort object.
		/// </summary>
		/// <returns>A string composed of the contents of the stream and the input buffer of the OpenNETCF.IO.Ports.SerialPort object.</returns>
		public string ReadExisting() {
			//TODO read existing bytes and return string
			throw new NotSupportedException("not yet");
		}
		#endregion

		#region Write
		/// <summary>
		/// Writes a specified count of characters to an output buffer at the specified offset.
		/// </summary>
		/// <param name="buffer">The character array to which the output is written.</param>
		/// <param name="offset">The offset in the buffer array where writing should begin.</param>
		/// <param name="count">The number of characters to write.</param>
		public void Write(char[] buffer, int offset, int count) {
			byte[] bytesFromChars = this.Encoding.GetBytes(buffer, offset, count);
			this.Write(bytesFromChars, 0, bytesFromChars.Length);
		}
		/// <summary>
		/// Writes the parameter string to the output.
		/// </summary>
		/// <param name="str">The string for output.</param>
		public void Write(string str) {
			byte[] bytesFromString = this.mEncoding.GetBytes(str);
			this.Write(bytesFromString, 0, bytesFromString.Length);
		}
		/// <summary>
		/// Writes the specified string and the OpenNETCF.IO.Ports.SerialPort.NewLine value to the output buffer.
		/// </summary>
		/// <param name="str">The string to be written to output.</param>
		public void WriteLine(string str) {
			this.Write(str + this.NewLine);
		}
		/// <summary>
		/// Writes a specified count of bytes to an output buffer at the specified offset.
		/// </summary>
		/// <param name="buffer">The byte array to which the output is written.</param>
		/// <param name="offset">The offset in the buffer array where writing should begin.</param>
		/// <param name="count">The number of bytes to be write.</param>
		public void Write(byte[] buffer, int offset, int count) {
			if (!this.IsOpen) {
				throw new InvalidOperationException("Port is not open");
			}
			if (buffer == null) {
				throw new ArgumentNullException("buffer");
			}
			if (offset < 0) {
				throw new ArgumentOutOfRangeException("offset must be > 0");
			}
			if (count < 0) {
				throw new ArgumentOutOfRangeException("count must be > 0");
			}
			if ((buffer.Length - offset) < count) {
				throw new ArgumentException("FAILED: ((buffer.Length - offset) < count)");
			}
			if (buffer.Length == 0) {
				return;
			}

			//if in break don't write
			if (this.mInBreak){
				throw new ApplicationException("Can't write while in break");
			}

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

			//for desktop we should probably be doing other stuff here but if you are in .NET 2.0 you are not using this anyway
			int written = 0;
			if (!m_CommAPI.WriteFile(hPort, temp, count, ref written, this.mTxOverlapped)){
				int er = Marshal.GetLastWin32Error();
				if (er == 0x461){
					throw new ApplicationException("Write timed out 1");
				}
				throw new ApplicationException("writefile failed " + er);
			}

			if (written == 0){
				throw new ApplicationException("Write timed out 2");
			}
		}

		#endregion
		#endregion

		#region Privates
		private void CommEventThread() {
			CommEventFlags eventFlags = new CommEventFlags();
			AutoResetEvent rxevent = new AutoResetEvent(false);

			// specify the set of events to be monitored for the port.
			bool b;
			if(CommAPI.FullFramework) {
				b = m_CommAPI.SetCommMask(hPort, CommEventFlags.ALLPC);

				// set up the overlapped IO
				OVERLAPPED o = new OVERLAPPED();
				this.mRxOverlapped = LocalAlloc(0x40, Marshal.SizeOf(o));
				o.Offset = 0; 
				o.OffsetHigh = 0;
				o.hEvent = rxevent.Handle;
				Marshal.StructureToPtr(o, this.mRxOverlapped, true);
			}
			else {
				b = m_CommAPI.SetCommMask(hPort, CommEventFlags.ALLCE_2);
			}
			

			try {
				// let Open() know we're started
				this.mThreadStarted.Set();

				#region >>>> thread loop <<<<
				while(hPort != (IntPtr)CommAPI.INVALID_HANDLE_VALUE) {
					// wait for a Comm event
					if(!m_CommAPI.WaitCommEvent(hPort, ref eventFlags)) {
						int e = Marshal.GetLastWin32Error();

						if(e == (int)APIErrors.ERROR_IO_PENDING) {
							// IO pending so just wait and try again
							rxevent.WaitOne();
							Thread.Sleep(0);
							continue;
						}

						if(e == (int)APIErrors.ERROR_INVALID_HANDLE) {
							// Calling Port.Close() causes hPort to become invalid
							// Since Thread.Abort() is unsupported in the CF, we must
							// accept that calling Close will throw an error here.

							// Close signals the this.mCloseEvent, so wait on it
							// We wait 1 second, though Close should happen much sooner
							int eventResult = m_CommAPI.WaitForSingleObject(this.mCloseEvent, 1000);

							if(eventResult == (int)APIConstants.WAIT_OBJECT_0) {
								// the event was set so close was called
								hPort = (IntPtr)CommAPI.INVALID_HANDLE_VALUE;
					
								// reset our ResetEvent for the next call to Open
								this.mThreadStarted.Reset();

								if(this.mIsOpen) { // this should not be the case...if so, throw an exception for the owner
									string error = String.Format("Wait Failed: {0}", e);
									throw new ApplicationException(error);
								}

								return;
							}
						}

						// WaitCommEvent failed
						// 995 means an exit was requested (thread killed)
						if(e == 995) {
							return;
						}
						else {
							string error = String.Format("Wait Failed: {0}", e);
							throw new ApplicationException(error);
						}
					}

					// Re-specify the set of events to be monitored for the port.
					if(CommAPI.FullFramework) {
						m_CommAPI.SetCommMask(hPort, CommEventFlags.ALLPC);
					}
					else {
						m_CommAPI.SetCommMask(hPort, CommEventFlags.ALLCE);
					}
					// Process the flag - extracted main handling into its own method
					//ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessEvents), eventFlags);					
					this.ProcessEvents(eventFlags);

				} // while(not invalid handle)
				#endregion
			} // try
			catch{
				if(this.mRxOverlapped != IntPtr.Zero) 
					LocalFree(this.mRxOverlapped);

				throw;
			}
		}
		private Decoder GetDecoder(){
			if (mDecoder == null){
				this.mDecoder = mEncoding.GetDecoder();			
			}
			return mDecoder;
		}

		private void ProcessEvents(object flags){
			CommEventFlags eventFlags = (CommEventFlags)flags;

			// check the event for errors
			#region >>>> error checking <<<<
			if(((uint)eventFlags & (uint)CommEventFlags.ERR) != 0) {
				CommErrorFlags errorFlags = new CommErrorFlags();
				CommStat commStat = new CommStat();

				// get the error status
				if(!m_CommAPI.ClearCommError(hPort, ref errorFlags, commStat)) {
					// ClearCommError failed!
					string error = String.Format("ClearCommError Failed: {0}", Marshal.GetLastWin32Error());
					throw new ApplicationException(error);
				}

				if(((uint)errorFlags & (uint)CommErrorFlags.BREAK) != 0) {
					// BREAK can set an error, so make sure the BREAK bit is set an continue
					eventFlags |= CommEventFlags.BREAK;
				}
				else {
					// we have an error.  Build a meaningful string and throw an exception
					if (ErrorReceived != null){
						if ((errorFlags & CommErrorFlags.TXFULL) != 0) {
							ErrorReceived(this,new SerialErrorReceivedEventArgs(SerialError.TXFull));	
						}
						if ((errorFlags & CommErrorFlags.RXOVER) != 0) {
							ErrorReceived(this,new SerialErrorReceivedEventArgs(SerialError.RXOver));	
						}
						if ((errorFlags & CommErrorFlags.OVERRUN) != 0) {
							ErrorReceived(this,new SerialErrorReceivedEventArgs(SerialError.Overrun));	
						}
						if ((errorFlags & CommErrorFlags.RXPARITY) != 0) {
							ErrorReceived(this,new SerialErrorReceivedEventArgs(SerialError.RXParity));	
						}
						if ((errorFlags & CommErrorFlags.FRAME) != 0) { 
							ErrorReceived(this,new SerialErrorReceivedEventArgs(SerialError.Frame));	
						}
					}
					return;
				}
			} // if(((uint)eventFlags & (uint)CommEventFlags.ERR) != 0)
			#endregion

			#region >>>> Receive data subsection <<<<
			// check for RXCHAR
			if (DataReceived != null){
				if((eventFlags & CommEventFlags.RXCHAR) != 0) {
					DataReceived(this,new SerialDataReceivedEventArgs(SerialData.Chars));
				}
				if(((uint)eventFlags & 2) != 0) {
					DataReceived(this,new SerialDataReceivedEventArgs(SerialData.Eof));
				}
			}
			#endregion

			#region >>>> line status checking <<<<
			if(PinChanged != null){
				// check the CTS
				if(((uint)eventFlags & (uint)CommEventFlags.CTS) != 0) {
					PinChanged(this,new SerialPinChangedEventArgs(SerialPinChange.CtsChanged));
				}

				// check the DSR
				if(((uint)eventFlags & (uint)CommEventFlags.DSR) != 0) {
					PinChanged(this,new SerialPinChangedEventArgs(SerialPinChange.DsrChanged));
				}
				
				// check for a RING
				if(((uint)eventFlags & (uint)CommEventFlags.RING) != 0) {
					PinChanged(this,new SerialPinChangedEventArgs(SerialPinChange.Ring));
				}

				// check for a RLSD
				if(((uint)eventFlags & (uint)CommEventFlags.RLSD) != 0) {
					PinChanged(this,new SerialPinChangedEventArgs(SerialPinChange.CDChanged));
				}

				// check for a break
				if(((uint)eventFlags & (uint)CommEventFlags.BREAK) != 0) {
					PinChanged(this,new SerialPinChangedEventArgs(SerialPinChange.Break));
				}
			}
			#endregion
		}

		private bool UpdateSettings() {
			if(!this.mIsOpen) return false;

			m_CommAPI.PurgeComm(hPort,0x4 | 0x8);

			bool outX = false;
			bool inX = false;
			bool outCts = false;
			byte rtsCtrl = 0x01;

			if (mHandshake != Handshake.None){			
				if (mHandshake == Handshake.RequestToSend || mHandshake == Handshake.RequestToSendXOnXOff){
					//outCts = true; by design
					rtsCtrl = 0x02;
				}else if (this.mRts == 0){
					rtsCtrl = 0x00;
				}
				if (mHandshake == Handshake.XOnXOff || mHandshake == Handshake.RequestToSendXOnXOff){
					outX = true;
					inX = true;
				}
			}

			// transfer the port settings to a DCB structure
			m_CommAPI.GetCommState(hPort, this.mDcb);
			this.mDcb.BaudRate = (uint)mBaudRate;
			this.mDcb.ByteSize = this.mByteSize;
			this.mDcb.EofChar = 0;// (sbyte)0x04;
			this.mDcb.ErrorChar = (sbyte)mErrorChar;
			this.mDcb.EvtChar = (sbyte)0x00;
			this.mDcb.fAbortOnError = false;
			this.mDcb.fBinary = true;
			this.mDcb.fDsrSensitivity = false;
			this.mDcb.fDtrControl = (byte)this.mDtr;
			this.mDcb.fErrorChar = (this.mDcb.ErrorChar != 0);
			this.mDcb.fInX = inX;
			this.mDcb.fNull = this.mDiscardNull;
			this.mDcb.fOutX = outX;
			this.mDcb.fOutxCtsFlow = outCts;
			this.mDcb.fOutxDsrFlow = false;
			this.mDcb.fParity = (mParity == Parity.None) ? false : true;
			this.mDcb.fRtsControl = rtsCtrl;
			this.mDcb.fTXContinueOnXoff = true;
			this.mDcb.Parity = (byte)mParity;
			this.mDcb.StopBits = (byte)this.mStopBits;
			this.mDcb.XoffChar = (sbyte)0x13; //ASCII.DC3;
			this.mDcb.XonChar = (sbyte)0x11; //ASCII.DC1;

			this.mDcb.XonLim = this.mDcb.XoffLim = 0;//(ushort)(this.mRxBufferSize / 10);

			// store some state variables
			this.mDtr = this.mDcb.fDtrControl == 0x01 ? 1 : 0;
			this.mRts = this.mDcb.fRtsControl == 0x01 ? 1 : 0;

			return m_CommAPI.SetCommState(hPort, this.mDcb);
		}

		private void UpdateTimeouts(){
			// set the Comm timeouts
			CommTimeouts ct = new CommTimeouts();

			// reading we'll return immediately
			// this doesn't seem to work as documented
			ct.ReadIntervalTimeout = 0xffffffff;
			if (this.mReadTimeout > 0){
				ct.ReadTotalTimeoutConstant = (uint)this.mReadTimeout;
				ct.ReadTotalTimeoutMultiplier = 0;
			}else{
				ct.ReadTotalTimeoutConstant = 0;
				ct.ReadTotalTimeoutMultiplier = 0;
			}

			uint writeTimeoutOrZero; 
			if (mWriteTimeout == InfiniteTimeout){
				writeTimeoutOrZero = 0;
			}else{
				writeTimeoutOrZero = (uint)mWriteTimeout; 
			}
			ct.WriteTotalTimeoutConstant = writeTimeoutOrZero;
			ct.WriteTotalTimeoutMultiplier = 0;

			m_CommAPI.SetCommTimeouts(hPort, ct);
		}

		[DllImport("kernel32", EntryPoint="LocalAlloc", SetLastError=true)]
		internal static extern IntPtr LocalAlloc(int uFlags, int uBytes);

		[DllImport("kernel32", EntryPoint = "LocalFree", SetLastError = true)]
		internal static extern IntPtr LocalFree(IntPtr hMem);

		#endregion
	}
}

⌨️ 快捷键说明

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