Class: NRF24

Inherits:
Object
  • Object
show all
Defined in:
lib/nrf24/version.rb,
lib/nrf24/constants.rb,
lib/nrf24/nrf24-ruby.rb,
lib/nrf24/bcm2835_driver.rb

Defined Under Namespace

Modules: Bcm2835Driver Classes: OverSizedPayload, TX_Timeout

Constant Summary collapse

VERSION =
'0.5.1'
COMMANDS =
{
    :r_register => 0x00,
    :w_register => 0x20,
    :activate => 0x50, # non-plus register only
    :r_rx_pl_wid => 0x60,
    :r_rx_payload => 0x61,
    :w_tx_payload => 0xa0,
    :w_ack_payload => 0xa8,
    :w_tx_payload_noack => 0xb0,
    :flush_tx => 0xe1,
    :flush_rx => 0xe2,
    :reuse_tx_pl => 0xe3,
    :nop => 0xff
}
REGS =
{
    :config => 0x00, # Configuration Register
    :en_aa => 0x01, # Enable ‘Auto Acknowledgment’ Function Disable this functionality to be compatible with nRF2401,
    :en_rxaddr => 0x02, # Enabled RX Addresses
    :setup_aw => 0x03, # Setup of Address Widths (common for all data pipes)
    :setup_retr => 0x04, # Setup of Automatic Retransmission
    :rf_ch => 0x05, # RF Channel
    :rf_setup => 0x06, # RF Setup Register (power, rate)
    :nrf_status => 0x07, # a.k.a. nrf24l01.rbStatus
    :status => 0x07,
    :observe_tx => 0x08, # Transmit observe register (packets lost, retransmits)
    :cd => 0x09, # Legacy (nRF24l01 non+) name
    :rpd => 0x09, # Received power detection (1 == > -64dBm)

    :rx_addr_p0 => 0x0a, # Receive address data pipe 0. 5 Bytes maximum length. (LSByte is written first. Write the number of bytes defined by SETUP_AW)
    :rx_addr_p1 => 0x0b, # Receive address data pipe 1. 5 Bytes maximum length. (LSByte is written first. Write the number of bytes defined by SETUP_AW)
    :rx_addr_p2 => 0x0c, # Receive address data pipe 2. Only LSB. MSBytes are equal to RX_ADDR_P1[39:8]
    :rx_addr_p3 => 0x0d, # Receive address data pipe 3. Only LSB. MSBytes are equal to RX_ADDR_P1[39:8]
    :rx_addr_p4 => 0x0e, # Receive address data pipe 4. Only LSB. MSBytes are equal to RX_ADDR_P1[39:8]
    :rx_addr_p5 => 0x0f, # Receive address data pipe 5. Only LSB. MSBytes are equal to RX_ADDR_P1[39:8]

    :tx_addr => 0x10, # Transmit address. Used for a PTX device only. (LSByte is written first) Set RX_ADDR_P0 equal to this address to handle automatic acknowledge if this is a PTX device with Enhanced ShockBurst™ enabled.

    :rx_pw_p0 => 0x11, # Number of bytes in RX payload in data pipe 0-5 (1 to 32 bytes).
    :rx_pw_p1 => 0x12, #
    :rx_pw_p2 => 0x13, # 0 Pipe not used
    :rx_pw_p3 => 0x14, # 1 = 1 byte
    :rx_pw_p4 => 0x15, # …
    :rx_pw_p5 => 0x16, # 32 = 32 bytes

    :fifo_status => 0x17, # FIFO Status Register
    :dynpd => 0x1c,
    :feature => 0x1d
}
MASK_RX_DR =

CONFIG

6
MASK_TX_DS =
5
MASK_MAX_RT =
4
EN_CRC =
3
CRCO =
2
PWR_UP =
1
PRIM_RX =
0
ARD =

SETUP_RETR

4
ARC =
0
RX_DR =

STATUS

6
TX_DS =

Data Ready RX FIFO interrupt

5
MAX_RT =

Data Sent TX FIFO interrupt

4
RX_P_NO =

Maximum number of TX retransmits interrupt Write 1 to clear bit. If MAX_RT is asserted it must be cleared to enable further communication.

1
TX_FULL =

bit 3:1 Data pipe number for the payload available for reading from RX_FIFO 000-101: Data Pipe Number 110: Not Used 111: RX FIFO Empty

