PageRenderTime 23ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/mcs/class/System/System.IO.Ports/WinSerialStream.cs

https://github.com/skolima/mono
C# | 577 lines | 442 code | 97 blank | 38 comment | 68 complexity | 55fc3352e7862e8b2e204adf33c7a788 MD5 | raw file
  1. //
  2. // System.IO.Ports.WinSerialStream.cs
  3. //
  4. // Authors:
  5. // Carlos Alberto Cortez (calberto.cortez@gmail.com)
  6. //
  7. // (c) Copyright 2006 Novell, Inc. (http://www.novell.com)
  8. //
  9. using System;
  10. using System.Text;
  11. using System.IO;
  12. using System.Runtime.InteropServices;
  13. using System.Threading;
  14. using System.ComponentModel;
  15. namespace System.IO.Ports
  16. {
  17. class WinSerialStream : Stream, ISerialStream, IDisposable
  18. {
  19. // Windows API Constants
  20. const uint GenericRead = 0x80000000;
  21. const uint GenericWrite = 0x40000000;
  22. const uint OpenExisting = 3;
  23. const uint FileFlagOverlapped = 0x40000000;
  24. const uint PurgeRxClear = 0x0008;
  25. const uint PurgeTxClear = 0x0004;
  26. const uint WinInfiniteTimeout = 0xFFFFFFFF;
  27. const uint FileIOPending = 997;
  28. // Signal constants
  29. const uint SetRts = 3;
  30. const uint ClearRts = 4;
  31. const uint SetDtr = 5;
  32. const uint ClearDtr = 6;
  33. const uint SetBreak = 8;
  34. const uint ClearBreak = 9;
  35. const uint CtsOn = 0x0010;
  36. const uint DsrOn = 0x0020;
  37. const uint RsldOn = 0x0080;
  38. // Event constants
  39. const uint EvRxChar = 0x0001;
  40. const uint EvCts = 0x0008;
  41. const uint EvDsr = 0x0010;
  42. const uint EvRlsd = 0x0020;
  43. const uint EvBreak = 0x0040;
  44. const uint EvErr = 0x0080;
  45. const uint EvRing = 0x0100;
  46. int handle;
  47. int read_timeout;
  48. int write_timeout;
  49. bool disposed;
  50. IntPtr write_overlapped;
  51. IntPtr read_overlapped;
  52. ManualResetEvent read_event;
  53. ManualResetEvent write_event;
  54. Timeouts timeouts;
  55. [DllImport("kernel32", SetLastError = true)]
  56. static extern int CreateFile(string port_name, uint desired_access,
  57. uint share_mode, uint security_attrs, uint creation, uint flags,
  58. uint template);
  59. [DllImport("kernel32", SetLastError = true)]
  60. static extern bool SetupComm(int handle, int read_buffer_size, int write_buffer_size);
  61. [DllImport("kernel32", SetLastError = true)]
  62. static extern bool PurgeComm(int handle, uint flags);
  63. [DllImport("kernel32", SetLastError = true)]
  64. static extern bool SetCommTimeouts(int handle, Timeouts timeouts);
  65. public WinSerialStream (string port_name, int baud_rate, int data_bits, Parity parity, StopBits sb,
  66. bool dtr_enable, bool rts_enable, Handshake hs, int read_timeout, int write_timeout,
  67. int read_buffer_size, int write_buffer_size)
  68. {
  69. handle = CreateFile (port_name != null && !port_name.StartsWith(@"\\.\")
  70. ? @"\\.\" + port_name : port_name,
  71. GenericRead | GenericWrite, 0, 0, OpenExisting,
  72. FileFlagOverlapped, 0);
  73. if (handle == -1)
  74. ReportIOError (port_name);
  75. // Set port low level attributes
  76. SetAttributes (baud_rate, parity, data_bits, sb, hs);
  77. // Clean buffers and set sizes
  78. if (!PurgeComm (handle, PurgeRxClear | PurgeTxClear) ||
  79. !SetupComm (handle, read_buffer_size, write_buffer_size))
  80. ReportIOError (null);
  81. // Set timeouts
  82. this.read_timeout = read_timeout;
  83. this.write_timeout = write_timeout;
  84. timeouts = new Timeouts (read_timeout, write_timeout);
  85. if (!SetCommTimeouts(handle, timeouts))
  86. ReportIOError (null);
  87. /// Set DTR and RTS
  88. SetSignal(SerialSignal.Dtr, dtr_enable);
  89. if (hs != Handshake.RequestToSend &&
  90. hs != Handshake.RequestToSendXOnXOff)
  91. SetSignal(SerialSignal.Rts, rts_enable);
  92. // Init overlapped structures
  93. NativeOverlapped wo = new NativeOverlapped ();
  94. write_event = new ManualResetEvent (false);
  95. wo.EventHandle = write_event.Handle;
  96. write_overlapped = Marshal.AllocHGlobal (Marshal.SizeOf (typeof (NativeOverlapped)));
  97. Marshal.StructureToPtr (wo, write_overlapped, true);
  98. NativeOverlapped ro = new NativeOverlapped ();
  99. read_event = new ManualResetEvent (false);
  100. ro.EventHandle = read_event.Handle;
  101. read_overlapped = Marshal.AllocHGlobal (Marshal.SizeOf (typeof (NativeOverlapped)));
  102. Marshal.StructureToPtr (ro, read_overlapped, true);
  103. }
  104. public override bool CanRead {
  105. get {
  106. return true;
  107. }
  108. }
  109. public override bool CanSeek {
  110. get {
  111. return false;
  112. }
  113. }
  114. public override bool CanTimeout {
  115. get {
  116. return true;
  117. }
  118. }
  119. public override bool CanWrite {
  120. get {
  121. return true;
  122. }
  123. }
  124. public override int ReadTimeout {
  125. get {
  126. return read_timeout;
  127. }
  128. set {
  129. if (value < 0 && value != SerialPort.InfiniteTimeout)
  130. throw new ArgumentOutOfRangeException ("value");
  131. timeouts.SetValues (value, write_timeout);
  132. if (!SetCommTimeouts (handle, timeouts))
  133. ReportIOError (null);
  134. read_timeout = value;
  135. }
  136. }
  137. public override int WriteTimeout {
  138. get {
  139. return write_timeout;
  140. }
  141. set
  142. {
  143. if (value < 0 && value != SerialPort.InfiniteTimeout)
  144. throw new ArgumentOutOfRangeException ("value");
  145. timeouts.SetValues (read_timeout, value);
  146. if (!SetCommTimeouts (handle, timeouts))
  147. ReportIOError (null);
  148. write_timeout = value;
  149. }
  150. }
  151. public override long Length {
  152. get {
  153. throw new NotSupportedException ();
  154. }
  155. }
  156. public override long Position {
  157. get {
  158. throw new NotSupportedException ();
  159. }
  160. set {
  161. throw new NotSupportedException ();
  162. }
  163. }
  164. [DllImport("kernel32", SetLastError = true)]
  165. static extern bool CloseHandle (int handle);
  166. protected override void Dispose (bool disposing)
  167. {
  168. if (disposed)
  169. return;
  170. disposed = true;
  171. CloseHandle (handle);
  172. Marshal.FreeHGlobal (write_overlapped);
  173. Marshal.FreeHGlobal (read_overlapped);
  174. }
  175. void IDisposable.Dispose ()
  176. {
  177. Dispose (true);
  178. GC.SuppressFinalize (this);
  179. }
  180. public override void Close ()
  181. {
  182. ((IDisposable)this).Dispose ();
  183. }
  184. ~WinSerialStream ()
  185. {
  186. Dispose (false);
  187. }
  188. public override void Flush ()
  189. {
  190. CheckDisposed ();
  191. // No dothing by now
  192. }
  193. public override long Seek (long offset, SeekOrigin origin)
  194. {
  195. throw new NotSupportedException();
  196. }
  197. public override void SetLength (long value)
  198. {
  199. throw new NotSupportedException();
  200. }
  201. #if !TARGET_JVM
  202. [DllImport("kernel32", SetLastError = true)]
  203. static extern unsafe bool ReadFile (int handle, byte* buffer, int bytes_to_read,
  204. out int bytes_read, IntPtr overlapped);
  205. [DllImport("kernel32", SetLastError = true)]
  206. static extern unsafe bool GetOverlappedResult (int handle, IntPtr overlapped,
  207. ref int bytes_transfered, bool wait);
  208. #endif
  209. public override int Read ([In, Out] byte [] buffer, int offset, int count)
  210. {
  211. CheckDisposed ();
  212. if (buffer == null)
  213. throw new ArgumentNullException ("buffer");
  214. if (offset < 0 || count < 0)
  215. throw new ArgumentOutOfRangeException ("offset or count less than zero.");
  216. if (buffer.Length - offset < count )
  217. throw new ArgumentException ("offset+count",
  218. "The size of the buffer is less than offset + count.");
  219. int bytes_read;
  220. unsafe {
  221. fixed (byte* ptr = buffer) {
  222. if (ReadFile (handle, ptr + offset, count, out bytes_read, read_overlapped))
  223. return bytes_read;
  224. // Test for overlapped behavior
  225. if (Marshal.GetLastWin32Error () != FileIOPending)
  226. ReportIOError (null);
  227. if (!GetOverlappedResult (handle, read_overlapped, ref bytes_read, true))
  228. ReportIOError (null);
  229. }
  230. }
  231. if (bytes_read == 0)
  232. throw new TimeoutException (); // We didn't get any byte
  233. return bytes_read;
  234. }
  235. #if !TARGET_JVM
  236. [DllImport("kernel32", SetLastError = true)]
  237. static extern unsafe bool WriteFile (int handle, byte* buffer, int bytes_to_write,
  238. out int bytes_written, IntPtr overlapped);
  239. #endif
  240. public override void Write (byte [] buffer, int offset, int count)
  241. {
  242. CheckDisposed ();
  243. if (buffer == null)
  244. throw new ArgumentNullException ("buffer");
  245. if (offset < 0 || count < 0)
  246. throw new ArgumentOutOfRangeException ();
  247. if (buffer.Length - offset < count)
  248. throw new ArgumentException ("offset+count",
  249. "The size of the buffer is less than offset + count.");
  250. int bytes_written = 0;
  251. unsafe {
  252. fixed (byte* ptr = buffer) {
  253. if (WriteFile (handle, ptr + offset, count, out bytes_written, write_overlapped))
  254. return;
  255. if (Marshal.GetLastWin32Error() != FileIOPending)
  256. ReportIOError (null);
  257. if (!GetOverlappedResult(handle, write_overlapped, ref bytes_written, true))
  258. ReportIOError (null);
  259. }
  260. }
  261. // If the operation timed out, then
  262. // we transfered less bytes than the requested ones
  263. if (bytes_written < count)
  264. throw new TimeoutException ();
  265. }
  266. [DllImport("kernel32", SetLastError = true)]
  267. static extern bool GetCommState (int handle, [Out] DCB dcb);
  268. [DllImport ("kernel32", SetLastError=true)]
  269. static extern bool SetCommState (int handle, DCB dcb);
  270. public void SetAttributes (int baud_rate, Parity parity, int data_bits, StopBits bits, Handshake hs)
  271. {
  272. DCB dcb = new DCB ();
  273. if (!GetCommState (handle, dcb))
  274. ReportIOError (null);
  275. dcb.SetValues (baud_rate, parity, data_bits, bits, hs);
  276. if (!SetCommState (handle, dcb))
  277. ReportIOError (null);
  278. }
  279. void ReportIOError(string optional_arg)
  280. {
  281. int error = Marshal.GetLastWin32Error ();
  282. string message;
  283. switch (error) {
  284. case 2:
  285. case 3:
  286. message = "The port `" + optional_arg + "' does not exist.";
  287. break;
  288. case 87:
  289. message = "Parameter is incorrect.";
  290. break;
  291. default:
  292. // As fallback, we show the win32 error
  293. message = new Win32Exception ().Message;
  294. break;
  295. }
  296. throw new IOException (message);
  297. }
  298. void CheckDisposed ()
  299. {
  300. if (disposed)
  301. throw new ObjectDisposedException (GetType ().FullName);
  302. }
  303. // ISerialStream members
  304. public void DiscardInBuffer ()
  305. {
  306. if (!PurgeComm (handle, PurgeRxClear))
  307. ReportIOError (null);
  308. }
  309. public void DiscardOutBuffer ()
  310. {
  311. if (!PurgeComm (handle, PurgeTxClear))
  312. ReportIOError (null);
  313. }
  314. [DllImport ("kernel32", SetLastError=true)]
  315. static extern bool ClearCommError (int handle, out uint errors, out CommStat stat);
  316. public int BytesToRead {
  317. get {
  318. uint errors;
  319. CommStat stat;
  320. if (!ClearCommError (handle, out errors, out stat))
  321. ReportIOError (null);
  322. return (int)stat.BytesIn;
  323. }
  324. }
  325. public int BytesToWrite {
  326. get {
  327. uint errors;
  328. CommStat stat;
  329. if (!ClearCommError (handle, out errors, out stat))
  330. ReportIOError (null);
  331. return (int)stat.BytesOut;
  332. }
  333. }
  334. [DllImport ("kernel32", SetLastError=true)]
  335. static extern bool GetCommModemStatus (int handle, out uint flags);
  336. public SerialSignal GetSignals ()
  337. {
  338. uint flags;
  339. if (!GetCommModemStatus (handle, out flags))
  340. ReportIOError (null);
  341. SerialSignal signals = SerialSignal.None;
  342. if ((flags & RsldOn) != 0)
  343. signals |= SerialSignal.Cd;
  344. if ((flags & CtsOn) != 0)
  345. signals |= SerialSignal.Cts;
  346. if ((flags & DsrOn) != 0)
  347. signals |= SerialSignal.Dsr;
  348. return signals;
  349. }
  350. [DllImport ("kernel32", SetLastError=true)]
  351. static extern bool EscapeCommFunction (int handle, uint flags);
  352. public void SetSignal (SerialSignal signal, bool value)
  353. {
  354. if (signal != SerialSignal.Rts && signal != SerialSignal.Dtr)
  355. throw new Exception ("Wrong internal value");
  356. uint flag;
  357. if (signal == SerialSignal.Rts)
  358. if (value)
  359. flag = SetRts;
  360. else
  361. flag = ClearRts;
  362. else
  363. if (value)
  364. flag = SetDtr;
  365. else
  366. flag = ClearDtr;
  367. if (!EscapeCommFunction (handle, flag))
  368. ReportIOError (null);
  369. }
  370. public void SetBreakState (bool value)
  371. {
  372. if (!EscapeCommFunction (handle, value ? SetBreak : ClearBreak))
  373. ReportIOError (null);
  374. }
  375. }
  376. [StructLayout (LayoutKind.Sequential)]
  377. class DCB
  378. {
  379. public int dcb_length;
  380. public int baud_rate;
  381. public int flags;
  382. public short w_reserved;
  383. public short xon_lim;
  384. public short xoff_lim;
  385. public byte byte_size;
  386. public byte parity;
  387. public byte stop_bits;
  388. public byte xon_char;
  389. public byte xoff_char;
  390. public byte error_char;
  391. public byte eof_char;
  392. public byte evt_char;
  393. public short w_reserved1;
  394. // flags:
  395. //const int fBinary = 0x0001;
  396. //const int fParity = 0x0002;
  397. const int fOutxCtsFlow = 0x0004;
  398. //const int fOutxDsrFlow1 = 0x0008;
  399. //const int fOutxDsrFlow2 = 0x0010;
  400. //const int fDtrControl = 0x00020;
  401. //const int fDsrSensitivity = 0x0040;
  402. //const int fTXContinueOnXoff = 0x0080;
  403. const int fOutX = 0x0100;
  404. const int fInX = 0x0200;
  405. //const int fErrorChar = 0x0400;
  406. //const int fNull = 0x0800;
  407. //const int fRtsControl1 = 0x1000;
  408. const int fRtsControl2 = 0x2000;
  409. //const int fAbortOnError = 0x4000;
  410. public void SetValues (int baud_rate, Parity parity, int byte_size, StopBits sb, Handshake hs)
  411. {
  412. switch (sb) {
  413. case StopBits.One:
  414. stop_bits = 0;
  415. break;
  416. case StopBits.OnePointFive:
  417. stop_bits = 1;
  418. break;
  419. case StopBits.Two:
  420. stop_bits = 2;
  421. break;
  422. default: // Shouldn't happen
  423. break;
  424. }
  425. this.baud_rate = baud_rate;
  426. this.parity = (byte)parity;
  427. this.byte_size = (byte)byte_size;
  428. // Clear Handshake flags
  429. flags &= ~(fOutxCtsFlow | fOutX | fInX | fRtsControl2);
  430. // Set Handshake flags
  431. switch (hs)
  432. {
  433. case Handshake.None:
  434. break;
  435. case Handshake.XOnXOff:
  436. flags |= fOutX | fInX;
  437. break;
  438. case Handshake.RequestToSend:
  439. flags |= fOutxCtsFlow | fRtsControl2;
  440. break;
  441. case Handshake.RequestToSendXOnXOff:
  442. flags |= fOutxCtsFlow | fOutX | fInX | fRtsControl2;
  443. break;
  444. default: // Shouldn't happen
  445. break;
  446. }
  447. }
  448. }
  449. [StructLayout (LayoutKind.Sequential)]
  450. class Timeouts
  451. {
  452. public uint ReadIntervalTimeout;
  453. public uint ReadTotalTimeoutMultiplier;
  454. public uint ReadTotalTimeoutConstant;
  455. public uint WriteTotalTimeoutMultiplier;
  456. public uint WriteTotalTimeoutConstant;
  457. public const uint MaxDWord = 0xFFFFFFFF;
  458. public Timeouts (int read_timeout, int write_timeout)
  459. {
  460. SetValues (read_timeout, write_timeout);
  461. }
  462. public void SetValues (int read_timeout, int write_timeout)
  463. {
  464. // FIXME: The windows api docs are not very clear about read timeouts,
  465. // and we have to simulate infinite with a big value (uint.MaxValue - 1)
  466. ReadIntervalTimeout = MaxDWord;
  467. ReadTotalTimeoutMultiplier = MaxDWord;
  468. ReadTotalTimeoutConstant = (read_timeout == -1 ? MaxDWord - 1 : (uint) read_timeout);
  469. WriteTotalTimeoutMultiplier = 0;
  470. WriteTotalTimeoutConstant = (write_timeout == -1 ? MaxDWord : (uint) write_timeout);
  471. }
  472. }
  473. [StructLayout (LayoutKind.Sequential)]
  474. struct CommStat
  475. {
  476. public uint flags;
  477. public uint BytesIn;
  478. public uint BytesOut;
  479. }
  480. }