nrf24l01-ruby 0.5
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/.gitignore +10 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +98 -0
- data/binlib/libbcm2835.so +0 -0
- data/example/nrf24_listening_example.rb +51 -0
- data/lib/nrf24-ruby.rb +4 -0
- data/lib/nrf24/bcm2835_driver.rb +31 -0
- data/lib/nrf24/constants.rb +99 -0
- data/lib/nrf24/nrf24-ruby.rb +446 -0
- data/lib/nrf24/version.rb +3 -0
- data/nrf24-ruby.gemspec +24 -0
- metadata +81 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 80a9154047d11cb58a2a2da3656ad3ad2c56199a
|
4
|
+
data.tar.gz: f1ba069e70574c42536902817ce1fcdb28b66c55
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b361d65c676843f806d9dd6fc2f5acf61c9f19a9cd338eb80203a60530e15415d834bd05b9232c024c23a7941bcc64871daa1ba9c6f02bf6f75fef05ae7f3f9e
|
7
|
+
data.tar.gz: 68f63fa0d582514e17fdb317018236d21d0417e5ddfb33a3e78970a67409e701ef600bc70caf099ed22d952910f5f478178f030c0a1895e7453069b99480296a
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 Rogier Lodewijks
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
# nRF24 lib for Ruby
|
2
|
+
|
3
|
+
nrf24-ruby is a pure Ruby library for controlling the ubiquitous nRF24l01(+) radio module. Currently primary target is
|
4
|
+
the Raspberry Pi, but it shouldn't be too hard to port to a different platform (supporting SPI).
|
5
|
+
|
6
|
+
No webserver, no message bus, no frills, yet a fully functional lib written in clear Ruby. (If you're in need of frills,
|
7
|
+
bells, whistles and the like. This library gem works merrily together with all kinds of whistle implementing gems :smile:)
|
8
|
+
|
9
|
+
This gem was based on the [C++ RF24 library by tmrh20](https://github.com/TMRh20/RF24). I made the Ruby implementation
|
10
|
+
mostly because wrapping C++ from Ruby sucks donkey balls.
|
11
|
+
|
12
|
+
## Installing
|
13
|
+
Currently there's only one hardware driver included, which relies on the bcm2835 gem that wraps the [bcm2835 C library](http://www.airspayce.com/mikem/bcm2835). Therefore we need
|
14
|
+
this C lib installed on our system.
|
15
|
+
|
16
|
+
Build the lib
|
17
|
+
|
18
|
+
wget http://www.airspayce.com/mikem/bcm2835/bcm2835-1.49.tar.gz
|
19
|
+
tar zxvf bcm2835-1.49.tar.gz
|
20
|
+
cd bcm2835-1.49
|
21
|
+
./configure
|
22
|
+
make
|
23
|
+
sudo make check
|
24
|
+
|
25
|
+
Make the shared library (.so file) and copy into the correct location
|
26
|
+
|
27
|
+
cd src
|
28
|
+
gcc -shared -o libbcm2835.so bcm2835.o
|
29
|
+
sudo cp libbcm2835.so /usr/local/lib
|
30
|
+
|
31
|
+
_In case you don't feel like building the lib yourself, it's included in /binlib at your convenience._
|
32
|
+
|
33
|
+
**Caveat:** currently we're calling directly into the BCM2835's protected memory space, so we need to run as root.
|
34
|
+
|
35
|
+
Add this line to your application's Gemfile:
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
gem 'nrf24-ruby'
|
39
|
+
```
|
40
|
+
|
41
|
+
And then execute:
|
42
|
+
|
43
|
+
$ bundle
|
44
|
+
|
45
|
+
Or install it yourself as:
|
46
|
+
|
47
|
+
$ gem install nrf24-ruby
|
48
|
+
|
49
|
+
|
50
|
+
|
51
|
+
## Examples
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
require 'nrf24-ruby'
|
55
|
+
```
|
56
|
+
|
57
|
+
The lib may be called using a block
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
NRF24.begin {
|
61
|
+
|
62
|
+
set_channel 23
|
63
|
+
|
64
|
+
print_regs
|
65
|
+
|
66
|
+
open_reading_pipe 1, [65, 65, 65, 65, 65]
|
67
|
+
|
68
|
+
start_listening
|
69
|
+
|
70
|
+
loop do
|
71
|
+
p read if data_available?
|
72
|
+
sleep 0.01
|
73
|
+
end
|
74
|
+
|
75
|
+
}
|
76
|
+
```
|
77
|
+
Or use the plain old instance based approach
|
78
|
+
|
79
|
+
```ruby
|
80
|
+
nrf = NRF24.new(channel: 0x4c)
|
81
|
+
|
82
|
+
nrf.rf_setup :rate_250kbps, :max_power
|
83
|
+
|
84
|
+
address = 'AAAAA'.unpack('c*')
|
85
|
+
nrf.open_reading_pipe 1, address
|
86
|
+
|
87
|
+
nrf.start_listening
|
88
|
+
|
89
|
+
loop do
|
90
|
+
if pipe = nrf.data_available?
|
91
|
+
puts "data on pipe #{pipe}, fifo flags: #{nrf.fifo_flags}"
|
92
|
+
data = nrf.read
|
93
|
+
p data
|
94
|
+
end
|
95
|
+
|
96
|
+
sleep 0.1 # Currently interrupt handling is not supported on Raspberry Pi, so we need to poll for new data
|
97
|
+
end
|
98
|
+
```
|
Binary file
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'msgpack'
|
2
|
+
require 'nrf24-ruby'
|
3
|
+
|
4
|
+
def with_block
|
5
|
+
|
6
|
+
NRF24.begin(channel: 85) {
|
7
|
+
puts "setting channel to #{ch = rand 125}"
|
8
|
+
# ch=85
|
9
|
+
# set_channel ch
|
10
|
+
print_regs
|
11
|
+
|
12
|
+
rf_setup :rate_250kbps, :max_power
|
13
|
+
open_reading_pipe 1, 'AAAAA'.unpack('c*')
|
14
|
+
start_listening
|
15
|
+
|
16
|
+
loop do
|
17
|
+
if data_available?
|
18
|
+
p read
|
19
|
+
puts "bytes received: #{read.count}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
def classic
|
27
|
+
nrf = NRF24.new channel: 85
|
28
|
+
|
29
|
+
nrf.rf_setup :rate_250kbps, :max_power
|
30
|
+
|
31
|
+
address = 'AAAAA'.unpack('c*')
|
32
|
+
nrf.open_reading_pipe 1, address
|
33
|
+
|
34
|
+
nrf.start_listening
|
35
|
+
|
36
|
+
nrf.print_regs
|
37
|
+
nrf.flush_rx
|
38
|
+
|
39
|
+
loop do
|
40
|
+
if pipe = nrf.data_available?
|
41
|
+
puts "Got data on pipe #{pipe}, FIFO flags: #{nrf.fifo_flags}"
|
42
|
+
data = nrf.read
|
43
|
+
p data
|
44
|
+
end
|
45
|
+
|
46
|
+
sleep 0.1
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
classic
|
data/lib/nrf24-ruby.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'bcm2835'
|
2
|
+
|
3
|
+
class NRF24
|
4
|
+
module Bcm2835Driver
|
5
|
+
|
6
|
+
def init_io
|
7
|
+
@spi = Bcm2835::SPI.begin
|
8
|
+
spi.clock Bcm2835::SPI::CLOCK_DIVIDER_128
|
9
|
+
spi.bit_order(Bcm2835::SPI::MSBFIRST)
|
10
|
+
Bcm2835::GPIO.output cepin
|
11
|
+
Bcm2835::GPIO.output csnpin
|
12
|
+
end
|
13
|
+
|
14
|
+
def ce_high
|
15
|
+
Bcm2835::GPIO.set cepin
|
16
|
+
end
|
17
|
+
|
18
|
+
def ce_low
|
19
|
+
Bcm2835::GPIO.clear cepin
|
20
|
+
end
|
21
|
+
|
22
|
+
def csn_high
|
23
|
+
Bcm2835::GPIO.set csnpin
|
24
|
+
end
|
25
|
+
|
26
|
+
def csn_low
|
27
|
+
Bcm2835::GPIO.clear csnpin
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
class NRF24
|
2
|
+
|
3
|
+
COMMANDS = {
|
4
|
+
:r_register => 0x00,
|
5
|
+
:w_register => 0x20,
|
6
|
+
:activate => 0x50, # non-plus register only
|
7
|
+
:r_rx_pl_wid => 0x60,
|
8
|
+
:r_rx_payload => 0x61,
|
9
|
+
:w_tx_payload => 0xa0,
|
10
|
+
:w_ack_payload => 0xa8,
|
11
|
+
:w_tx_payload_noack => 0xb0,
|
12
|
+
:flush_tx => 0xe1,
|
13
|
+
:flush_rx => 0xe2,
|
14
|
+
:reuse_tx_pl => 0xe3,
|
15
|
+
:nop => 0xff
|
16
|
+
}
|
17
|
+
|
18
|
+
REGS = {
|
19
|
+
:config => 0x00, # Configuration Register
|
20
|
+
:en_aa => 0x01, # Enable ‘Auto Acknowledgment’ Function Disable this functionality to be compatible with nRF2401,
|
21
|
+
:en_rxaddr => 0x02, # Enabled RX Addresses
|
22
|
+
:setup_aw => 0x03, # Setup of Address Widths (common for all data pipes)
|
23
|
+
:setup_retr => 0x04, # Setup of Automatic Retransmission
|
24
|
+
:rf_ch => 0x05, # RF Channel
|
25
|
+
:rf_setup => 0x06, # RF Setup Register (power, rate)
|
26
|
+
:nrf_status => 0x07, # a.k.a. nrf24l01.rbStatus
|
27
|
+
:status => 0x07,
|
28
|
+
:observe_tx => 0x08, # Transmit observe register (packets lost, retransmits)
|
29
|
+
:cd => 0x09, # Legacy (nRF24l01 non+) name
|
30
|
+
:rpd => 0x09, # Received power detection (1 == > -64dBm)
|
31
|
+
|
32
|
+
: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)
|
33
|
+
: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)
|
34
|
+
:rx_addr_p2 => 0x0c, # Receive address data pipe 2. Only LSB. MSBytes are equal to RX_ADDR_P1[39:8]
|
35
|
+
:rx_addr_p3 => 0x0d, # Receive address data pipe 3. Only LSB. MSBytes are equal to RX_ADDR_P1[39:8]
|
36
|
+
:rx_addr_p4 => 0x0e, # Receive address data pipe 4. Only LSB. MSBytes are equal to RX_ADDR_P1[39:8]
|
37
|
+
:rx_addr_p5 => 0x0f, # Receive address data pipe 5. Only LSB. MSBytes are equal to RX_ADDR_P1[39:8]
|
38
|
+
|
39
|
+
: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.
|
40
|
+
|
41
|
+
:rx_pw_p0 => 0x11, # Number of bytes in RX payload in data pipe 0-5 (1 to 32 bytes).
|
42
|
+
:rx_pw_p1 => 0x12, #
|
43
|
+
:rx_pw_p2 => 0x13, # 0 Pipe not used
|
44
|
+
:rx_pw_p3 => 0x14, # 1 = 1 byte
|
45
|
+
:rx_pw_p4 => 0x15, # …
|
46
|
+
:rx_pw_p5 => 0x16, # 32 = 32 bytes
|
47
|
+
|
48
|
+
:fifo_status => 0x17, # FIFO Status Register
|
49
|
+
:dynpd => 0x1c,
|
50
|
+
:feature => 0x1d
|
51
|
+
}
|
52
|
+
|
53
|
+
# CONFIG
|
54
|
+
MASK_RX_DR = 6
|
55
|
+
MASK_TX_DS = 5
|
56
|
+
MASK_MAX_RT = 4
|
57
|
+
EN_CRC = 3
|
58
|
+
CRCO = 2
|
59
|
+
PWR_UP = 1
|
60
|
+
PRIM_RX = 0
|
61
|
+
|
62
|
+
# SETUP_RETR
|
63
|
+
ARD = 4
|
64
|
+
ARC = 0
|
65
|
+
|
66
|
+
# STATUS
|
67
|
+
RX_DR = 6 # Data Ready RX FIFO interrupt
|
68
|
+
TX_DS = 5 # Data Sent TX FIFO interrupt
|
69
|
+
MAX_RT = 4 # Maximum number of TX retransmits interrupt Write 1 to clear bit. If MAX_RT is asserted it must be cleared to enable further communication.
|
70
|
+
RX_P_NO = 1 # 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
|
71
|
+
TX_FULL = 0 # TX FIFO full flag. 1: TX FIFO full. 0: Available locations in TX FIFO.
|
72
|
+
|
73
|
+
# observe_tx
|
74
|
+
PLOS_CNT = 4 # 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.
|
75
|
+
ARC_CNT = 0 # 3:0 Count retransmitted packets.
|
76
|
+
|
77
|
+
# FIFO_STATUS
|
78
|
+
TX_REUSE = 6
|
79
|
+
FIFO_TX_FULL = 5
|
80
|
+
FIFO_TX_EMPTY = 4
|
81
|
+
FIFO_RX_FULL = 1
|
82
|
+
FIFO_RX_EMPTY = 0
|
83
|
+
|
84
|
+
# FEATURE
|
85
|
+
EN_DPL = 2
|
86
|
+
EN_ACK_PAY = 1
|
87
|
+
EN_DYN_ACK = 0
|
88
|
+
|
89
|
+
# RF_SETUP
|
90
|
+
RF_DR_LOW = 5
|
91
|
+
PLL_LOCK = 4
|
92
|
+
RF_DR_HIGH = 3
|
93
|
+
RF_PWR_LOW = 1
|
94
|
+
RF_PWR_HIGH = 2
|
95
|
+
LNA_HCURR = 0
|
96
|
+
|
97
|
+
REGISTER_MASK = 0x1F
|
98
|
+
|
99
|
+
end
|
@@ -0,0 +1,446 @@
|
|
1
|
+
require_relative 'constants'
|
2
|
+
class NRF24
|
3
|
+
|
4
|
+
class OverSizedPayload < RuntimeError
|
5
|
+
end
|
6
|
+
|
7
|
+
class TX_Timeout < RuntimeError
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_reader :static_payload_size
|
11
|
+
|
12
|
+
def self.begin *opts, &block
|
13
|
+
nrf = NRF24.new *opts
|
14
|
+
nrf.instance_eval &block if block_given?
|
15
|
+
ensure
|
16
|
+
nrf.send :radio_deinit
|
17
|
+
end
|
18
|
+
|
19
|
+
def start_listening
|
20
|
+
set_register :config, get_register(:config) | bv(PRIM_RX)
|
21
|
+
clear_interrupt_flags
|
22
|
+
ce_high
|
23
|
+
|
24
|
+
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)
|
25
|
+
|
26
|
+
flush_tx if get_register(:feature)[EN_ACK_PAY] > 0
|
27
|
+
end
|
28
|
+
|
29
|
+
def stop_listening
|
30
|
+
ce_low
|
31
|
+
flush_tx if get_register(:feature)[EN_ACK_PAY] > 0
|
32
|
+
set_register :config, get_register(:config) & inv_bv(PRIM_RX)
|
33
|
+
set_register :en_rxaddr, get_register(:en_rxaddr) | 1
|
34
|
+
end
|
35
|
+
|
36
|
+
def write_no_ack payload, *args
|
37
|
+
write(payload, :no_ack, *args)
|
38
|
+
end
|
39
|
+
|
40
|
+
def write payload, type = :ack, timeout = 2
|
41
|
+
start = Time.now
|
42
|
+
|
43
|
+
while fifo_tx_full?
|
44
|
+
if status[MAX_RT] > 0
|
45
|
+
set_register :nrf_status, bv(MAX_RT)
|
46
|
+
return :max_rt
|
47
|
+
end
|
48
|
+
raise TX_Timeout, "TX FIFO full" if Time.now - start > timeout
|
49
|
+
end
|
50
|
+
|
51
|
+
write_payload payload, type
|
52
|
+
|
53
|
+
pulse_ce
|
54
|
+
end
|
55
|
+
|
56
|
+
def write_payload payload, type = :ack
|
57
|
+
if dynamic_payload_enabled?
|
58
|
+
raise OverSizedPayload if payload.size > 32
|
59
|
+
else
|
60
|
+
raise OverSizedPayload if payload.size > static_payload_size
|
61
|
+
padding = static_payload_size - payload.size
|
62
|
+
end
|
63
|
+
|
64
|
+
with_csn {
|
65
|
+
spi.write COMMANDS[type == :no_ack ? :w_tx_payload_noack : :w_tx_payload]
|
66
|
+
spi.write payload
|
67
|
+
spi.write ([0] * padding)
|
68
|
+
}
|
69
|
+
end
|
70
|
+
|
71
|
+
def open_writing_pipe address
|
72
|
+
set_register :rx_addr_p0, address
|
73
|
+
set_register :tx_addr, address
|
74
|
+
set_register :rx_pw_p0, static_payload_size
|
75
|
+
end
|
76
|
+
|
77
|
+
def set_ack_payload pipe, payload
|
78
|
+
raise OverSizedPayload, "ack payload can be 32 bytes max!" if payload.size > 32
|
79
|
+
with_csn {
|
80
|
+
spi.write COMMANDS[:w_ack_payload] | (pipe & 7)
|
81
|
+
spi.write payload
|
82
|
+
}
|
83
|
+
end
|
84
|
+
|
85
|
+
def enable_auto_ack pipes = :all
|
86
|
+
if pipes == :all
|
87
|
+
set_register :en_aa, 0b111111
|
88
|
+
elsif pipes.is_a? Enumerable
|
89
|
+
pipes.map { |p| enable_auto_ack p }
|
90
|
+
else
|
91
|
+
return if pipes > 5
|
92
|
+
set_register :en_aa, get_register(:en_aa) | bv(pipes)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def disable_auto_ack pipes = :all
|
97
|
+
if pipes == :all
|
98
|
+
set_register :en_aa, 0
|
99
|
+
elsif pipes.is_a? Enumerable
|
100
|
+
pipes.map { |p| disable_auto_ack p }
|
101
|
+
else
|
102
|
+
return if pipes > 5
|
103
|
+
set_register :en_aa, get_register(:en_aa) & inv_bv(pipes)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def read
|
108
|
+
payload = read_payload
|
109
|
+
clear_interrupt_flags
|
110
|
+
payload
|
111
|
+
end
|
112
|
+
|
113
|
+
def read_payload
|
114
|
+
send_command :r_rx_payload, payload_size
|
115
|
+
end
|
116
|
+
|
117
|
+
def open_reading_pipe pipe, address
|
118
|
+
@pipe0_reading_address = address if pipe == 0
|
119
|
+
|
120
|
+
if pipe <= 5
|
121
|
+
if pipe < 2
|
122
|
+
set_register REGS[:rx_addr_p0] + pipe, address
|
123
|
+
else
|
124
|
+
set_register REGS[:rx_addr_p0] + pipe, address.first # Only LSB TODO Handle Numeric (byte) address
|
125
|
+
end
|
126
|
+
set_register REGS[:rx_pw_p0] + pipe, static_payload_size
|
127
|
+
|
128
|
+
set_register :en_rxaddr, get_register(:en_rxaddr) | bv(pipe)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def close_reading_pipe pipe
|
133
|
+
set_register :en_rxaddr, get_register(:en_rxaddr) & inv_bv(pipe)
|
134
|
+
end
|
135
|
+
|
136
|
+
def payload_size
|
137
|
+
if dynamic_payload_enabled?
|
138
|
+
get_dynamic_payload_size
|
139
|
+
else
|
140
|
+
static_payload_size
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def set_payload_size pipe, size
|
145
|
+
if pipe.is_a? Enumerable
|
146
|
+
pipe.map { |p| set_payload_size p, size }
|
147
|
+
else
|
148
|
+
return if pipe > 5 # Lets make sure not to screw up other regs
|
149
|
+
set_register(REGS[:rx_pw_p0] + pipe, size)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def get_dynamic_payload_size
|
154
|
+
send_command :r_rx_pl_wid, 1
|
155
|
+
end
|
156
|
+
|
157
|
+
def enable_dynamic_payloads
|
158
|
+
set_register :feature, get_register(:feature) | bv(EN_DPL)
|
159
|
+
set_register :dynpd, 63 # Enable for all pipes
|
160
|
+
end
|
161
|
+
|
162
|
+
def disable_dynamic_payloads
|
163
|
+
set_register :feature, get_register(:feature) & inv_bv(EN_DPL)
|
164
|
+
set_register :dynpd, 0
|
165
|
+
end
|
166
|
+
|
167
|
+
def dynamic_payload_enabled?
|
168
|
+
get_register(:feature)[EN_DPL] > 0
|
169
|
+
end
|
170
|
+
|
171
|
+
def power_up
|
172
|
+
config = get_register(:config)
|
173
|
+
if config[PWR_UP] == 0
|
174
|
+
set_register :config, config | bv(PWR_UP)
|
175
|
+
sleep 0.01
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def power_down
|
180
|
+
ce_low
|
181
|
+
config = get_register(:config) & inv_bv(PWR_UP)
|
182
|
+
set_register :config, config
|
183
|
+
end
|
184
|
+
|
185
|
+
def channel
|
186
|
+
get_register :rf_ch
|
187
|
+
end
|
188
|
+
|
189
|
+
def set_channel ch
|
190
|
+
set_register :rf_ch, ch
|
191
|
+
end
|
192
|
+
|
193
|
+
def rf_setup datarate = :rate_1mbps, power = :max_power
|
194
|
+
available_rates = {
|
195
|
+
:rate_250kbps => 32, 250 => 32,
|
196
|
+
:rate_1mbps => 0, 1 => 0, 1000 => 0,
|
197
|
+
:rate_2mbps => 8, 2 => 8, 2000 => 8
|
198
|
+
}
|
199
|
+
|
200
|
+
pa_settings = {
|
201
|
+
:min_power => 0, -18 => 0, 18 => 0,
|
202
|
+
:low_power => 2, -12 => 2, 12 => 2,
|
203
|
+
:high_power => 4, -6 => 4, 6 => 4,
|
204
|
+
:max_power => 6, 0 => 6
|
205
|
+
}
|
206
|
+
|
207
|
+
rate = available_rates[datarate]
|
208
|
+
power = pa_settings[power]
|
209
|
+
|
210
|
+
return nil unless rate && power
|
211
|
+
|
212
|
+
set_register :rf_setup, (rate | power)
|
213
|
+
get_register :rf_setup
|
214
|
+
end
|
215
|
+
|
216
|
+
def datarate
|
217
|
+
rf_setup = get_register :rf_setup
|
218
|
+
|
219
|
+
if rf_setup[RF_DR_LOW] == 1
|
220
|
+
:rate_250kbps
|
221
|
+
elsif rf_setup[RF_DR_HIGH] == 1
|
222
|
+
:rate_2mbps
|
223
|
+
else
|
224
|
+
:rate_1mbps
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
def crc_length
|
229
|
+
config = get_register(:config)
|
230
|
+
|
231
|
+
if config[EN_CRC] > 0 or get_register(:en_aa) > 0
|
232
|
+
config[CRCO] == 1 ? :crc_16 : :crc_8
|
233
|
+
else
|
234
|
+
:crc_none
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
def set_crc_length length
|
239
|
+
config = get_register(:config) & (~(bv(CRCO) | bv(EN_CRC)) & 0xff)
|
240
|
+
|
241
|
+
if [:crc_16, 16, 2].include? length
|
242
|
+
config |= (bv(EN_CRC) | bv(CRCO))
|
243
|
+
elsif [:crc_8, 8, 1].include? length
|
244
|
+
config |= bv(EN_CRC)
|
245
|
+
end
|
246
|
+
set_register :config, config
|
247
|
+
end
|
248
|
+
|
249
|
+
def disable_crc
|
250
|
+
set_register :config, get_register(:config) & inv_bv(EN_CRC)
|
251
|
+
end
|
252
|
+
|
253
|
+
def set_retries delay, count
|
254
|
+
set_register :setup_retr, ((delay & 0xf) << ARD) | ((count & 0xf) << ARC)
|
255
|
+
end
|
256
|
+
|
257
|
+
def set_tx_address addr
|
258
|
+
set_register :tx_addr, addr
|
259
|
+
end
|
260
|
+
|
261
|
+
def address_width
|
262
|
+
@address_width || (get_register(:setup_aw) + 2)
|
263
|
+
end
|
264
|
+
|
265
|
+
def set_address_width aw = 5
|
266
|
+
aw = (aw - 2) % 4;
|
267
|
+
set_register :setup_aw, aw
|
268
|
+
@address_width = aw + 2
|
269
|
+
end
|
270
|
+
|
271
|
+
def flush_tx
|
272
|
+
send_command :flush_tx
|
273
|
+
end
|
274
|
+
|
275
|
+
def flush_rx
|
276
|
+
send_command :flush_rx
|
277
|
+
end
|
278
|
+
|
279
|
+
def reuse_tx_payload
|
280
|
+
set_register :nrf_status, bv(MAX_RT)
|
281
|
+
send_commnad :reuse_tx_pl
|
282
|
+
pulse_ce
|
283
|
+
end
|
284
|
+
|
285
|
+
def data_available?
|
286
|
+
(status >> RX_P_NO) & 0b111 if not fifo_rx_empty?
|
287
|
+
end
|
288
|
+
|
289
|
+
def fifo_tx_full?
|
290
|
+
get_register(:fifo_status)[FIFO_TX_FULL] > 0
|
291
|
+
end
|
292
|
+
|
293
|
+
def fifo_tx_empty?
|
294
|
+
get_register(:fifo_status)[FIFO_TX_EMPTY] > 0
|
295
|
+
end
|
296
|
+
|
297
|
+
def fifo_rx_full?
|
298
|
+
get_register(:fifo_status)[FIFO_RX_FULL] > 0
|
299
|
+
end
|
300
|
+
|
301
|
+
def fifo_rx_empty?
|
302
|
+
get_register(:fifo_status)[FIFO_RX_EMPTY] > 0
|
303
|
+
end
|
304
|
+
|
305
|
+
def fifo_flags
|
306
|
+
flags = []
|
307
|
+
fifo_status = get_register(:fifo_status)
|
308
|
+
|
309
|
+
flags << :tx_full if fifo_tx_full?
|
310
|
+
flags << :tx_empty if fifo_tx_empty?
|
311
|
+
flags << :rx_full if fifo_rx_full?
|
312
|
+
flags << :rx_empty if fifo_rx_empty?
|
313
|
+
|
314
|
+
flags
|
315
|
+
end
|
316
|
+
|
317
|
+
def received_power
|
318
|
+
get_register(:rpd)
|
319
|
+
end
|
320
|
+
|
321
|
+
def clear_interrupt_flags
|
322
|
+
set_register :nrf_status, (1 << RX_DR) | (1 << TX_DS) | (1 << MAX_RT)
|
323
|
+
end
|
324
|
+
|
325
|
+
def activate
|
326
|
+
send_command :activate, 0x73
|
327
|
+
end
|
328
|
+
|
329
|
+
def status
|
330
|
+
with_csn {
|
331
|
+
spi.read
|
332
|
+
}
|
333
|
+
end
|
334
|
+
|
335
|
+
def set_register reg, value
|
336
|
+
reg = REGS[reg] unless reg.is_a? Numeric
|
337
|
+
with_csn {
|
338
|
+
spi.write(COMMANDS[:w_register] | (REGISTER_MASK & reg))
|
339
|
+
spi.write value
|
340
|
+
}
|
341
|
+
end
|
342
|
+
|
343
|
+
def get_register reg, len = 1
|
344
|
+
reg = REGS[reg] unless reg.is_a? Numeric
|
345
|
+
with_csn {
|
346
|
+
spi.write(COMMANDS[:r_register] | (REGISTER_MASK & reg))
|
347
|
+
len == 1 ? spi.read : spi.read(len) # do not return an array when len == 1
|
348
|
+
} if reg
|
349
|
+
end
|
350
|
+
|
351
|
+
def send_command command, data_len = 0
|
352
|
+
command = COMMANDS[command] unless command.is_a? Numeric
|
353
|
+
with_csn {
|
354
|
+
spi.write command
|
355
|
+
spi.read(data_len) if data_len > 0
|
356
|
+
}
|
357
|
+
end
|
358
|
+
|
359
|
+
def print_regs
|
360
|
+
REGS.each do |i, v|
|
361
|
+
len = [:rx_addr_p0, :rx_addr_p1, :tx_addr].include?(i) ? address_width : 1
|
362
|
+
puts "register #{v.to_s(16).rjust(2, "0")} (#{i}): #{get_register i, len}"
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
366
|
+
private
|
367
|
+
|
368
|
+
alias_method :channel=, :set_channel
|
369
|
+
alias_method :tx_address=, :set_tx_address
|
370
|
+
alias_method :address_width=, :set_address_width
|
371
|
+
alias_method :crc_length=, :set_crc_length
|
372
|
+
|
373
|
+
attr_reader :spi, :cepin, :csnpin
|
374
|
+
|
375
|
+
def initialize opts = {}
|
376
|
+
opts = {cepin: 22, csnpin: 8, static_payload_size: 32, channel: 76, driver: Bcm2835Driver}.merge opts
|
377
|
+
|
378
|
+
@cepin = opts[:cepin]
|
379
|
+
@csnpin = opts[:csnpin]
|
380
|
+
@static_payload_size = [opts[:static_payload_size], 32].min
|
381
|
+
@channel = opts[:channel]
|
382
|
+
|
383
|
+
extend opts[:driver]
|
384
|
+
|
385
|
+
init_io
|
386
|
+
radio_init
|
387
|
+
|
388
|
+
@pipe0_reading_address = nil
|
389
|
+
end
|
390
|
+
|
391
|
+
def radio_init
|
392
|
+
activate # nrf24l01 (non-plus) compatibility
|
393
|
+
|
394
|
+
set_address_width
|
395
|
+
|
396
|
+
set_channel @channel
|
397
|
+
|
398
|
+
set_payload_size (0..5), static_payload_size
|
399
|
+
disable_dynamic_payloads
|
400
|
+
enable_auto_ack
|
401
|
+
|
402
|
+
set_register :config, ((1 << EN_CRC) | (1 << CRCO) | (1 << PWR_UP) | (1 << PRIM_RX))
|
403
|
+
|
404
|
+
clear_interrupt_flags
|
405
|
+
|
406
|
+
flush_rx
|
407
|
+
flush_tx
|
408
|
+
end
|
409
|
+
|
410
|
+
def radio_deinit
|
411
|
+
ce_low
|
412
|
+
radio_init
|
413
|
+
rf_setup
|
414
|
+
set_channel 0
|
415
|
+
end
|
416
|
+
|
417
|
+
def with_csn
|
418
|
+
csn_low
|
419
|
+
ret = yield
|
420
|
+
csn_high
|
421
|
+
ret
|
422
|
+
end
|
423
|
+
|
424
|
+
def with_ce
|
425
|
+
ce_high
|
426
|
+
ret = yield
|
427
|
+
ce_low
|
428
|
+
ret
|
429
|
+
end
|
430
|
+
|
431
|
+
def pulse_ce us = 10
|
432
|
+
ce_high
|
433
|
+
sleep(0.000001 * us)
|
434
|
+
ce_low
|
435
|
+
end
|
436
|
+
|
437
|
+
# Low level bit vector stuff
|
438
|
+
def bv d
|
439
|
+
1 << d
|
440
|
+
end
|
441
|
+
|
442
|
+
def inv_bv d, mask = 0xff
|
443
|
+
~(1 << d) & mask
|
444
|
+
end
|
445
|
+
|
446
|
+
end
|
data/nrf24-ruby.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'nrf24/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "nrf24l01-ruby"
|
8
|
+
spec.version = NRF24::VERSION
|
9
|
+
spec.authors = ["Rogier Lodewijks"]
|
10
|
+
spec.email = ["rogier@lodewijks.org"]
|
11
|
+
|
12
|
+
spec.summary = %q{nrf24-ruby is a pure Ruby library for controlling the ubiquitous Nordic nRF24l01(+) radio module.}
|
13
|
+
spec.description = %q{nrf24-ruby is a pure Ruby library for controlling the ubiquitous Nordic nRF24l01(+) radio module. Currently primary target is the Raspberry Pi, but it shouldn't be too hard to port to a different platform (supporting SPI). No webserver, no message bus, no frills, yet a fully functional lib written in clear Ruby.}
|
14
|
+
|
15
|
+
spec.homepage = "https://github.com/eflukx/nrf24-ruby"
|
16
|
+
spec.license = "MIT"
|
17
|
+
|
18
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
19
|
+
spec.bindir = "exe"
|
20
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
21
|
+
spec.require_paths = ["lib", "lib/nrf24"]
|
22
|
+
|
23
|
+
spec.add_dependency 'bcm2835', '~> 0.0', '>= 0.0.1'
|
24
|
+
end
|
metadata
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: nrf24l01-ruby
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '0.5'
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Rogier Lodewijks
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-04-03 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bcm2835
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.0'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 0.0.1
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0.0'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 0.0.1
|
33
|
+
description: nrf24-ruby is a pure Ruby library for controlling the ubiquitous Nordic
|
34
|
+
nRF24l01(+) radio module. Currently primary target is the Raspberry Pi, but it shouldn't
|
35
|
+
be too hard to port to a different platform (supporting SPI). No webserver, no message
|
36
|
+
bus, no frills, yet a fully functional lib written in clear Ruby.
|
37
|
+
email:
|
38
|
+
- rogier@lodewijks.org
|
39
|
+
executables: []
|
40
|
+
extensions: []
|
41
|
+
extra_rdoc_files: []
|
42
|
+
files:
|
43
|
+
- ".gitignore"
|
44
|
+
- Gemfile
|
45
|
+
- LICENSE.txt
|
46
|
+
- README.md
|
47
|
+
- binlib/libbcm2835.so
|
48
|
+
- example/nrf24_listening_example.rb
|
49
|
+
- lib/nrf24-ruby.rb
|
50
|
+
- lib/nrf24/bcm2835_driver.rb
|
51
|
+
- lib/nrf24/constants.rb
|
52
|
+
- lib/nrf24/nrf24-ruby.rb
|
53
|
+
- lib/nrf24/version.rb
|
54
|
+
- nrf24-ruby.gemspec
|
55
|
+
homepage: https://github.com/eflukx/nrf24-ruby
|
56
|
+
licenses:
|
57
|
+
- MIT
|
58
|
+
metadata: {}
|
59
|
+
post_install_message:
|
60
|
+
rdoc_options: []
|
61
|
+
require_paths:
|
62
|
+
- lib
|
63
|
+
- lib/nrf24
|
64
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0'
|
74
|
+
requirements: []
|
75
|
+
rubyforge_project:
|
76
|
+
rubygems_version: 2.2.5
|
77
|
+
signing_key:
|
78
|
+
specification_version: 4
|
79
|
+
summary: nrf24-ruby is a pure Ruby library for controlling the ubiquitous Nordic nRF24l01(+)
|
80
|
+
radio module.
|
81
|
+
test_files: []
|