beaglebone 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +674 -0
- data/README.md +6 -0
- data/beaglebone.gemspec +12 -0
- data/examples/ain.rb +92 -0
- data/examples/gpio.rb +196 -0
- data/examples/i2c.rb +110 -0
- data/examples/pwm.rb +63 -0
- data/examples/shiftregister.rb +12 -0
- data/examples/spi.rb +62 -0
- data/examples/uart.rb +64 -0
- data/lib/beaglebone/ain.rb +480 -0
- data/lib/beaglebone/beaglebone.rb +287 -0
- data/lib/beaglebone/gpio.rb +598 -0
- data/lib/beaglebone/i2c.rb +186 -0
- data/lib/beaglebone/pwm.rb +479 -0
- data/lib/beaglebone/shiftregister.rb +21 -0
- data/lib/beaglebone/spi.rb +322 -0
- data/lib/beaglebone/uart.rb +388 -0
- data/lib/beaglebone.rb +8 -0
- metadata +63 -0
@@ -0,0 +1,322 @@
|
|
1
|
+
module Beaglebone
|
2
|
+
|
3
|
+
module SPI
|
4
|
+
#some ioctl defines
|
5
|
+
IOC_NONE = 0
|
6
|
+
IOC_WRITE = 1
|
7
|
+
IOC_READ = 2
|
8
|
+
|
9
|
+
IOC_NRBITS = 8
|
10
|
+
IOC_TYPEBITS = 8
|
11
|
+
IOC_SIZEBITS = 14
|
12
|
+
IOC_DIRBITS = 2
|
13
|
+
|
14
|
+
IOC_NRSHIFT = 0
|
15
|
+
IOC_TYPESHIFT = IOC_NRSHIFT+IOC_NRBITS
|
16
|
+
IOC_SIZESHIFT = IOC_TYPESHIFT+IOC_TYPEBITS
|
17
|
+
IOC_DIRSHIFT = IOC_SIZESHIFT+IOC_SIZEBITS
|
18
|
+
|
19
|
+
#spi defines
|
20
|
+
SPI_CPHA = 0x01
|
21
|
+
SPI_CPOL = 0x02
|
22
|
+
|
23
|
+
SPI_MODE_0 = (0|0)
|
24
|
+
SPI_MODE_1 = (0|SPI_CPHA)
|
25
|
+
SPI_MODE_2 = (SPI_CPOL|0)
|
26
|
+
SPI_MODE_3 = (SPI_CPOL|SPI_CPHA)
|
27
|
+
|
28
|
+
SPI_CS_HIGH = 0x04
|
29
|
+
SPI_LSB_FIRST = 0x08
|
30
|
+
SPI_3WIRE = 0x10
|
31
|
+
SPI_LOOP = 0x20
|
32
|
+
SPI_NO_CS = 0x40
|
33
|
+
SPI_READY = 0x80
|
34
|
+
|
35
|
+
SPI_IOC_MAGIC = 'k'.ord
|
36
|
+
|
37
|
+
SPI_IOC_RD_MODE = 2147576577 #ior(SPI_IOC_MAGIC, 1, 1)
|
38
|
+
SPI_IOC_WR_MODE = 1073834753 #iow(SPI_IOC_MAGIC, 1, 1)
|
39
|
+
|
40
|
+
SPI_IOC_RD_LSB_FIRST = 2147576578 #ior(SPI_IOC_MAGIC, 2, 1)
|
41
|
+
SPI_IOC_WR_LSB_FIRST = 1073834754 #iow(SPI_IOC_MAGIC, 2, 1)
|
42
|
+
|
43
|
+
SPI_IOC_RD_BITS_PER_WORD = 2147576579 #ior(SPI_IOC_MAGIC, 3, 1)
|
44
|
+
SPI_IOC_WR_BITS_PER_WORD = 1073834755 #iow(SPI_IOC_MAGIC, 3, 1)
|
45
|
+
|
46
|
+
SPI_IOC_RD_MAX_SPEED_HZ = 2147773188 #ior(SPI_IOC_MAGIC, 4, 4)
|
47
|
+
SPI_IOC_WR_MAX_SPEED_HZ = 1074031364 #iow(SPI_IOC_MAGIC, 4, 4)
|
48
|
+
|
49
|
+
SPI_IOC_MESSAGE_1 = 1075866368
|
50
|
+
|
51
|
+
SPI_IOC_TRANSFER_STRUCT_SIZE = 32
|
52
|
+
|
53
|
+
@spistatus = {}
|
54
|
+
@spimutex = Mutex.new
|
55
|
+
|
56
|
+
class << self
|
57
|
+
|
58
|
+
attr_accessor :spistatus, :spimutex
|
59
|
+
def xfer(spi, tx_data, readbytes=0, speed=nil, delay=nil, bpw=nil)
|
60
|
+
check_spi_enabled(spi)
|
61
|
+
|
62
|
+
speed = speed || get_spi_status(spi, :speed)
|
63
|
+
delay = delay || 0
|
64
|
+
bpw = bpw || get_spi_status(spi, :bpw)
|
65
|
+
|
66
|
+
if tx_data.size > readbytes
|
67
|
+
readbytes = tx_data.size
|
68
|
+
end
|
69
|
+
|
70
|
+
rx_data = ' ' * readbytes
|
71
|
+
|
72
|
+
lock_spi(spi) do
|
73
|
+
spi_fd = get_spi_status(spi, :fd_spi)
|
74
|
+
|
75
|
+
### SPI IOC transfer structure
|
76
|
+
# __u64 tx_buf;
|
77
|
+
# __u64 rx_buf;
|
78
|
+
#
|
79
|
+
# __u32 len;
|
80
|
+
# __u32 speed_hz;
|
81
|
+
#
|
82
|
+
# __u16 delay_usecs;
|
83
|
+
# __u8 bits_per_word;
|
84
|
+
# __u8 cs_change;
|
85
|
+
# __u32 pad;
|
86
|
+
###
|
87
|
+
|
88
|
+
msg = [ tx_data, 0,
|
89
|
+
rx_data, 0,
|
90
|
+
readbytes,
|
91
|
+
speed,
|
92
|
+
delay,
|
93
|
+
bpw,
|
94
|
+
0,
|
95
|
+
0].pack('pLpLLLSCCL')
|
96
|
+
|
97
|
+
#ioctl call to begin data transfer
|
98
|
+
spi_fd.ioctl(SPI_IOC_MESSAGE_1, msg)
|
99
|
+
#speedup with defined int
|
100
|
+
#spi_fd.ioctl(spi_ioc_message(1), msg)
|
101
|
+
|
102
|
+
end
|
103
|
+
rx_data
|
104
|
+
end
|
105
|
+
|
106
|
+
def file(spi)
|
107
|
+
check_spi_enabled(spi)
|
108
|
+
get_spi_status(spi, :fd_spi)
|
109
|
+
end
|
110
|
+
|
111
|
+
def set_speed(spi, speed)
|
112
|
+
speed = speed.to_i
|
113
|
+
raise ArgumentError, "Speed (#{speed.to_s}) must be a positive integer" unless speed > 0
|
114
|
+
|
115
|
+
check_spi_enabled(spi)
|
116
|
+
spi_fd = get_spi_status(spi, :fd_spi)
|
117
|
+
|
118
|
+
spi_fd.ioctl(SPI_IOC_WR_MAX_SPEED_HZ, [speed].pack('L'))
|
119
|
+
spi_fd.ioctl(SPI_IOC_RD_MAX_SPEED_HZ, [speed].pack('L'))
|
120
|
+
set_spi_status(spi, :speed, speed)
|
121
|
+
end
|
122
|
+
|
123
|
+
def set_mode(spi, mode)
|
124
|
+
check_spi_enabled(spi)
|
125
|
+
raise ArgumentError, "Mode (#{mode.to_s}) is unknown" unless [SPI_MODE_0, SPI_MODE_1, SPI_MODE_2, SPI_MODE_3].include?(mode)
|
126
|
+
spi_fd = get_spi_status(spi, :fd_spi)
|
127
|
+
|
128
|
+
spi_fd.ioctl(SPI_IOC_WR_MODE, [mode].pack('C'))
|
129
|
+
spi_fd.ioctl(SPI_IOC_RD_MODE, [mode].pack('C'))
|
130
|
+
end
|
131
|
+
|
132
|
+
def set_bpw(spi, bpw)
|
133
|
+
bpw = bpw.to_i
|
134
|
+
raise ArgumentError, "BPW (#{bpw.to_s}) must be a positive integer" unless bpw > 0
|
135
|
+
|
136
|
+
check_spi_enabled(spi)
|
137
|
+
spi_fd = get_spi_status(spi, :fd_spi)
|
138
|
+
|
139
|
+
spi_fd.ioctl(SPI_IOC_WR_BITS_PER_WORD, [bpw].pack('C'))
|
140
|
+
spi_fd.ioctl(SPI_IOC_RD_BITS_PER_WORD, [bpw].pack('C'))
|
141
|
+
set_spi_status(spi, :bpw, bpw)
|
142
|
+
end
|
143
|
+
|
144
|
+
def setup(spi, mode=nil, speed=1000000, bpw=8)
|
145
|
+
check_spi_valid(spi)
|
146
|
+
|
147
|
+
#make sure spi not already enabled
|
148
|
+
return if get_spi_status(spi)
|
149
|
+
|
150
|
+
mode = mode || SPI_MODE_0
|
151
|
+
|
152
|
+
spiinfo = SPIS[spi]
|
153
|
+
|
154
|
+
#ensure dtb is loaded
|
155
|
+
Beaglebone::device_tree_load("#{spiinfo[:devicetree]}") if spiinfo[:devicetree]
|
156
|
+
|
157
|
+
#open the spi device.
|
158
|
+
spi_fd = File.open("#{spiinfo[:dev]}#{SPIS[:counter]}.0", 'r+')
|
159
|
+
|
160
|
+
set_spi_status(spi, :fd_spi, spi_fd)
|
161
|
+
set_spi_status(spi, :mutex, Mutex.new)
|
162
|
+
|
163
|
+
set_mode(spi, mode)
|
164
|
+
set_bpw(spi, bpw)
|
165
|
+
set_speed(spi, speed)
|
166
|
+
|
167
|
+
SPIS[:counter] += 1
|
168
|
+
|
169
|
+
spiinfo[:pins].each do |pin|
|
170
|
+
Beaglebone::set_pin_status(pin, :spi, spiinfo[:id])
|
171
|
+
Beaglebone::set_pin_status(pin, :type, :spi)
|
172
|
+
Beaglebone::set_pin_status(pin, :fd_spi, spi_fd)
|
173
|
+
end
|
174
|
+
|
175
|
+
end
|
176
|
+
|
177
|
+
def disable(spi)
|
178
|
+
check_spi_valid(spi)
|
179
|
+
check_spi_enabled(spi)
|
180
|
+
|
181
|
+
SPIS[spi][:pins].each do |pin|
|
182
|
+
disable_spi_pin(pin)
|
183
|
+
end
|
184
|
+
|
185
|
+
delete_spi_status(spi)
|
186
|
+
|
187
|
+
#removing spi tree causes a crash... can't really disable.
|
188
|
+
#Beaglebone::device_tree_unload("#{SPIS[spi][:devicetree]}") if SPIS[spi][:devicetree]
|
189
|
+
|
190
|
+
end
|
191
|
+
|
192
|
+
def cleanup
|
193
|
+
#reset all spis we've used and unload the device tree
|
194
|
+
spistatus.clone.keys.each { |spi| disable(spi)}
|
195
|
+
end
|
196
|
+
|
197
|
+
private
|
198
|
+
|
199
|
+
def check_spi_valid(spi)
|
200
|
+
raise ArgumentError, "Invalid spi Specified #{spi.to_s}" unless SPIS[spi] && SPIS[spi][:sclk]
|
201
|
+
spiinfo = SPIS[spi.to_sym.upcase]
|
202
|
+
|
203
|
+
unless spiinfo[:sclk] && [nil,:spi].include?(Beaglebone::get_pin_status(spiinfo[:sclk], :type))
|
204
|
+
raise StandardError, "SCLK Pin for #{spi.to_s} in use"
|
205
|
+
end
|
206
|
+
|
207
|
+
unless spiinfo[:d0] && [nil,:spi].include?(Beaglebone::get_pin_status(spiinfo[:d0], :type))
|
208
|
+
raise StandardError, "D0 Pin for #{spi.to_s} in use"
|
209
|
+
end
|
210
|
+
|
211
|
+
unless spiinfo[:d1] && [nil,:spi].include?(Beaglebone::get_pin_status(spiinfo[:d1], :type))
|
212
|
+
raise StandardError, "D1 Pin for #{spi.to_s} in use"
|
213
|
+
end
|
214
|
+
|
215
|
+
unless spiinfo[:cs0] && [nil,:spi].include?(Beaglebone::get_pin_status(spiinfo[:cs0], :type))
|
216
|
+
raise StandardError, "CS0 Pin for #{spi.to_s} in use"
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
def lock_spi(spi)
|
221
|
+
check_spi_enabled(spi)
|
222
|
+
mutex = get_spi_status(spi, :mutex)
|
223
|
+
|
224
|
+
mutex.synchronize do
|
225
|
+
yield
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
def check_spi_enabled(spi)
|
230
|
+
raise ArgumentError, "spi not enabled #{spi.to_s}" unless get_spi_status(spi)
|
231
|
+
end
|
232
|
+
|
233
|
+
def disable_spi_pin(pin)
|
234
|
+
Beaglebone::check_valid_pin(pin, :spi)
|
235
|
+
|
236
|
+
Beaglebone::delete_pin_status(pin)
|
237
|
+
end
|
238
|
+
|
239
|
+
#ports of ioctl definitions
|
240
|
+
def ioc(dir,type,nr,size)
|
241
|
+
(((dir) << IOC_DIRSHIFT) |
|
242
|
+
((type) << IOC_TYPESHIFT) |
|
243
|
+
((nr) << IOC_NRSHIFT) |
|
244
|
+
((size) << IOC_SIZESHIFT))
|
245
|
+
end
|
246
|
+
|
247
|
+
def ior(type,nr,size)
|
248
|
+
ioc(IOC_READ,(type),(nr),size)
|
249
|
+
end
|
250
|
+
|
251
|
+
def iow(type,nr,size)
|
252
|
+
ioc(IOC_WRITE,(type),(nr),size)
|
253
|
+
end
|
254
|
+
|
255
|
+
def spi_msgsize(n)
|
256
|
+
n*SPI_IOC_TRANSFER_STRUCT_SIZE < 1<<IOC_SIZEBITS ? n*SPI_IOC_TRANSFER_STRUCT_SIZE : 0
|
257
|
+
end
|
258
|
+
|
259
|
+
def spi_ioc_message(n)
|
260
|
+
iow(SPI_IOC_MAGIC, 0, spi_msgsize(n))
|
261
|
+
end
|
262
|
+
|
263
|
+
def get_spi_status(spi, key = nil)
|
264
|
+
spimutex.synchronize do
|
265
|
+
if key
|
266
|
+
spistatus[spi] ? spistatus[spi][key] : nil
|
267
|
+
else
|
268
|
+
spistatus[spi]
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
def set_spi_status(spi, key, value)
|
274
|
+
spimutex.synchronize do
|
275
|
+
spistatus[spi] ||= {}
|
276
|
+
spistatus[spi][key] = value
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
def delete_spi_status(spi, key = nil)
|
281
|
+
spimutex.synchronize do
|
282
|
+
if key.nil?
|
283
|
+
spistatus.delete(spi)
|
284
|
+
else
|
285
|
+
spistatus[spi].delete(key) if spistatus[spi]
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
#oo interface
|
294
|
+
class SPIDevice
|
295
|
+
def initialize(spi, mode=nil, speed=1000000, bpw=8)
|
296
|
+
@spi = spi
|
297
|
+
SPI::setup(@spi, mode, speed, bpw)
|
298
|
+
end
|
299
|
+
|
300
|
+
def xfer(tx_data, readbytes=0, speed=nil, delay=nil, bpw=nil)
|
301
|
+
SPI::xfer(@spi, tx_data, readbytes, speed, delay, bpw)
|
302
|
+
end
|
303
|
+
|
304
|
+
def disable
|
305
|
+
SPI::disable(@spi)
|
306
|
+
end
|
307
|
+
|
308
|
+
def set_speed(speed)
|
309
|
+
SPI::set_speed(@spi, speed)
|
310
|
+
end
|
311
|
+
|
312
|
+
def set_mode(mode)
|
313
|
+
SPI::set_mode(@spi, mode)
|
314
|
+
end
|
315
|
+
|
316
|
+
def set_bpw(bpw)
|
317
|
+
SPI::set_bpw(@spi, bpw)
|
318
|
+
end
|
319
|
+
|
320
|
+
end
|
321
|
+
|
322
|
+
end
|
@@ -0,0 +1,388 @@
|
|
1
|
+
module Beaglebone
|
2
|
+
module UART
|
3
|
+
SPEEDS = [ 110, 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, 56000, 57600, 115200 ]
|
4
|
+
@uartstatus = {}
|
5
|
+
@uartmutex = Mutex.new
|
6
|
+
|
7
|
+
class << self
|
8
|
+
attr_accessor :uartstatus, :uartmutex
|
9
|
+
|
10
|
+
def readchar(uart)
|
11
|
+
readchars(uart, 1)
|
12
|
+
end
|
13
|
+
|
14
|
+
def readchars(uart, bytes)
|
15
|
+
check_uart_enabled(uart)
|
16
|
+
ensure_read_lock(uart)
|
17
|
+
|
18
|
+
buffer = ''
|
19
|
+
|
20
|
+
pin_rx = UARTS[uart][:rx]
|
21
|
+
|
22
|
+
Beaglebone::check_valid_pin(pin_rx, :uart)
|
23
|
+
|
24
|
+
fd = Beaglebone::get_pin_status(pin_rx, :fd_uart)
|
25
|
+
|
26
|
+
set_uart_status(uart, :waiting, true)
|
27
|
+
|
28
|
+
while bytes > 0 do
|
29
|
+
buffer << fd.readchar
|
30
|
+
bytes -= 1
|
31
|
+
end
|
32
|
+
set_uart_status(uart, :waiting, false)
|
33
|
+
|
34
|
+
buffer
|
35
|
+
end
|
36
|
+
|
37
|
+
def readline(uart)
|
38
|
+
check_uart_enabled(uart)
|
39
|
+
ensure_read_lock(uart)
|
40
|
+
|
41
|
+
pin_rx = UARTS[uart][:rx]
|
42
|
+
|
43
|
+
Beaglebone::check_valid_pin(pin_rx, :uart)
|
44
|
+
|
45
|
+
fd = Beaglebone::get_pin_status(pin_rx, :fd_uart)
|
46
|
+
|
47
|
+
set_uart_status(uart, :waiting, true)
|
48
|
+
|
49
|
+
data = fd.readline.strip
|
50
|
+
|
51
|
+
set_uart_status(uart, :waiting, false)
|
52
|
+
|
53
|
+
data
|
54
|
+
end
|
55
|
+
|
56
|
+
def each_char(uart)
|
57
|
+
loop do
|
58
|
+
data = readchars(uart, 1)
|
59
|
+
yield data
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
def each_chars(uart, chars)
|
65
|
+
loop do
|
66
|
+
data = readchars(uart, chars)
|
67
|
+
yield data
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def each_line(uart)
|
72
|
+
loop do
|
73
|
+
data = readline(uart)
|
74
|
+
yield data
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def writeln(uart, data)
|
79
|
+
write(uart, data + "\n")
|
80
|
+
end
|
81
|
+
|
82
|
+
def write(uart, data)
|
83
|
+
check_uart_enabled(uart)
|
84
|
+
|
85
|
+
pin_tx = UARTS[uart][:tx]
|
86
|
+
|
87
|
+
Beaglebone::check_valid_pin(pin_tx, :uart)
|
88
|
+
|
89
|
+
fd = Beaglebone::get_pin_status(pin_tx, :fd_uart)
|
90
|
+
|
91
|
+
ret = fd.write(data)
|
92
|
+
fd.flush
|
93
|
+
|
94
|
+
ret
|
95
|
+
end
|
96
|
+
|
97
|
+
def run_once_on_each_line(callback, uart)
|
98
|
+
run_on_each_line(callback, uart, 1)
|
99
|
+
end
|
100
|
+
|
101
|
+
def run_on_each_line(callback, uart, repeats=nil)
|
102
|
+
check_uart_enabled(uart)
|
103
|
+
|
104
|
+
raise StandardError, "Already waiting for data on uart: #{uart}" if get_uart_status(uart, :waiting)
|
105
|
+
raise StandardError, "Already waiting for data on uart: #{uart}" if get_uart_status(uart, :thread)
|
106
|
+
|
107
|
+
thread = Thread.new(callback, uart, repeats) do |c, u, r|
|
108
|
+
begin
|
109
|
+
count = 0
|
110
|
+
each_line(u) do |line|
|
111
|
+
|
112
|
+
c.call(u, line, count) if c
|
113
|
+
|
114
|
+
count += 1
|
115
|
+
break if r && count >= r
|
116
|
+
end
|
117
|
+
rescue => ex
|
118
|
+
puts ex
|
119
|
+
puts ex.backtrace
|
120
|
+
ensure
|
121
|
+
delete_uart_status(u, :thread)
|
122
|
+
set_uart_status(uart, :waiting, false)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
set_uart_status(uart, :thread, thread)
|
126
|
+
end
|
127
|
+
|
128
|
+
def run_once_on_each_char(callback, uart)
|
129
|
+
run_once_on_each_chars(callback, uart, 1)
|
130
|
+
end
|
131
|
+
|
132
|
+
def run_once_on_each_chars(callback, uart, chars=1)
|
133
|
+
run_on_each_chars(callback, uart, chars, 1)
|
134
|
+
end
|
135
|
+
|
136
|
+
def run_on_each_char(callback, uart, repeats=nil)
|
137
|
+
run_on_each_chars(callback, uart, 1, repeats)
|
138
|
+
end
|
139
|
+
|
140
|
+
def run_on_each_chars(callback, uart, chars=1, repeats=nil)
|
141
|
+
check_uart_enabled(uart)
|
142
|
+
|
143
|
+
raise StandardError, "Already waiting for data on uart: #{uart}" if get_uart_status(uart, :waiting)
|
144
|
+
raise StandardError, "Already waiting for data on uart: #{uart}" if get_uart_status(uart, :thread)
|
145
|
+
|
146
|
+
thread = Thread.new(callback, uart, chars, repeats) do |c, u, ch, r|
|
147
|
+
begin
|
148
|
+
count = 0
|
149
|
+
each_chars(u, ch) do |line|
|
150
|
+
|
151
|
+
c.call(u, line, count) if c
|
152
|
+
|
153
|
+
count += 1
|
154
|
+
break if r && count >= r
|
155
|
+
end
|
156
|
+
rescue => ex
|
157
|
+
puts ex
|
158
|
+
puts ex.backtrace
|
159
|
+
ensure
|
160
|
+
delete_uart_status(u, :thread)
|
161
|
+
set_uart_status(uart, :waiting, false)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
set_uart_status(uart, :thread, thread)
|
165
|
+
end
|
166
|
+
|
167
|
+
def set_speed(uart, speed)
|
168
|
+
check_uart_valid(uart)
|
169
|
+
check_speed_valid(speed)
|
170
|
+
|
171
|
+
uartinfo = UARTS[uart]
|
172
|
+
system("stty -F #{uartinfo[:dev]} #{speed}")
|
173
|
+
end
|
174
|
+
|
175
|
+
def setup(uart, speed=9600)
|
176
|
+
check_uart_valid(uart)
|
177
|
+
check_speed_valid(speed)
|
178
|
+
|
179
|
+
#make sure uart not already enabled
|
180
|
+
return if get_uart_status(uart)
|
181
|
+
|
182
|
+
uartinfo = UARTS[uart]
|
183
|
+
|
184
|
+
#ensure dtb is loaded
|
185
|
+
Beaglebone::device_tree_load("#{TREES[:UART][:pin]}#{uartinfo[:id]}")
|
186
|
+
|
187
|
+
#open the uart device
|
188
|
+
uart_fd = File.open(uartinfo[:dev], 'r+')
|
189
|
+
|
190
|
+
if uartinfo[:tx]
|
191
|
+
Beaglebone::set_pin_status(uartinfo[:tx], :uart, uartinfo[:id])
|
192
|
+
Beaglebone::set_pin_status(uartinfo[:tx], :type, :uart)
|
193
|
+
Beaglebone::set_pin_status(uartinfo[:tx], :fd_uart, uart_fd)
|
194
|
+
end
|
195
|
+
|
196
|
+
if uartinfo[:rx]
|
197
|
+
Beaglebone::set_pin_status(uartinfo[:rx], :uart, uartinfo[:id])
|
198
|
+
Beaglebone::set_pin_status(uartinfo[:tx], :type, :uart)
|
199
|
+
Beaglebone::set_pin_status(uartinfo[:rx], :fd_uart, uart_fd)
|
200
|
+
end
|
201
|
+
|
202
|
+
system("stty -F #{uartinfo[:dev]} raw")
|
203
|
+
system("stty -F #{uartinfo[:dev]} #{speed}")
|
204
|
+
|
205
|
+
set_uart_status(uart, :fd_uart, uart_fd)
|
206
|
+
end
|
207
|
+
|
208
|
+
def disable(uart)
|
209
|
+
check_uart_valid(uart)
|
210
|
+
check_uart_enabled(uart)
|
211
|
+
|
212
|
+
stop_read_wait(uart)
|
213
|
+
|
214
|
+
disable_uart_pin(UARTS[uart][:rx]) if UARTS[uart][:rx]
|
215
|
+
disable_uart_pin(UARTS[uart][:tx]) if UARTS[uart][:tx]
|
216
|
+
|
217
|
+
delete_uart_status(uart)
|
218
|
+
end
|
219
|
+
|
220
|
+
#stop background read
|
221
|
+
def stop_read_wait(uart)
|
222
|
+
thread = get_uart_status(uart, :thread)
|
223
|
+
|
224
|
+
thread.exit if thread
|
225
|
+
thread.join if thread
|
226
|
+
end
|
227
|
+
|
228
|
+
def cleanup
|
229
|
+
#reset all UARTs we've used and unload the device tree
|
230
|
+
uartstatus.clone.keys.each { |uart| disable(uart)}
|
231
|
+
end
|
232
|
+
|
233
|
+
private
|
234
|
+
|
235
|
+
def get_uart_status(uart, key = nil)
|
236
|
+
uartmutex.synchronize do
|
237
|
+
if key
|
238
|
+
uartstatus[uart] ? uartstatus[uart][key] : nil
|
239
|
+
else
|
240
|
+
uartstatus[uart]
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
def set_uart_status(uart, key, value)
|
246
|
+
uartmutex.synchronize do
|
247
|
+
uartstatus[uart] ||= {}
|
248
|
+
uartstatus[uart][key] = value
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
def delete_uart_status(uart, key = nil)
|
253
|
+
uartmutex.synchronize do
|
254
|
+
if key.nil?
|
255
|
+
uartstatus.delete(uart)
|
256
|
+
else
|
257
|
+
uartstatus[uart].delete(key) if uartstatus[uart]
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
def check_uart_valid(uart)
|
263
|
+
raise ArgumentError, "Invalid UART Specified #{uart.to_s}" unless UARTS[uart]
|
264
|
+
uartinfo = UARTS[uart.to_sym.upcase]
|
265
|
+
|
266
|
+
unless uartinfo[:tx] && [nil,:uart].include?(Beaglebone::get_pin_status(uartinfo[:tx], :type))
|
267
|
+
raise StandardError, "TX Pin for #{uart.to_s} in use"
|
268
|
+
end
|
269
|
+
|
270
|
+
unless uartinfo[:rx] && [nil,:uart].include?(Beaglebone::get_pin_status(uartinfo[:rx], :type))
|
271
|
+
raise StandardError, "RX Pin for #{uart.to_s} in use"
|
272
|
+
end
|
273
|
+
|
274
|
+
end
|
275
|
+
|
276
|
+
def check_uart_enabled(uart)
|
277
|
+
raise ArgumentError, "UART not enabled #{uart.to_s}" unless get_uart_status(uart)
|
278
|
+
end
|
279
|
+
|
280
|
+
def ensure_read_lock(uart)
|
281
|
+
#ensure we're the only ones reading
|
282
|
+
if get_uart_status(uart, :thread) && get_uart_status(uart, :thread) != Thread.current
|
283
|
+
raise StandardError, "Already waiting for data on uart: #{uart}"
|
284
|
+
end
|
285
|
+
|
286
|
+
if get_uart_status(uart, :waiting) && get_uart_status(uart, :thread) != Thread.current
|
287
|
+
raise StandardError, "Already waiting for data on uart: #{uart}"
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
def check_speed_valid(speed)
|
292
|
+
raise ArgumentError, "Invalid speed specified: #{speed}" unless SPEEDS.include?(speed)
|
293
|
+
end
|
294
|
+
|
295
|
+
def disable_uart_pin(pin)
|
296
|
+
Beaglebone::check_valid_pin(pin, :uart)
|
297
|
+
|
298
|
+
id = Beaglebone::get_pin_status(pin, :uart)
|
299
|
+
|
300
|
+
Beaglebone::delete_pin_status(pin)
|
301
|
+
|
302
|
+
#removing uart tree causes a crash... can't really disable.
|
303
|
+
return if true
|
304
|
+
|
305
|
+
Beaglebone::device_tree_unload("#{TREES[:UART][:pin]}#{id}")
|
306
|
+
|
307
|
+
end
|
308
|
+
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
#oo interface
|
313
|
+
class UARTDevice
|
314
|
+
def initialize(uart, speed=9600)
|
315
|
+
@uart = uart
|
316
|
+
UART::setup(@uart, speed)
|
317
|
+
end
|
318
|
+
|
319
|
+
def set_speed(speed)
|
320
|
+
UART::set_speed(@uart, speed)
|
321
|
+
end
|
322
|
+
|
323
|
+
def write(data)
|
324
|
+
UART::write(@uart, data)
|
325
|
+
end
|
326
|
+
|
327
|
+
def writeln(data)
|
328
|
+
UART::writeln(@uart, data)
|
329
|
+
end
|
330
|
+
|
331
|
+
def readchar
|
332
|
+
UART::readchar(@uart)
|
333
|
+
end
|
334
|
+
|
335
|
+
def readchars(bytes)
|
336
|
+
UART::readchars(@uart, bytes)
|
337
|
+
end
|
338
|
+
|
339
|
+
def readline
|
340
|
+
UART::readline(@uart)
|
341
|
+
end
|
342
|
+
|
343
|
+
def each_char(&block)
|
344
|
+
UART::each_char(@uart, &block)
|
345
|
+
end
|
346
|
+
|
347
|
+
def each_chars(chars, &block)
|
348
|
+
UART::each_chars(@uart, chars, &block)
|
349
|
+
end
|
350
|
+
|
351
|
+
def each_line(&block)
|
352
|
+
UART::each_line(@uart, &block)
|
353
|
+
end
|
354
|
+
|
355
|
+
def run_on_each_line(callback, repeats=nil)
|
356
|
+
UART::run_on_each_line(callback, @uart, repeats)
|
357
|
+
end
|
358
|
+
|
359
|
+
def run_once_on_each_line(callback)
|
360
|
+
UART::run_once_on_each_line(callback, @uart)
|
361
|
+
end
|
362
|
+
|
363
|
+
def run_on_each_char(callback, repeats=nil)
|
364
|
+
UART::run_on_each_char(callback, @uart, repeats)
|
365
|
+
end
|
366
|
+
|
367
|
+
def run_once_on_each_char(callback)
|
368
|
+
UART::run_once_on_each_char(callback, @uart)
|
369
|
+
end
|
370
|
+
|
371
|
+
def run_on_each_chars(callback, chars=1, repeats=nil)
|
372
|
+
UART::run_on_each_chars(callback, @uart, chars, repeats)
|
373
|
+
end
|
374
|
+
|
375
|
+
def run_once_on_each_chars(callback, chars=1)
|
376
|
+
UART::run_once_on_each_chars(callback, @uart, chars)
|
377
|
+
end
|
378
|
+
|
379
|
+
def stop_read_wait
|
380
|
+
UART::stop_read_wait(@uart)
|
381
|
+
end
|
382
|
+
|
383
|
+
def disable
|
384
|
+
UART::disable(@uart)
|
385
|
+
end
|
386
|
+
|
387
|
+
end
|
388
|
+
end
|