//
// System.IO.Ports.SerialPortStream.cs
//
// Authors:
// Chris Toshok (toshok@ximian.com)
// Carlos Alberto Cortez (calberto.cortez@gmail.com)
//
// (c) Copyright 2006 Novell, Inc. (http://www.novell.com)
//
#if NET_2_0
using System;
using System.IO;
using System.Runtime.InteropServices;
namespace System.IO.Ports{
class SerialPortStream : Stream, ISerialStream, IDisposable
{
int fd;
int read_timeout;
int write_timeout;
bool disposed;
[DllImport ("MonoPosixHelper", SetLastError = true)]
static extern int open_serial (string portName);
public 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)
{
fd = open_serial (portName);
if (fd == -1)
ThrowIOException ();
if (!set_attributes (fd, baudRate, parity, dataBits, stopBits, handshake))
ThrowIOException (); // Probably Win32Exc for compatibility
read_timeout = readTimeout;
write_timeout = writeTimeout;
SetSignal (SerialSignal.Dtr, dtrEnable);
if (handshake != Handshake.RequestToSend &&
handshake != Handshake.RequestToSendXOnXOff)
SetSignal (SerialSignal.Rts, rtsEnable);
}
public override bool CanRead {
get {
return true;
}
}
public override bool CanSeek {
get {
return false;
}
}
public override bool CanWrite {
get {
return true;
}
}
public override bool CanTimeout {
get {
return true;
}
}
public override int ReadTimeout {
get {
return read_timeout;
}
set {
if (value < 0 && value != SerialPort.InfiniteTimeout)
throw new ArgumentOutOfRangeException ("value");
read_timeout = value;
}
}
public override int WriteTimeout {
get {
return write_timeout;
}
set {
if (value < 0 && value != SerialPort.InfiniteTimeout)
throw new ArgumentOutOfRangeException ("value");
write_timeout = value;
}
}
public override long Length {
get {
throw new NotSupportedException ();
}
}
public override long Position {
get {
throw new NotSupportedException ();
}
set {
throw new NotSupportedException ();
}
}
public override void Flush ()
{
// If used, this _could_ flush the serial port
// buffer (not the SerialPort class buffer)
}
[DllImport ("MonoPosixHelper", SetLastError = true)]
static extern int read_serial (int fd, byte [] buffer, int offset, int count);
[DllImport ("MonoPosixHelper", SetLastError = true)]
static extern bool poll_serial (int fd, out int error, int timeout);
public override int Read ([In,Out] byte[] buffer, int offset, int count)
{
CheckDisposed ();
if (buffer == null)
throw new ArgumentNullException ("buffer");
if (offset < 0 || count < 0)
throw new ArgumentOutOfRangeException ("offset or count less than zero.");
if (buffer.Length - offset < count )
throw new ArgumentException ("offset+count",
"The size of the buffer is less than offset + count.");
int error;
bool poll_result = poll_serial (fd, out error, read_timeout);
if (error == -1)
ThrowIOException ();
if (!poll_result) {
// see bug 79735 http://bugzilla.ximian.com/show_bug.cgi?id=79735
// should the next line read: return -1;
throw new TimeoutException();
}
int result = read_serial (fd, buffer, offset, count);
if (result == -1)
ThrowIOException ();
return result;
}
public override long Seek (long offset, SeekOrigin origin)
{
throw new NotSupportedException ();
}
public override void SetLength (long value)
{
throw new NotSupportedException ();
}
[DllImport ("MonoPosixHelper", SetLastError = true)]
static extern int write_serial (int fd, byte [] buffer, int offset, int count, int timeout);
public override void Write (byte[] buffer, int offset, int count)
{
CheckDisposed ();
if (buffer == null)
throw new ArgumentNullException ("buffer");
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.");
// FIXME: this reports every write error as timeout
if (write_serial (fd, buffer, offset, count, write_timeout) < 0)
throw new TimeoutException("The operation has timed-out");
}
protected override void Dispose (bool disposing)
{
if (disposed)
return;
disposed = true;
if (close_serial (fd) != 0)
ThrowIOException();
}
[DllImport ("MonoPosixHelper", SetLastError = true)]
static extern int close_serial (int fd);
public override void Close ()
{
((IDisposable) this).Dispose ();
}
void IDisposable.Dispose ()
{
Dispose (true);
GC.SuppressFinalize (this);
}
~SerialPortStream ()
{
Dispose (false);
}
void CheckDisposed ()
{
if (disposed)
throw new ObjectDisposedException (GetType ().FullName);
}
[DllImport ("MonoPosixHelper", SetLastError = true)]
static extern bool set_attributes (int fd, int baudRate, Parity parity, int dataBits, StopBits stopBits, Handshake handshake);
public void SetAttributes (int baud_rate, Parity parity, int data_bits, StopBits sb, Handshake hs)
{
if (!set_attributes (fd, baud_rate, parity, data_bits, sb, hs))
ThrowIOException ();
}
[DllImport("MonoPosixHelper", SetLastError = true)]
static extern int get_bytes_in_buffer (int fd, int input);
public int BytesToRead {
get {
int result = get_bytes_in_buffer (fd, 1);
if (result == -1)
ThrowIOException ();
return result;
}
}
public int BytesToWrite {
get {
int result = get_bytes_in_buffer (fd, 0);
if (result == -1)
ThrowIOException ();
return result;
}
}
[DllImport ("MonoPosixHelper", SetLastError = true)]
static extern int discard_buffer (int fd, bool inputBuffer);
public void DiscardInBuffer ()
{
if (discard_buffer (fd, true) != 0)
ThrowIOException();
}
public void DiscardOutBuffer ()
{
if (discard_buffer (fd, false) != 0)
ThrowIOException();
}
[DllImport ("MonoPosixHelper", SetLastError = true)]
static extern SerialSignal get_signals (int fd, out int error);
public SerialSignal GetSignals ()
{
int error;
SerialSignal signals = get_signals (fd, out error);
if (error == -1)
ThrowIOException ();
return signals;
}
[DllImport ("MonoPosixHelper", SetLastError = true)]
static extern int set_signal (int fd, SerialSignal signal, bool value);
public void SetSignal (SerialSignal signal, bool value)
{
if (signal < SerialSignal.Cd || signal > SerialSignal.Rts ||
signal == SerialSignal.Cd ||
signal == SerialSignal.Cts ||
signal == SerialSignal.Dsr)
throw new Exception ("Invalid internal value");
if (set_signal (fd, signal, value) == -1)
ThrowIOException ();
}
[DllImport ("MonoPosixHelper", SetLastError = true)]
static extern int breakprop (int fd);
public void SetBreakState (bool value)
{
if (value)
if (breakprop (fd) == -1)
ThrowIOException ();
}
[DllImport ("libc")]
static extern IntPtr strerror (int errnum);
static void ThrowIOException ()
{
int errnum = Marshal.GetLastWin32Error ();
string error_message = Marshal.PtrToStringAnsi (strerror (errnum));
throw new IOException (error_message);
}
}
}
#endif
|