-
Notifications
You must be signed in to change notification settings - Fork 0
/
RH_NRF905.h
424 lines (375 loc) · 18.8 KB
/
RH_NRF905.h
1
2
3
4
5
6
7
8
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
47
48
49
50
51
52
53
54
55
56
57
58
59
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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
// RH_NRF905.h
// Author: Mike McCauley (mikem@airspayce.com)
// Copyright (C) 2014 Mike McCauley
// $Id: RH_NRF905.h,v 1.11 2017/07/25 05:26:50 mikem Exp $
//
#ifndef RH_NRF905_h
#define RH_NRF905_h
#include <RHGenericSPI.h>
#include <RHNRFSPIDriver.h>
// This is the maximum (and only) number of bytes that can be carried by the nRF905.
// We use some for headers, leaving fewer for RadioHead messages
#define RH_NRF905_MAX_PAYLOAD_LEN 32
// The length of the headers we add.
// The headers are inside the nRF905 payload
// As well as the usual TO, FROM, ID, FLAGS, we also need LEN, since
// nRF905 only has fixed width messages.
// REVISIT: could we have put the LEN into the FLAGS field?
#define RH_NRF905_HEADER_LEN 5
// This is the maximum RadioHead user message length that can be supported by this library. Limited by
// the supported message lengths in the nRF905
#define RH_NRF905_MAX_MESSAGE_LEN (RH_NRF905_MAX_PAYLOAD_LEN-RH_NRF905_HEADER_LEN)
// Register names
#define RH_NRF905_REG_MASK 0x0f
#define RH_NRF905_REG_W_CONFIG 0x00
#define RH_NRF905_REG_R_CONFIG 0x10
#define RH_NRF905_REG_W_TX_PAYLOAD 0x20
#define RH_NRF905_REG_R_TX_PAYLOAD 0x21
#define RH_NRF905_REG_W_TX_ADDRESS 0x22
#define RH_NRF905_REG_R_TX_ADDRESS 0x23
#define RH_NRF905_REG_R_RX_PAYLOAD 0x24
#define RH_NRF905_REG_CHANNEL_CONFIG 0x80
// Configuration register
#define RH_NRF905_CONFIG_0 0x00
#define RH_NRF905_CONFIG_0_CH_NO 0xff
#define RH_NRF905_CONFIG_1 0x01
#define RH_NRF905_CONFIG_1_AUTO_RETRAN 0x20
#define RH_NRF905_CONFIG_1_RX_RED_PWR 0x10
#define RH_NRF905_CONFIG_1_PA_PWR 0x0c
#define RH_NRF905_CONFIG_1_PA_PWR_N10DBM 0x00
#define RH_NRF905_CONFIG_1_PA_PWR_N2DBM 0x04
#define RH_NRF905_CONFIG_1_PA_PWR_6DBM 0x08
#define RH_NRF905_CONFIG_1_PA_PWR_10DBM 0x0c
#define RH_NRF905_CONFIG_1_HFREQ_PLL 0x02
#define RH_NRF905_CONFIG_1_CH_NO 0x01
#define RH_NRF905_CONFIG_2 0x02
#define RH_NRF905_CONFIG_2_TX_AFW 0x70
#define RH_NRF905_CONFIG_2_RX_AFW 0x07
#define RH_NRF905_CONFIG_3 0x03
#define RH_NRF905_CONFIG_3_RX_PW 0x3f
#define RH_NRF905_CONFIG_4 0x04
#define RH_NRF905_CONFIG_4_TX_PW 0x3f
#define RH_NRF905_CONFIG_5 0x05
#define RH_NRF905_CONFIG_5_RX_ADDRESS 0xff
#define RH_NRF905_CONFIG_6 0x06
#define RH_NRF905_CONFIG_6_RX_ADDRESS 0xff
#define RH_NRF905_CONFIG_7 0x07
#define RH_NRF905_CONFIG_7_RX_ADDRESS 0xff
#define RH_NRF905_CONFIG_8 0x08
#define RH_NRF905_CONFIG_8_RX_ADDRESS 0xff
#define RH_NRF905_CONFIG_9 0x09
#define RH_NRF905_CONFIG_9_CRC_MODE_16BIT 0x80
#define RH_NRF905_CONFIG_9_CRC_EN 0x40
#define RH_NRF905_CONFIG_9_XOF 0x38
#define RH_NRF905_CONFIG_9_XOF_4MHZ 0x00
#define RH_NRF905_CONFIG_9_XOF_8MHZ 0x08
#define RH_NRF905_CONFIG_9_XOF_12MHZ 0x10
#define RH_NRF905_CONFIG_9_XOF_16MHZ 0x18
#define RH_NRF905_CONFIG_9_XOF_20MHZ 0x20
#define RH_NRF905_CONFIG_9_UP_CLK_EN 0x04
#define RH_NRF905_CONFIG_9_UP_CLK_FREQ 0x03
#define RH_NRF905_CONFIG_9_UP_CLK_FREQ_4MHZ 0x00
#define RH_NRF905_CONFIG_9_UP_CLK_FREQ_2MHZ 0x01
#define RH_NRF905_CONFIG_9_UP_CLK_FREQ_1MHZ 0x02
#define RH_NRF905_CONFIG_9_UP_CLK_FREQ_500KHZ 0x03
// Status register is always read as first byte
#define RH_NRF905_STATUS_AM 0x80
#define RH_NRF905_STATUS_DR 0x20
/////////////////////////////////////////////////////////////////////
/// \class RH_NRF905 RH_NRF905.h <RH_NRF905.h>
/// \brief Send and receive unaddressed, unreliable datagrams by nRF905 and compatible transceivers.
///
/// This base class provides basic functions for sending and receiving unaddressed, unreliable datagrams
/// of arbitrary length to 28 octets per packet. Use one of the Manager classes to get addressing and
/// acknowledgement reliability, routing, meshes etc.
///
/// The nRF905 transceiver is configured to use Enhanced Shockburst with 16 Bit CRC, and 32 octet packets.
///
/// Naturally, for any 2 radios to communicate that must be configured to use the same frequency
/// and with identical network addresses.
///
/// The nRF905 from Nordic Semiconductor http://www.nordicsemi.com/eng/Products/Sub-1-GHz-RF/nRF905
/// (http://www.nordicsemi.com/jpn/nordic/content_download/2452/29528/file/Product_Specification_nRF905_v1.5.pdf)
/// is a low-cost 433/868/915 MHz ISM transceiver module. It supports a number of channel frequencies at
/// 100kHz deviation and 50kHz bandwidth with Manchester encoding.
///
/// We tested with inexpensive nRF905 modules from eBay, similar to:
/// http://www.aliexpress.com/store/product/Free-ship-NRF905-433MHz-Wireless-Transmission-Module-Transceiver-Module-with-Antenna-for-the-433MHz-ISM-band/513046_607163305.html
///
/// This library provides functions for sending and receiving messages of up to 27 octets on any
/// frequency supported by the nRF905.
///
/// Several nRF905 modules can be connected to an Arduino, permitting the construction of translators
/// and frequency changers, etc.
///
/// Example Arduino programs are included to show the main modes of use.
///
/// \par Packet Format
///
/// All messages sent and received by this class conform to this fixed length packet format
///
/// - 4 octets NETWORK ADDRESS
/// - 32 octets PAYLOAD, consisting of:
/// - 1 octet TO header
/// - 1 octet FROM header
/// - 1 octet ID header
/// - 1 octet FLAGS header
/// - 1 octet user message length header
/// - 0 to 27 octets of user message, trailing octets after the user message length are ignored
/// - 2 octets CRC
///
/// All messages sent and received by this driver are 32 octets. The user message length is embedded in the message.
///
/// \par Connecting nRF905
///
/// The nRF905 is a 3.3V part is is *NOT* 5V tolerant. So you MUST use a 3.3V CPU such as Teensy, Arduino Due etc
/// or else provide for level shifters between the CPU and the nRF905. Failure to consider this will probably
/// break your nRF905.
///
/// The electrical connection between the nRF905 and the CPU require 3.3V, the 3 x SPI pins (SCK, SDI, SDO),
/// a Chip Enable pin, a Transmit Enable pin and a Slave Select pin.
///
/// The examples below assume the commonly found cheap Chinese nRF905 modules. The RH_RF905 driver assumes the
/// the nRF905 has a 16MHz crystal.
///
/// Connect the nRF905 to Teensy (or Arduino with suitable level shifters) like this
/// \code
/// CPU nRF905 module
/// 3V3----------VCC (3.3V)
/// pin D8-----------CE (chip enable in)
/// pin D9-----------TX_EN (transmit enable in)
/// SS pin D10----------CSN (chip select in)
/// SCK pin D13----------SCK (SPI clock in)
/// MOSI pin D11----------MOSI (SPI Data in)
/// MISO pin D12----------MISO (SPI data out)
/// GND----------GND (ground in)
/// \endcode
///
/// Caution: Arduino Due is a 3.3V part and is not 5V tolerant (so too is the nRF905 module
/// so they can be connected directly together. Unlike other Arduinos the Due has it default SPI
/// connections on a dedicated 6 pin SPI header in the center of the board, which is
/// physically compatible with Uno, Leonardo and Mega2560. A little dot marks pin 1 on the header.
/// You must connect to these
/// and *not* to the usual Arduino SPI pins Digital 11, 12 and 13.
/// See http://21stdigitalhome.blogspot.com.au/2013/02/arduino-due-hardware-spi.html
///
/// Connect the nRF905 to Arduino Due like this
/// \code
/// CPU nRF905 module
/// 3V3----------VCC (3.3V)
/// pin D8-----------CE (chip enable in)
/// pin D9-----------TX_EN (transmit enable in)
/// SS pin D10----------CSN (chip select in)
/// SCK on SPI header pin 3----------SCK (SPI clock in)
/// MOSI on SPI header pin 4----------MOSI (SPI Data in)
/// MISO on SPI header pin 1----------MISO (SPI data out)
/// GND----------GND (ground in)
/// \endcode
///
/// and you can then use the default constructor RH_NRF905().
/// You can override the default settings for the CE, TX_EN and CSN pins
/// in the NRF905() constructor if you wish to connect the slave select CSN to other than the normal one for your
/// CPU.
///
/// It is possible to have 2 radios conected to one CPU, provided each radio has its own
/// CSN, TX_EN and CE line (SCK, MOSI and MISO are common to both radios)
///
/// \par Transmitter Power
///
/// You can control the transmitter power to be one of 4 power levels: -10, -2, 6 or 10dBm,
/// using the setRF() function, eg:
/// \code
/// nrf905.setRF(RH_NRF905::TransmitPower10dBm);
/// \endcode
///
/// We have made some actual power measurements against
/// programmed power for an nRF905 module from www.rfinchina.com under the following conditions:
/// - Teensy 3.1
/// - nRF905 module (with SMA antenna connector) wired to Teensy as described above, channel 108.
/// - 20cm SMA-SMA cable
/// - MiniKits AD8307 HF/VHF Power Head (calibrated against Rohde&Schwartz 806.2020 test set)
/// - Tektronix TDS220 scope to measure the Vout from power head
/// \code
/// Program power Measured Power
/// dBm dBm
/// -10 -16
/// -2 -8
/// 6 0
/// 10 8
/// \endcode
/// (Caution: we dont claim laboratory accuracy for these measurements)
/// You would not expect to get anywhere near these powers to air with a simple 1/4 wavelength wire antenna.
///
/// \par Example programs
///
/// Several example programs are provided. They work out of the box with Teensy 3.1 and Arduino Due
/// connected as show above.
///
/// \par Radio Performance
///
/// Frequency accuracy may be debatable.
///
/// \par Memory
///
/// Memory usage of this class is minimal. The compiled client and server sketches are about 16000 bytes on Teensy.
///
class RH_NRF905 : public RHNRFSPIDriver
{
public:
/// \brief Convenient values for setting transmitter power in setRF()
/// These are designed to agree with the values for RH_NRF905_CONFIG_1_PA_PWR after
/// left shifting by 2
/// To be passed to setRF();
typedef enum
{
TransmitPowerm10dBm = 0, ///< -10 dBm
TransmitPowerm2dBm, ///< -2 dBm
TransmitPower6dBm, ///< 6 dBm
TransmitPower10dBm ///< 10 dBm
} TransmitPower;
/// Constructor. You can have multiple instances, but each instance must have its own
/// chip enable and slave select pin.
/// After constructing, you must call init() to initialise the interface
/// and the radio module
/// \param[in] chipEnablePin the Arduino pin to use to enable the chip for transmit/receive
/// \param[in] txEnablePin the Arduino pin cponnected to the txEn pin on the radio that enable transmit mode
/// \param[in] slaveSelectPin the Arduino pin number of the output to use to select the NRF905 before
/// accessing it. Defaults to the normal SS pin for your Arduino (D10 for Diecimila, Uno etc, D53 for Mega,
/// D10 for Maple, Teensy)
/// \param[in] spi Pointer to the SPI interface object to use.
/// Defaults to the standard Arduino hardware SPI interface
RH_NRF905(uint8_t chipEnablePin = 8, uint8_t txEnablePin = 9, uint8_t slaveSelectPin = SS, RHGenericSPI& spi = hardware_spi);
/// Initialises this instance and the radio module connected to it.
/// The following steps are taken:g
/// - Set the chip enable and chip select pins to output LOW, HIGH respectively.
/// - Initialise the SPI output pins
/// - Initialise the SPI interface library to 8MHz (Hint, if you want to lower
/// the SPI frequency (perhaps where you have other SPI shields, low voltages etc),
/// call SPI.setClockDivider() after init()).
/// -Flush the receiver and transmitter buffers
/// - Set the radio to receive with powerUpRx();
/// \return true if everything was successful
bool init();
/// Reads a single register from the NRF905
/// \param[in] reg Register number, one of NR905_REG_*
/// \return The value of the register
uint8_t spiReadRegister(uint8_t reg);
/// Writes a single byte to the NRF905, and at the ame time reads the current STATUS register
/// \param[in] reg Register number, one of NRF905_REG_*
/// \param[in] val The value to write
/// \return the current STATUS (read while the command is sent)
uint8_t spiWriteRegister(uint8_t reg, uint8_t val);
/// Reads a number of consecutive registers from the NRF905 using burst read mode
/// \param[in] reg Register number of the first register, one of NRF905_REG_*
/// \param[in] dest Array to write the register values to. Must be at least len bytes
/// \param[in] len Number of bytes to read
/// \return the current STATUS (read while the command is sent)
uint8_t spiBurstReadRegister(uint8_t reg, uint8_t* dest, uint8_t len);
/// Write a number of consecutive registers using burst write mode
/// \param[in] reg Register number of the first register, one of NRF905_REG_*
/// \param[in] src Array of new register values to write. Must be at least len bytes
/// \param[in] len Number of bytes to write
/// \return the current STATUS (read while the command is sent)
uint8_t spiBurstWriteRegister(uint8_t reg, uint8_t* src, uint8_t len);
/// Reads and returns the device status register NRF905_REG_02_DEVICE_STATUS
/// \return The value of the device status register
uint8_t statusRead();
/// Sets the transmit and receive channel number.
/// The RF frequency used is (422.4 + channel/10) * (1+hiFrequency) MHz
/// \param[in] channel The channel number.
/// \param[in] hiFrequency false for low frequency band (422.4MHz and up), true for high frequency band (845MHz and up)
/// \return true on success
bool setChannel(uint16_t channel, bool hiFrequency = false);
/// Sets the Network address.
/// Only nodes with the same network address can communicate with each other. You
/// can set different network addresses in different sets of nodes to isolate them from each other.
/// The default network address is 0xE7E7E7E7
/// \param[in] address The new network address. Must match the network address of any receiving node(s).
/// \param[in] len Number of bytes of address to set (1 to 4).
/// \return true on success, false if len is not in the range 1-4 inclusive.
bool setNetworkAddress(uint8_t* address, uint8_t len);
/// Sets the transmitter power to use
/// \param [in] power Transmitter power. One of NRF905::TransmitPower.
/// \return true on success
bool setRF(TransmitPower power);
/// Sets the radio in power down mode.
/// Sets chip enable to LOW.
/// \return true on success
void setModeIdle();
/// Sets the radio in RX mode.
/// Sets chip enable to HIGH to enable the chip in RX mode.
/// \return true on success
void setModeRx();
/// Sets the radio in TX mode.
/// Pulses the chip enable LOW then HIGH to enable the chip in TX mode.
/// \return true on success
void setModeTx();
/// Sends data to the address set by setTransmitAddress()
/// Sets the radio to TX mode
/// \param [in] data Data bytes to send.
/// \param [in] len Number of data bytes to set in the TX buffer. The actual size of the
/// transmitted data payload is set by setPayloadSize. Maximum message length actually
/// transmitted is RH_NRF905_MAX_MESSAGE_LEN = 27.
/// \return true on success (which does not necessarily mean the receiver got the message, only that the message was
/// successfully transmitted). Returns false if the requested message length exceeds RH_NRF905_MAX_MESSAGE_LEN.
bool send(const uint8_t* data, uint8_t len);
/// Blocks until the current message (if any)
/// has been transmitted
/// \return true on success, false if the chip is not in transmit mode
virtual bool waitPacketSent();
/// Indicates if the chip is in transmit mode and
/// there is a packet currently being transmitted
/// \return true if the chip is in transmit mode and there is a transmission in progress
bool isSending();
/// Prints the value of a single chip register
/// to the Serial device if RH_HAVE_SERIAL is defined for the current platform
/// For debugging purposes only.
/// \return true on success
bool printRegister(uint8_t reg);
/// Prints the value of all chip registers
/// to the Serial device if RH_HAVE_SERIAL is defined for the current platform
/// For debugging purposes only.
/// \return true on success
bool printRegisters();
/// Checks whether a received message is available.
/// This can be called multiple times in a timeout loop
/// \return true if a complete, valid message has been received and is able to be retrieved by
/// recv()
bool available();
/// Turns the receiver on if it not already on.
/// If there is a valid message available, copy it to buf and return true
/// else return false.
/// If a message is copied, *len is set to the length (Caution, 0 length messages are permitted).
/// You should be sure to call this function frequently enough to not miss any messages
/// It is recommended that you call it in your main loop.
/// \param[in] buf Location to copy the received message
/// \param[in,out] len Pointer to available space in buf. Set to the actual number of octets copied.
/// \return true if a valid message was copied to buf
bool recv(uint8_t* buf, uint8_t* len);
/// The maximum message length supported by this driver
/// \return The maximum message length supported by this driver
uint8_t maxMessageLength();
protected:
/// Examine the revceive buffer to determine whether the message is for this node
void validateRxBuf();
/// Clear our local receive buffer
void clearRxBuf();
private:
/// This idle mode chip configuration
uint8_t _configuration;
/// the number of the chip enable pin
uint8_t _chipEnablePin;
/// The number of the transmit enable pin
uint8_t _txEnablePin;
/// Number of octets in the buffer
uint8_t _bufLen;
/// The receiver/transmitter buffer
uint8_t _buf[RH_NRF905_MAX_PAYLOAD_LEN];
/// True when there is a valid message in the buffer
bool _rxBufValid;
};
/// @example nrf905_client.pde
/// @example nrf905_server.pde
/// @example nrf905_reliable_datagram_client.pde
/// @example nrf905_reliable_datagram_server.pde
#endif