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