Class: Denko::Board
- Inherits:
-
Object
- Object
- Denko::Board
- Includes:
- Denko::Behaviors::Subcomponents
- Defined in:
- lib/denko/board.rb,
lib/denko/board/i2c.rb,
lib/denko/board/map.rb,
lib/denko/board/spi.rb,
lib/denko/board/core.rb,
lib/denko/board/tone.rb,
lib/denko/board/uart.rb,
lib/denko/board/pulse.rb,
lib/denko/board/servo.rb,
lib/denko/board/eeprom.rb,
lib/denko/board/infrared.rb,
lib/denko/board/one_wire.rb,
lib/denko/board/led_array.rb,
lib/denko/board/message_pack.rb,
lib/denko/board/spi_bit_bang.rb,
lib/denko/board/uart_bit_bang.rb
Constant Summary collapse
- I2C_FREQUENCIES =
{ 100000 => 0x00, 400000 => 0x01, 1000000 => 0x02, 3400000 => 0x03, }
- MAPS_FOLDER =
File.join(Denko.root, "vendor/board-maps/yaml")
- DIVIDERS =
[1, 2, 4, 8, 16, 32, 64, 128]
- PIN_MODES =
{ output: 0b000, output_pwm: 0b010, output_dac: 0b100, input: 0b001, input_pulldown: 0b011, input_pullup: 0b101, input_output: 0b111 }
- UART_BAUD_RATES =
[ 300, 600, 750, 1200, 2400, 4800, 9600, 19200, 31250, 38400, 57600, 74880, 115200, 230400 ]
Instance Attribute Summary collapse
-
#analog_read_high ⇒ Object
(also: #adc_high)
readonly
Returns the value of attribute analog_read_high.
-
#analog_write_high ⇒ Object
(also: #pwm_high, #dac_high)
readonly
Returns the value of attribute analog_write_high.
-
#aux_limit ⇒ Object
readonly
Returns the value of attribute aux_limit.
-
#eeprom_length ⇒ Object
readonly
Returns the value of attribute eeprom_length.
-
#high ⇒ Object
readonly
Returns the value of attribute high.
-
#i2c_limit ⇒ Object
readonly
Returns the value of attribute i2c_limit.
-
#low ⇒ Object
readonly
Returns the value of attribute low.
-
#map ⇒ Object
readonly
Returns the value of attribute map.
-
#name ⇒ Object
readonly
Returns the value of attribute name.
-
#serial_buffer_size ⇒ Object
readonly
Returns the value of attribute serial_buffer_size.
-
#version ⇒ Object
readonly
Returns the value of attribute version.
Instance Method Summary collapse
- #analog_listen(pin, divider = 16) ⇒ Object
-
#analog_read(pin, negative_pin = nil, gain = nil, sample_rate = nil) ⇒ Object
CMD = 5.
- #analog_read_resolution ⇒ Object
- #analog_read_resolution=(value) ⇒ Object
- #analog_write_resolution ⇒ Object
- #analog_write_resolution=(value) ⇒ Object
- #convert_pin(pin) ⇒ Object
-
#dac_write(pin, value) ⇒ Object
CMD = 4.
-
#digital_listen(pin, divider = 4) ⇒ Object
Convenience methods that wrap set_listener.
-
#digital_read(pin) ⇒ Object
CMD = 2.
-
#digital_write(pin, value) ⇒ Object
CMD = 1.
-
#eeprom ⇒ Object
Component generating convenience methods.
-
#eeprom_read(address, num_bytes) ⇒ Object
CMD = 7.
-
#eeprom_write(address, bytes) ⇒ Object
CMD = 8.
- #finish_write ⇒ Object
-
#halt_resume_check ⇒ Object
CMD = 92.
- #hcsr04_read(echo_pin, trigger_pin) ⇒ Object
- #i2c_convert_frequency(freq) ⇒ Object
-
#i2c_read(address, register, read_length, frequency = 100000, repeated_start = false) ⇒ Object
CMD = 35.
-
#i2c_search ⇒ Object
CMD = 33.
-
#i2c_write(address, bytes, frequency = 100000, repeated_start = false) ⇒ Object
CMD = 34.
- #infrared_emit(pin, frequency, pulses) ⇒ Object
-
#initialize(transport, options = {}) ⇒ Board
constructor
A new instance of Board.
- #load_map(board_name) ⇒ Object
-
#micro_delay(duration) ⇒ Object
CMD = 99.
-
#no_tone(pin) ⇒ Object
CMD = 18.
- #one_wire_read(pin, num_bytes) ⇒ Object
- #one_wire_reset(pin, value = 0) ⇒ Object
- #one_wire_search(pin, branch_mask) ⇒ Object
- #one_wire_write(pin, parasite_power, *data) ⇒ Object
- #pack(*args, **kwargs) ⇒ Object
-
#pulse_read(pin, reset: false, reset_time: 0, pulse_limit: 100, timeout: 200) ⇒ Object
CMD = 9.
-
#pwm_write(pin, value) ⇒ Object
CMD = 3.
-
#servo_toggle(pin, value = :off, min: 544, max: 2400) ⇒ Object
CMD = 10.
-
#servo_write(pin, value = 0) ⇒ Object
CMD = 11.
-
#set_analog_read_resolution(value) ⇒ Object
CMD = 97.
-
#set_analog_write_resolution(value) ⇒ Object
CMD = 96.
-
#set_listener(pin, state = :off, **options) ⇒ Object
CMD = 6.
-
#set_pin_mode(pin, mode = :input) ⇒ Object
CMD = 0.
-
#set_register_divider(value) ⇒ Object
CMD = 95.
- #show_ws2812(pin, pixel_buffer) ⇒ Object
- #spi_bb_header(clock, input, output, write, read, mode, bit_order) ⇒ Object
-
#spi_bb_listen(select_pin, clock: nil, input: nil, read: 0, frequency: nil, mode: nil, bit_order: nil) ⇒ Object
CMD = 22.
-
#spi_bb_transfer(select_pin, clock: nil, output: nil, input: nil, write: [], read: 0, frequency: nil, mode: nil, bit_order: nil) ⇒ Object
CMD = 21.
- #spi_header(write, read, frequency, mode, bit_order) ⇒ Object
- #spi_header_generic(write, read, mode, bit_order) ⇒ Object
-
#spi_listen(select_pin, read: 0, frequency: nil, mode: nil, bit_order: nil) ⇒ Object
CMD = 27.
-
#spi_stop(select_pin) ⇒ Object
CMD = 28.
-
#spi_transfer(select_pin, write: [], read: 0, frequency: nil, mode: nil, bit_order: nil) ⇒ Object
CMD = 26.
- #stop_listener(pin) ⇒ Object
- #substitute_zero_pins ⇒ Object
-
#tone(pin, frequency, duration = nil) ⇒ Object
CMD = 17.
-
#uart_bb_start(tx, rx, baud, listening = true) ⇒ Object
CMD = 12.
-
#uart_bb_stop ⇒ Object
CMD = 12.
-
#uart_bb_write(data) ⇒ Object
CMD = 13.
-
#uart_start(index, baud, listening = true) ⇒ Object
CMD = 14.
-
#uart_stop(index) ⇒ Object
CMD = 14.
-
#uart_write(index, data) ⇒ Object
CMD = 15.
- #update(line) ⇒ Object
- #write(msg) ⇒ Object
-
#write_and_halt(msg) ⇒ Object
Use Board#write_and_halt to call C++ board functions that disable interrupts for a long time.
Methods included from Denko::Behaviors::Subcomponents
#add_component, #components, #remove_component, #single_pin_components
Constructor Details
#initialize(transport, options = {}) ⇒ Board
Returns a new instance of Board.
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 37 38 39 40 41 42 43 44 45 46 |
# File 'lib/denko/board.rb', line 9 def initialize(transport, ={}) # Shake hands @transport = transport ack = transport.handshake # Split handshake acknowledgement into separate values. @name, @version, @serial_buffer_size, @aux_limit, @eeprom_length, @i2c_limit = ack.split(",") # Tell transport how much serial buffer the board has, for flow control. @serial_buffer_size = @serial_buffer_size.to_i raise StandardError, "no serial buffer size given in handshake" if @serial_buffer_size < 1 @transport.remote_buffer_size = @serial_buffer_size # Load board map by name. @name = nil if @name.empty? load_map(@name) # Leave room for null termination of aux messages. @aux_limit = @aux_limit.to_i - 1 # Set I2C transaction size limit. Safe minimum is 32. # This makes I2C fail silently if board does not implement. @i2c_limit = @i2c_limit.to_i @i2c_limit = 32 if @i2c_limit == 0 # Remaining settings @version = nil if @version.empty? @eeprom_length = @eeprom_length.to_i # Transport calls #update on board when data is received. transport.add_observer(self) # Set digital and analog IO levels. @low = 0 @high = 1 self.analog_write_resolution = [:write_bits] || 8 self.analog_read_resolution = [:read_bits] || 10 end |
Instance Attribute Details
#analog_read_high ⇒ Object (readonly) Also known as: adc_high
Returns the value of attribute analog_read_high.
7 8 9 |
# File 'lib/denko/board.rb', line 7 def analog_read_high @analog_read_high end |
#analog_write_high ⇒ Object (readonly) Also known as: pwm_high, dac_high
Returns the value of attribute analog_write_high.
7 8 9 |
# File 'lib/denko/board.rb', line 7 def analog_write_high @analog_write_high end |
#aux_limit ⇒ Object (readonly)
Returns the value of attribute aux_limit.
6 7 8 |
# File 'lib/denko/board.rb', line 6 def aux_limit @aux_limit end |
#eeprom_length ⇒ Object (readonly)
Returns the value of attribute eeprom_length.
6 7 8 |
# File 'lib/denko/board.rb', line 6 def eeprom_length @eeprom_length end |
#high ⇒ Object (readonly)
Returns the value of attribute high.
7 8 9 |
# File 'lib/denko/board.rb', line 7 def high @high end |
#i2c_limit ⇒ Object (readonly)
Returns the value of attribute i2c_limit.
10 11 12 |
# File 'lib/denko/board/i2c.rb', line 10 def i2c_limit @i2c_limit end |
#low ⇒ Object (readonly)
Returns the value of attribute low.
7 8 9 |
# File 'lib/denko/board.rb', line 7 def low @low end |
#map ⇒ Object (readonly)
Returns the value of attribute map.
7 8 9 |
# File 'lib/denko/board/map.rb', line 7 def map @map end |
#name ⇒ Object (readonly)
Returns the value of attribute name.
6 7 8 |
# File 'lib/denko/board.rb', line 6 def name @name end |
#serial_buffer_size ⇒ Object (readonly)
Returns the value of attribute serial_buffer_size.
6 7 8 |
# File 'lib/denko/board.rb', line 6 def serial_buffer_size @serial_buffer_size end |
#version ⇒ Object (readonly)
Returns the value of attribute version.
6 7 8 |
# File 'lib/denko/board.rb', line 6 def version @version end |
Instance Method Details
#analog_listen(pin, divider = 16) ⇒ Object
99 100 101 |
# File 'lib/denko/board/core.rb', line 99 def analog_listen(pin, divider=16) set_listener(pin, :on, mode: :analog, divider: divider) end |
#analog_read(pin, negative_pin = nil, gain = nil, sample_rate = nil) ⇒ Object
CMD = 5
55 56 57 |
# File 'lib/denko/board/core.rb', line 55 def analog_read(pin, negative_pin=nil, gain=nil, sample_rate=nil) write Message.encode command: 5, pin: pin end |
#analog_read_resolution ⇒ Object
70 71 72 |
# File 'lib/denko/board.rb', line 70 def analog_read_resolution @read_bits end |
#analog_read_resolution=(value) ⇒ Object
60 61 62 63 64 |
# File 'lib/denko/board.rb', line 60 def analog_read_resolution=(value) set_analog_read_resolution(value) @read_bits = value @analog_read_high = (2 ** @read_bits) - 1 end |
#analog_write_resolution ⇒ Object
66 67 68 |
# File 'lib/denko/board.rb', line 66 def analog_write_resolution @write_bits end |
#analog_write_resolution=(value) ⇒ Object
54 55 56 57 58 |
# File 'lib/denko/board.rb', line 54 def analog_write_resolution=(value) set_analog_write_resolution(value) @write_bits = value @analog_write_high = (2 ** @write_bits) - 1 end |
#convert_pin(pin) ⇒ Object
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 |
# File 'lib/denko/board/map.rb', line 29 def convert_pin(pin) # Convert non numerical strings to symbols. pin = pin.to_sym if (pin.class == String) && !(pin.match (/\A\d+\.*\d*/)) # Handle symbols. if (pin.class == Symbol) if map && map[pin] return map[pin] elsif map raise ArgumentError, "error in pin: #{pin.inspect}. Make sure that pin is defined for this board by calling Board#map" else raise ArgumentError, "error in pin: #{pin.inspect}. Given a Symbol, but board has no map. Try using GPIO integer instead" end end # Handle integers. return pin if pin.class == Integer # Try #to_i on anyting else. Will catch numerical strings. begin return pin.to_i rescue raise ArgumentError, "error in pin: #{pin.inspect}" end end |
#dac_write(pin, value) ⇒ Object
CMD = 4
47 48 49 50 51 52 |
# File 'lib/denko/board/core.rb', line 47 def dac_write(pin,value) if (value < 0) || (value > dac_high) raise ArgumentError, "cannot write DAC value: #{value}. Should be Integer in range 0..#{dac_high} " end write Message.encode command: 4, pin: pin, value: value.round end |
#digital_listen(pin, divider = 4) ⇒ Object
Convenience methods that wrap set_listener.
95 96 97 |
# File 'lib/denko/board/core.rb', line 95 def digital_listen(pin, divider=4) set_listener(pin, :on, mode: :digital, divider: divider) end |
#digital_read(pin) ⇒ Object
CMD = 2
34 35 36 |
# File 'lib/denko/board/core.rb', line 34 def digital_read(pin) write Message.encode command: 2, pin: pin end |
#digital_write(pin, value) ⇒ Object
CMD = 1
26 27 28 29 30 31 |
# File 'lib/denko/board/core.rb', line 26 def digital_write(pin,value) unless (value == 1) || (value == 0) raise ArgumentError, "cannot write digital value: #{value}. Should be Integer either 0 or 1" end write Message.encode command: 1, pin: pin, value: value end |
#eeprom ⇒ Object
Component generating convenience methods. TODO: add more!
112 113 114 115 |
# File 'lib/denko/board.rb', line 112 def eeprom raise StandardError, 'board has no built-in EEPROM, or EEPROM disabled in sketch' if @eeprom_length == 0 @eeprom ||= EEPROM::BuiltIn.new(board: self) end |
#eeprom_read(address, num_bytes) ⇒ Object
CMD = 7
4 5 6 7 8 9 |
# File 'lib/denko/board/eeprom.rb', line 4 def eeprom_read(address, num_bytes) address = pack :uint16, address write Message.encode command: 7, value: num_bytes, aux_message: address end |
#eeprom_write(address, bytes) ⇒ Object
CMD = 8
12 13 14 15 16 17 18 |
# File 'lib/denko/board/eeprom.rb', line 12 def eeprom_write(address, bytes) address = pack :uint16, address bytes = pack :uint8, bytes, min: 1, max: 128 write Message.encode command: 8, value: bytes.length, aux_message: address + bytes end |
#finish_write ⇒ Object
48 49 50 51 52 |
# File 'lib/denko/board.rb', line 48 def finish_write sleep 0.001 while @transport.writing? write "\n91\n" sleep 0.001 while @transport.writing? end |
#halt_resume_check ⇒ Object
CMD = 92
For diagnostics and testing mostly. What this does: 1) Tell the Connection to halt transmission immediately, after this message. 2) The board will send back a ready signal, which the Connection should read and resume transmisison.
See comments on Board#write_and_halt for more info and use case.
115 116 117 |
# File 'lib/denko/board/core.rb', line 115 def halt_resume_check write_and_halt Message.encode command: 92 end |
#hcsr04_read(echo_pin, trigger_pin) ⇒ Object
26 27 28 |
# File 'lib/denko/board/pulse.rb', line 26 def hcsr04_read(echo_pin, trigger_pin) write Message.encode(command: 20, pin: echo_pin, value: trigger_pin) end |
#i2c_convert_frequency(freq) ⇒ Object
12 13 14 15 16 17 18 19 20 |
# File 'lib/denko/board/i2c.rb', line 12 def i2c_convert_frequency(freq) # Default to 100 kHz. freq = 100000 unless freq unless I2C_FREQUENCIES.include?(freq) raise ArgumentError, "I2C frequency must be in: #{I2C_FREQUENCIES.keys.inspect}" end I2C_FREQUENCIES[freq] end |
#i2c_read(address, register, read_length, frequency = 100000, repeated_start = false) ⇒ Object
CMD = 35
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/denko/board/i2c.rb', line 43 def i2c_read(address, register, read_length, frequency=100000, repeated_start=false) raise ArgumentError, "I2C read must be 1..#{i2c_limit} bytes long" if (read_length > i2c_limit || read_length < 1) # Use top bit of address to select stop condition (1), or repated start (0). send_stop = repeated_start ? 0 : 1 frequency = i2c_convert_frequency(frequency) # A register address starting register address can be given (up to 4 bytes) if register register = [register].flatten raise ArgumentError, 'maximum 4 byte register address for I2C read' if register.length > 4 register_packed = pack(:uint8, [register.length] + register) else register_packed = pack(:uint8, [0]) end write Message.encode command: 35, pin: address | (send_stop << 7), value: read_length, aux_message: pack(:uint8, frequency) + register_packed end |
#i2c_search ⇒ Object
CMD = 33
23 24 25 |
# File 'lib/denko/board/i2c.rb', line 23 def i2c_search write Message.encode command: 33 end |
#i2c_write(address, bytes, frequency = 100000, repeated_start = false) ⇒ Object
CMD = 34
28 29 30 31 32 33 34 35 36 37 38 39 40 |
# File 'lib/denko/board/i2c.rb', line 28 def i2c_write(address, bytes, frequency=100000, repeated_start=false) bytes = [bytes] unless bytes.class == Array raise ArgumentError, "I2C write must be 1..#{i2c_limit} bytes long" if (bytes.length > i2c_limit || bytes.length < 1) # Use top bit of address to select stop condition (1), or repated start (0). send_stop = repeated_start ? 0 : 1 frequency = i2c_convert_frequency(frequency) write Message.encode command: 34, pin: address | (send_stop << 7), value: bytes.length, aux_message: pack(:uint8, frequency) + pack(:uint8, bytes) end |
#infrared_emit(pin, frequency, pulses) ⇒ Object
3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# File 'lib/denko/board/infrared.rb', line 3 def infrared_emit(pin, frequency, pulses) # # Limit to 255 marks/spaces (not pairs) for now. # # Length must be 1-byte long, not literally 1 # Pulses max is 2x255 bytes long since each is 2 bytes. length = pack :uint8, pulses.length, max: 1 bytes = pack :uint16, pulses, min: 1, max: 510 write Message.encode command: 16, pin: pin, value: frequency, aux_message: length + bytes end |
#load_map(board_name) ⇒ Object
17 18 19 20 21 22 23 24 25 26 27 |
# File 'lib/denko/board/map.rb', line 17 def load_map(board_name) if board_name map_path = File.join(MAPS_FOLDER, "#{board_name}.yml") @map = YAML.load_file(map_path) substitute_zero_pins else @map = nil end rescue raise StandardError, "error loading board map from file for board name: '#{board_name}'" end |
#micro_delay(duration) ⇒ Object
CMD = 99
144 145 146 147 148 149 |
# File 'lib/denko/board/core.rb', line 144 def micro_delay(duration) if (duration < 0) || (duration > 0xFFFF) raise ArgumentError, "error in duration: #{duration}. Should be Integer in range 0..65535" end write Message.encode command: 99, aux_message: pack(:uint16, [duration]) end |
#no_tone(pin) ⇒ Object
CMD = 18
19 20 21 |
# File 'lib/denko/board/tone.rb', line 19 def no_tone(pin) write Message.encode command: 18, pin: pin end |
#one_wire_read(pin, num_bytes) ⇒ Object
28 29 30 31 32 |
# File 'lib/denko/board/one_wire.rb', line 28 def one_wire_read(pin, num_bytes) write Message.encode command: 44, pin: pin, value: num_bytes end |
#one_wire_reset(pin, value = 0) ⇒ Object
3 4 5 6 7 |
# File 'lib/denko/board/one_wire.rb', line 3 def one_wire_reset(pin, value=0) write Message.encode command: 41, pin: pin, value: value end |
#one_wire_search(pin, branch_mask) ⇒ Object
9 10 11 12 13 |
# File 'lib/denko/board/one_wire.rb', line 9 def one_wire_search(pin, branch_mask) write Message.encode command: 42, pin: pin, aux_message: pack(:uint64, branch_mask, max: 8) end |
#one_wire_write(pin, parasite_power, *data) ⇒ Object
15 16 17 18 19 20 21 22 23 24 25 26 |
# File 'lib/denko/board/one_wire.rb', line 15 def one_wire_write(pin, parasite_power, *data) bytes = pack :uint8, data, min: 1, max: 127 # Should be 128 with 0 = 1. # Set high bit of length if the bus must drive high after write. length = bytes.length length = length | 0b10000000 if parasite_power write Message.encode command: 43, pin: pin, value: length, aux_message: bytes end |
#pack(*args, **kwargs) ⇒ Object
3 4 5 |
# File 'lib/denko/board/message_pack.rb', line 3 def pack(*args, **kwargs) Message.pack(*args, **kwargs) end |
#pulse_read(pin, reset: false, reset_time: 0, pulse_limit: 100, timeout: 200) ⇒ Object
CMD = 9
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
# File 'lib/denko/board/pulse.rb', line 4 def pulse_read(pin, reset: false, reset_time: 0, pulse_limit: 100, timeout: 200) # Validation raise ArgumentError, "error in reset: #{reset}. Should be either #{high} or #{low}" if reset && ![high, low].include?(reset) raise ArgumentError, "errror in reset_time: #{reset_time}. Should be 0..65535 microseconds" if (reset_time < 0) || (reset_time > 0xFFFF) raise ArgumentError, "errror in pulse_limit: #{pulse_limit}. Should be 0..255 pulses" if (pulse_limit < 0) || (pulse_limit > 0xFF) raise ArgumentError, "errror in timeout: #{timeout}. Should be 0..65535 milliseconds" if (timeout < 0) || (timeout > 0xFFFF) # Bit 0 of settings mask controls whether to hold high/low for reset. settings = reset ? 1 : 0 # Bit 1 of settings mask controls whether to hold high (1) or to hold low (0). settings = settings | 0b10 if (reset && reset != low) # Pack and send. aux = pack :uint16, [reset_time, timeout] aux << pack(:uint8, pulse_limit) write Message.encode command: 9, pin: pin, value: settings, aux_message: aux end |
#pwm_write(pin, value) ⇒ Object
CMD = 3
39 40 41 42 43 44 |
# File 'lib/denko/board/core.rb', line 39 def pwm_write(pin,value) if (value < 0) || (value > pwm_high) raise ArgumentError, "cannot write PWM value: #{value}. Should be Integer in range 0..#{pwm_high} " end write Message.encode command: 3, pin: pin, value: value.round end |
#servo_toggle(pin, value = :off, min: 544, max: 2400) ⇒ Object
CMD = 10
4 5 6 7 8 9 |
# File 'lib/denko/board/servo.rb', line 4 def servo_toggle(pin, value=:off, min: 544, max: 2400) write Message.encode command: 10, pin: pin, value: (value == :off) ? 0 : 1, aux_message: pack(:uint16, [min, max]) end |
#servo_write(pin, value = 0) ⇒ Object
CMD = 11
12 13 14 15 16 |
# File 'lib/denko/board/servo.rb', line 12 def servo_write(pin, value=0) write Message.encode command: 11, pin: pin, aux_message: pack(:uint16, value) end |
#set_analog_read_resolution(value) ⇒ Object
CMD = 97
136 137 138 139 140 141 |
# File 'lib/denko/board/core.rb', line 136 def set_analog_read_resolution(value) if (value < 0) || (value > 16) raise ArgumentError, "cannot set resolution: #{value}. Should be Integer in range 0..16" end write Message.encode(command: 97, value: value) end |
#set_analog_write_resolution(value) ⇒ Object
CMD = 96
128 129 130 131 132 133 |
# File 'lib/denko/board/core.rb', line 128 def set_analog_write_resolution(value) if (value < 0) || (value > 16) raise ArgumentError, "cannot set resolution: #{value}. Should be Integer in range 0..16" end write Message.encode(command: 96, value: value) end |
#set_listener(pin, state = :off, **options) ⇒ Object
CMD = 6
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/denko/board/core.rb', line 60 def set_listener(pin, state=:off, **) # Default to digital listener and validate. [:mode] ||= :digital unless ([:mode] == :digital) || ([:mode] == :analog) raise ArgumentError, "error in mode: #{[:mode]}. Should be one of: [:digital, :analog]" end mode_byte = ([:mode] == :digital) ? 0 : 1 # Default to 4ms divider if digital, 16ms if analog. if [:mode] == :digital [:divider] ||= 4 else [:divider] ||= 16 end # Convert divider to exponent and validate. exponent = Math.log2([:divider]).round if (exponent < 0) || (exponent > 7) raise ArgumentError, "error in divider: #{[:divider]}. Should be one of: #{DIVIDERS.inspect}" end # Validate state. unless (state == :on) || (state == :off) raise ArgumentError, "error in state: #{[:state]}. Should be one of: [:on, :off]" end state_byte = (state == :on) ? 1 : 0 # Send it. write Message.encode command: 6, pin: pin, value: state_byte, aux_message: pack(:uint8, [mode_byte, exponent]) end |
#set_pin_mode(pin, mode = :input) ⇒ Object
CMD = 0
16 17 18 19 20 21 22 23 |
# File 'lib/denko/board/core.rb', line 16 def set_pin_mode(pin, mode=:input) unless PIN_MODES.keys.include? mode raise ArgumentError, "cannot set mode: #{mode}. Should be one of: #{PIN_MODES.keys.inspect}" end write Message.encode command: 0, pin: pin, value: PIN_MODES[mode] end |
#set_register_divider(value) ⇒ Object
CMD = 95
120 121 122 123 124 125 |
# File 'lib/denko/board/core.rb', line 120 def set_register_divider(value) unless DIVIDERS.include?(value) raise ArgumentError, "error in divider: #{value}. Should be one of: #{DIVIDERS.inspect}" end write Message.encode(command: 95, value: value) end |
#show_ws2812(pin, pixel_buffer) ⇒ Object
3 4 5 6 7 8 9 10 11 12 13 |
# File 'lib/denko/board/led_array.rb', line 3 def show_ws2812(pin, pixel_buffer) # Settings are blank for now. settings = pack :uint8, [0, 0, 0, 0] packed_pixels = pack :uint8, pixel_buffer write_and_halt Message.encode command: 19, pin: pin, value: pixel_buffer.length, aux_message: settings + packed_pixels end |
#spi_bb_header(clock, input, output, write, read, mode, bit_order) ⇒ Object
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# File 'lib/denko/board/spi_bit_bang.rb', line 3 def spi_bb_header(clock, input, output, write, read, mode, bit_order) # Validate clock and data pins raise ArgumentError, "no clock pin given" unless clock raise ArgumentError, "no input or output pin given. Require either or both" unless(input || output) # Set the other to disabled if only one given. input ||= 255 ouptut ||= 255 # Get the generic part of the SPI header. header = spi_header_generic(write, read, mode, bit_order) # Generic header + packed pins + empty byte = bit bang SPI bheader. header = header + pack(:uint8, [clock, input, output, 0]) end |
#spi_bb_listen(select_pin, clock: nil, input: nil, read: 0, frequency: nil, mode: nil, bit_order: nil) ⇒ Object
CMD = 22
31 32 33 34 35 36 37 38 39 |
# File 'lib/denko/board/spi_bit_bang.rb', line 31 def spi_bb_listen(select_pin, clock: nil, input: nil, read: 0, frequency: nil, mode: nil, bit_order: nil) raise ArgumentError, 'no bytes to read. Give read: argument > 0' unless (read > 0) header = spi_bb_header(clock, input, nil, [], read, mode, bit_order) self.write Message.encode command: 22, pin: select_pin, aux_message: header end |
#spi_bb_transfer(select_pin, clock: nil, output: nil, input: nil, write: [], read: 0, frequency: nil, mode: nil, bit_order: nil) ⇒ Object
CMD = 21
20 21 22 23 24 25 26 27 28 |
# File 'lib/denko/board/spi_bit_bang.rb', line 20 def spi_bb_transfer(select_pin, clock: nil, output: nil, input: nil, write: [], read: 0, frequency: nil, mode: nil, bit_order: nil) raise ArgumentError, "no bytes given to read or write" if (read == 0) && (write.empty?) header = spi_bb_header(clock, input, output, write, read, mode, bit_order) self.write Message.encode command: 21, pin: select_pin, aux_message: header + pack(:uint8, write) end |
#spi_header(write, read, frequency, mode, bit_order) ⇒ Object
24 25 26 27 28 29 30 31 32 33 34 35 36 |
# File 'lib/denko/board/spi.rb', line 24 def spi_header(write, read, frequency, mode, bit_order) # Set default frequency and validate. frequency ||= 1000000 unless [Integer, Float].include? frequency.class raise ArgumentError, "error in SPI frequency: #{frequency.inspect}" end # Get the generic part of the SPI header. header = spi_header_generic(write, read, mode, bit_order) # Generic header + packed frequency = hardware SPI header. header + pack(:uint32, frequency) end |
#spi_header_generic(write, read, mode, bit_order) ⇒ Object
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
# File 'lib/denko/board/spi.rb', line 3 def spi_header_generic(write, read, mode, bit_order) # Defaults. mode ||= 0 bit_order ||= :msbfrst raise ArgumentError, "can't read more than 255 SPI bytes at a time" if read > 255 raise ArgumentError, "can't write more than 255 SPI bytes at a time" if write.length > 255 # Lowest 2 bits of settings control the SPI mode. settings = mode unless (0..3).include? settings raise ArgumentError, "invalid SPI mode: #{settings.inspect}. Must be 0, 1, 2, or 3" end # Bit 7 of settings toggles MSBFIRST (1) or LSBFIRST (0) for both read and write. settings = settings | 0b10000000 unless bit_order == :lsbfirst # Return generic portion of header (used by both hardware and bit bang SPI). pack(:uint8, [settings, read, write.length]) end |
#spi_listen(select_pin, read: 0, frequency: nil, mode: nil, bit_order: nil) ⇒ Object
CMD = 27
50 51 52 53 54 55 56 57 58 |
# File 'lib/denko/board/spi.rb', line 50 def spi_listen(select_pin, read: 0, frequency: nil, mode: nil, bit_order: nil) raise ArgumentError, 'no bytes to read. Give read: argument > 0' unless (read > 0) header = spi_header([], read, frequency, mode, bit_order) self.write Message.encode command: 27, pin: select_pin, aux_message: header end |
#spi_stop(select_pin) ⇒ Object
CMD = 28
61 62 63 |
# File 'lib/denko/board/spi.rb', line 61 def spi_stop(select_pin) self.write Message.encode command: 28, pin: select_pin end |
#spi_transfer(select_pin, write: [], read: 0, frequency: nil, mode: nil, bit_order: nil) ⇒ Object
CMD = 26
39 40 41 42 43 44 45 46 47 |
# File 'lib/denko/board/spi.rb', line 39 def spi_transfer(select_pin, write: [], read: 0, frequency: nil, mode: nil, bit_order: nil) raise ArgumentError, "no bytes given to read or write" if (read == 0) && (write.empty?) header = spi_header(write, read, frequency, mode, bit_order) self.write Message.encode command: 26, pin: select_pin, aux_message: header + pack(:uint8, write) end |
#stop_listener(pin) ⇒ Object
103 104 105 |
# File 'lib/denko/board/core.rb', line 103 def stop_listener(pin) set_listener(pin, :off) end |
#substitute_zero_pins ⇒ Object
9 10 11 12 13 14 15 |
# File 'lib/denko/board/map.rb', line 9 def substitute_zero_pins ["SDA", "SCL", "MOSI", "MISO", "SCK", "SS"].each do |name| symbol = name.to_sym zero_symbol = (name + "0").to_sym @map[symbol] = @map[zero_symbol] if (@map[zero_symbol] && !@map[symbol]) end end |
#tone(pin, frequency, duration = nil) ⇒ Object
CMD = 17
4 5 6 7 8 9 10 11 12 13 14 15 16 |
# File 'lib/denko/board/tone.rb', line 4 def tone(pin, frequency, duration=nil) raise ArgumentError, "Tone cannot generate frequencies lower than 31Hz" if frequency < 31 raise ArgumentError, "Tone duration cannot be more than 65535 milliseconds" if (duration && (duration > 0xFFFF)) # Pack the frequency and optional duration as binary. aux = pack(:uint16, frequency) aux << pack(:uint16, duration) if duration write Message.encode command: 17, pin: pin, value: duration ? 1 : 0, aux_message: aux end |
#uart_bb_start(tx, rx, baud, listening = true) ⇒ Object
CMD = 12
4 5 6 7 8 9 10 11 12 |
# File 'lib/denko/board/uart_bit_bang.rb', line 4 def uart_bb_start(tx, rx, baud, listening=true) config = 0b01000000 config |= 0b10000000 if listening self.write Message.encode command: 12, pin: tx, value: rx, aux_message: pack(:uint32, baud) + pack(:uint8, config) end |
#uart_bb_stop ⇒ Object
CMD = 12
15 16 17 18 19 |
# File 'lib/denko/board/uart_bit_bang.rb', line 15 def uart_bb_stop config = 0b00000000 self.write Message.encode command: 12, aux_message: pack(:uint32, [0]) + pack(:uint8, config) end |
#uart_bb_write(data) ⇒ Object
CMD = 13
22 23 24 25 26 27 28 29 30 31 |
# File 'lib/denko/board/uart_bit_bang.rb', line 22 def uart_bb_write(data) if data.class == Array data = pack(:uint8, data) elsif data.class == String else raise ArgumentError, "data to write to UART should be Array of bytes or String. Given: #{data.inspect}" end self.write Message.encode(command: 13, value: data.length, aux_message: data) end |
#uart_start(index, baud, listening = true) ⇒ Object
CMD = 14
8 9 10 11 12 13 14 15 16 17 18 19 20 |
# File 'lib/denko/board/uart.rb', line 8 def uart_start(index, baud, listening=true) raise ArgumentError, "given UART: #{index} out of range. Only 1..3 supported" if (index < 1 || index > 3) unless UART_BAUD_RATES.include?(baud) raise ArgumentError, "given baud rate: #{baud} not supported. Must be in #{UART_BAUD_RATES.inspect}" end config = index | 0b01000000 config |= 0b10000000 if listening self.write Message.encode command: 14, pin: config, aux_message: pack(:uint32, baud) end |
#uart_stop(index) ⇒ Object
CMD = 14
23 24 25 26 |
# File 'lib/denko/board/uart.rb', line 23 def uart_stop(index) raise ArgumentError, "given UART: #{index} out of range. Only 1..3 supported" if (index < 1 || index > 3) self.write Message.encode(command: 14, pin: index) end |
#uart_write(index, data) ⇒ Object
CMD = 15
29 30 31 32 33 34 35 36 37 38 39 40 |
# File 'lib/denko/board/uart.rb', line 29 def uart_write(index, data) raise ArgumentError, "given UART: #{index} out of range. Only 1..3 supported" if (index < 1 || index > 3) if data.class == Array data = pack(:uint8, data) elsif data.class == String else raise ArgumentError, "data to write to UART should be Array of bytes or String. Given: #{data.inspect}" end self.write Message.encode(command: 15, pin: index, value: data.length, aux_message: data) end |
#update(line) ⇒ Object
101 102 103 104 105 106 107 |
# File 'lib/denko/board.rb', line 101 def update(line) pin, = line.split(":", 2) pin = pin.to_i if single_pin_components[pin] single_pin_components[pin].update() end end |
#write(msg) ⇒ Object
78 79 80 |
# File 'lib/denko/board.rb', line 78 def write(msg) @transport.write(msg) end |
#write_and_halt(msg) ⇒ Object
Use Board#write_and_halt to call C++ board functions that disable interrupts for a long time. “Long” being more than 1 serial character (~85us for 115200 baud).
The “halt” part tells the TxRx to halt transmission to the board after this message. Since it expects interrupts to be disabled, any data sent could be lost.
When the board function has re-enabled interrupts, it should call sendReady(). That signal is read by the TxRx, telling it to resume transmisison.
92 93 94 |
# File 'lib/denko/board.rb', line 92 def write_and_halt(msg) @transport.write(msg, true) end |