Class: CCutrer::SerialPort

Inherits:
File
  • Object
show all
Defined in:
lib/ccutrer-serialport.rb,
lib/ccutrer/serial_port.rb,
lib/ccutrer/serial_port/osx.rb,
lib/ccutrer/serial_port/linux.rb,
lib/ccutrer/serial_port/posix.rb,
lib/ccutrer/serial_port/termios.rb,
lib/ccutrer/serial_port/version.rb

Defined Under Namespace

Modules: Termios

Constant Summary collapse

ON_WINDOWS =
RbConfig::CONFIG["host_os"] =~ /mswin|windows|mingw/i
ON_LINUX =
RbConfig::CONFIG["host_os"] =~ /linux/i
VERSION =
"1.2.0"

Instance Method Summary collapse

Constructor Details

#initialize(address, baud: nil, data_bits: nil, parity: nil, stop_bits: nil) ⇒ SerialPort

Returns a new instance of SerialPort.

Raises:

  • (IOError)


7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/ccutrer/serial_port.rb', line 7

def initialize(address, baud: nil, data_bits: nil, parity: nil, stop_bits: nil)
  super(address, IO::RDWR | IO::NOCTTY | IO::NONBLOCK)

  raise IOError, "Not a serial port" unless tty?

  @termios = Termios::Termios.new
  refresh

  # base config
  @termios[:c_iflag] = Termios::IGNPAR
  @termios[:c_oflag] = 0
  @termios[:c_cflag] =
    Termios::CREAD |
    Termios::CLOCAL
  @termios[:c_lflag] = 0

  @termios[:c_cc][Termios::VTIME] = 0
  @termios[:c_cc][Termios::VMIN] = 0

  configure do
    self.baud = baud if baud
    self.data_bits = data_bits if data_bits
    self.parity = parity if parity
    self.stop_bits = stop_bits if stop_bits
  end
  raise Errno::EINVAL if baud && baud != self.baud
  raise Errno::EINVAL if data_bits && data_bits != self.data_bits
  raise Errno::EINVAL if parity && parity != self.parity
  raise Errno::EINVAL if stop_bits && stop_bits != self.stop_bits
end

Instance Method Details

#baudObject



61
62
63
# File 'lib/ccutrer/serial_port.rb', line 61

def baud
  Termios.cfgetibaud(@termios)
end

#baud=(baud) ⇒ Object

Raises:

  • (ArgumentError)


65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/ccutrer/serial_port.rb', line 65

def baud=(baud)
  raise ArgumentError, "Invalid baud" unless Termios::BAUD_RATES.key?(baud)

  err = Termios.cfsetibaud(@termios, baud)
  raise SystemCallError, FFI.errno if err == -1

  err = Termios.cfsetobaud(@termios, baud)
  raise SystemCallError, FFI.errno if err == -1

  apply
  refresh
end

#configureObject



50
51
52
53
54
55
56
57
58
# File 'lib/ccutrer/serial_port.rb', line 50

def configure
  @configuring = true
  yield
  @configuring = false
  apply
  refresh
ensure
  @configuring = false
end

#data_bitsObject



96
97
98
# File 'lib/ccutrer/serial_port.rb', line 96

def data_bits
  Termios::DATA_BITS.invert[@termios[:c_cflag] & Termios::CSIZE]
end

#data_bits=(data_bits) ⇒ Object

Raises:

  • (ArgumentError)


100
101
102
103
104
105
106
107
# File 'lib/ccutrer/serial_port.rb', line 100

def data_bits=(data_bits)
  raise ArgumentError, "Invalid data bits" unless Termios::DATA_BITS.key?(data_bits)

  @termios[:c_cflag] &= ~Termios::CSIZE
  @termios[:c_cflag] |= Termios::DATA_BITS[data_bits]
  apply
  refresh
end

#getbyteObject



46
47
48
# File 'lib/ccutrer/serial_port.rb', line 46

def getbyte
  read(1)&.getbyte(0)
end

#inspectObject



135
136
137
# File 'lib/ccutrer/serial_port.rb', line 135

def inspect
  "#<#{self.class.name}:#{path} #{baud} #{data_bits}#{parity.to_s[0].upcase}#{stop_bits}>"
end

#parityObject



109
110
111
# File 'lib/ccutrer/serial_port.rb', line 109

def parity
  Termios::PARITY.invert[@termios[:c_cflag] & Termios::PARITY[:odd]]
end

#parity=(parity) ⇒ Object

Raises:

  • (ArgumentError)


113
114
115
116
117
118
119
120
# File 'lib/ccutrer/serial_port.rb', line 113

def parity=(parity)
  raise ArgumentError, "Invalid parity" unless Termios::PARITY.key?(parity)

  @termios[:c_cflag] &= ~Termios::PARITY[:odd]
  @termios[:c_cflag] |= Termios::PARITY[parity]
  apply
  refresh
end

#read(length, outbuf = nil) ⇒ Object

Read up to length bytes that are currently available without waiting.



39
40
41
42
43
44
# File 'lib/ccutrer/serial_port.rb', line 39

def read(length, outbuf = nil)
  result = read_nonblock(length, outbuf, exception: false)
  return result unless result == :wait_readable

  nil
end

#stop_bitsObject



122
123
124
# File 'lib/ccutrer/serial_port.rb', line 122

def stop_bits
  @termios[:c_cflag].nobits?(Termios::CSTOPB) ? 1 : 2
end

#stop_bits=(stop_bits) ⇒ Object

Raises:

  • (ArgumentError)


126
127
128
129
130
131
132
133
# File 'lib/ccutrer/serial_port.rb', line 126

def stop_bits=(stop_bits)
  raise ArgumentError, "Invalid stop bits" unless Termios::STOP_BITS.key?(stop_bits)

  @termios[:c_cflag] &= ~Termios::CSTOPB
  @termios[:c_cflag] |= Termios::STOP_BITS[stop_bits]
  apply
  refresh
end