0
PLOS_CNT =

observe_tx

4
ARC_CNT =

7:4 Count lost packets. The counter is overflow protected to 15, and discontinues at max until reset. The counter is reset by writing to RF_CH.

0
TX_REUSE =

FIFO_STATUS

6
FIFO_TX_FULL =
5
FIFO_TX_EMPTY =
4
FIFO_RX_FULL =
1
FIFO_RX_EMPTY =
0
EN_DPL =

FEATURE

2
EN_ACK_PAY =
1
EN_DYN_ACK =
0
RF_DR_LOW =

RF_SETUP

5
PLL_LOCK =
4
RF_DR_HIGH =
3
RF_PWR_LOW =
1
RF_PWR_HIGH =
2
LNA_HCURR =
0
REGISTER_MASK =
0x1F

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#static_payload_sizeObject (readonly)

Returns the value of attribute static_payload_size.



10
11
12
# File 'lib/nrf24/nrf24-ruby.rb', line 10

def static_payload_size
  @static_payload_size
end

Class Method Details

.begin(*opts, &block) ⇒ Object



12
13
14
15
16
17
# File 'lib/nrf24/nrf24-ruby.rb', line 12

def self.begin *opts, &block
  nrf = NRF24.new *opts
  nrf.instance_eval &block if block_given?
ensure
  nrf.send :radio_deinit
end

Instance Method Details

#activateObject



325
326
327
# File 'lib/nrf24/nrf24-ruby.rb', line 325

def activate
  send_command :activate, 0x73
end

#address_widthObject



261
262
263
# File 'lib/nrf24/nrf24-ruby.rb', line 261

def address_width
  @address_width || (get_register(:setup_aw) + 2)
end

#channelObject



185
186
187
# File 'lib/nrf24/nrf24-ruby.rb', line 185

def channel
  get_register :rf_ch
end

#clear_interrupt_flagsObject



321
322
323
# File 'lib/nrf24/nrf24-ruby.rb', line 321

def clear_interrupt_flags
  set_register :nrf_status, (1 << RX_DR) | (1 << TX_DS) | (1 << MAX_RT)
end

#close_reading_pipe(pipe) ⇒ Object



132
133
134
# File 'lib/nrf24/nrf24-ruby.rb', line 132

def close_reading_pipe pipe
  set_register :en_rxaddr, get_register(:en_rxaddr) & inv_bv(pipe)
end

#crc_lengthObject



228
229
230
231
232
233
234
235
236
# File 'lib/nrf24/nrf24-ruby.rb', line 228

def crc_length
  config = get_register(:config)

  if config[EN_CRC] > 0 or get_register(:en_aa) > 0
    config[CRCO] == 1 ? :crc_16 : :crc_8
  else
    :crc_none
  end
end

#data_available?Boolean

Returns:

  • (Boolean)


285
286
287
# File 'lib/nrf24/nrf24-ruby.rb', line 285

def data_available?
  (status >> RX_P_NO) & 0b111 if not fifo_rx_empty?
end

#datarateObject



216
217
218
219
220
221
222
223
224
225
226
# File 'lib/nrf24/nrf24-ruby.rb', line 216

def datarate
  rf_setup = get_register :rf_setup

  if rf_setup[RF_DR_LOW] == 1
    :rate_250kbps
  elsif rf_setup[RF_DR_HIGH] == 1
    :rate_2mbps
  else
    :rate_1mbps
  end
end

#disable_auto_ack(pipes = :all) ⇒ Object



96
97
98
99
100
101
102
103
104
105
# File 'lib/nrf24/nrf24-ruby.rb', line 96

def disable_auto_ack pipes = :all
  if pipes == :all
    set_register :en_aa, 0
  elsif pipes.is_a? Enumerable
    pipes.map { |p| disable_auto_ack p }
  else
    return if pipes > 5
    set_register :en_aa, get_register(:en_aa) & inv_bv(pipes)
  end
end

#disable_crcObject



249
250
251
# File 'lib/nrf24/nrf24-ruby.rb', line 249

def disable_crc
  set_register :config, get_register(:config) & inv_bv(EN_CRC)
end

#disable_dynamic_payloadsObject



162
163
164
165
# File 'lib/nrf24/nrf24-ruby.rb', line 162

