Module: Denko::Behaviors::Reader
- Included in:
- AnalogIO::ADS111X, Poller, Connection::BinaryEcho, DigitalIO::Input, EEPROM::Board, I2C::BusCommon, I2C::Peripheral, OneWire::Bus, SPI::BusCommon
- Defined in:
- lib/denko/behaviors/reader.rb
Constant Summary collapse
- READ_WAIT_TIME =
0.001
Constants included from Lifecycle
Instance Attribute Summary
Attributes included from State
Instance Method Summary collapse
-
#_read ⇒ Object
NEVER call this directly.
-
#read(*args, **kwargs, &block) ⇒ Object
Delegates to #_read.
- #read_busy? ⇒ Boolean
-
#read_nb(*args, **kwargs, &block) ⇒ Object
Delegates to #_read.
-
#read_raw(reader, *args, **kwargs) ⇒ Object
Similar to #read_using, but does not trigger #pre_callback_filter, or run any callbacks except :read_raw.
-
#read_using(reader, *args, **kwargs, &block) ⇒ Object
Take a proc/lambda/method as the first agrument and use it to read.
-
#update(data) ⇒ Object
Override #update to allow “raw reads” or “normal reads”:.
Methods included from Callbacks
#add_callback, #callbacks, #pre_callback_filter, #remove_callback
Methods included from State
Methods included from Lifecycle
Instance Method Details
#_read ⇒ Object
NEVER call this directly. Use #read_nb instead.
Define #_read in including class to get data which updates the peripheral state. See #read_using comments for more info.
72 73 74 |
# File 'lib/denko/behaviors/reader.rb', line 72 def _read raise NotImplementedError.new("#{self.class.name}#_read is not defined.") end |
#read(*args, **kwargs, &block) ⇒ Object
Delegates to #_read. Data passes through #pre_callback_filter, runs all callbacks, and @state is set. BLOCKS calling thread.
50 51 52 |
# File 'lib/denko/behaviors/reader.rb', line 50 def read(*args, **kwargs, &block) read_using(self.method(:_read), *args, **kwargs, &block) end |
#read_busy? ⇒ Boolean
131 132 133 134 135 |
# File 'lib/denko/behaviors/reader.rb', line 131 def read_busy? # mruby gets stuck waiting somewhere, but doesn't have threads # so it can never really be busy. !Denko.mruby? && (@reading_normally || @reading_raw) end |
#read_nb(*args, **kwargs, &block) ⇒ Object
Delegates to #_read. Data passes through #pre_callback_filter, runs all callbacks, and @state is set. DOES NOT BLOCK calling thread.
58 59 60 61 62 63 64 |
# File 'lib/denko/behaviors/reader.rb', line 58 def read_nb(*args, **kwargs, &block) @reader_mutex.lock sleep READ_WAIT_TIME while read_busy? @reading_normally = true _read(*args, **kwargs, &block) @reader_mutex.unlock end |
#read_raw(reader, *args, **kwargs) ⇒ Object
Similar to #read_using, but does not trigger #pre_callback_filter, or run any callbacks except :read_raw. BLOCKS calling thread. Use for things like sensor status, config etc.
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
# File 'lib/denko/behaviors/reader.rb', line 110 def read_raw(reader, *args, **kwargs) # Can't guarantee read order. raise StandardError, "#read_raw unavailable while listening" if @listening # Lock, THEN wait for any normal read to finish. @reader_mutex.lock sleep READ_WAIT_TIME while read_busy? @reading_raw = true # Special :read_raw one-time callback. return_value = nil add_callback(:read_raw) { |bytes| return_value = bytes } # Call reader, but block and keep the lock until :read_raw callback gets run. reader.call(*args, **kwargs) sleep READ_WAIT_TIME while callbacks[:read_raw] @reader_mutex.unlock return_value end |
#read_using(reader, *args, **kwargs, &block) ⇒ Object
Take a proc/lambda/method as the first agrument and use it to read. Arguments are passed through, allowing dynamic read methods to be defined. Eg. send commands (in args) to a bus, then wait for data read back.
Data is received when the board/bus calls #update on us. If a read was started by this method, the data will pass through #pre_callback_filter, trigger all callbacks, and set @state. Use this for reading the state of peripherals, like digital pin level, enviro sensor reading etc.
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/denko/behaviors/reader.rb', line 86 def read_using(reader, *args, **kwargs, &block) # Lock, THEN wait for other normal reads to finish. @reader_mutex.lock sleep READ_WAIT_TIME while read_busy? @reading_normally = true # One-time callbacks. return_value = nil add_callback(:read) { |filtered_data| return_value = filtered_data } add_callback(:read, &block) if block_given? reader.call(*args, **kwargs) @reader_mutex.unlock # Wait for #update to remove the :read callbacks (return_value is set). sleep READ_WAIT_TIME while callbacks[:read] return_value end |
#update(data) ⇒ Object
Override #update to allow “raw reads” or “normal reads”:
- Normal reads perform normal #update behavior, passing through
#pre_callback_filter, running all callbacks and returning filtered_data.
Use normal for anything that updates the state of a component, and handle
that in in #pre_callback_filter and #update_state.
May or may not block calling thread, depending on platform.
- Raw reads bypass #pre_callback_filter, callbacks, and return
raw data. Use raw for reading things like sensor config/serial etc.
DOES NOT take block callbacks from the use. ALWAYS handle the return value.
ALWAYS blocks the calling thread.
31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/denko/behaviors/reader.rb', line 31 def update(data) if @reading_raw @callback_mutex.lock @callbacks[:read_raw].each { |c| c.call(data) } @callbacks.delete(:read_raw) @callback_mutex.unlock @reading_raw = false data else return_value = super(data) @reading_normally = false return_value end end |