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)] open_serial(string portName)27 static extern int open_serial (string portName); 28 SerialPortStream(string portName, int baudRate, int dataBits, Parity parity, StopBits stopBits, bool dtrEnable, bool rtsEnable, Handshake handshake, int readTimeout, int writeTimeout, int readBufferSize, int writeBufferSize)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 Flush()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)] read_serial(int fd, byte [] buffer, int offset, int count)122 static extern int read_serial (int fd, byte [] buffer, int offset, int count); 123 124 125 [DllImport ("MonoPosixHelper", SetLastError = true)] poll_serial(int fd, out int error, int timeout)126 static extern bool poll_serial (int fd, out int error, int timeout); 127 Read([In,Out] byte[] buffer, int offset, int count)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 Seek(long offset, SeekOrigin origin)157 public override long Seek (long offset, SeekOrigin origin) 158 { 159 throw new NotSupportedException (); 160 } 161 SetLength(long value)162 public override void SetLength (long value) 163 { 164 throw new NotSupportedException (); 165 } 166 167 [DllImport ("MonoPosixHelper", SetLastError = true)] write_serial(int fd, byte [] buffer, int offset, int count, int timeout)168 static extern int write_serial (int fd, byte [] buffer, int offset, int count, int timeout); 169 Write(byte[] buffer, int offset, int count)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 Dispose(bool disposing)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)] close_serial(int fd)199 static extern int close_serial (int fd); 200 Close()201 public override void Close () 202 { 203 ((IDisposable) this).Dispose (); 204 } 205 IDisposable.Dispose()206 void IDisposable.Dispose () 207 { 208 Dispose (true); 209 GC.SuppressFinalize (this); 210 } 211 ~SerialPortStream()212 ~SerialPortStream () 213 { 214 try { 215 Dispose (false); 216 } catch (IOException) { 217 } 218 } 219 CheckDisposed()220 void CheckDisposed () 221 { 222 if (disposed) 223 throw new ObjectDisposedException (GetType ().FullName); 224 } 225 226 [DllImport ("MonoPosixHelper", SetLastError = true)] set_attributes(int fd, int baudRate, Parity parity, int dataBits, StopBits stopBits, Handshake handshake)227 static extern bool set_attributes (int fd, int baudRate, Parity parity, int dataBits, StopBits stopBits, Handshake handshake); 228 SetAttributes(int baud_rate, Parity parity, int data_bits, StopBits sb, Handshake hs)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)] get_bytes_in_buffer(int fd, int input)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)] discard_buffer(int fd, bool inputBuffer)257 static extern int discard_buffer (int fd, bool inputBuffer); 258 DiscardInBuffer()259 public void DiscardInBuffer () 260 { 261 if (discard_buffer (fd, true) != 0) 262 ThrowIOException(); 263 } 264 DiscardOutBuffer()265 public void DiscardOutBuffer () 266 { 267 if (discard_buffer (fd, false) != 0) 268 ThrowIOException(); 269 } 270 271 [DllImport ("MonoPosixHelper", SetLastError = true)] get_signals(int fd, out int error)272 static extern SerialSignal get_signals (int fd, out int error); 273 GetSignals()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)] set_signal(int fd, SerialSignal signal, bool value)285 static extern int set_signal (int fd, SerialSignal signal, bool value); 286 SetSignal(SerialSignal signal, bool value)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)] breakprop(int fd)300 static extern int breakprop (int fd); 301 SetBreakState(bool value)302 public void SetBreakState (bool value) 303 { 304 if (value) 305 if (breakprop (fd) == -1) 306 ThrowIOException (); 307 } 308 309 [DllImport ("libc")] strerror(int errnum)310 static extern IntPtr strerror (int errnum); 311 ThrowIOException()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")] is_baud_rate_legal(int baud_rate)321 static extern bool is_baud_rate_legal (int baud_rate); 322 TryBaudRate(int baudRate)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 336