def disable_dynamic_payloads
  set_register :feature, get_register(:feature) & inv_bv(EN_DPL)
  set_register :dynpd, 0
end

#dynamic_payload_enabled?Boolean

Returns:

  • (Boolean)


167
168
169
# File 'lib/nrf24/nrf24-ruby.rb', line 167

def dynamic_payload_enabled?
  get_register(:feature)[EN_DPL] > 0
end

#enable_auto_ack(pipes = :all) ⇒ Object



85
86
87
88
89
90
91
92
93
94
# File 'lib/nrf24/nrf24-ruby.rb', line 85

def enable_auto_ack pipes = :all
  if pipes == :all
    set_register :en_aa, 0b111111
  elsif pipes.is_a? Enumerable
    pipes.map { |p| enable_auto_ack p }
  else
    return if pipes > 5
    set_register :en_aa, get_register(:en_aa) | bv(pipes)
  end
end

#enable_dynamic_payloadsObject



157
158
159
160
# File 'lib/nrf24/nrf24-ruby.rb', line 157

def enable_dynamic_payloads
  set_register :feature, get_register(:feature) | bv(EN_DPL)
  set_register :dynpd, 63 # Enable for all pipes
end

#fifo_flagsObject



305
306
307
308
309
310
311
312
313
314
315
# File 'lib/nrf24/nrf24-ruby.rb', line 305

def fifo_flags
  flags = []
  fifo_status = get_register(:fifo_status)

  flags << :tx_full if fifo_tx_full?
  flags << :tx_empty if fifo_tx_empty?
  flags << :rx_full if fifo_rx_full?
  flags << :rx_empty if fifo_rx_empty?

  flags
end

#fifo_rx_empty?Boolean

Returns:

  • (Boolean)


301
302
303
# File 'lib/nrf24/nrf24-ruby.rb', line 301

def fifo_rx_empty?
  get_register(:fifo_status)[FIFO_RX_EMPTY] > 0
end

#fifo_rx_full?Boolean

Returns:

  • (Boolean)


297
298
299
# File 'lib/nrf24/nrf24-ruby.rb', line 297

def fifo_rx_full?
  get_register(:fifo_status)[FIFO_RX_FULL] > 0
end

#fifo_tx_empty?Boolean

Returns:

  • (Boolean)


293
294
295
# File 'lib/nrf24/nrf24-ruby.rb', line 293

def fifo_tx_empty?
  get_register(:fifo_status)[FIFO_TX_EMPTY] > 0
end

#fifo_tx_full?Boolean

Returns:

  • (Boolean)


289
290
291
# File 'lib/nrf24/nrf24-ruby.rb', line 289

def fifo_tx_full?
  get_register(:fifo_status)[FIFO_TX_FULL] > 0
end

#flush_rxObject



275
276
277
# File 'lib/nrf24/nrf24-ruby.rb', line 275

def flush_rx
  send_command :flush_rx
end

#flush_txObject



271
272
273
# File 'lib/nrf24/nrf24-ruby.rb', line 271

def flush_tx
  send_command :flush_tx
end

#get_dynamic_payload_sizeObject



153
154
155
# File 'lib/nrf24/nrf24-ruby.rb', line 153

def get_dynamic_payload_size
  send_command :r_rx_pl_wid, 1
end

#get_register(reg, len = 1) ⇒ Object



343
344
345
346
347
348
349
# File 'lib/nrf24/nrf24-ruby.rb', line 343

def get_register reg, len = 1
  reg = REGS[reg] unless reg.is_a? Numeric
  with_csn {
    spi.write(COMMANDS[:r_register] | (REGISTER_MASK & reg))
    len == 1 ? spi.read : spi.read(len) # do not return an array when len == 1
  } if reg
end

#open_reading_pipe(pipe, address) ⇒ Object



117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/nrf24/nrf24-ruby.rb', line 117

def open_reading_pipe pipe, address
  @pipe0_reading_address = address if pipe == 0

  if pipe <= 5
    if pipe < 2
      set_register REGS[:rx_addr_p0] + pipe, address
    else
      set_register REGS[:rx_addr_p0] + pipe, address.first # Only LSB TODO Handle Numeric (byte) address
    end
    set_register REGS[:rx_pw_p0] + pipe, static_payload_size

    set_register :en_rxaddr, get_register(:en_rxaddr) | bv(pipe)
  end
end

