V148
Fork of RadioHead-148 by
Diff: RH_NRF905.h
- Revision:
- 0:ab4e012489ef
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/RH_NRF905.h Thu Oct 15 01:27:00 2015 +0000 @@ -0,0 +1,396 @@ +// RH_NRF905.h +// Author: Mike McCauley (mikem@airspayce.com) +// Copyright (C) 2014 Mike McCauley +// $Id: RH_NRF905.h,v 1.7 2015/03/09 06:04:26 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 addressed, reliable, acknowledged 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 probbaly +/// 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 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 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 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 PA_PWR + /// 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(PINS chipEnablePin, PINS txEnablePin, PINS slaveSelectPin, 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 teh TX buffer. The actual size of the + /// transmitted data payload is set by setPayloadSize + /// \return true on success (which does not necessarily mean the receiver got the message, only that the message was + /// successfully transmitted). + 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