Wed Feb 24 15:47:16 CET 2010 Paolo Molaro <lupus@ximian.com>
[mono.git] / mcs / class / System / System.IO.Ports / SerialPortStream.cs
1 //
2 // System.IO.Ports.SerialPortStream.cs
3 //
4 // Authors:
5 //      Chris Toshok (toshok@ximian.com)
6 //      Carlos Alberto Cortez (calberto.cortez@gmail.com)
7 //
8 // (c) Copyright 2006 Novell, Inc. (http://www.novell.com)
9 //
10
11
12 #if NET_2_0
13
14 using System;
15 using System.IO;
16 using System.Runtime.InteropServices;
17
18 namespace System.IO.Ports
19 {
20         class SerialPortStream : Stream, ISerialStream, IDisposable
21         {
22                 int fd;
23                 int read_timeout;
24                 int write_timeout;
25                 bool disposed;
26
27                 [DllImport ("MonoPosixHelper", SetLastError = true)]
28                 static extern int open_serial (string portName);
29
30                 public SerialPortStream (string portName, int baudRate, int dataBits, Parity parity, StopBits stopBits,
31                                 bool dtrEnable, bool rtsEnable, Handshake handshake, int readTimeout, int writeTimeout,
32                                 int readBufferSize, int writeBufferSize)
33                 {
34                         fd = open_serial (portName);
35                         if (fd == -1)
36                                 ThrowIOException ();
37                         
38                         if (!set_attributes (fd, baudRate, parity, dataBits, stopBits, handshake))
39                                 ThrowIOException (); // Probably Win32Exc for compatibility
40
41                         read_timeout = readTimeout;
42                         write_timeout = writeTimeout;
43                         
44                         SetSignal (SerialSignal.Dtr, dtrEnable);
45                         
46                         if (handshake != Handshake.RequestToSend && 
47                                         handshake != Handshake.RequestToSendXOnXOff)
48                                 SetSignal (SerialSignal.Rts, rtsEnable);
49                 }
50
51                 public override bool CanRead {
52                         get {
53                                 return true;
54                         }
55                 }
56
57                 public override bool CanSeek {
58                         get {
59                                 return false;
60                         }
61                 }
62
63                 public override bool CanWrite {
64                         get {
65                                 return true;
66                         }
67                 }
68
69                 public override bool CanTimeout {
70                         get {
71                                 return true;
72                         }
73                 }
74
75                 public override int ReadTimeout {
76                         get {
77                                 return read_timeout;
78                         }
79                         set {
80                                 if (value < 0 && value != SerialPort.InfiniteTimeout)
81                                         throw new ArgumentOutOfRangeException ("value");
82
83                                 read_timeout = value;
84                         }
85                 }
86
87                 public override int WriteTimeout {
88                         get {
89                                 return write_timeout;
90                         }
91                         set {
92                                 if (value < 0 && value != SerialPort.InfiniteTimeout)
93                                         throw new ArgumentOutOfRangeException ("value");
94
95                                 write_timeout = value;
96                         }
97                 }
98
99                 public override long Length {
100                         get {
101                                 throw new NotSupportedException ();
102                         }
103                 }
104
105                 public override long Position {
106                         get {
107                                 throw new NotSupportedException ();
108                         }
109                         set {
110                                 throw new NotSupportedException ();
111                         }
112                 }
113
114                 public override void Flush ()
115                 {
116                         // If used, this _could_ flush the serial port
117                         // buffer (not the SerialPort class buffer)
118                 }
119
120                 [DllImport ("MonoPosixHelper", SetLastError = true)]
121                 static extern int read_serial (int fd, byte [] buffer, int offset, int count);
122                 
123
124                 [DllImport ("MonoPosixHelper", SetLastError = true)]
125                 static extern bool poll_serial (int fd, out int error, int timeout);
126
127                 public override int Read ([In,Out] byte[] buffer, int offset, int count)
128                 {
129                         CheckDisposed ();
130                         if (buffer == null)
131                                 throw new ArgumentNullException ("buffer");
132                         if (offset < 0 || count < 0)
133                                 throw new ArgumentOutOfRangeException ("offset or count less than zero.");
134
135                         if (buffer.Length - offset < count )
136                                 throw new ArgumentException ("offset+count",
137                                                               "The size of the buffer is less than offset + count.");
138                         
139                         int error;
140                         bool poll_result = poll_serial (fd, out error, read_timeout);
141                         if (error == -1)
142                                 ThrowIOException ();
143
144                         if (!poll_result) {
145                                 // see bug 79735   http://bugzilla.ximian.com/show_bug.cgi?id=79735
146                                 // should the next line read: return -1; 
147                                 throw new TimeoutException();
148                         }
149
150                         int result = read_serial (fd, buffer, offset, count);
151                         if (result == -1)
152                                 ThrowIOException ();
153                         return result;
154                 }
155
156                 public override long Seek (long offset, SeekOrigin origin)
157                 {
158                         throw new NotSupportedException ();
159                 }
160
161                 public override void SetLength (long value)
162                 {
163                         throw new NotSupportedException ();
164                 }
165
166                 [DllImport ("MonoPosixHelper", SetLastError = true)]
167                 static extern int write_serial (int fd, byte [] buffer, int offset, int count, int timeout);
168
169                 public override void Write (byte[] buffer, int offset, int count)
170                 {
171                         CheckDisposed ();
172                         if (buffer == null)
173                                 throw new ArgumentNullException ("buffer");
174
175                         if (offset < 0 || count < 0)
176                                 throw new ArgumentOutOfRangeException ();
177
178                         if (buffer.Length - offset < count)
179                                 throw new ArgumentException ("offset+count",
180                                                              "The size of the buffer is less than offset + count.");
181
182                         // FIXME: this reports every write error as timeout
183                         if (write_serial (fd, buffer, offset, count, write_timeout) < 0)
184                                 throw new TimeoutException("The operation has timed-out");
185                 }
186
187                 protected override void Dispose (bool disposing)
188                 {
189                         if (disposed)
190                                 return;
191                         
192                         disposed = true;
193                         if (close_serial (fd) != 0)
194                                 ThrowIOException();
195                 }
196
197                 [DllImport ("MonoPosixHelper", SetLastError = true)]
198                 static extern int close_serial (int fd);
199
200                 public override void Close ()
201                 {
202                         ((IDisposable) this).Dispose ();
203                 }
204
205                 void IDisposable.Dispose ()
206                 {
207                         Dispose (true);
208                         GC.SuppressFinalize (this);
209                 }
210
211                 ~SerialPortStream ()
212                 {
213                         Dispose (false);
214                 }
215
216                 void CheckDisposed ()
217                 {
218                         if (disposed)
219                                 throw new ObjectDisposedException (GetType ().FullName);
220                 }
221
222                 [DllImport ("MonoPosixHelper", SetLastError = true)]
223                 static extern bool set_attributes (int fd, int baudRate, Parity parity, int dataBits, StopBits stopBits, Handshake handshake);
224
225                 public void SetAttributes (int baud_rate, Parity parity, int data_bits, StopBits sb, Handshake hs)
226                 {
227                         if (!set_attributes (fd, baud_rate, parity, data_bits, sb, hs))
228                                 ThrowIOException ();
229                 }
230
231                 [DllImport("MonoPosixHelper", SetLastError = true)]
232                 static extern int get_bytes_in_buffer (int fd, int input);
233                 
234                 public int BytesToRead {
235                         get {
236                                 int result = get_bytes_in_buffer (fd, 1);
237                                 if (result == -1)
238                                         ThrowIOException ();
239                                 return result;
240                         }
241                 }
242
243                 public int BytesToWrite {
244                         get {
245                                 int result = get_bytes_in_buffer (fd, 0);
246                                 if (result == -1)
247                                         ThrowIOException ();
248                                 return result;
249                         }
250                 }
251
252                 [DllImport ("MonoPosixHelper", SetLastError = true)]
253                 static extern int discard_buffer (int fd, bool inputBuffer);
254
255                 public void DiscardInBuffer ()
256                 {
257                         if (discard_buffer (fd, true) != 0)
258                                 ThrowIOException();
259                 }
260
261                 public void DiscardOutBuffer ()
262                 {
263                         if (discard_buffer (fd, false) != 0)
264                                 ThrowIOException();
265                 }
266                 
267                 [DllImport ("MonoPosixHelper", SetLastError = true)]
268                 static extern SerialSignal get_signals (int fd, out int error);
269
270                 public SerialSignal GetSignals ()
271                 {
272                         int error;
273                         SerialSignal signals = get_signals (fd, out error);
274                         if (error == -1)
275                                 ThrowIOException ();
276
277                         return signals;
278                 }
279
280                 [DllImport ("MonoPosixHelper", SetLastError = true)]
281                 static extern int set_signal (int fd, SerialSignal signal, bool value);
282
283                 public void SetSignal (SerialSignal signal, bool value)
284                 {
285                         if (signal < SerialSignal.Cd || signal > SerialSignal.Rts ||
286                                         signal == SerialSignal.Cd ||
287                                         signal == SerialSignal.Cts ||
288                                         signal == SerialSignal.Dsr)
289                                 throw new Exception ("Invalid internal value");
290
291                         if (set_signal (fd, signal, value) == -1)
292                                 ThrowIOException ();
293                 }
294
295                 [DllImport ("MonoPosixHelper", SetLastError = true)]
296                 static extern int breakprop (int fd);
297
298                 public void SetBreakState (bool value)
299                 {
300                         if (value)
301                                 if (breakprop (fd) == -1)
302                                         ThrowIOException ();
303                 }
304
305                 [DllImport ("libc")]
306                 static extern IntPtr strerror (int errnum);
307
308                 static void ThrowIOException ()
309                 {
310                         int errnum = Marshal.GetLastWin32Error ();
311                         string error_message = Marshal.PtrToStringAnsi (strerror (errnum));
312
313                         throw new IOException (error_message);
314                 }
315         }
316 }
317
318 #endif
319
320