#open_writing_pipe(address) ⇒ Object



71
72
73
74
75
# File 'lib/nrf24/nrf24-ruby.rb', line 71

def open_writing_pipe address
  set_register :rx_addr_p0, address
  set_register :tx_addr, address
  set_register :rx_pw_p0, static_payload_size
end

#payload_sizeObject



136
137
138
139
140
141
142
# File 'lib/nrf24/nrf24-ruby.rb', line 136

def payload_size
  if dynamic_payload_enabled?
    get_dynamic_payload_size
  else
    static_payload_size
  end
end

#power_downObject



179
180
181
182
183
# File 'lib/nrf24/nrf24-ruby.rb', line 179

def power_down
  ce_low
  config = get_register(:config) & inv_bv(PWR_UP)
  set_register :config, config
end

#power_upObject



171
172
173
174
175
176
177
# File 'lib/nrf24/nrf24-ruby.rb', line 171

def power_up
  config = get_register(:config)
  if config[PWR_UP] == 0
    set_register :config, config | bv(PWR_UP)
    sleep 0.01
  end
end


359
360
361
362
363
364
# File 'lib/nrf24/nrf24-ruby.rb', line 359

def print_regs
  REGS.each do |i, v|
    len = [:rx_addr_p0, :rx_addr_p1, :tx_addr].include?(i) ? address_width : 1
    puts "register #{v.to_s(16).rjust(2, "0")} (#{i}): #{get_register i, len}"
  end
end

#readObject



107
108
109
110
111
# File 'lib/nrf24/nrf24-ruby.rb', line 107

def read
  payload = read_payload
  clear_interrupt_flags
  payload
end

#read_payloadObject



113
114
115
# File 'lib/nrf24/nrf24-ruby.rb', line 113

def read_payload
  send_command :r_rx_payload, payload_size
end

#received_powerObject



317
318
319
# File 'lib/nrf24/nrf24-ruby.rb', line 317

def received_power
  get_register(:rpd)
end

#reuse_tx_payloadObject



279
280
281
282
283
# File 'lib/nrf24/nrf24-ruby.rb', line 279

def reuse_tx_payload
  set_register :nrf_status, bv(MAX_RT)
  send_commnad :reuse_tx_pl
  pulse_ce
end

#rf_setup(datarate = :rate_1mbps, power = :max_power) ⇒ Object



193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
# File 'lib/nrf24/nrf24-ruby.rb', line 193

def rf_setup datarate = :rate_1mbps, power = :max_power
  available_rates = {
      :rate_250kbps => 32, 250 => 32,
      :rate_1mbps => 0, 1 => 0, 1000 => 0,
      :rate_2mbps => 8, 2 => 8, 2000 => 8
  }

  pa_settings = {
      :min_power => 0, -18 => 0, 18 => 0,
      :low_power => 2, -12 => 2, 12 => 2,
      :high_power => 4, -6 => 4, 6 => 4,
      :max_power => 6, 0 => 6
  }

  rate = available_rates[datarate]
  power = pa_settings[power]

  return nil unless rate && power

  set_register :rf_setup, (rate | power)
  get_register :rf_setup
end

#send_command(command, data_len = 0) ⇒ Object



351
352
353
354
355
356
357
# File 'lib/nrf24/nrf24-ruby.rb', line 351

def send_command command, data_len = 0
  command = COMMANDS[command] unless command.is_a? Numeric
  with_csn {
    spi.write command
    spi.read(data_len) if data_len > 0
  }
end

#set_ack_payload(pipe, payload) ⇒ Object

Raises:



77
78
79
80
81
82
83
# File 'lib/nrf24/nrf24-ruby.rb', line 77

def set_ack_payload pipe, payload
  raise OverSizedPayload, "ack payload can be 32 bytes max!" if payload.size > 32
  with_csn {
    spi.write COMMANDS[:w_ack_payload] | (pipe & 7)
    spi.write payload
  }
end

#set_address_width(aw = 5) ⇒ Object Also known as: address_width=



265
266
267
268
269
# File 'lib/nrf24/nrf24-ruby.rb', line 265

def set_address_width aw = 5
  aw = (aw - 2) % 4;
  set_register :setup_aw, aw
  @address_width = aw + 2
end

#set_channel(ch) ⇒ Object Also known as: channel=



