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) ⇒ PosixSerialDriver

Returns a new instance of PosixSerialDriver.

Parameters:

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

    Name of the serial port

  • (defaults to: 9600)

    Serial port baud rate

  • (defaults to: :NONE)

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

  • (defaults to: 1)

    Number of stop bits

  • (defaults to: 10.0)

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

  • (defaults to: nil)

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

Raises:



21
22
23
24
25
26
27
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
# File 'lib/cosmos/io/posix_serial_driver.rb', line 21

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

  # 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 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::CS8 # 8-bit bytes
  cflags |= Termios::CLOCAL # Ignore Modem Control Lines
  cflags |= Termios::CSTOPB if stop_bits == 2
  cflags |= Termios::PARENB if parity
  cflags |= Termios::PADODD if parity == :ODD
  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



73
74
75
76
77
78
79
# File 'lib/cosmos/io/posix_serial_driver.rb', line 73

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:

  • Whether the serial port has been closed



82
83
84
85
86
87
88
# File 'lib/cosmos/io/posix_serial_driver.rb', line 82

def closed?
  if @handle
    false
  else
    true
  end
end

#readString

Returns Binary data read from the serial port.

Returns:

  • Binary data read from the serial port



115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/cosmos/io/posix_serial_driver.rb', line 115

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:

  • Binary data read from the serial port



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

def read_nonblock
  data = ''

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

  data
end

#write(data) ⇒ Object

Parameters:

  • Binary data to write to the serial port



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/cosmos/io/posix_serial_driver.rb', line 91

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