You've already forked linux-packaging-mono
							
							
		
			
				
	
	
		
			576 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			576 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| //
 | |
| // System.IO.Ports.WinSerialStream.cs
 | |
| //
 | |
| // Authors:
 | |
| //	Carlos Alberto Cortez (calberto.cortez@gmail.com)
 | |
| //
 | |
| // (c) Copyright 2006 Novell, Inc. (http://www.novell.com)
 | |
| //
 | |
| 
 | |
| using System;
 | |
| using System.Text;
 | |
| using System.IO;
 | |
| using System.Runtime.InteropServices;
 | |
| using System.Threading;
 | |
| using System.ComponentModel;
 | |
| 
 | |
| namespace System.IO.Ports
 | |
| {
 | |
| 	class WinSerialStream : Stream, ISerialStream, IDisposable
 | |
| 	{
 | |
| 		// Windows API Constants
 | |
| 		const uint GenericRead = 0x80000000;
 | |
| 		const uint GenericWrite = 0x40000000;
 | |
| 		const uint OpenExisting = 3;
 | |
| 		const uint FileFlagOverlapped = 0x40000000;
 | |
| 		const uint PurgeRxClear = 0x0008;
 | |
| 		const uint PurgeTxClear = 0x0004;
 | |
| 		const uint WinInfiniteTimeout = 0xFFFFFFFF;
 | |
| 		const uint FileIOPending = 997;
 | |
| 
 | |
| 		// Signal constants
 | |
| 		const uint SetRts = 3;
 | |
| 		const uint ClearRts = 4;
 | |
| 		const uint SetDtr = 5;
 | |
| 		const uint ClearDtr = 6;
 | |
| 		const uint SetBreak = 8;
 | |
| 		const uint ClearBreak = 9;
 | |
| 		const uint CtsOn = 0x0010;
 | |
| 		const uint DsrOn = 0x0020;
 | |
| 		const uint RsldOn = 0x0080;
 | |
| 
 | |
| 		// Event constants
 | |
| 		const uint EvRxChar = 0x0001;
 | |
| 		const uint EvCts = 0x0008;
 | |
| 		const uint EvDsr = 0x0010;
 | |
| 		const uint EvRlsd = 0x0020;
 | |
| 		const uint EvBreak = 0x0040;
 | |
| 		const uint EvErr = 0x0080;
 | |
| 		const uint EvRing = 0x0100;
 | |
| 
 | |
| 		int handle;
 | |
| 		int read_timeout;
 | |
| 		int write_timeout;
 | |
| 		bool disposed;
 | |
| 		IntPtr write_overlapped;
 | |
| 		IntPtr read_overlapped;
 | |
| 		ManualResetEvent read_event;
 | |
| 		ManualResetEvent write_event;
 | |
| 		Timeouts timeouts;
 | |
| 
 | |
| 		[DllImport("kernel32", SetLastError = true)]
 | |
| 		static extern int CreateFile(string port_name, uint desired_access,
 | |
| 				uint share_mode, uint security_attrs, uint creation, uint flags,
 | |
| 				uint template);
 | |
| 
 | |
| 		[DllImport("kernel32", SetLastError = true)]
 | |
| 		static extern bool SetupComm(int handle, int read_buffer_size, int write_buffer_size);
 | |
| 
 | |
| 		[DllImport("kernel32", SetLastError = true)]
 | |
| 		static extern bool PurgeComm(int handle, uint flags);
 | |
| 
 | |
| 		[DllImport("kernel32", SetLastError = true)]
 | |
| 		static extern bool SetCommTimeouts(int handle, Timeouts timeouts);
 | |
| 
 | |
| 		public WinSerialStream (string port_name, int baud_rate, int data_bits, Parity parity, StopBits sb,
 | |
| 				bool dtr_enable, bool rts_enable, Handshake hs, int read_timeout, int write_timeout,
 | |
| 				int read_buffer_size, int write_buffer_size)
 | |
| 		{
 | |
| 			handle = CreateFile (port_name != null && !port_name.StartsWith(@"\\.\")
 | |
| 					? @"\\.\" + port_name : port_name,
 | |
| 					GenericRead | GenericWrite, 0, 0, OpenExisting,
 | |
| 					FileFlagOverlapped, 0);
 | |
| 
 | |
| 			if (handle == -1)
 | |
| 				ReportIOError (port_name);
 | |
| 
 | |
| 			// Set port low level attributes
 | |
| 			SetAttributes (baud_rate, parity, data_bits, sb, hs);
 | |
| 
 | |
| 			// Clean buffers and set sizes
 | |
| 			if (!PurgeComm (handle, PurgeRxClear | PurgeTxClear) ||
 | |
| 					!SetupComm (handle, read_buffer_size, write_buffer_size))
 | |
| 				ReportIOError (null);
 | |
| 
 | |
| 			// Set timeouts
 | |
| 			this.read_timeout = read_timeout;
 | |
| 			this.write_timeout = write_timeout;
 | |
| 			timeouts = new Timeouts (read_timeout, write_timeout);
 | |
| 			if (!SetCommTimeouts(handle, timeouts))
 | |
| 				ReportIOError (null);
 | |
| 
 | |
| 			/// Set DTR and RTS
 | |
| 			SetSignal(SerialSignal.Dtr, dtr_enable);
 | |
| 
 | |
| 			if (hs != Handshake.RequestToSend &&
 | |
| 					hs != Handshake.RequestToSendXOnXOff)
 | |
| 				SetSignal(SerialSignal.Rts, rts_enable);
 | |
| 
 | |
| 			// Init overlapped structures
 | |
| 			NativeOverlapped wo = new NativeOverlapped ();
 | |
| 			write_event = new ManualResetEvent (false);
 | |
| #pragma warning disable 618
 | |
| 			wo.EventHandle = write_event.Handle;
 | |
| 			write_overlapped = Marshal.AllocHGlobal (Marshal.SizeOf (typeof (NativeOverlapped)));
 | |
| 			Marshal.StructureToPtr (wo, write_overlapped, true);
 | |
| 
 | |
| 			NativeOverlapped ro = new NativeOverlapped ();
 | |
| 			read_event = new ManualResetEvent (false);
 | |
| 			ro.EventHandle = read_event.Handle;
 | |
| 			read_overlapped = Marshal.AllocHGlobal (Marshal.SizeOf (typeof (NativeOverlapped)));
 | |
| 			Marshal.StructureToPtr (ro, read_overlapped, true);
 | |
| #pragma warning restore 618
 | |
| 		}
 | |
| 
 | |
| 		public override bool CanRead {
 | |
| 			get {
 | |
| 				return true;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		public override bool CanSeek {
 | |
| 			get {
 | |
| 				return false;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		public override bool CanTimeout {
 | |
| 			get {
 | |
| 				return true;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		public override bool CanWrite {
 | |
| 			get {
 | |
| 				return true;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		public override int ReadTimeout {
 | |
| 			get {
 | |
| 				return read_timeout;
 | |
| 			}
 | |
| 			set {
 | |
| 				if (value < 0 && value != SerialPort.InfiniteTimeout)
 | |
| 					throw new ArgumentOutOfRangeException ("value");
 | |
| 
 | |
| 				timeouts.SetValues (value, write_timeout);
 | |
| 				if (!SetCommTimeouts (handle, timeouts))
 | |
| 					ReportIOError (null);
 | |
| 
 | |
| 				read_timeout = value;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		public override int WriteTimeout {
 | |
| 			get {
 | |
| 				return write_timeout;
 | |
| 			}
 | |
| 			set
 | |
| 			{
 | |
| 				if (value < 0 && value != SerialPort.InfiniteTimeout)
 | |
| 					throw new ArgumentOutOfRangeException ("value");
 | |
| 
 | |
| 				timeouts.SetValues (read_timeout, value);
 | |
| 				if (!SetCommTimeouts (handle, timeouts))
 | |
| 					ReportIOError (null);
 | |
| 
 | |
| 				write_timeout = value;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		public override long Length {
 | |
| 			get {
 | |
| 				throw new NotSupportedException ();
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		public override long Position {
 | |
| 			get {
 | |
| 				throw new NotSupportedException ();
 | |
| 			}
 | |
| 			set {
 | |
| 				throw new NotSupportedException ();
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		[DllImport("kernel32", SetLastError = true)]
 | |
| 		static extern bool CloseHandle (int handle);
 | |
| 
 | |
| 		protected override void Dispose (bool disposing)
 | |
| 		{
 | |
| 			if (disposed)
 | |
| 				return;
 | |
| 
 | |
| 			disposed = true;
 | |
| 			CloseHandle (handle);
 | |
| 			Marshal.FreeHGlobal (write_overlapped);
 | |
| 			Marshal.FreeHGlobal (read_overlapped);
 | |
| 		}
 | |
| 
 | |
| 		void IDisposable.Dispose ()
 | |
| 		{
 | |
| 			Dispose (true);
 | |
| 			GC.SuppressFinalize (this);
 | |
| 		}
 | |
| 
 | |
| 		public override void Close ()
 | |
| 		{
 | |
| 			((IDisposable)this).Dispose ();
 | |
| 		}
 | |
| 
 | |
| 		~WinSerialStream ()
 | |
| 		{
 | |
| 			Dispose (false);
 | |
| 		}
 | |
| 
 | |
| 		public override void Flush ()
 | |
| 		{
 | |
| 			CheckDisposed ();
 | |
| 			// No dothing by now
 | |
| 		}
 | |
| 
 | |
| 		public override long Seek (long offset, SeekOrigin origin)
 | |
| 		{
 | |
| 			throw new NotSupportedException();
 | |
| 		}
 | |
| 
 | |
| 		public override void SetLength (long value)
 | |
| 		{
 | |
| 			throw new NotSupportedException();
 | |
| 		}
 | |
| 
 | |
| 		[DllImport("kernel32", SetLastError = true)]
 | |
| 			static extern unsafe bool ReadFile (int handle, byte* buffer, int bytes_to_read,
 | |
| 					out int bytes_read, IntPtr overlapped);
 | |
| 
 | |
| 		[DllImport("kernel32", SetLastError = true)]
 | |
| 			static extern unsafe bool GetOverlappedResult (int handle, IntPtr overlapped,
 | |
| 					ref int bytes_transfered, bool wait);
 | |
| 
 | |
| 		public override int Read ([In, Out] byte [] buffer, int offset, int count)
 | |
| 		{
 | |
| 			CheckDisposed ();
 | |
| 			if (buffer == null)
 | |
| 				throw new ArgumentNullException ("buffer");
 | |
| 			if (offset < 0 || count < 0)
 | |
| 				throw new ArgumentOutOfRangeException ("offset or count less than zero.");
 | |
| 
 | |
| 			if (buffer.Length - offset < count )
 | |
| 				throw new ArgumentException ("offset+count",
 | |
| 							      "The size of the buffer is less than offset + count.");
 | |
| 
 | |
| 			int bytes_read;
 | |
| 
 | |
| 			unsafe {
 | |
| 				fixed (byte* ptr = buffer) {
 | |
| 					if (ReadFile (handle, ptr + offset, count, out bytes_read, read_overlapped))
 | |
| 						return bytes_read;
 | |
| 				
 | |
| 					// Test for overlapped behavior
 | |
| 					if (Marshal.GetLastWin32Error () != FileIOPending)
 | |
| 						ReportIOError (null);
 | |
| 				
 | |
| 					if (!GetOverlappedResult (handle, read_overlapped, ref bytes_read, true))
 | |
| 						ReportIOError (null);
 | |
| 			
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			if (bytes_read == 0)
 | |
| 				throw new TimeoutException (); // We didn't get any byte
 | |
| 
 | |
| 			return bytes_read;
 | |
| 		}
 | |
| 
 | |
| 		[DllImport("kernel32", SetLastError = true)]
 | |
| 		static extern unsafe bool WriteFile (int handle, byte* buffer, int bytes_to_write,
 | |
| 				out int bytes_written, IntPtr overlapped);
 | |
| 
 | |
| 		public override void Write (byte [] buffer, int offset, int count)
 | |
| 		{
 | |
| 			CheckDisposed ();
 | |
| 			if (buffer == null)
 | |
| 				throw new ArgumentNullException ("buffer");
 | |
| 
 | |
| 			if (offset < 0 || count < 0)
 | |
| 				throw new ArgumentOutOfRangeException ();
 | |
| 
 | |
| 			if (buffer.Length - offset < count)
 | |
| 				throw new ArgumentException ("offset+count",
 | |
| 							     "The size of the buffer is less than offset + count.");
 | |
| 
 | |
| 			int bytes_written = 0;
 | |
| 
 | |
| 			unsafe {
 | |
| 				fixed (byte* ptr = buffer) {
 | |
| 					if (WriteFile (handle, ptr + offset, count, out bytes_written, write_overlapped))
 | |
| 						return;
 | |
| 					if (Marshal.GetLastWin32Error() != FileIOPending)
 | |
| 						ReportIOError (null);
 | |
| 					
 | |
| 					if (!GetOverlappedResult(handle, write_overlapped, ref bytes_written, true))
 | |
| 						ReportIOError (null);
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			// If the operation timed out, then
 | |
| 			// we transfered less bytes than the requested ones
 | |
| 			if (bytes_written < count)
 | |
| 				throw new TimeoutException ();
 | |
| 		}
 | |
| 
 | |
| 		[DllImport("kernel32", SetLastError = true)]
 | |
| 		static extern bool GetCommState (int handle, [Out] DCB dcb);
 | |
| 
 | |
| 		[DllImport ("kernel32", SetLastError=true)]
 | |
| 		static extern bool SetCommState (int handle, DCB dcb);
 | |
| 
 | |
| 		public void SetAttributes (int baud_rate, Parity parity, int data_bits, StopBits bits, Handshake hs)
 | |
| 		{
 | |
| 			DCB dcb = new DCB ();
 | |
| 			if (!GetCommState (handle, dcb))
 | |
| 				ReportIOError (null);
 | |
| 
 | |
| 			dcb.SetValues (baud_rate, parity, data_bits, bits, hs);
 | |
| 			if (!SetCommState (handle, dcb))
 | |
| 				ReportIOError (null);
 | |
| 		}
 | |
| 
 | |
| 		void ReportIOError(string optional_arg)
 | |
| 		{
 | |
| 			int error = Marshal.GetLastWin32Error ();
 | |
| 			string message;
 | |
| 			switch (error) {
 | |
| 				case 2:
 | |
| 				case 3:
 | |
| 					message = "The port `" + optional_arg + "' does not exist.";
 | |
| 					break;
 | |
| 				case 87:
 | |
| 					message = "Parameter is incorrect.";
 | |
| 					break;
 | |
| 				default:
 | |
| 					// As fallback, we show the win32 error
 | |
| 					message = new Win32Exception ().Message;
 | |
| 					break;
 | |
| 			}
 | |
| 
 | |
| 			throw new IOException (message);
 | |
| 		}
 | |
| 
 | |
| 		void CheckDisposed ()
 | |
| 		{
 | |
| 			if (disposed)
 | |
| 				throw new ObjectDisposedException (GetType ().FullName);
 | |
| 		}
 | |
| 
 | |
| 		// ISerialStream members
 | |
| 		public void DiscardInBuffer ()
 | |
| 		{
 | |
| 			if (!PurgeComm (handle, PurgeRxClear))
 | |
| 				ReportIOError (null);
 | |
| 		}
 | |
| 
 | |
| 		public void DiscardOutBuffer ()
 | |
| 		{
 | |
| 			if (!PurgeComm (handle, PurgeTxClear))
 | |
| 				ReportIOError (null);
 | |
| 		}
 | |
| 
 | |
| 		[DllImport ("kernel32", SetLastError=true)]
 | |
| 		static extern bool ClearCommError (int handle, out uint errors, out CommStat stat);
 | |
| 
 | |
| 		public int BytesToRead {
 | |
| 			get {
 | |
| 				uint errors;
 | |
| 				CommStat stat;
 | |
| 				if (!ClearCommError (handle, out errors, out stat))
 | |
| 					ReportIOError (null);
 | |
| 
 | |
| 				return (int)stat.BytesIn;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		public int BytesToWrite {
 | |
| 			get {
 | |
| 				uint errors;
 | |
| 				CommStat stat;
 | |
| 				if (!ClearCommError (handle, out errors, out stat))
 | |
| 					ReportIOError (null);
 | |
| 
 | |
| 				return (int)stat.BytesOut;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		[DllImport ("kernel32", SetLastError=true)]
 | |
| 		static extern bool GetCommModemStatus (int handle, out uint flags);
 | |
| 
 | |
| 		public SerialSignal GetSignals ()
 | |
| 		{
 | |
| 			uint flags;
 | |
| 			if (!GetCommModemStatus (handle, out flags))
 | |
| 				ReportIOError (null);
 | |
| 
 | |
| 			SerialSignal signals = SerialSignal.None;
 | |
| 			if ((flags & RsldOn) != 0)
 | |
| 				signals |= SerialSignal.Cd;
 | |
| 			if ((flags & CtsOn) != 0)
 | |
| 				signals |= SerialSignal.Cts;
 | |
| 			if ((flags & DsrOn) != 0)
 | |
| 				signals |= SerialSignal.Dsr;
 | |
| 
 | |
| 			return signals;
 | |
| 		}
 | |
| 		
 | |
| 		[DllImport ("kernel32", SetLastError=true)]
 | |
| 		static extern bool EscapeCommFunction (int handle, uint flags);
 | |
| 
 | |
| 		public void SetSignal (SerialSignal signal, bool value)
 | |
| 		{
 | |
| 			if (signal != SerialSignal.Rts && signal != SerialSignal.Dtr)
 | |
| 				throw new Exception ("Wrong internal value");
 | |
| 
 | |
| 			uint flag;
 | |
| 			if (signal == SerialSignal.Rts)
 | |
| 				if (value)
 | |
| 					flag = SetRts;
 | |
| 				else
 | |
| 					flag = ClearRts;
 | |
| 			else
 | |
| 				if (value)
 | |
| 					flag = SetDtr;
 | |
| 				else
 | |
| 					flag = ClearDtr;
 | |
| 
 | |
| 			if (!EscapeCommFunction (handle, flag))
 | |
| 				ReportIOError (null);
 | |
| 		}
 | |
| 
 | |
| 		public void SetBreakState (bool value)
 | |
| 		{
 | |
| 			if (!EscapeCommFunction (handle, value ? SetBreak : ClearBreak))
 | |
| 				ReportIOError (null);
 | |
| 		}
 | |
| 
 | |
| 	}
 | |
| 	
 | |
| 	[StructLayout (LayoutKind.Sequential)]
 | |
| 	class DCB
 | |
| 	{
 | |
| 		public int dcb_length;
 | |
| 		public int baud_rate;
 | |
| 		public int flags;
 | |
| 		public short w_reserved;
 | |
| 		public short xon_lim;
 | |
| 		public short xoff_lim;
 | |
| 		public byte byte_size;
 | |
| 		public byte parity;
 | |
| 		public byte stop_bits;
 | |
| 		public byte xon_char;
 | |
| 		public byte xoff_char;
 | |
| 		public byte error_char;
 | |
| 		public byte eof_char;
 | |
| 		public byte evt_char;
 | |
| 		public short w_reserved1;
 | |
| 
 | |
| 		// flags:
 | |
| 		//const int fBinary = 0x0001;
 | |
| 		//const int fParity = 0x0002;
 | |
| 		const int fOutxCtsFlow = 0x0004;
 | |
| 		//const int fOutxDsrFlow1 = 0x0008;
 | |
| 		//const int fOutxDsrFlow2 = 0x0010;
 | |
| 		//const int fDtrControl = 0x00020;
 | |
| 		//const int fDsrSensitivity = 0x0040;
 | |
| 		//const int fTXContinueOnXoff = 0x0080;
 | |
| 		const int fOutX = 0x0100;
 | |
| 		const int fInX = 0x0200;
 | |
| 		//const int fErrorChar = 0x0400;
 | |
| 		//const int fNull = 0x0800;
 | |
| 		//const int fRtsControl1 = 0x1000;
 | |
| 		const int fRtsControl2 = 0x2000;
 | |
| 		//const int fAbortOnError = 0x4000;
 | |
| 
 | |
| 		public void SetValues (int baud_rate, Parity parity, int byte_size, StopBits sb, Handshake hs)
 | |
| 		{
 | |
| 			switch (sb) {
 | |
| 				case StopBits.One:
 | |
| 					stop_bits = 0;
 | |
| 					break;
 | |
| 				case StopBits.OnePointFive:
 | |
| 					stop_bits = 1;
 | |
| 					break;
 | |
| 				case StopBits.Two:
 | |
| 					stop_bits = 2;
 | |
| 					break;
 | |
| 				default: // Shouldn't happen
 | |
| 					break;
 | |
| 			}
 | |
| 
 | |
| 			this.baud_rate = baud_rate;
 | |
| 			this.parity = (byte)parity;
 | |
| 			this.byte_size = (byte)byte_size;
 | |
| 
 | |
| 			// Clear Handshake flags
 | |
| 			flags &= ~(fOutxCtsFlow | fOutX | fInX | fRtsControl2);
 | |
| 
 | |
| 			// Set Handshake flags
 | |
| 			switch (hs)
 | |
| 			{
 | |
| 				case Handshake.None:
 | |
| 					break;
 | |
| 				case Handshake.XOnXOff:
 | |
| 					flags |= fOutX | fInX;
 | |
| 					break;
 | |
| 				case Handshake.RequestToSend:
 | |
| 					flags |= fOutxCtsFlow | fRtsControl2;
 | |
| 					break;
 | |
| 				case Handshake.RequestToSendXOnXOff:
 | |
| 					flags |= fOutxCtsFlow | fOutX | fInX | fRtsControl2;
 | |
| 					break;
 | |
| 				default: // Shouldn't happen
 | |
| 					break;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	
 | |
| 	[StructLayout (LayoutKind.Sequential)]
 | |
| 	class Timeouts
 | |
| 	{
 | |
| 		public uint ReadIntervalTimeout;
 | |
| 		public uint ReadTotalTimeoutMultiplier;
 | |
| 		public uint ReadTotalTimeoutConstant;
 | |
| 		public uint WriteTotalTimeoutMultiplier;
 | |
| 		public uint WriteTotalTimeoutConstant;
 | |
| 
 | |
| 		public const uint MaxDWord = 0xFFFFFFFF;
 | |
| 
 | |
| 		public Timeouts (int read_timeout, int write_timeout)
 | |
| 		{
 | |
| 			SetValues (read_timeout, write_timeout);
 | |
| 		}
 | |
| 
 | |
| 		public void SetValues (int read_timeout, int write_timeout)
 | |
| 		{
 | |
| 			// FIXME: The windows api docs are not very clear about read timeouts,
 | |
| 			// and we have to simulate infinite with a big value (uint.MaxValue - 1)
 | |
| 			ReadIntervalTimeout = MaxDWord;
 | |
| 			ReadTotalTimeoutMultiplier = MaxDWord;
 | |
| 			ReadTotalTimeoutConstant = (read_timeout == -1 ? MaxDWord - 1 : (uint) read_timeout);
 | |
| 
 | |
| 			WriteTotalTimeoutMultiplier = 0;
 | |
| 			WriteTotalTimeoutConstant = (write_timeout == -1 ? MaxDWord : (uint) write_timeout);
 | |
| 		}
 | |
| 
 | |
| 	}
 | |
| 
 | |
| 	[StructLayout (LayoutKind.Sequential)]
 | |
| 	struct CommStat
 | |
| 	{
 | |
| 		public uint flags;
 | |
| 		public uint BytesIn;
 | |
| 		public uint BytesOut;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 |