189
190
191
# File 'lib/nrf24/nrf24-ruby.rb', line 189

def set_channel ch
  set_register :rf_ch, ch
end

#set_crc_length(length) ⇒ Object Also known as: crc_length=



238
239
240
241
242
243
244
245
246
247
# File 'lib/nrf24/nrf24-ruby.rb', line 238

def set_crc_length length
  config = get_register(:config) & (~(bv(CRCO) | bv(EN_CRC)) & 0xff)

  if [:crc_16, 16, 2].include? length
    config |= (bv(EN_CRC) | bv(CRCO))
  elsif [:crc_8, 8, 1].include? length
    config |= bv(EN_CRC)
  end
  set_register :config, config
end

#set_payload_size(pipe, size) ⇒ Object



144
145
146
147
148
149
150
151
# File 'lib/nrf24/nrf24-ruby.rb', line 144

def set_payload_size pipe, size
  if pipe.is_a? Enumerable
    pipe.map { |p| set_payload_size p, size }
  else
    return if pipe > 5 # Lets make sure not to screw up other regs
    set_register(REGS[:rx_pw_p0] + pipe, size)
  end
end

#set_register(reg, value) ⇒ Object



335
336
337
338
339
340
341
# File 'lib/nrf24/nrf24-ruby.rb', line 335

def set_register reg, value
  reg = REGS[reg] unless reg.is_a? Numeric
  with_csn {
    spi.write(COMMANDS[:w_register] | (REGISTER_MASK & reg))
    spi.write value
  }
end

#set_retries(delay, count) ⇒ Object



253
254
255
# File 'lib/nrf24/nrf24-ruby.rb', line 253

def set_retries delay, count
  set_register :setup_retr, ((delay & 0xf) << ARD) | ((count & 0xf) << ARC)
end

#set_tx_address(addr) ⇒ Object Also known as: tx_address=



257
258
259
# File 'lib/nrf24/nrf24-ruby.rb', line 257

def set_tx_address addr
  set_register :tx_addr, addr
end

#start_listeningObject



19
20
21
22
23
24
25
26
27
# File 'lib/nrf24/nrf24-ruby.rb', line 19

def start_listening
  set_register :config, get_register(:config) | bv(PRIM_RX)
  clear_interrupt_flags
  ce_high

  set_register :rx_addr_p0, @pipe0_reading_address if @pipe0_reading_address # Restore address, as this could be overwritten during a PTX cycle (Pipe 0 is used for receiving auto-acks)

  flush_tx if get_register(:feature)[EN_ACK_PAY] > 0
end

#statusObject



329
330
331
332
333
# File 'lib/nrf24/nrf24-ruby.rb', line 329

def status
  with_csn {
    spi.read
  }
end

#stop_listeningObject



29
30
31
32
33
34
# File 'lib/nrf24/nrf24-ruby.rb', line 29

def stop_listening
  ce_low
  flush_tx if get_register(:feature)[EN_ACK_PAY] > 0
  set_register :config, get_register(:config) & inv_bv(PRIM_RX)
  set_register :en_rxaddr, get_register(:en_rxaddr) | 1
end

#write(payload, type = :ack, timeout = 2) ⇒ Object



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/nrf24/nrf24-ruby.rb', line 40

def write payload, type = :ack, timeout = 2
  start = Time.now

  while fifo_tx_full?
    if status[MAX_RT] > 0
      set_register :nrf_status, bv(MAX_RT)
      return :max_rt
    end
    raise TX_Timeout, "TX FIFO full" if Time.now - start > timeout
  end

  write_payload payload, type

  pulse_ce
end

#write_no_ack(payload, *args) ⇒ Object



36
37
38
# File 'lib/nrf24/nrf24-ruby.rb', line 36

def write_no_ack payload, *args
  write(payload, :no_ack, *args)
end

#write_payload(payload, type = :ack) ⇒ Object



56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/nrf24/nrf24-ruby.rb', line 56

def write_payload payload, type = :ack
  if dynamic_payload_enabled?
    raise OverSizedPayload if payload.size > 32
  else
    raise OverSizedPayload if payload.size > static_payload_size
    padding = static_payload_size - payload.size
  end

  with_csn {
    spi.write COMMANDS[type == :no_ack ? :w_tx_payload_noack : :w_tx_payload]
    spi.write payload
    spi.write ([0] * padding)
  }
end