Class: Cosmos::PosixSerialDriver

Inherits:
Object
  • Object
show all
Defined in:
lib/cosmos/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|nil) (defaults to: 10.0)

    Number of seconds to wait for the write to complete or nil to block

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

    Number of seconds to wait for the read to complete or nil to block

  • 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)


28
29
30
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
# File 'lib/cosmos/io/posix_serial_driver.rb', line 28

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



85
86
87
88
89
90
91
# File 'lib/cosmos/io/posix_serial_driver.rb', line 85

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



94
95
96
97
98
99
100
# File 'lib/cosmos/io/posix_serial_driver.rb', line 94

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



128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/cosmos/io/posix_serial_driver.rb', line 128

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



144
145
146
147
148
149
150
151
152
153
154
# File 'lib/cosmos/io/posix_serial_driver.rb', line 144

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



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/cosmos/io/posix_serial_driver.rb', line 103

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