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.

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



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



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



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



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