* SerialPort.cs:
[mono.git] / mcs / class / System / System.IO.Ports / SerialPort.cs
1 /* -*- Mode: Csharp; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
3 #if NET_2_0
4
5 using System;
6 using System.ComponentModel;
7 using System.Text;
8 using System.Runtime.InteropServices;
9
10 namespace System.IO.Ports
11 {
12         public class SerialPort : Component
13         {
14                 public const int InfiniteTimeout = -1;
15                 const int DefaultReadBufferSize = 4096;
16                 const int DefaultWriteBufferSize = 2048;
17                 const int DefaultBaudRate = 9600;
18                 const int DefaultDataBits = 8;
19                 const Parity DefaultParity = Parity.None;
20                 const StopBits DefaultStopBits = StopBits.One;
21
22                 bool is_open;
23                 int baud_rate;
24                 Parity parity;
25                 StopBits stop_bits;
26                 Handshake handshake;
27                 int data_bits;
28                 bool break_state = false;
29                 bool dtr_enable = false;
30                 bool rts_enable = false;
31                 ISerialStream stream;
32                 Encoding encoding = Encoding.ASCII;
33                 string new_line = Environment.NewLine;
34                 string port_name;
35                 int read_timeout = InfiniteTimeout;
36                 int write_timeout = InfiniteTimeout;
37                 int readBufferSize = DefaultReadBufferSize;
38                 int writeBufferSize = DefaultWriteBufferSize;
39                 object error_received = new object ();
40                 object data_received = new object ();
41                 object pin_changed = new object ();
42                 
43                 static string default_port_name = "ttyS0";
44
45                 public SerialPort () : 
46                         this (GetDefaultPortName (), DefaultBaudRate, DefaultParity, DefaultDataBits, DefaultStopBits)
47                 {
48                 }
49
50                 /*
51                   IContainer is in 2.0?
52                   public SerialPort (IContainer container) {
53                   }
54                 */
55
56                 public SerialPort (string portName) :
57                         this (portName, DefaultBaudRate, DefaultParity, DefaultDataBits, DefaultStopBits)
58                 {
59                 }
60
61                 public SerialPort (string portName, int baudRate) :
62                         this (portName, baudRate, DefaultParity, DefaultDataBits, DefaultStopBits)
63                 {
64                 }
65
66                 public SerialPort (string portName, int baudRate, Parity parity) :
67                         this (portName, baudRate, parity, DefaultDataBits, DefaultStopBits)
68                 {
69                 }
70
71                 public SerialPort (string portName, int baudRate, Parity parity, int dataBits) :
72                         this (portName, baudRate, parity, dataBits, DefaultStopBits)
73                 {
74                 }
75
76                 public SerialPort (string portName, int baudRate, Parity parity, int dataBits, StopBits stopBits) 
77                 {
78                         port_name = portName;
79                         baud_rate = baudRate;
80                         data_bits = dataBits;
81                         stop_bits = stopBits;
82                         this.parity = parity;
83                 }
84
85                 static string GetDefaultPortName ()
86                 {
87                         return default_port_name;
88                 }
89
90                 public Stream BaseStream {
91                         get {
92                                 if (!is_open)
93                                         throw new InvalidOperationException ();
94
95                                 return (Stream) stream;
96                         }
97                 }
98
99                 public int BaudRate {
100                         get {
101                                 return baud_rate;
102                         }
103                         set {
104                                 if (value <= 0)
105                                         throw new ArgumentOutOfRangeException ("value");
106                                 
107                                 if (is_open)
108                                         stream.SetAttributes (value, parity, data_bits, stop_bits, handshake);
109                                 
110                                 baud_rate = value;
111                         }
112                 }
113
114                 public bool BreakState {
115                         get {
116                                 return break_state;
117                         }
118                         set {
119                                 CheckOpen ();
120                                 if (value == break_state)
121                                         return; // Do nothing.
122
123                                 break_state = value;
124                                 // Update the state
125                         }
126                 }
127
128                 public int BytesToRead {
129                         get {
130                                 CheckOpen ();
131                                 return stream.BytesToRead;
132                         }
133                 }
134
135                 public int BytesToWrite {
136                         get {
137                                 CheckOpen ();
138                                 return stream.BytesToWrite;
139                         }
140                 }
141
142                 public bool CDHolding {
143                         get {
144                                 CheckOpen ();
145                                 return (stream.GetSignals () & SerialSignal.Cd) != 0;
146                         }
147                 }
148
149                 public bool CtsHolding {
150                         get {
151                                 CheckOpen ();
152                                 return (stream.GetSignals () & SerialSignal.Cts) != 0;
153                         }
154                 }
155
156                 public int DataBits {
157                         get {
158                                 return data_bits;
159                         }
160                         set {
161                                 if (value < 5 || value > 8)
162                                         throw new ArgumentOutOfRangeException ("value");
163
164                                 if (is_open)
165                                         stream.SetAttributes (baud_rate, parity, value, stop_bits, handshake);
166                                 
167                                 data_bits = value;
168                         }
169                 }
170
171                 public bool DiscardNull {
172                         get {
173                                 CheckOpen ();
174                                 throw new NotImplementedException ();
175                         }
176                         set {
177                                 CheckOpen ();
178                                 throw new NotImplementedException ();
179                         }
180                 }
181
182                 public bool DsrHolding {
183                         get {
184                                 CheckOpen ();
185                                 return (stream.GetSignals () & SerialSignal.Dsr) != 0;
186                         }
187                 }
188
189                 public bool DtrEnable {
190                         get {
191                                 return dtr_enable;
192                         }
193                         set {
194                                 if (value == dtr_enable)
195                                         return;
196                                 if (is_open)
197                                         stream.SetSignal (SerialSignal.Dtr, value);
198                                 
199                                 dtr_enable = value;
200                         }
201                 }
202
203                 public Encoding Encoding {
204                         get {
205                                 return encoding;
206                         }
207                         set {
208                                 if (value == null)
209                                         throw new ArgumentNullException ("value");
210
211                                 encoding = value;
212                         }
213                 }
214
215                 public Handshake Handshake {
216                         get {
217                                 return handshake;
218                         }
219                         set {
220                                 if (value < Handshake.None || value > Handshake.RequestToSendXOnXOff)
221                                         throw new ArgumentOutOfRangeException ("value");
222
223                                 if (is_open)
224                                         stream.SetAttributes (baud_rate, parity, data_bits, stop_bits, value);
225                                 
226                                 handshake = value;
227                         }
228                 }
229
230                 public bool IsOpen {
231                         get {
232                                 return is_open;
233                         }
234                 }
235
236                 public string NewLine {
237                         get {
238                                 return new_line;
239                         }
240                         set {
241                                 if (value == null)
242                                         throw new ArgumentNullException ("value");
243                                 
244                                 new_line = value;
245                         }
246                 }
247
248                 public Parity Parity {
249                         get {
250                                 return parity;
251                         }
252                         set {
253                                 if (value < Parity.None || value > Parity.Space)
254                                         throw new ArgumentOutOfRangeException ("value");
255
256                                 if (is_open)
257                                         stream.SetAttributes (baud_rate, value, data_bits, stop_bits, handshake);
258                                 
259                                 parity = value;
260                         }
261                 }
262
263                 public byte ParityReplace {
264                         get {
265                                 throw new NotImplementedException ();
266                         }
267                         set {
268                                 throw new NotImplementedException ();
269                         }
270                 }
271
272                 public string PortName {
273                         get {
274                                 return port_name;
275                         }
276                         set {
277                                 if (is_open)
278                                         throw new InvalidOperationException ("Port name cannot be set while port is open.");
279                                 if (value == null)
280                                         throw new ArgumentNullException ("value");
281                                 if (value.Length == 0 || value.StartsWith ("\\\\"))
282                                         throw new ArgumentException ("value");
283
284                                 port_name = value;
285                         }
286                 }
287
288                 public int ReadBufferSize {
289                         get {
290                                 return readBufferSize;
291                         }
292                         set {
293                                 if (is_open)
294                                         throw new InvalidOperationException ();
295                                 if (value <= 0)
296                                         throw new ArgumentOutOfRangeException ("value");
297                                 if (value <= DefaultReadBufferSize)
298                                         return;
299
300                                 readBufferSize = value;
301                         }
302                 }
303
304                 public int ReadTimeout {
305                         get {
306                                 return read_timeout;
307                         }
308                         set {
309                                 if (value <= 0 && value != InfiniteTimeout)
310                                         throw new ArgumentOutOfRangeException ("value");
311
312                                 if (is_open)
313                                         stream.ReadTimeout = value;
314                                 
315                                 read_timeout = value;
316                         }
317                 }
318
319                 public int ReceivedBytesThreshold {
320                         get {
321                                 throw new NotImplementedException ();
322                         }
323                         set {
324                                 if (value <= 0)
325                                         throw new ArgumentOutOfRangeException ("value");
326
327                                 throw new NotImplementedException ();
328                         }
329                 }
330
331                 public bool RtsEnable {
332                         get {
333                                 return rts_enable;
334                         }
335                         set {
336                                 if (value == rts_enable)
337                                         return;
338                                 if (is_open)
339                                         stream.SetSignal (SerialSignal.Rts, value);
340                                 
341                                 rts_enable = value;
342                         }
343                 }
344
345                 public StopBits StopBits {
346                         get {
347                                 return stop_bits;
348                         }
349                         set {
350                                 if (value < StopBits.One || value > StopBits.OnePointFive)
351                                         throw new ArgumentOutOfRangeException ("value");
352                                 
353                                 if (is_open)
354                                         stream.SetAttributes (baud_rate, parity, data_bits, value, handshake);
355                                 
356                                 stop_bits = value;
357                         }
358                 }
359
360                 public int WriteBufferSize {
361                         get {
362                                 return writeBufferSize;
363                         }
364                         set {
365                                 if (is_open)
366                                         throw new InvalidOperationException ();
367                                 if (value <= 0)
368                                         throw new ArgumentOutOfRangeException ("value");
369                                 if (value <= DefaultWriteBufferSize)
370                                         return;
371
372                                 writeBufferSize = value;
373                         }
374                 }
375
376                 public int WriteTimeout {
377                         get {
378                                 return write_timeout;
379                         }
380                         set {
381                                 if (value <= 0 && value != InfiniteTimeout)
382                                         throw new ArgumentOutOfRangeException ("value");
383
384                                 if (is_open)
385                                         stream.WriteTimeout = value;
386                                 
387                                 write_timeout = value;
388                         }
389                 }
390
391                 // methods
392
393                 public void Close ()
394                 {
395                         Dispose (false);
396                 }
397
398                 protected override void Dispose (bool disposing)
399                 {
400                         if (!is_open)
401                                 return;
402                         
403                         is_open = false;
404                         stream.Close ();
405                         stream = null;
406                 }
407
408                 public void DiscardInBuffer ()
409                 {
410                         CheckOpen ();
411                         stream.DiscardInBuffer ();
412                 }
413
414                 public void DiscardOutBuffer ()
415                 {
416                         CheckOpen ();
417                         stream.DiscardOutBuffer ();
418                 }
419
420                 public static string [] GetPortNames ()
421                 {
422                         int p = (int) Environment.OSVersion.Platform;
423                         if (p == 4 || p == 128) // Are we on Unix?
424                                 return Directory.GetFiles ("/dev/", "ttyS*");
425
426                         throw new NotImplementedException ("Detection of ports is not implemented for this platform yet.");
427                 }
428
429                 static bool IsWindows {
430                         get {
431                                 PlatformID id =  Environment.OSVersion.Platform;
432                                 return id == PlatformID.Win32Windows || id == PlatformID.Win32NT; // WinCE not supported
433                         }
434                 }
435
436                 public void Open ()
437                 {
438                         if (is_open)
439                                 throw new InvalidOperationException ("Port is already open");
440                         
441                         if (IsWindows) // Use windows kernel32 backend
442                                 stream = new WinSerialStream (port_name, baud_rate, data_bits, parity, stop_bits,
443                                                 handshake, read_timeout, write_timeout, readBufferSize, writeBufferSize);
444                         else // Use standard unix backend
445                                 stream = new SerialPortStream (port_name, baud_rate, data_bits, parity, stop_bits, dtr_enable,
446                                         rts_enable, handshake, read_timeout, write_timeout, readBufferSize, writeBufferSize);
447                         
448                         is_open = true;
449                 }
450
451                 public int Read (byte[] buffer, int offset, int count)
452                 {
453                         CheckOpen ();
454                         if (buffer == null)
455                                 throw new ArgumentNullException ("buffer");
456                         if (offset < 0 || offset >= buffer.Length)
457                                 throw new ArgumentOutOfRangeException ("offset");
458                         if (count < 0 || count > buffer.Length)
459                                 throw new ArgumentOutOfRangeException ("count");
460                         if (count > buffer.Length - offset)
461                                 throw new ArgumentException ("count > buffer.Length - offset");
462                         
463                         return stream.Read (buffer, offset, count);
464                 }
465
466                 public int Read (char[] buffer, int offset, int count)
467                 {
468                         CheckOpen ();
469                         if (buffer == null)
470                                 throw new ArgumentNullException ("buffer");
471                         if (offset < 0 || offset >= buffer.Length)
472                                 throw new ArgumentOutOfRangeException ("offset");
473                         if (count < 0 || count > buffer.Length)
474                                 throw new ArgumentOutOfRangeException ("count");
475                         if (count > buffer.Length - offset)
476                                 throw new ArgumentException ("count > buffer.Length - offset");
477
478                         byte [] bytes = encoding.GetBytes (buffer, offset, count);
479                         return stream.Read (bytes, 0, bytes.Length);
480                 }
481
482                 public int ReadByte ()
483                 {
484                         byte [] buff = new byte [1];
485                         if (Read (buff, 0, 1) > 0)
486                                 return buff [0];
487
488                         return -1;
489                 }
490
491                 public int ReadChar ()
492                 {
493                         throw new NotImplementedException ();
494                 }
495
496                 public string ReadExisting ()
497                 {
498                         throw new NotImplementedException ();
499                 }
500
501                 public string ReadLine ()
502                 {
503                         return ReadTo (new_line);
504                 }
505
506                 public string ReadTo (string value)
507                 {
508                         CheckOpen ();
509                         if (value == null)
510                                 throw new ArgumentNullException ("value");
511                         if (value.Length == 0)
512                                 throw new ArgumentException ("value");
513
514                         throw new NotImplementedException ();
515                 }
516
517                 public void Write (string str)
518                 {
519                         CheckOpen ();
520                         if (str == null)
521                                 throw new ArgumentNullException ("str");
522                         
523                         byte [] buffer = encoding.GetBytes (str);
524                         Write (buffer, 0, buffer.Length);
525                 }
526
527                 public void Write (byte [] buffer, int offset, int count)
528                 {
529                         CheckOpen ();
530                         if (buffer == null)
531                                 throw new ArgumentNullException ("buffer");
532                         if (offset < 0 || offset >= buffer.Length)
533                                 throw new ArgumentOutOfRangeException ("offset");
534                         if (count < 0 || count > buffer.Length)
535                                 throw new ArgumentOutOfRangeException ("count");
536                         if (count > buffer.Length - offset)
537                                 throw new ArgumentException ("count > buffer.Length - offset");
538
539                         stream.Write (buffer, offset, count);
540                 }
541
542                 public void Write (char [] buffer, int offset, int count)
543                 {
544                         CheckOpen ();
545                         if (buffer == null)
546                                 throw new ArgumentNullException ("buffer");
547                         if (offset < 0 || offset >= buffer.Length)
548                                 throw new ArgumentOutOfRangeException ("offset");
549                         if (count < 0 || count > buffer.Length)
550                                 throw new ArgumentOutOfRangeException ("count");
551                         if (count > buffer.Length - offset)
552                                 throw new ArgumentException ("count > buffer.Length - offset");
553
554                         byte [] bytes = encoding.GetBytes (buffer, offset, count);
555                         stream.Write (bytes, 0, bytes.Length);
556                 }
557
558                 public void WriteLine (string str)
559                 {
560                         Write (str + new_line);
561                 }
562
563                 void CheckOpen ()
564                 {
565                         if (!is_open)
566                                 throw new InvalidOperationException ("Specified port is not open.");
567                 }
568
569                 internal void OnErrorReceived (SerialErrorReceivedEventArgs args)
570                 {
571                         SerialErrorReceivedEventHandler handler =
572                                 (SerialErrorReceivedEventHandler) Events [error_received];
573
574                         if (handler != null)
575                                 handler (this, args);
576                 }
577
578                 internal void OnDataReceived (SerialDataReceivedEventArgs args)
579                 {
580                         SerialDataReceivedEventHandler handler =
581                                 (SerialDataReceivedEventHandler) Events [data_received];
582
583                         if (handler != null)
584                                 handler (this, args);
585                 }
586                 
587                 internal void OnDataReceived (SerialPinChangedEventArgs args)
588                 {
589                         SerialPinChangedEventHandler handler =
590                                 (SerialPinChangedEventHandler) Events [pin_changed];
591
592                         if (handler != null)
593                                 handler (this, args);
594                 }
595
596                 // events
597                 public event SerialErrorReceivedEventHandler ErrorReceived {
598                         add { Events.AddHandler (error_received, value); }
599                         remove { Events.RemoveHandler (error_received, value); }
600                 }
601                 
602                 public event SerialPinChangedEventHandler PinChanged {
603                         add { Events.AddHandler (pin_changed, value); }
604                         remove { Events.RemoveHandler (pin_changed, value); }
605                 }
606                 
607                 public event SerialDataReceivedEventHandler DataReceived {
608                         add { Events.AddHandler (data_received, value); }
609                         remove { Events.RemoveHandler (data_received, value); }
610                 }
611         }
612
613         public delegate void SerialDataReceivedEventHandler (object sender, SerialDataReceivedEventArgs e);
614         public delegate void SerialPinChangedEventHandler (object sender, SerialPinChangedEventArgs e);
615         public delegate void SerialErrorReceivedEventHandler (object sender, SerialErrorReceivedEventArgs e);
616
617 }
618
619 #endif