RadioHead
RH_NRF51.h
1 // RH_NRF51.h
2 // Author: Mike McCauley
3 // Copyright (C) 2015 Mike McCauley
4 // $Id: RH_NRF51.h,v 1.5 2017/07/25 05:26:50 mikem Exp $
5 //
6 
7 #ifndef RH_NRF51_h
8 #define RH_NRF51_h
9 
10 #include <RHGenericDriver.h>
11 
12 // This is the maximum number of bytes that can be carried by the nRF51.
13 // We use some for headers, keeping fewer for RadioHead messages
14 #define RH_NRF51_MAX_PAYLOAD_LEN 254
15 
16 // The length of the headers we add.
17 // The headers are inside the nRF51 payload
18 // We add:
19 // S0 (not used)
20 // LEN
21 // S1 (not used)
22 // to
23 // from
24 // id
25 // flags
26 #define RH_NRF51_HEADER_LEN 7
27 
28 // This is the maximum RadioHead user message length that can be supported by this library. Limited by
29 // the supported message lengths in the nRF51
30 #define RH_NRF51_MAX_MESSAGE_LEN (RH_NRF51_MAX_PAYLOAD_LEN-RH_NRF51_HEADER_LEN)
31 
32 // Define to be 1 if you want to support AES CCA encryption using the built-in
33 // encryption engine.
34 #define RH_NRF51_HAVE_ENCRYPTION 1
35 
36 // When encryption is enabled, have a much shorter max message length
37 #define RH_NRF51_MAX_ENCRYPTED_MESSAGE_LEN (27-4)
38 
39 // The required length of the AES encryption key
40 #define RH_NRF51_ENCRYPTION_KEY_LENGTH 16
41 
42 // This is the size of the CCM data structure for AES encryption
43 // REVISIT: use a struct?
44 #define RH_NRF51_AES_CCM_CNF_SIZE 33
45 
46 /////////////////////////////////////////////////////////////////////
47 /// \class RH_NRF51 RH_NRF51.h <RH_NRF51.h>
48 /// \brief Send and receive unaddressed, unreliable datagrams by nRF51 and nRF52 compatible transceivers.
49 ///
50 /// Supported transceivers include:
51 /// - Nordic nRF51 based 2.4GHz radio modules, such as nRF51822
52 /// and other compatible chips, such as used in RedBearLabs devices like:
53 /// http://store.redbearlab.com/products/redbearlab-nrf51822
54 /// http://store.redbearlab.com/products/blenano
55 /// and
56 /// Sparkfun nRF52832 breakout board, with Arduino 1.6.13 and
57 /// Sparkfun nRF52 boards manager 0.2.3
58 ///
59 /// This base class provides basic functions for sending and receiving unaddressed, unreliable datagrams
60 /// of arbitrary length to 254 octets per packet. Use one of the Manager classes to get addressing and
61 /// acknowledgement reliability, routing, meshes etc.
62 ///
63 /// The nRF51822 (https://www.nordicsemi.com/eng/Products/Bluetooth-Smart-Bluetooth-low-energy/nRF51822)
64 /// and nRF52832 (https://learn.sparkfun.com/tutorials/nrf52832-breakout-board-hookup-guide)
65 /// is a complete SoC (system on a chip) with ARM microprocessor and 2.4 GHz radio, which supports a range of channels
66 /// and transmission bit rates. Chip antenna is on-board.
67 ///
68 /// This library provides functions for sending and receiving messages of up to 254 octets on any
69 /// frequency supported by the nRF51822/nRF52832, at a selected data rate.
70 ///
71 /// The nRF51 transceiver is configured to use Enhanced Shockburst with no acknowledgement and no retransmits.
72 /// TXADDRESS and RXADDRESSES:RXADDR0 (ie pipe 0) are the logical address used. The on-air network address
73 /// is set in BASE0 and PREFIX0. SHORTS is used to automatically transition the radio between Ready, Start and Disable.
74 /// No interrupts are used.
75 ///
76 /// Naturally, for any 2 radios to communicate that must be configured to use the same frequency and
77 /// data rate, and with identical network addresses.
78 ///
79 /// Example programs are included to show the main modes of use.
80 ///
81 /// \par Packet Format
82 ///
83 /// All messages sent and received by this class conform to this packet format. It is NOT compatible
84 /// with the one used by RH_NRF24 and the nRF24L01 product specification, mainly because the nRF24 only supports
85 /// 6 bits of message length.
86 ///
87 /// - 1 octets PREAMBLE
88 /// - 3 to 5 octets NETWORK ADDRESS
89 /// - 1 octet S0 (not used, required if encryption used)
90 /// - 8 bits PAYLOAD LENGTH
91 /// - 1 octet S1 (not used, required if encryption used)
92 /// - 0 to 251 octets PAYLOAD (possibly encrypted), consisting of:
93 /// - 1 octet TO header
94 /// - 1 octet FROM header
95 /// - 1 octet ID header
96 /// - 1 octet FLAGS header
97 /// - 0 to 247 octets of user message
98 /// - 2 octets CRC (Algorithm x^16+x^12^x^5+1 with initial value 0xFFFF).
99 ///
100 /// \par Example programs
101 ///
102 /// Several example programs are provided.
103 ///
104 /// The sample programs are designed to be built using Arduino 1.6.4 or later using the procedures outlined
105 /// in http://redbearlab.com/getting-started-nrf51822/
106 /// or with Sparkfun nRF52832 breakout board, with Arduino 1.6.13 and
107 /// Sparkfun nRF52 boards manager 0.2.3 using the procedures outlined in
108 /// https://learn.sparkfun.com/tutorials/nrf52832-breakout-board-hookup-guide
109 ///
110 /// \par Radio Performance
111 ///
112 /// At DataRate2Mbps (2Mb/s), payload length vs airtime:
113 /// 0 bytes takes about 70us, 128 bytes takes 520us, 254 bytes take 1020us.
114 /// You can extrapolate linearly to slower data rates.
115 ///
116 /// The RF powers claimed by the chip manufacturer have not been independently verified here.
117 ///
118 /// \par Memory
119 ///
120 /// The compiled client and server sketches are about 42k bytes on Arduino.
121 /// The reliable client and server sketches compile to about 43k bytes on Arduino. Unfortunately the
122 /// Arduino build environmnet does not drop unused clsses and code, so the resulting programs include
123 /// all the unused classes ad code. This needs to be revisited.
124 /// RAM requirements are minimal.
125 ///
126 class RH_NRF51 : public RHGenericDriver
127 {
128 public:
129 
130  /// \brief Defines convenient values for setting data rates in setRF()
131  typedef enum
132  {
133  DataRate1Mbps = 0, ///< 1 Mbps
134  DataRate2Mbps, ///< 2 Mbps
135  DataRate250kbps ///< 250 kbps
136  } DataRate;
137 
138  /// \brief Convenient values for setting transmitter power in setRF()
139  typedef enum
140  {
141  // Add 20dBm for nRF24L01p with PA and LNA modules
142  TransmitPower4dBm = 0, ///< 4 dBm
143  TransmitPower0dBm, ///< 0 dBm
144  TransmitPowerm4dBm, ///< -4 dBm
145  TransmitPowerm8dBm, ///< -8 dBm
146  TransmitPowerm12dBm, ///< -12 dBm
147  TransmitPowerm16dBm, ///< -16 dBm
148  TransmitPowerm20dBm, ///< -20 dBm
149  TransmitPowerm30dBm, ///< -30 dBm
150  } TransmitPower;
151 
152  /// Constructor.
153  /// After constructing, you must call init() to initialise the interface
154  /// and the radio module
155  RH_NRF51();
156 
157  /// Initialises this instance and the radio module connected to it.
158  /// The following steps are taken:
159  /// - Start the processors High Frequency clock DC/DC converter and
160  /// - Disable and reset the radio
161  /// - Set the logical channel to 0 for transmit and receive (only pipe 0 is used)
162  /// - Configure the CRC (2 octets, algorithm x^16+x^12^x^5+1 with initial value 0xffff)
163  /// - Set the default network address of 0xE7E7E7E7E7
164  /// - Set channel to 2
165  /// - Set data rate to DataRate2Mbps
166  /// - Set TX power to TransmitPower0dBm
167  /// \return true if everything was successful
168  bool init();
169 
170  /// Sets the transmit and receive channel number.
171  /// The frequency used is (2400 + channel) MHz
172  /// \return true on success
173  bool setChannel(uint8_t channel);
174 
175  /// Sets the Network address.
176  /// Only nodes with the same network address can communicate with each other. You
177  /// can set different network addresses in different sets of nodes to isolate them from each other.
178  /// Internally, this sets the nRF51 BASE0 and PREFIX0 to be the given network address.
179  /// The first octet of the address is used for PREFIX0 and the rest is used for BASE0. BALEN is
180  /// set to the approprtae base length.
181  /// The default network address is 0xE7E7E7E7E7.
182  /// \param[in] address The new network address. Must match the network address of any receiving node(s).
183  /// \param[in] len Number of bytes of address to set (3 to 5).
184  /// \return true on success, false if len is not in the range 3-5 inclusive.
185  bool setNetworkAddress(uint8_t* address, uint8_t len);
186 
187  /// Sets the data rate and transmitter power to use.
188  /// \param [in] data_rate The data rate to use for all packets transmitted and received. One of RH_NRF51::DataRate.
189  /// \param [in] power Transmitter power. One of RH_NRF51::TransmitPower.
190  /// \return true on success
191  bool setRF(DataRate data_rate, TransmitPower power);
192 
193  /// Sets the radio in power down mode, with the configuration set to the
194  /// last value from setOpMode().
195  /// Sets chip enable to LOW.
196  void setModeIdle();
197 
198  /// Sets the radio in RX mode.
199  void setModeRx();
200 
201  /// Sets the radio in TX mode.
202  void setModeTx();
203 
204  /// Sends data to the address set by setTransmitAddress()
205  /// Sets the radio to TX mode.
206  /// Caution: when encryption is enabled, the maximum message length is reduced to 23 octets.
207  /// \param [in] data Data bytes to send.
208  /// \param [in] len Number of data bytes to send
209  /// \return true on success (which does not necessarily mean the receiver got the message, only that the message was
210  /// successfully transmitted). False if the message is too long or was otherwise not transmitted.
211  bool send(const uint8_t* data, uint8_t len);
212 
213  /// Blocks until the current message (if any)
214  /// has been transmitted
215  /// \return true on success, false if the chip is not in transmit mode or other transmit failure
216  virtual bool waitPacketSent();
217 
218  /// Indicates if the chip is in transmit mode and
219  /// there is a packet currently being transmitted
220  /// \return true if the chip is in transmit mode and there is a transmission in progress
221  bool isSending();
222 
223  /// Prints the value of all NRF_RADIO registers.
224  /// to the Serial device if RH_HAVE_SERIAL is defined for the current platform
225  /// For debugging purposes only.
226  /// Caution: there are 1024 of them (many reserved and set to 0).
227  /// \return true on success
228  bool printRegisters();
229 
230  /// Checks whether a received message is available.
231  /// This can be called multiple times in a timeout loop
232  /// \return true if a complete, valid message has been received and is able to be retrieved by
233  /// recv()
234  bool available();
235 
236  /// Turns the receiver on if it not already on.
237  /// Once a message with CRC correct is received, the receiver will be returned to Idle mode.
238  /// If there is a valid message available, copy it to buf and return true
239  /// else return false.
240  /// If a message is copied, *len is set to the length (Caution, 0 length messages are permitted).
241  /// You should be sure to call this function frequently enough to not miss any messages
242  /// It is recommended that you call it in your main loop.
243  /// \param[in] buf Location to copy the received message
244  /// \param[in,out] len Pointer to available space in buf. Set to the actual number of octets copied.
245  /// \return true if a valid message was copied to buf
246  bool recv(uint8_t* buf, uint8_t* len);
247 
248  /// Enables AES encryption and sets the AES encryption key, used
249  /// to encrypt and decrypt all messages using the on-chip AES CCM mode encryption engine.
250  /// The default is disabled.
251  /// In the AES configuration, the message counter and IV is always set to 0, which
252  /// means the same keystream is used for every message with a given key.
253  /// Caution: when encryption is enabled, the maximum message length is reduced to 23 octets.
254  /// \param[in] key The key to use. Must be 16 bytes long. The same key must be installed
255  /// in other instances of RH_RF51, otherwise communications will not work correctly. If key is NULL,
256  /// encryption is disabled, which is the default.
257  void setEncryptionKey(uint8_t* key = NULL);
258 
259  /// The maximum message length supported by this driver
260  /// \return The maximum message length supported by this driver
261  uint8_t maxMessageLength();
262 
263  /// Reeads the current die temperature using the built in TEMP peripheral.
264  /// Blocks while the temperature is measured, which takes about 30 microseconds.
265  // \return the current die temperature in degrees C.
266  float get_temperature();
267 
268 protected:
269  /// Examine the receive buffer to determine whether the message is for this node
270  void validateRxBuf();
271 
272  /// Clear our local receive buffer
273  void clearRxBuf();
274 
275 private:
276  /// The receiver/transmitter buffer
277  /// First octet is the payload length, remainder is the payload
278  uint8_t _buf[RH_NRF51_MAX_PAYLOAD_LEN+1];
279 
280  /// True when there is a valid message in the buffer
281  bool _rxBufValid;
282 
283 #if RH_NRF51_HAVE_ENCRYPTION
284  /// True if an AES key has been specified and that we are therfore encrypting
285  /// and decrypting messages on the fly
286  bool _encrypting;
287 
288  /// Scratch area for AES encryption
289  uint8_t _scratch[RH_NRF51_MAX_PAYLOAD_LEN+1+16];
290 
291  /// Where the AES encryption key and IV are stored
292  uint8_t _encryption_cnf[RH_NRF51_AES_CCM_CNF_SIZE];
293 #endif
294 };
295 
296 /// @example nrf51_client.pde
297 /// @example nrf51_server.pde
298 /// @example nrf51_reliable_datagram_client.pde
299 /// @example nrf51_reliable_datagram_server.pde
300 /// @example nrf51_audio_tx.pde
301 /// @example nrf51_audio_rx.pde
302 #endif
RH_NRF51::validateRxBuf
void validateRxBuf()
Examine the receive buffer to determine whether the message is for this node.
RHGenericDriver::_rxGood
volatile uint16_t _rxGood
Count of the number of successfully transmitted messaged.
Definition: RHGenericDriver.h:292
RH_NRF51::TransmitPower4dBm
@ TransmitPower4dBm
4 dBm
Definition: RH_NRF51.h:142
RH_NRF51
Send and receive unaddressed, unreliable datagrams by nRF51 and nRF52 compatible transceivers.
Definition: RH_NRF51.h:126
RH_NRF51::DataRate1Mbps
@ DataRate1Mbps
1 Mbps
Definition: RH_NRF51.h:133
RH_NRF51::available
bool available()
RH_NRF51::DataRate
DataRate
Defines convenient values for setting data rates in setRF()
Definition: RH_NRF51.h:131
RH_NRF51::init
bool init()
RH_NRF51::isSending
bool isSending()
RHGenericDriver::_rxHeaderFrom
volatile uint8_t _rxHeaderFrom
FROM header in the last received mesasge.
Definition: RHGenericDriver.h:265
RH_NRF51::get_temperature
float get_temperature()
RH_NRF51::setModeTx
void setModeTx()
Sets the radio in TX mode.
RH_NRF51::TransmitPowerm4dBm
@ TransmitPowerm4dBm
-4 dBm
Definition: RH_NRF51.h:144
RH_NRF51::setModeRx
void setModeRx()
Sets the radio in RX mode.
RHGenericDriver::_rxBad
volatile uint16_t _rxBad
Count of the number of bad messages (eg bad checksum etc) received.
Definition: RHGenericDriver.h:289
RH_NRF51::DataRate2Mbps
@ DataRate2Mbps
2 Mbps
Definition: RH_NRF51.h:134
RHGenericDriver::_rxHeaderTo
volatile uint8_t _rxHeaderTo
TO header in the last received mesasge.
Definition: RHGenericDriver.h:262
RH_NRF51::RH_NRF51
RH_NRF51()
RHGenericDriver::_txHeaderFrom
uint8_t _txHeaderFrom
FROM header to send in all messages.
Definition: RHGenericDriver.h:277
RHGenericDriver
Abstract base class for a RadioHead driver.
Definition: RHGenericDriver.h:41
RH_NRF51::TransmitPowerm30dBm
@ TransmitPowerm30dBm
-30 dBm
Definition: RH_NRF51.h:149
RH_NRF51::recv
bool recv(uint8_t *buf, uint8_t *len)
RH_NRF51::setEncryptionKey
void setEncryptionKey(uint8_t *key=NULL)
RH_NRF51::send
bool send(const uint8_t *data, uint8_t len)
RH_NRF51::TransmitPowerm8dBm
@ TransmitPowerm8dBm
-8 dBm
Definition: RH_NRF51.h:145
RHGenericDriver::_thisAddress
uint8_t _thisAddress
This node id.
Definition: RHGenericDriver.h:256
RHGenericDriver::_txGood
volatile uint16_t _txGood
Count of the number of bad messages (correct checksum etc) received.
Definition: RHGenericDriver.h:295
RH_NRF51::printRegisters
bool printRegisters()
RH_NRF51::TransmitPowerm12dBm
@ TransmitPowerm12dBm
-12 dBm
Definition: RH_NRF51.h:146
RHGenericDriver::_promiscuous
bool _promiscuous
Whether the transport is in promiscuous mode.
Definition: RHGenericDriver.h:259
RH_NRF51::DataRate250kbps
@ DataRate250kbps
250 kbps
Definition: RH_NRF51.h:135
RH_NRF51::clearRxBuf
void clearRxBuf()
Clear our local receive buffer.
RHGenericDriver::_rxHeaderFlags
volatile uint8_t _rxHeaderFlags
FLAGS header in the last received mesasge.
Definition: RHGenericDriver.h:271
RH_NRF51::setRF
bool setRF(DataRate data_rate, TransmitPower power)
RH_NRF51::TransmitPower
TransmitPower
Convenient values for setting transmitter power in setRF()
Definition: RH_NRF51.h:139
RH_NRF51::setModeIdle
void setModeIdle()
RH_NRF51::TransmitPowerm16dBm
@ TransmitPowerm16dBm
-16 dBm
Definition: RH_NRF51.h:147
RH_NRF51::waitPacketSent
virtual bool waitPacketSent()
RH_NRF51::TransmitPowerm20dBm
@ TransmitPowerm20dBm
-20 dBm
Definition: RH_NRF51.h:148
RHGenericDriver::_txHeaderId
uint8_t _txHeaderId
ID header to send in all messages.
Definition: RHGenericDriver.h:280
RHGenericDriver::_txHeaderTo
uint8_t _txHeaderTo
TO header to send in all messages.
Definition: RHGenericDriver.h:274
RHGenericDriver::_txHeaderFlags
uint8_t _txHeaderFlags
FLAGS header to send in all messages.
Definition: RHGenericDriver.h:283
RHGenericDriver::_rxHeaderId
volatile uint8_t _rxHeaderId
ID header in the last received mesasge.
Definition: RHGenericDriver.h:268
RH_NRF51::TransmitPower0dBm
@ TransmitPower0dBm
0 dBm
Definition: RH_NRF51.h:143
RHGenericDriver::RHModeIdle
@ RHModeIdle
Transport is idle.
Definition: RHGenericDriver.h:52
RHGenericDriver::_mode
volatile RHMode _mode
The current transport operating mode.
Definition: RHGenericDriver.h:253
RH_NRF51::maxMessageLength
uint8_t maxMessageLength()
RH_NRF51::setNetworkAddress
bool setNetworkAddress(uint8_t *address, uint8_t len)
RHGenericDriver::RHModeTx
@ RHModeTx
Transport is in the process of transmitting a message.
Definition: RHGenericDriver.h:53
RHGenericDriver::mode
virtual RHMode mode()
Definition: RHGenericDriver.cpp:159
RHGenericDriver::RHModeRx
@ RHModeRx
Transport is in the process of receiving a message.
Definition: RHGenericDriver.h:54
RHGenericDriver::waitCAD
virtual bool waitCAD()
Definition: RHGenericDriver.cpp:72
RH_NRF51::setChannel
bool setChannel(uint8_t channel)