181b81b4a4
Former-commit-id: cf92446697332992ec36726e78eb8703e1f259d7
336 lines
7.9 KiB
C#
336 lines
7.9 KiB
C#
//
|
|
// 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)
|
|
//
|
|
// Slightly modified by Konrad M. Kruczynski (added baud rate value checking)
|
|
|
|
|
|
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 ();
|
|
|
|
TryBaudRate (baudRate);
|
|
|
|
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 ()
|
|
{
|
|
try {
|
|
Dispose (false);
|
|
} catch (IOException) {
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
[DllImport ("MonoPosixHelper")]
|
|
static extern bool is_baud_rate_legal (int baud_rate);
|
|
|
|
private void TryBaudRate (int baudRate)
|
|
{
|
|
if (!is_baud_rate_legal (baudRate))
|
|
{
|
|
// this kind of exception to be compatible with MSDN API
|
|
throw new ArgumentOutOfRangeException ("baudRate",
|
|
"Given baud rate is not supported on this platform.");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|