2 // System.IO.Ports.WinSerialStream.cs
5 // Carlos Alberto Cortez (calberto.cortez@gmail.com)
7 // (c) Copyright 2006 Novell, Inc. (http://www.novell.com)
13 using System.Runtime.InteropServices;
14 using System.Threading;
15 using System.ComponentModel;
19 namespace System.IO.Ports
21 class WinSerialStream : Stream, ISerialStream, IDisposable
23 // Windows API Constants
24 const uint GenericRead = 0x80000000;
25 const uint GenericWrite = 0x40000000;
26 const uint OpenExisting = 3;
27 const uint FileFlagOverlapped = 0x40000000;
28 const uint PurgeRxClear = 0x0004;
29 const uint PurgeTxClear = 0x0008;
30 const uint WinInfiniteTimeout = 0xFFFFFFFF;
31 const uint FileIOPending = 997;
34 const uint SetRts = 3;
35 const uint ClearRts = 4;
36 const uint SetDtr = 5;
37 const uint ClearDtr = 6;
38 const uint SetBreak = 8;
39 const uint ClearBreak = 9;
40 const uint CtsOn = 0x0010;
41 const uint DsrOn = 0x0020;
42 const uint RsldOn = 0x0080;
45 const uint EvRxChar = 0x0001;
46 const uint EvCts = 0x0008;
47 const uint EvDsr = 0x0010;
48 const uint EvRlsd = 0x0020;
49 const uint EvBreak = 0x0040;
50 const uint EvErr = 0x0080;
51 const uint EvRing = 0x0100;
57 IntPtr write_overlapped;
58 IntPtr read_overlapped;
59 ManualResetEvent read_event;
60 ManualResetEvent write_event;
63 [DllImport("kernel32", SetLastError = true)]
64 static extern int CreateFile(string port_name, uint desired_access,
65 uint share_mode, uint security_attrs, uint creation, uint flags,
68 [DllImport("kernel32", SetLastError = true)]
69 static extern bool SetupComm(int handle, int read_buffer_size, int write_buffer_size);
71 [DllImport("kernel32", SetLastError = true)]
72 static extern bool PurgeComm(int handle, uint flags);
74 [DllImport("kernel32", SetLastError = true)]
75 static extern bool SetCommTimeouts(int handle, Timeouts timeouts);
77 public WinSerialStream (string port_name, int baud_rate, int data_bits, Parity parity,
78 StopBits sb, Handshake hs, int read_timeout, int write_timeout,
79 int read_buffer_size, int write_buffer_size)
81 handle = CreateFile (port_name, GenericRead | GenericWrite, 0, 0, OpenExisting,
82 FileFlagOverlapped, 0);
85 ReportIOError (port_name);
87 // Set port low level attributes
88 SetAttributes (baud_rate, parity, data_bits, sb, hs);
90 // Clean buffers and set sizes
91 if (!PurgeComm (handle, PurgeRxClear | PurgeTxClear) ||
92 !SetupComm (handle, read_buffer_size, write_buffer_size))
96 this.read_timeout = read_timeout;
97 this.write_timeout = write_timeout;
98 timeouts = new Timeouts (read_timeout, write_timeout);
99 if (!SetCommTimeouts(handle, timeouts))
100 ReportIOError (null);
102 // Init overlapped structures
103 NativeOverlapped wo = new NativeOverlapped ();
104 write_event = new ManualResetEvent (false);
105 wo.EventHandle = (int) write_event.Handle;
106 write_overlapped = Marshal.AllocHGlobal (Marshal.SizeOf (typeof (NativeOverlapped)));
107 Marshal.StructureToPtr (wo, write_overlapped, true);
109 NativeOverlapped ro = new NativeOverlapped ();
110 read_event = new ManualResetEvent (false);
111 ro.EventHandle = (int) read_event.Handle;
112 read_overlapped = Marshal.AllocHGlobal (Marshal.SizeOf (typeof (NativeOverlapped)));
113 Marshal.StructureToPtr (ro, read_overlapped, true);
116 public override bool CanRead {
122 public override bool CanSeek {
128 public override bool CanTimeout {
134 public override bool CanWrite {
140 public override int ReadTimeout {
145 if (value < 0 && value != SerialPort.InfiniteTimeout)
146 throw new ArgumentOutOfRangeException ("value");
148 timeouts.SetValues (value, write_timeout);
149 if (!SetCommTimeouts (handle, timeouts))
150 ReportIOError (null);
152 read_timeout = value;
156 public override int WriteTimeout {
158 return write_timeout;
162 if (value < 0 && value != SerialPort.InfiniteTimeout)
163 throw new ArgumentOutOfRangeException ("value");
165 timeouts.SetValues (read_timeout, value);
166 if (!SetCommTimeouts (handle, timeouts))
167 ReportIOError (null);
169 write_timeout = value;
173 public override long Length {
175 throw new NotSupportedException ();
179 public override long Position {
181 throw new NotSupportedException ();
184 throw new NotSupportedException ();
188 [DllImport("kernel32", SetLastError = true)]
189 static extern bool CloseHandle (int handle);
191 protected override void Dispose (bool disposing)
197 CloseHandle (handle);
198 Marshal.FreeHGlobal (write_overlapped);
199 Marshal.FreeHGlobal (read_overlapped);
202 void IDisposable.Dispose ()
205 GC.SuppressFinalize (this);
208 public override void Close ()
210 ((IDisposable)this).Dispose ();
218 public override void Flush ()
224 public override long Seek (long offset, SeekOrigin origin)
226 throw new NotSupportedException();
229 public override void SetLength (long value)
231 throw new NotSupportedException();
235 [DllImport("kernel32", SetLastError = true)]
236 static extern unsafe bool ReadFile (int handle, byte* buffer, int bytes_to_read,
237 out int bytes_read, IntPtr overlapped);
239 [DllImport("kernel32", SetLastError = true)]
240 static extern unsafe bool GetOverlappedResult (int handle, IntPtr overlapped,
241 ref int bytes_transfered, bool wait);
244 public override int Read ([In, Out] byte [] buffer, int offset, int count)
248 throw new ArgumentNullException ("buffer");
249 if (offset < 0 || count < 0)
250 throw new ArgumentOutOfRangeException ("offset or count less than zero.");
252 if (buffer.Length - offset < count )
253 throw new ArgumentException ("offset+count",
254 "The size of the buffer is less than offset + count.");
259 fixed (byte* ptr = buffer) {
260 if (ReadFile (handle, ptr + offset, count, out bytes_read, read_overlapped))
263 // Test for overlapped behavior
264 if (Marshal.GetLastWin32Error () != FileIOPending)
265 ReportIOError (null);
267 if (!GetOverlappedResult (handle, read_overlapped, ref bytes_read, true))
268 ReportIOError (null);
274 throw new TimeoutException (); // We didn't get any byte
280 [DllImport("kernel32", SetLastError = true)]
281 static extern unsafe bool WriteFile (int handle, byte* buffer, int bytes_to_write,
282 out int bytes_written, IntPtr overlapped);
285 public override void Write (byte [] buffer, int offset, int count)
289 throw new ArgumentNullException ("buffer");
291 if (offset < 0 || count < 0)
292 throw new ArgumentOutOfRangeException ();
294 if (buffer.Length - offset < count)
295 throw new ArgumentException ("offset+count",
296 "The size of the buffer is less than offset + count.");
298 int bytes_written = 0;
301 fixed (byte* ptr = buffer) {
302 if (WriteFile (handle, ptr + offset, count, out bytes_written, write_overlapped))
304 if (Marshal.GetLastWin32Error() != FileIOPending)
305 ReportIOError (null);
307 if (!GetOverlappedResult(handle, write_overlapped, ref bytes_written, true))
308 ReportIOError (null);
312 // If the operation timed out, then
313 // we transfered less bytes than the requested ones
314 if (bytes_written < count)
315 throw new TimeoutException ();
318 [DllImport("kernel32", SetLastError = true)]
319 static extern bool GetCommState (int handle, [Out] DCB dcb);
321 [DllImport ("kernel32", SetLastError=true)]
322 static extern bool SetCommState (int handle, DCB dcb);
324 public void SetAttributes (int baud_rate, Parity parity, int data_bits, StopBits bits, Handshake hs)
326 DCB dcb = new DCB ();
327 if (!GetCommState (handle, dcb))
328 ReportIOError (null);
330 dcb.SetValues (baud_rate, parity, data_bits, bits, hs);
331 if (!SetCommState (handle, dcb))
332 ReportIOError (null);
335 void ReportIOError(string optional_arg)
337 int error = Marshal.GetLastWin32Error ();
342 message = "The port `" + optional_arg + "' does not exist.";
345 message = "Parameter is incorrect.";
348 // As fallback, we show the win32 error
349 message = new Win32Exception ().Message;
353 throw new IOException (message);
356 void CheckDisposed ()
359 throw new ObjectDisposedException (GetType ().FullName);
362 // ISerialStream members
363 public void DiscardInBuffer ()
365 if (!PurgeComm (handle, PurgeRxClear))
366 ReportIOError (null);
369 public void DiscardOutBuffer ()
371 if (!PurgeComm (handle, PurgeRxClear))
372 ReportIOError (null);
375 [DllImport ("kernel32", SetLastError=true)]
376 static extern bool ClearCommError (int handle, out CommStat stat);
378 public int BytesToRead {
381 if (!ClearCommError (handle, out stat))
382 ReportIOError (null);
384 return (int)stat.BytesIn;
388 public int BytesToWrite {
391 if (!ClearCommError (handle, out stat))
392 ReportIOError (null);
394 return (int)stat.BytesOut;
398 [DllImport ("kernel32", SetLastError=true)]
399 static extern bool GetCommModemStatus (int handle, out uint flags);
401 public SerialSignal GetSignals ()
404 if (!GetCommModemStatus (handle, out flags))
405 ReportIOError (null);
407 SerialSignal signals = SerialSignal.None;
408 if ((flags & RsldOn) != 0)
409 signals |= SerialSignal.Cd;
410 if ((flags & CtsOn) != 0)
411 signals |= SerialSignal.Cts;
412 if ((flags & DsrOn) != 0)
413 signals |= SerialSignal.Dsr;
418 [DllImport ("kernel32", SetLastError=true)]
419 static extern bool EscapeCommFunction (int handle, uint flags);
421 public void SetSignal (SerialSignal signal, bool value)
423 if (signal != SerialSignal.Rts || signal != SerialSignal.Dtr)
424 throw new Exception ("Wrong internal value");
427 if (signal == SerialSignal.Rts)
438 if (!EscapeCommFunction (handle, flag))
439 ReportIOError (null);
442 public void SetBreakState (bool value)
444 if (!EscapeCommFunction (handle, value ? SetBreak : ClearBreak))
445 ReportIOError (null);
450 [StructLayout (LayoutKind.Sequential)]
453 public int dcb_length;
454 public int baud_rate;
456 public short w_reserved;
457 public short xon_lim;
458 public short xoff_lim;
459 public byte byte_size;
461 public byte stop_bits;
462 public byte xon_char;
463 public byte xoff_char;
464 public byte error_char;
465 public byte eof_char;
466 public byte evt_char;
467 public short w_reserved1;
469 public void SetValues (int baud_rate, Parity parity, int byte_size, StopBits sb, Handshake hs)
475 case StopBits.OnePointFive:
481 default: // Shouldn't happen
485 this.baud_rate = baud_rate;
486 this.parity = (byte) parity;
487 this.byte_size = (byte) byte_size;
492 [StructLayout (LayoutKind.Sequential)]
495 public uint ReadIntervalTimeout;
496 public uint ReadTotalTimeoutMultiplier;
497 public uint ReadTotalTimeoutConstant;
498 public uint WriteTotalTimeoutMultiplier;
499 public uint WriteTotalTimeoutConstant;
501 public const uint MaxDWord = 0xFFFFFFFF;
503 public Timeouts (int read_timeout, int write_timeout)
505 SetValues (read_timeout, write_timeout);
508 public void SetValues (int read_timeout, int write_timeout)
510 // FIXME: The windows api docs are not very clear about read timeouts,
511 // and we have to simulate infinite with a big value (uint.MaxValue - 1)
512 ReadIntervalTimeout = MaxDWord;
513 ReadTotalTimeoutMultiplier = MaxDWord;
514 ReadTotalTimeoutConstant = (read_timeout == -1 ? MaxDWord - 1 : (uint) read_timeout);
516 WriteTotalTimeoutMultiplier = 0;
517 WriteTotalTimeoutConstant = (write_timeout == -1 ? MaxDWord : (uint) write_timeout);
522 [StructLayout (LayoutKind.Sequential)]
527 public uint BytesOut;