module Beaglebone::UART
UART
¶ ↑
Procedural methods for UART
control
Summary¶ ↑
setup is called to initialize a UART
device
Constants
- SPEEDS
Valid
UART
speeds- UARTTEMPLATE
dts template for UART3 device
Attributes
Public Class Methods
Disable all UART
devices
# File lib/beaglebone/uart.rb, line 397 def cleanup #reset all UARTs we've used and unload the device tree uartstatus.clone.keys.each { |uart| disable(uart)} end
Disable a UART
device.
@note device trees cannot be unloaded at this time without kernel panic.
@param uart should be a symbol representing the UART
device
@example
UART.disable(:UART1)
# File lib/beaglebone/uart.rb, line 376 def disable(uart) check_uart_valid(uart) check_uart_enabled(uart) stop_read_wait(uart) disable_uart_pin(UARTS[uart][:rx]) if UARTS[uart][:rx] disable_uart_pin(UARTS[uart][:tx]) if UARTS[uart][:tx] delete_uart_status(uart) end
Read a character from a UART
device and pass it to the specified block
@param uart should be a symbol representing the UART
device
@example
UART.each_char(:UART1) { |x| puts "read: #{x}" }
# File lib/beaglebone/uart.rb, line 233 def each_char(uart) loop do data = readchars(uart, 1) yield data end end
Read characters from a UART
device and pass them to the specified block
@param uart should be a symbol representing the UART
device @param chars should be the number of chars to read
@example
UART.each_chars(:UART1, 2) { |x| puts "read: #{x}" }
# File lib/beaglebone/uart.rb, line 248 def each_chars(uart, chars) loop do data = readchars(uart, chars) yield data end end
Read characters from a UART
device
@param uart should be a symbol representing the UART
device @param bytes number of bytes to read
@return String the characters read from the UART
device
@example
UART.readchars(:UART1, 2) => "xx"
# File lib/beaglebone/uart.rb, line 177 def readchars(uart, bytes) check_uart_enabled(uart) ensure_read_lock(uart) buffer = '' pin_rx = UARTS[uart][:rx] Beaglebone::check_valid_pin(pin_rx, :uart) fd = Beaglebone::get_pin_status(pin_rx, :fd_uart) set_uart_status(uart, :waiting, true) while bytes > 0 do buffer << fd.readchar bytes -= 1 end set_uart_status(uart, :waiting, false) buffer end
Read a line from a UART
device
@param uart should be a symbol representing the UART
device
@return String the line read from the UART
device
@example
UART.readline(:UART1) => "A line of text"
# File lib/beaglebone/uart.rb, line 208 def readline(uart) check_uart_enabled(uart) ensure_read_lock(uart) pin_rx = UARTS[uart][:rx] Beaglebone::check_valid_pin(pin_rx, :uart) fd = Beaglebone::get_pin_status(pin_rx, :fd_uart) set_uart_status(uart, :waiting, true) data = fd.readline.chop set_uart_status(uart, :waiting, false) data end
Convenience method for run_on_each_chars
with chars set to 1 @see run_on_each_chars
# File lib/beaglebone/uart.rb, line 364 def run_on_each_char(callback, uart, repeats=nil) run_on_each_chars(callback, uart, 1, repeats) end
Runs a callback after receiving data from a UART
device This creates a new thread that runs in the background
@param callback A method to call when the data is received. This method should take 3 arguments, the UART
, the line read, and the counter @param uart should be a symbol representing the UART
device @param chars should be the number of chars to read @param repeats is optional and specifies the number of times the callback will be run
@example
callback = lambda { |uart, data, count| puts "[#{uart}:#{count}] #{data} "} UART.run_on_each_chars(callback, :UART1, 2)
# File lib/beaglebone/uart.rb, line 323 def run_on_each_chars(callback, uart, chars=1, repeats=nil) check_uart_enabled(uart) raise StandardError, "Already waiting for data on uart: #{uart}" if get_uart_status(uart, :waiting) raise StandardError, "Already waiting for data on uart: #{uart}" if get_uart_status(uart, :thread) thread = Thread.new(callback, uart, chars, repeats) do |c, u, ch, r| begin count = 0 each_chars(u, ch) do |line| c.call(u, line, count) if c count += 1 break if r && count >= r end rescue => ex puts ex puts ex.backtrace ensure delete_uart_status(u, :thread) set_uart_status(uart, :waiting, false) end end set_uart_status(uart, :thread, thread) end
Runs a callback after receiving a line of data from a UART
device This creates a new thread that runs in the background
@param callback A method to call when the data is received. This method should take 3 arguments, the UART
, the line read, and the counter @param uart should be a symbol representing the UART
device @param repeats is optional and specifies the number of times the callback will be run
@example
callback = lambda { |uart, line, count| puts "[#{uart}:#{count}] #{line} "} UART.run_on_each_line(callback, :UART1)
# File lib/beaglebone/uart.rb, line 279 def run_on_each_line(callback, uart, repeats=nil) check_uart_enabled(uart) raise StandardError, "Already waiting for data on uart: #{uart}" if get_uart_status(uart, :waiting) raise StandardError, "Already waiting for data on uart: #{uart}" if get_uart_status(uart, :thread) thread = Thread.new(callback, uart, repeats) do |c, u, r| begin count = 0 each_line(u) do |line| c.call(u, line, count) if c count += 1 break if r && count >= r end rescue => ex puts ex puts ex.backtrace ensure delete_uart_status(u, :thread) set_uart_status(uart, :waiting, false) end end set_uart_status(uart, :thread, thread) end
Convenience method for run_on_each_chars
with chars and repeats set to 1 @see run_on_each_chars
# File lib/beaglebone/uart.rb, line 352 def run_once_on_each_char(callback, uart) run_once_on_each_chars(callback, uart, 1) end
Convenience method for run_on_each_chars
with chars and repeats set to 1 @see run_on_each_chars
# File lib/beaglebone/uart.rb, line 358 def run_once_on_each_chars(callback, uart, chars=1) run_on_each_chars(callback, uart, chars, 1) end
Convenience method for run_on_each_line
with repeats set to 1 @see run_on_each_line
# File lib/beaglebone/uart.rb, line 308 def run_once_on_each_line(callback, uart) run_on_each_line(callback, uart, 1) end
Set the speed of the UART
@param speed should be an integer thats a valid speed. @see SPEEDS
@example
UART.set_speed(:UART1, 9600)
# File lib/beaglebone/uart.rb, line 109 def set_speed(uart, speed) check_uart_valid(uart) check_speed_valid(speed) uartinfo = UARTS[uart] system("stty -F #{uartinfo[:dev]} #{speed}") end
Initialize a UART
device
@param uart should be a symbol representing the UART
device @param speed should be an integer thats a valid speed. @see SPEEDS
@example
UART.setup(:UART1, 9600)
# File lib/beaglebone/uart.rb, line 67 def setup(uart, speed=9600) check_uart_valid(uart) check_speed_valid(speed) #make sure uart not already enabled return if get_uart_status(uart) uartinfo = UARTS[uart] #ensure we have a dtb to load create_device_tree(uart) #ensure dtb is loaded Beaglebone::device_tree_load("#{TREES[:UART][:pin]}#{uartinfo[:id]}") #open the uart device uart_fd = File.open(uartinfo[:dev], 'r+') if uartinfo[:tx] Beaglebone::set_pin_status(uartinfo[:tx], :uart, uartinfo[:id]) Beaglebone::set_pin_status(uartinfo[:tx], :type, :uart) Beaglebone::set_pin_status(uartinfo[:tx], :fd_uart, uart_fd) end if uartinfo[:rx] Beaglebone::set_pin_status(uartinfo[:rx], :uart, uartinfo[:id]) Beaglebone::set_pin_status(uartinfo[:tx], :type, :uart) Beaglebone::set_pin_status(uartinfo[:rx], :fd_uart, uart_fd) end system("stty -F #{uartinfo[:dev]} raw") system("stty -F #{uartinfo[:dev]} #{speed}") set_uart_status(uart, :fd_uart, uart_fd) end
Stops any threads waiting for data on the specified UART
# File lib/beaglebone/uart.rb, line 389 def stop_read_wait(uart) thread = get_uart_status(uart, :thread) thread.exit if thread thread.join if thread end
Write data to a UART
device
@param uart should be a symbol representing the UART
device @param data the data to write
@return Integer the number of bytes written
@example
UART.write(:UART1, "1234") => 4
# File lib/beaglebone/uart.rb, line 126 def write(uart, data) check_uart_enabled(uart) pin_tx = UARTS[uart][:tx] Beaglebone::check_valid_pin(pin_tx, :uart) fd = Beaglebone::get_pin_status(pin_tx, :fd_uart) ret = fd.write(data) fd.flush ret end
Write a line data to a UART
device. This is a convenience method using write @see write
@param uart should be a symbol representing the UART
device @param data the data to write
@return Integer the number of bytes written
@example
UART.writeln(:UART1, "1234") => 5
# File lib/beaglebone/uart.rb, line 152 def writeln(uart, data) write(uart, data + "\n") end
Private Class Methods
check to make sure the specified speed is valid
# File lib/beaglebone/uart.rb, line 471 def check_speed_valid(speed) raise ArgumentError, "Invalid speed specified: #{speed}" unless SPEEDS.include?(speed) end
ensure UART
is enabled
# File lib/beaglebone/uart.rb, line 454 def check_uart_enabled(uart) raise ArgumentError, "UART not enabled #{uart.to_s}" unless get_uart_status(uart) end
ensure UART
is valid
# File lib/beaglebone/uart.rb, line 435 def check_uart_valid(uart) raise ArgumentError, "Invalid UART Specified #{uart.to_s}" unless UARTS[uart] uartinfo = UARTS[uart.to_sym] if uartinfo[:tx] unless [nil,:uart].include?(Beaglebone::get_pin_status(uartinfo[:tx], :type)) raise StandardError, "TX Pin for #{uart.to_s} in use" end end if uartinfo[:rx] unless [nil,:uart].include?(Beaglebone::get_pin_status(uartinfo[:rx], :type)) raise StandardError, "RX Pin for #{uart.to_s} in use" end end end
# File lib/beaglebone/uart.rb, line 490 def create_device_tree(uart, force = false) uartinfo = UARTS[uart] #ensure valid uart, and a template to create this exists return unless uartinfo uartnum = uartinfo[:id] return unless uartnum && UARTTEMPLATE[uartnum] dts = UARTTEMPLATE[uartinfo[:id]].clone filename = "/lib/firmware/#{TREES[:UART][:pin]}#{uartnum}-00A0" dts_fn = "#{filename}.dts" dtb_fn = "#{filename}.dtbo" # if we've already built this file, we don't need to do it again return if File.exists?(dtb_fn) && !force dts_file = File.open(dts_fn, 'w') dts_file.write(dts) dts_file.close system("dtc -O dtb -o #{dtb_fn} -b 0 -@ #{dts_fn}") end
remove hash data for specified UART
# File lib/beaglebone/uart.rb, line 424 def delete_uart_status(uart, key = nil) uartmutex.synchronize do if key.nil? uartstatus.delete(uart) else uartstatus[uart].delete(key) if uartstatus[uart] end end end
disable a uart pin
# File lib/beaglebone/uart.rb, line 476 def disable_uart_pin(pin) Beaglebone::check_valid_pin(pin, :uart) id = Beaglebone::get_pin_status(pin, :uart) Beaglebone::delete_pin_status(pin) #removing uart tree causes a crash... can't really disable. return if true Beaglebone::device_tree_unload("#{TREES[:UART][:pin]}#{id}") end
ensure we have a read lock for the UART
# File lib/beaglebone/uart.rb, line 459 def ensure_read_lock(uart) #ensure we're the only ones reading if get_uart_status(uart, :thread) && get_uart_status(uart, :thread) != Thread.current raise StandardError, "Already waiting for data on uart: #{uart}" end if get_uart_status(uart, :waiting) && get_uart_status(uart, :thread) != Thread.current raise StandardError, "Already waiting for data on uart: #{uart}" end end
return hash data for specified UART
# File lib/beaglebone/uart.rb, line 405 def get_uart_status(uart, key = nil) uartmutex.synchronize do if key uartstatus[uart] ? uartstatus[uart][key] : nil else uartstatus[uart] end end end
set hash data for specified UART
# File lib/beaglebone/uart.rb, line 416 def set_uart_status(uart, key, value) uartmutex.synchronize do uartstatus[uart] ||= {} uartstatus[uart][key] = value end end