Class: OpenC3::PosixSerialDriver

Inherits:
Object
  • Object
show all
Defined in:
lib/openc3/io/posix_serial_driver.rb

Overview

Serial driver for use on Posix serial ports found on UNIX based systems

Instance Method Summary collapse

Constructor Details

#initialize(port_name = '/dev/ttyS0', baud_rate = 9600, parity = :NONE, stop_bits = 1, write_timeout = 10.0, read_timeout = nil, flow_control = :NONE, data_bits = 8) ⇒ PosixSerialDriver

Returns a new instance of PosixSerialDriver.

Parameters:

  • port_name (String) (defaults to: '/dev/ttyS0')

    Name of the serial port

  • baud_rate (Integer) (defaults to: 9600)

    Serial port baud rate

  • parity (Symbol) (defaults to: :NONE)

    Must be one of :EVEN, :ODD or :NONE

  • stop_bits (Integer) (defaults to: 1)

    Number of stop bits

  • write_timeout (Float) (defaults to: 10.0)

    Seconds to wait before aborting writes

  • read_timeout (Float|nil) (defaults to: nil)

    Seconds to wait before aborting reads. Pass nil to block until the read is complete.

  • flow_control (Symbol) (defaults to: :NONE)

    Currently supported :NONE and :RTSCTS (default :NONE)

  • data_bits (Integer) (defaults to: 8)

    Number of data bits (default 8)

Raises:

  • (ArgumentError)


31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/openc3/io/posix_serial_driver.rb', line 31

def initialize(port_name = '/dev/ttyS0',
               baud_rate = 9600,
               parity = :NONE,
               stop_bits = 1,
               write_timeout = 10.0,
               read_timeout = nil,
               flow_control = :NONE,
               data_bits = 8)

  # Convert Baud Rate into Termios constant
  begin
    baud_rate = Object.const_get("Termios::B#{baud_rate}")
  rescue NameError
    raise(ArgumentError, "Invalid Baud Rate, Not Defined by Termios: #{baud_rate}")
  end

  # Verify Parameters
  raise(ArgumentError, "Invalid Data Bits: #{data_bits}") unless [5, 6, 7, 8].include?(data_bits)
  raise(ArgumentError, "Invalid parity: #{parity}") if parity and !SerialDriver::VALID_PARITY.include?(parity)
  raise(ArgumentError, "Invalid Stop Bits: #{stop_bits}") unless [1, 2].include?(stop_bits)

  @write_timeout = write_timeout
  @read_timeout = read_timeout

  parity = nil if parity == :NONE

  # Open the serial Port
  @handle = Kernel.open(port_name, File::RDWR | File::NONBLOCK)
  flags = @handle.fcntl(Fcntl::F_GETFL, 0)
  @handle.fcntl(Fcntl::F_SETFL, flags & ~File::NONBLOCK)
  @handle.extend Termios

  # Configure the serial Port
  tio = Termios.new_termios()
  iflags = 0
  iflags |= Termios::IGNPAR unless parity
  cflags = 0
  cflags |= Termios::CREAD # Enable receiver
  cflags |= Termios.const_get("CS#{data_bits}") # data bits
  cflags |= Termios::CLOCAL # Ignore Modem Control Lines
  cflags |= Termios::CSTOPB if stop_bits == 2
  cflags |= Termios::PARENB if parity
  cflags |= Termios::PARODD if parity == :ODD
  cflags |= Termios::CRTSCTS if flow_control == :RTSCTS
  tio.iflag = iflags
  tio.oflag = 0
  tio.cflag = cflags
  tio.lflag = 0
  tio.cc[Termios::VTIME] = 0
  tio.cc[Termios::VMIN] = 1
  tio.ispeed = baud_rate
  tio.ospeed = baud_rate
  @handle.tcflush(Termios::TCIOFLUSH)
  @handle.tcsetattr(Termios::TCSANOW, tio)
end

Instance Method Details

#closeObject

Disconnects the driver from the comm port



88
89
90
91
92
93
94
# File 'lib/openc3/io/posix_serial_driver.rb', line 88

def close
  if @handle
    # Close the serial Port
    @handle.close
    @handle = nil
  end
end

#closed?Boolean

Returns Whether the serial port has been closed.

Returns:

  • (Boolean)

    Whether the serial port has been closed



97
98
99
100
101
102
103
# File 'lib/openc3/io/posix_serial_driver.rb', line 97

def closed?
  if @handle
    false
  else
    true
  end
end

#readString

Returns Binary data read from the serial port.

Returns:

  • (String)

    Binary data read from the serial port



131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/openc3/io/posix_serial_driver.rb', line 131

def read
  begin
    data = @handle.read_nonblock(65535)
  rescue Errno::EAGAIN, Errno::EWOULDBLOCK
    result = IO.fast_select([@handle], nil, nil, @read_timeout)
    if result
      retry
    else
      raise Timeout::Error, "Read Timeout"
    end
  end

  data
end

#read_nonblockString

Returns Binary data read from the serial port.

Returns:

  • (String)

    Binary data read from the serial port



147
148
149
150
151
152
153
154
155
156
157
# File 'lib/openc3/io/posix_serial_driver.rb', line 147

def read_nonblock
  data = ''

  begin
    data = @handle.read_nonblock(65535)
  rescue Errno::EAGAIN, Errno::EWOULDBLOCK
    # Do Nothing
  end

  data
end

#write(data) ⇒ Object

Parameters:

  • data (String)

    Binary data to write to the serial port



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/openc3/io/posix_serial_driver.rb', line 106

def write(data)
  num_bytes_to_send = data.length
  total_bytes_sent = 0
  bytes_sent = 0
  data_to_send = data

  loop do
    begin
      bytes_sent = @handle.write_nonblock(data_to_send)
    rescue Errno::EAGAIN, Errno::EWOULDBLOCK
      result = IO.fast_select(nil, [@handle], nil, @write_timeout)
      if result
        retry
      else
        raise Timeout::Error, "Write Timeout"
      end
    end
    total_bytes_sent += bytes_sent
    break if total_bytes_sent >= num_bytes_to_send

    data_to_send = data[total_bytes_sent..-1]
  end
end