New tests.
[mono.git] / mcs / class / System / System.IO.Ports / SerialPort.cs
index 1131c32651792304e62d043dc69da6dc1308dbe3..b5ac97e046eea1c8bbc656844f3ae557a0271a4e 100644 (file)
 using System;
 using System.Collections.Generic;
 using System.ComponentModel;
+using System.Diagnostics;
 using System.Text;
 using System.Runtime.InteropServices;
+using Microsoft.Win32;
 
 namespace System.IO.Ports
 {
+       [MonitoringDescription ("")]
        public class SerialPort : Component
        {
                public const int InfiniteTimeout = -1;
@@ -57,19 +60,16 @@ namespace System.IO.Ports
                object error_received = new object ();
                object data_received = new object ();
                object pin_changed = new object ();
-               
-               static string default_port_name = "ttyS0";
 
                public SerialPort () : 
                        this (GetDefaultPortName (), DefaultBaudRate, DefaultParity, DefaultDataBits, DefaultStopBits)
                {
                }
 
-               /*
-                 IContainer is in 2.0?
-                 public SerialPort (IContainer container) {
-                 }
-               */
+               public SerialPort (IContainer container) : this ()
+               {
+                       // TODO: What to do here?
+               }
 
                public SerialPort (string portName) :
                        this (portName, DefaultBaudRate, DefaultParity, DefaultDataBits, DefaultStopBits)
@@ -102,19 +102,30 @@ namespace System.IO.Ports
 
                static string GetDefaultPortName ()
                {
-                       return default_port_name;
+                       string[] ports = GetPortNames();
+                       if (ports.Length > 0) {
+                               return ports[0];
+                       } else {
+                               int p = (int)Environment.OSVersion.Platform;
+                               if (p == 4 || p == 128 || p == 6)
+                                       return "ttyS0"; // Default for Unix
+                               else
+                                       return "COM1"; // Default for Windows
+                       }
                }
 
+               [Browsable (false)]
+               [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
                public Stream BaseStream {
                        get {
-                               if (!is_open)
-                                       throw new InvalidOperationException ();
-
+                               CheckOpen ();
                                return (Stream) stream;
                        }
                }
 
                [DefaultValueAttribute (DefaultBaudRate)]
+               [Browsable (true)]
+               [MonitoringDescription ("")]
                public int BaudRate {
                        get {
                                return baud_rate;
@@ -130,6 +141,8 @@ namespace System.IO.Ports
                        }
                }
 
+               [Browsable (false)]
+               [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
                public bool BreakState {
                        get {
                                return break_state;
@@ -144,6 +157,8 @@ namespace System.IO.Ports
                        }
                }
 
+               [Browsable (false)]
+               [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
                public int BytesToRead {
                        get {
                                CheckOpen ();
@@ -151,6 +166,8 @@ namespace System.IO.Ports
                        }
                }
 
+               [Browsable (false)]
+               [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
                public int BytesToWrite {
                        get {
                                CheckOpen ();
@@ -158,6 +175,8 @@ namespace System.IO.Ports
                        }
                }
 
+               [Browsable (false)]
+               [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
                public bool CDHolding {
                        get {
                                CheckOpen ();
@@ -165,6 +184,8 @@ namespace System.IO.Ports
                        }
                }
 
+               [Browsable (false)]
+               [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
                public bool CtsHolding {
                        get {
                                CheckOpen ();
@@ -173,6 +194,8 @@ namespace System.IO.Ports
                }
 
                [DefaultValueAttribute(DefaultDataBits)]
+               [Browsable (true)]
+               [MonitoringDescription ("")]
                public int DataBits {
                        get {
                                return data_bits;
@@ -189,17 +212,23 @@ namespace System.IO.Ports
                }
 
                [MonoTODO("Not implemented")]
+               [Browsable (true)]
+               [MonitoringDescription ("")]
+               [DefaultValue (false)]
                public bool DiscardNull {
                        get {
-                               CheckOpen ();
                                throw new NotImplementedException ();
                        }
                        set {
-                               CheckOpen ();
+                               // LAMESPEC: Msdn states that an InvalidOperationException exception
+                               // is fired if the port is not open, which is *not* happening.
+
                                throw new NotImplementedException ();
                        }
                }
 
+               [Browsable (false)]
+               [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
                public bool DsrHolding {
                        get {
                                CheckOpen ();
@@ -208,6 +237,8 @@ namespace System.IO.Ports
                }
 
                [DefaultValueAttribute(false)]
+               [Browsable (true)]
+               [MonitoringDescription ("")]
                public bool DtrEnable {
                        get {
                                return dtr_enable;
@@ -222,6 +253,9 @@ namespace System.IO.Ports
                        }
                }
 
+               [Browsable (false)]
+               [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
+               [MonitoringDescription ("")]
                public Encoding Encoding {
                        get {
                                return encoding;
@@ -235,6 +269,8 @@ namespace System.IO.Ports
                }
 
                [DefaultValueAttribute(Handshake.None)]
+               [Browsable (true)]
+               [MonitoringDescription ("")]
                public Handshake Handshake {
                        get {
                                return handshake;
@@ -250,6 +286,7 @@ namespace System.IO.Ports
                        }
                }
 
+               [Browsable (false)]
                public bool IsOpen {
                        get {
                                return is_open;
@@ -257,6 +294,8 @@ namespace System.IO.Ports
                }
 
                [DefaultValueAttribute("\n")]
+               [Browsable (false)]
+               [MonitoringDescription ("")]
                public string NewLine {
                        get {
                                return new_line;
@@ -264,12 +303,16 @@ namespace System.IO.Ports
                        set {
                                if (value == null)
                                        throw new ArgumentNullException ("value");
+                               if (value.Length == 0)
+                                       throw new ArgumentException ("NewLine cannot be null or empty.", "value");
                                
                                new_line = value;
                        }
                }
 
                [DefaultValueAttribute(DefaultParity)]
+               [Browsable (true)]
+               [MonitoringDescription ("")]
                public Parity Parity {
                        get {
                                return parity;
@@ -286,6 +329,9 @@ namespace System.IO.Ports
                }
 
                [MonoTODO("Not implemented")]
+               [Browsable (true)]
+               [MonitoringDescription ("")]
+               [DefaultValue (63)]
                public byte ParityReplace {
                        get {
                                throw new NotImplementedException ();
@@ -296,6 +342,9 @@ namespace System.IO.Ports
                }
 
                
+               [Browsable (true)]
+               [MonitoringDescription ("")]
+               [DefaultValue ("COM1")] // silly Windows-ism. We should ignore it.
                public string PortName {
                        get {
                                return port_name;
@@ -313,6 +362,8 @@ namespace System.IO.Ports
                }
 
                [DefaultValueAttribute(DefaultReadBufferSize)]
+               [Browsable (true)]
+               [MonitoringDescription ("")]
                public int ReadBufferSize {
                        get {
                                return readBufferSize;
@@ -330,6 +381,8 @@ namespace System.IO.Ports
                }
 
                [DefaultValueAttribute(InfiniteTimeout)]
+               [Browsable (true)]
+               [MonitoringDescription ("")]
                public int ReadTimeout {
                        get {
                                return read_timeout;
@@ -347,6 +400,8 @@ namespace System.IO.Ports
 
                [MonoTODO("Not implemented")]
                [DefaultValueAttribute(1)]
+               [Browsable (true)]
+               [MonitoringDescription ("")]
                public int ReceivedBytesThreshold {
                        get {
                                throw new NotImplementedException ();
@@ -360,6 +415,8 @@ namespace System.IO.Ports
                }
 
                [DefaultValueAttribute(false)]
+               [Browsable (true)]
+               [MonitoringDescription ("")]
                public bool RtsEnable {
                        get {
                                return rts_enable;
@@ -375,6 +432,8 @@ namespace System.IO.Ports
                }
 
                [DefaultValueAttribute(DefaultStopBits)]
+               [Browsable (true)]
+               [MonitoringDescription ("")]
                public StopBits StopBits {
                        get {
                                return stop_bits;
@@ -391,6 +450,8 @@ namespace System.IO.Ports
                }
 
                [DefaultValueAttribute(DefaultWriteBufferSize)]
+               [Browsable (true)]
+               [MonitoringDescription ("")]
                public int WriteBufferSize {
                        get {
                                return writeBufferSize;
@@ -408,6 +469,8 @@ namespace System.IO.Ports
                }
 
                [DefaultValueAttribute(InfiniteTimeout)]
+               [Browsable (true)]
+               [MonitoringDescription ("")]
                public int WriteTimeout {
                        get {
                                return write_timeout;
@@ -427,7 +490,7 @@ namespace System.IO.Ports
 
                public void Close ()
                {
-                       Dispose (false);
+                       Dispose (true);
                }
 
                protected override void Dispose (bool disposing)
@@ -436,7 +499,9 @@ namespace System.IO.Ports
                                return;
                        
                        is_open = false;
-                       stream.Close ();
+                       // Do not close the base stream when the finalizer is run; the managed code can still hold a reference to it.
+                       if (disposing)
+                               stream.Close ();
                        stream = null;
                }
 
@@ -455,20 +520,46 @@ namespace System.IO.Ports
                public static string [] GetPortNames ()
                {
                        int p = (int) Environment.OSVersion.Platform;
+                       List<string> serial_ports = new List<string>();
                        
                        // Are we on Unix?
-                       if (p == 4 || p == 128){
-                               string [] ttys = Directory.GetFiles ("/dev/", "tty*");
-                               List<string> serial_ports = new List<string> ();
-                               
-                               foreach (string dev in ttys){
-                                       if (dev.StartsWith ("/dev/ttyS") || dev.StartsWith ("/dev/ttyUSB"))
-                                               serial_ports.Add (dev);
-                                               
+                       if (p == 4 || p == 128 || p == 6) {
+                               string[] ttys = Directory.GetFiles("/dev/", "tty*");
+                               bool linux_style = false;
+
+                               //
+                               // Probe for Linux-styled devices: /dev/ttyS* or /dev/ttyUSB*
+                               // 
+                               foreach (string dev in ttys) {
+                                       if (dev.StartsWith("/dev/ttyS") || dev.StartsWith("/dev/ttyUSB")){
+                                               linux_style = true;
+                                               break;
+                                       }
+                               }
+
+                               foreach (string dev in ttys) {
+                                       if (linux_style){
+                                               if (dev.StartsWith("/dev/ttyS") || dev.StartsWith("/dev/ttyUSB"))
+                                                       serial_ports.Add (dev);
+                                       } else {
+                                               if (dev != "/dev/tty" && dev.StartsWith ("/dev/tty") && !dev.StartsWith ("/dev/ttyC"))
+                                                       serial_ports.Add (dev);
+                                       }
+                               }
+                       } else {
+                               using (RegistryKey subkey = Registry.LocalMachine.OpenSubKey("HARDWARE\\DEVICEMAP\\SERIALCOMM"))
+                               {
+                                       if (subkey != null) {
+                                               string[] names = subkey.GetValueNames();
+                                               foreach (string value in names) {
+                                                       string port = subkey.GetValue(value, "").ToString();
+                                                       if (port != "")
+                                                               serial_ports.Add(port);
+                                               }
+                                       }
                                }
-                               return serial_ports.ToArray ();
                        }
-                       throw new NotImplementedException ("Detection of ports is not implemented for this platform yet.");
+                       return serial_ports.ToArray();
                }
 
                static bool IsWindows {
@@ -485,8 +576,8 @@ namespace System.IO.Ports
                        
 #if !TARGET_JVM
                        if (IsWindows) // Use windows kernel32 backend
-                               stream = new WinSerialStream (port_name, baud_rate, data_bits, parity, stop_bits,
-                                               handshake, read_timeout, write_timeout, readBufferSize, writeBufferSize);
+                               stream = new WinSerialStream (port_name, baud_rate, data_bits, parity, stop_bits, dtr_enable,
+                                       rts_enable, handshake, read_timeout, write_timeout, readBufferSize, writeBufferSize);
                        else // Use standard unix backend
 #endif
                                stream = new SerialPortStream (port_name, baud_rate, data_bits, parity, stop_bits, dtr_enable,
@@ -510,8 +601,7 @@ namespace System.IO.Ports
                        return stream.Read (buffer, offset, count);
                }
 
-               [Obsolete("Read of char buffers is currently broken")]
-               [MonoTODO("This is broken")]
+               [MonoTODO("Read of char buffers is currently broken")]
                public int Read (char[] buffer, int offset, int count)
                {
                        CheckOpen ();
@@ -578,17 +668,7 @@ namespace System.IO.Ports
 
                public string ReadLine ()
                {
-                       CheckOpen ();
-                       List<byte> bytes_read = new List<byte>();
-                       byte [] buff = new byte [1];
-                       
-                       while (true){
-                               int n = stream.Read (buff, 0, 1);
-                               if (n == -1 || buff [0] == '\n')
-                                       break;
-                               bytes_read.Add (buff [0]);
-                       } 
-                       return new String (encoding.GetChars (bytes_read.ToArray ()));
+                       return ReadTo (new_line);
                }
 
                public string ReadTo (string value)
@@ -651,12 +731,13 @@ namespace System.IO.Ports
                        CheckOpen ();
                        if (buffer == null)
                                throw new ArgumentNullException ("buffer");
-                       if (offset < 0 || offset >= buffer.Length)
-                               throw new ArgumentOutOfRangeException ("offset");
-                       if (count < 0 || count > buffer.Length)
-                               throw new ArgumentOutOfRangeException ("count");
-                       if (count > buffer.Length - offset)
-                               throw new ArgumentException ("count > buffer.Length - offset");
+
+                       if (offset < 0 || count < 0)
+                               throw new ArgumentOutOfRangeException ();
+
+                       if (buffer.Length - offset < count)
+                               throw new ArgumentException ("offset+count",
+                                                            "The size of the buffer is less than offset + count.");
 
                        byte [] bytes = encoding.GetBytes (buffer, offset, count);
                        stream.Write (bytes, 0, bytes.Length);
@@ -701,16 +782,19 @@ namespace System.IO.Ports
                }
 
                // events
+               [MonitoringDescription ("")]
                public event SerialErrorReceivedEventHandler ErrorReceived {
                        add { Events.AddHandler (error_received, value); }
                        remove { Events.RemoveHandler (error_received, value); }
                }
                
+               [MonitoringDescription ("")]
                public event SerialPinChangedEventHandler PinChanged {
                        add { Events.AddHandler (pin_changed, value); }
                        remove { Events.RemoveHandler (pin_changed, value); }
                }
                
+               [MonitoringDescription ("")]
                public event SerialDataReceivedEventHandler DataReceived {
                        add { Events.AddHandler (data_received, value); }
                        remove { Events.RemoveHandler (data_received, value); }