Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: Nucleo_IOT1 wireless
Revision 0:7313e63394c3, committed 2013-08-11
- Comitter:
- ianmcc
- Date:
- Sun Aug 11 11:58:05 2013 +0000
- Child:
- 1:cd113026825f
- Commit message:
- Initial
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nRF24L01P.cpp Sun Aug 11 11:58:05 2013 +0000
@@ -0,0 +1,555 @@
+#include "nRF24L01P.h"
+
+#define NRF24L01P_SPI_MAX_DATA_RATE 10000000
+
+#define NRF24L01P_CMD_R_REGISTER 0x00
+#define NRF24L01P_CMD_W_REGISTER 0x20
+#define NRF24L01P_CMD_R_RX_PAYLOAD 0x61
+#define NRF24L01P_CMD_W_TX_PAYLOAD 0xA0
+#define NRF24L01P_CMD_FLUSH_TX 0xE1
+#define NRF24L01P_CMD_FLUSH_RX 0xE2
+#define NRF24L01P_CMD_REUSE_TX_PL 0xE3
+#define NRF24L01P_CMD_R_RX_PL_WID 0x60
+#define NRF24L01P_CMD_W_ACK_PAYLOAD 0xA8
+#define NRF24L01P_CMD_W_TX_PYLD_NO_ACK 0xB0
+#define NRF24L01P_CMD_NOP 0xFF
+
+// registers
+#define NRF24L01P_CONFIG 0x00
+#define NRF24L01P_EN_AA 0x01
+#define NRF24L01P_EN_RXADDR 0x02
+#define NRF24L01P_SETUP_AW 0x03
+#define NRF24L01P_SETUP_RETR 0x04
+#define NRF24L01P_RF_CH 0x05
+#define NRF24L01P_RF_SETUP 0x06
+#define NRF24L01P_STATUS 0x07
+#define NRF24L01P_OBSERVE_TX 0x08
+#define NRF24L01P_RPD 0x09
+#define NRF24L01P_RX_ADDR_P0 0x0A
+#define NRF24L01P_RX_ADDR_P1 0x0B
+#define NRF24L01P_RX_ADDR_P2 0x0C
+#define NRF24L01P_RX_ADDR_P3 0x0D
+#define NRF24L01P_RX_ADDR_P4 0x0E
+#define NRF24L01P_RX_ADDR_P5 0x0F
+#define NRF24L01P_TX_ADDR 0x10
+#define NRF24L01P_RX_PW_P0 0x11
+#define NRF24L01P_RX_PW_P1 0x12
+#define NRF24L01P_RX_PW_P2 0x13
+#define NRF24L01P_RX_PW_P3 0x14
+#define NRF24L01P_RX_PW_P4 0x15
+#define NRF24L01P_RX_PW_P5 0x16
+#define NRF24L01P_FIFO_STATUS 0x17
+#define NRF24L01P_DYNPD 0x1C
+#define NRF24L01P_FEATURE 0x1D
+
+#define NRF24L01P_MAX 0x1F
+
+nRF24L01P::nRF24L01P(PinName mosi, PinName miso, PinName sck, PinName csn, long SPIFrequency)
+ : Spi(mosi, miso, sck),
+ NCS(csn)
+{
+ Spi.format(8,0); // 8-bit, ClockPhase = 0, ClockPolarity = 0
+ Spi.frequency(SPIFrequency);
+ NCS = 1;
+ this->reset();
+}
+
+void
+nRF24L01P::reset()
+{
+ this->write_register(NRF24L01P_CONFIG, 0x08); // power down
+ this->flush_tx_fifo();
+ this->flush_rx_fifo();
+ this->write_register(NRF24L01P_EN_AA, 0x3F);
+ this->write_register(NRF24L01P_EN_RXADDR, 0x03);
+ this->write_register(NRF24L01P_SETUP_AW, 0x03);
+ this->write_register(NRF24L01P_SETUP_RETR, 0x03);
+ this->write_register(NRF24L01P_RF_CH, 0x02);
+ this->write_register(NRF24L01P_RF_SETUP, 0x07);
+ this->write_register(NRF24L01P_STATUS, 0x0E);
+ this->write_register_40(NRF24L01P_RX_ADDR_P0, 0xE7E7E7E7E7ULL);
+ this->write_register_40(NRF24L01P_RX_ADDR_P1, 0xC2C2C2C2C2ULL);
+ this->write_register(NRF24L01P_RX_ADDR_P2, 0xC3);
+ this->write_register(NRF24L01P_RX_ADDR_P3, 0xC4);
+ this->write_register(NRF24L01P_RX_ADDR_P4, 0xC4);
+ this->write_register(NRF24L01P_RX_ADDR_P5, 0xC5);
+ this->write_register_40(NRF24L01P_TX_ADDR, 0xE7E7E7E7E7ULL);
+ this->write_register(NRF24L01P_RX_PW_P0, 0x00);
+ this->write_register(NRF24L01P_RX_PW_P1, 0x00);
+ this->write_register(NRF24L01P_RX_PW_P2, 0x00);
+ this->write_register(NRF24L01P_RX_PW_P3, 0x00);
+ this->write_register(NRF24L01P_RX_PW_P4, 0x00);
+ this->write_register(NRF24L01P_RX_PW_P5, 0x00);
+ this->write_register(NRF24L01P_FIFO_STATUS, 0x00);
+ this->write_register(NRF24L01P_DYNPD, 0x00);
+ this->write_register(NRF24L01P_FEATURE, 0x00);
+}
+
+void
+nRF24L01P::set_spi_frequency(long Freq)
+{
+ Spi.frequency(Freq);
+}
+
+void
+nRF24L01P::set_air_data_rate(int Rate)
+{
+ char r = 0;
+ if (Rate == 250)
+ r = 0x20;
+ else if (Rate == 1000)
+ r = 0x00;
+ else if (Rate == 2000)
+ r = 0x04;
+ char c = this->read_register(NRF24L01P_RF_SETUP);
+ this->write_register(NRF24L01P_RF_SETUP, (c & 0xDB) | r);
+}
+
+void
+nRF24L01P::set_channel(int Channel)
+{
+ char c = Channel;
+ c = c & 0x7F;
+ this->write_register(NRF24L01P_RF_CH, c);
+}
+
+bool
+nRF24L01P::received_power_detector()
+{
+ return this->read_register(NRF24L01P_RPD) == 0x01;
+}
+
+void
+nRF24L01P::set_tx_power(int Power)
+{
+ char p = 0;
+ if (Power == 0)
+ p = 0x03;
+ if (Power == -6)
+ p = 0x02;
+ else if (Power == -12)
+ p = 0x01;
+ else if (Power == -18)
+ p = 0x00;
+ char c = this->read_register(NRF24L01P_RF_SETUP);
+ this->write_register(NRF24L01P_RF_SETUP, (c & 0xFC) | p);
+}
+
+void
+nRF24L01P::enable_dynamic_payload(int Pipe, bool Enable)
+{
+ char Mask = 1 << Pipe;
+ char c = this->read_register(NRF24L01P_DYNPD);
+ if (Enable)
+ c = c | Mask;
+ else
+ c = c & ~Mask;
+ this->write_register(NRF24L01P_DYNPD, c);
+}
+
+void
+nRF24L01P::enable_ack_payload(bool Enable)
+{
+ char c = this->read_register(NRF24L01P_FEATURE);
+ this->write_register(NRF24L01P_FEATURE, Enable ? (c | 0x02) : (c & 0xFD));
+}
+
+void
+nRF24L01P::enable_no_ack(bool Enable)
+{
+ char c = this->read_register(NRF24L01P_FEATURE);
+ this->write_register(NRF24L01P_FEATURE, Enable ? (c | 0x01) : (c & 0xFE));
+}
+
+void
+nRF24L01P::set_address_width(int Width)
+{
+ char c = 0;
+ if (Width == 3)
+ c = 0x01;
+ else if (Width == 4)
+ c = 0x02;
+ else if (Width == 5)
+ c = 0x03;
+ this->write_register(NRF24L01P_SETUP_AW, c);
+}
+
+int
+nRF24L01P::get_address_width()
+{
+ int r = this->read_register(NRF24L01P_SETUP_AW);
+ switch (r & 0x03)
+ {
+ case 0x01 : return 3;
+ case 0x02 : return 4;
+ case 0x03 : return 5;
+ }
+ return 0;
+}
+
+void
+nRF24L01P::set_rx_address(int Pipe, uint64_t Address)
+{
+ if (Pipe < 0 || Pipe > 1)
+ error("RF24L01P::set_rx_address: invalid pipe");
+ this->write_register_40(NRF24L01P_RX_ADDR_P0+Pipe, Address);
+}
+
+void
+nRF24L01P::set_rx_address_low(int Pipe, uint8_t Address)
+{
+ this->write_register(NRF24L01P_RX_ADDR_P0+Pipe, Address);
+}
+
+void
+nRF24L01P::set_rx_payload_bytes(int Pipe, int Bytes)
+{
+ this->write_register(NRF24L01P_RX_PW_P0+Pipe, Bytes & 0x1F);
+}
+
+bool
+nRF24L01P::is_rx_full()
+{
+ return (this->read_register(NRF24L01P_FIFO_STATUS) & 0x02) != 0x00;
+}
+
+bool
+nRF24L01P::is_rx_empty()
+{
+ return (this->read_register(NRF24L01P_FIFO_STATUS) & 0x01) != 0x00;
+}
+
+bool
+nRF24L01P::is_rx_ready()
+{
+ return (this->read_register(NRF24L01P_STATUS) & 0x40) != 0x00;
+}
+
+void
+nRF24L01P::clear_rx_ready()
+{
+ char c = this->read_register(NRF24L01P_STATUS);
+ this->write_register(NRF24L01P_STATUS, c | 0x40);
+}
+
+void
+nRF24L01P::set_interrupt_rx_ready(bool Enable)
+{
+ char c = this->read_register(NRF24L01P_CONFIG);
+ this->write_register(NRF24L01P_CONFIG, Enable ? (c & 0xBF) : (c | 0x40));
+}
+
+bool
+nRF24L01P::is_tx_full()
+{
+ return (this->read_register(NRF24L01P_FIFO_STATUS) & 0x20) != 0x00;
+}
+
+bool
+nRF24L01P::is_tx_empty()
+{
+ return (this->read_register(NRF24L01P_FIFO_STATUS) & 0x10) != 0x00;
+}
+
+bool
+nRF24L01P::is_tx_sent()
+{
+ return (this->read_register(NRF24L01P_STATUS) & 0x20) != 0x00;
+}
+
+void
+nRF24L01P::clear_tx_sent()
+{
+ char c = this->read_register(NRF24L01P_STATUS);
+ this->write_register(NRF24L01P_STATUS, c | 0x20);
+}
+
+void
+nRF24L01P::set_interrupt_tx(bool Enable)
+{
+ char c = this->read_register(NRF24L01P_CONFIG);
+ this->write_register(NRF24L01P_CONFIG, Enable ? (c & 0xDF) : (c | 0x20));
+}
+
+void
+nRF24L01P::set_retransmit_delay(int Delay)
+{
+}
+
+bool
+nRF24L01P::is_max_rt()
+{
+ return (this->read_register(NRF24L01P_STATUS) & 0x10) != 0x00;
+}
+
+void
+nRF24L01P::clear_max_rt()
+{
+ char c = this->read_register(NRF24L01P_STATUS);
+ this->write_register(NRF24L01P_STATUS, c | 0x10);
+}
+
+void
+nRF24L01P::set_interrupt_max_rt(bool Enable)
+{
+ char c = this->read_register(NRF24L01P_CONFIG);
+ this->write_register(NRF24L01P_CONFIG, Enable ? (c & 0xEF) : (c | 0x10));
+}
+
+void
+nRF24L01P::set_crc_width(int Width)
+{
+ char c = this->read_register(NRF24L01P_CONFIG);
+ this->write_register(NRF24L01P_CONFIG, Width == 1 ? (c & 0xFB) : (c | 0x04));
+}
+
+void
+nRF24L01P::enable_crc(bool Enable)
+{
+ char c = this->read_register(NRF24L01P_CONFIG);
+ this->write_register(NRF24L01P_CONFIG, Enable ? (c | 0x08) : (c & 0xF7));
+}
+
+
+void
+nRF24L01P::set_power_up()
+{
+ char c = this->read_register(NRF24L01P_CONFIG);
+ this->write_register(NRF24L01P_CONFIG, c | 0x02);
+}
+
+void
+nRF24L01P::set_power_down()
+{
+ char c = this->read_register(NRF24L01P_CONFIG);
+ this->write_register(NRF24L01P_CONFIG, c & 0xFD);
+}
+
+void
+nRF24L01P::set_prx_mode()
+{
+ char c = this->read_register(NRF24L01P_CONFIG);
+ this->write_register(NRF24L01P_CONFIG, c | 0x01);
+}
+
+void
+nRF24L01P::set_ptx_mode()
+{
+ char c = this->read_register(NRF24L01P_CONFIG);
+ this->write_register(NRF24L01P_CONFIG, c & 0xFE);
+}
+
+
+void
+nRF24L01P::set_auto_acknowledge(int Pipe, bool Enable)
+{
+ char c = this->read_register(NRF24L01P_EN_AA);
+ char Mask = 1 << Pipe;
+ this->write_register(NRF24L01P_EN_AA, Enable ? (c | Mask) : (c & ~Mask));
+}
+
+void
+nRF24L01P::enable_rx_pipe(int Pipe, bool Enable)
+{
+ char c = this->read_register(NRF24L01P_EN_RXADDR);
+ char Mask = 1 << Pipe;
+ this->write_register(NRF24L01P_EN_RXADDR, Enable ? (c | Mask) : (c & ~Mask));
+}
+
+
+int
+nRF24L01P::which_rx_pipe()
+{
+ return (this->read_register(NRF24L01P_STATUS) & 0x0E) >> 1;
+}
+
+bool
+nRF24L01P::tx_full()
+{
+ return this->read_register(NRF24L01P_STATUS) & 0x01;
+}
+
+int
+nRF24L01P::num_lost_packets()
+{
+ return (this->read_register(NRF24L01P_OBSERVE_TX) & 0xF0) >> 4;
+}
+
+int
+nRF24L01P::num_retransmitted_packets()
+{
+ return this->read_register(NRF24L01P_OBSERVE_TX) & 0x0F;
+}
+
+void
+nRF24L01P::set_tx_address(uint64_t Address)
+{
+ this->write_register_40(NRF24L01P_TX_ADDR, Address);
+}
+
+// commands
+
+int
+nRF24L01P::read_register(int Register)
+{
+ NCS = 0;
+ Spi.write(NRF24L01P_CMD_R_REGISTER | Register);
+ int Result = Spi.write(NRF24L01P_CMD_NOP);
+ NCS = 1;
+ return Result;
+}
+
+int
+nRF24L01P::read_register_n(int Register, char* Buf, int Bytes)
+{
+ NCS = 0;
+ Spi.write(NRF24L01P_CMD_R_REGISTER | Register);
+ for (int i = 0; i < Bytes; ++i)
+ {
+ *Buf++ = Spi.write(NRF24L01P_CMD_NOP);
+ }
+ NCS = 1;
+ return 0;
+}
+
+int
+nRF24L01P::write_register(int Register, char x)
+{
+ NCS = 0;
+ Spi.write(NRF24L01P_CMD_W_REGISTER | Register);
+ Spi.write(x);
+ NCS = 1;
+ return 0;
+}
+
+int
+nRF24L01P::write_register_16(int Register, uint16_t x)
+{
+ NCS = 0;
+ Spi.write(NRF24L01P_CMD_W_REGISTER | Register);
+ Spi.write(x & 0xFF);
+ Spi.write((x >> 8) & 0xFF);
+ NCS = 1;
+ return 0;
+}
+
+int64_t
+nRF24L01P::write_register_40(int Register, uint64_t x)
+{
+ NCS = 0;
+ Spi.write(NRF24L01P_CMD_W_REGISTER | Register);
+ Spi.write(x & 0xFF);
+ x = x >> 8;
+ Spi.write(x & 0xFF);
+ x = x >> 8;
+ Spi.write(x & 0xFF);
+ x = x >> 8;
+ Spi.write(x & 0xFF);
+ x = x >> 8;
+ Spi.write(x & 0xFF);
+ NCS = 1;
+ return 0;
+}
+
+int
+nRF24L01P::write_register_bytes(int Register, char const* Buf, int Bytes)
+{
+ NCS = 0;
+ Spi.write(NRF24L01P_CMD_W_REGISTER | Register);
+ for (int i = 0; i < Bytes; ++i)
+ {
+ Spi.write(*Buf++);
+ }
+ NCS = 1;
+ return 0;
+}
+
+void
+nRF24L01P::write_tx_payload(char const* Buf, int Bytes)
+{
+ NCS = 0;
+ Spi.write(NRF24L01P_CMD_W_TX_PAYLOAD);
+ for (int i = 0; i < Bytes; ++i)
+ {
+ Spi.write(*Buf++);
+ }
+ NCS = 1;
+}
+
+void
+nRF24L01P::write_tx_payload_no_ack(char const* Buf, int Bytes)
+{
+ NCS = 0;
+ Spi.write(NRF24L01P_CMD_W_TX_PYLD_NO_ACK);
+ for (int i = 0; i < Bytes; ++i)
+ {
+ Spi.write(*Buf++);
+ }
+ NCS = 1;
+}
+
+void
+nRF24L01P::flush_tx_fifo()
+{
+ NCS = 0;
+ Spi.write(NRF24L01P_CMD_FLUSH_TX);
+ NCS = 1;
+}
+
+void
+nRF24L01P::reuse_tx_payload()
+{
+ NCS = 0;
+ Spi.write(NRF24L01P_CMD_REUSE_TX_PL);
+ NCS = 1;
+}
+
+int
+nRF24L01P::rx_payload_width()
+{
+ NCS = 0;
+ Spi.write(NRF24L01P_CMD_R_RX_PL_WID);
+ int Result = Spi.write(NRF24L01P_CMD_NOP);
+ NCS = 1;
+ return Result;
+
+}
+
+void
+nRF24L01P::read_rx_payload(char* Buf, int Bytes)
+{
+ NCS = 0;
+ Spi.write(NRF24L01P_CMD_R_RX_PAYLOAD);
+ for (int i = 0; i < Bytes; ++i)
+ {
+ *Buf++ = Spi.write(NRF24L01P_CMD_NOP);
+ }
+ NCS = 1;
+}
+
+int
+nRF24L01P::read_rx_payload(char* Buf)
+{
+ this->read_rx_payload(Buf, this->rx_payload_width());
+ return 0;
+}
+
+void
+nRF24L01P::flush_rx_fifo()
+{
+ NCS = 0;
+ Spi.write(NRF24L01P_CMD_FLUSH_RX);
+ NCS = 1;
+}
+
+void
+nRF24L01P::write_ack_payload(int Pipe, char const* Buf, int Bytes)
+{
+ NCS = 0;
+ Spi.write(NRF24L01P_CMD_W_ACK_PAYLOAD);
+ for (int i = 0; i < Bytes; ++i)
+ {
+ Spi.write(*Buf++);
+ }
+ NCS = 1;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nRF24L01P.h Sun Aug 11 11:58:05 2013 +0000
@@ -0,0 +1,263 @@
+//
+// Interface for Nordic Semiconductor nRF24L01 and nRF24L01+
+// see http://www.nordicsemi.no/files/Product/data_sheet/nRF24L01P_Product_Specification_1_0.pdf
+//
+// This class exposes basic SPI functionality for the nRF24L01+
+// A driver program is required to actually send or receive data.
+// This class doesn't provide any CE line control
+//
+// Differences between nRF24L01 and nRF24L01+
+// 1. The nRF24L01 doesn't support 250kHz air data rate
+// 2. The nRF24L01 received_power_detector() works differently
+//
+
+#ifndef NRF24L01P_H
+#define NRF24L01P_H
+
+#include "mbed.h"
+#include <stdint.h>
+
+#define NRF24L01P_MIN_RF_FREQUENCY 2400
+#define NRF24L01P_MAX_RF_FREQUENCY 2525
+
+// timing constants
+#define Tundef2pd_us 100000 // 100mS, time from reset to power-down mode
+#define Tstby2a_us 130 // 130uS, time from standby mode to TX/RX mode
+#define Thce_us 10 // 10uS, minimum time for CE high
+#define Tpd2stby_us 4500 // 4.5mS worst case, time from power-down to standby
+#define Tpece2csn_us 4 // 4uS, delay from CE positive edge to CSN low
+
+class nRF24L01P
+{
+ public:
+ nRF24L01P(PinName mosi, PinName miso, PinName sck, PinName csn, long SPIFrequency = 2000000);
+
+ // Clears the TX and RX FIFOs and resets all registers to their power-on values
+ void reset();
+
+ // change the SPI frequency
+ void set_spi_frequency(long Freq);
+
+ // register operations
+
+ // set the data rate in kb/s, valid values are 250 (nRF24L01+ only), 1000, 2000.
+ // DEFAULT:
+ void set_air_data_rate(int Rate);
+
+ // set the RF channel, 0 .. 125.
+ // The frequency in MHz is 2400 + Channel.
+ // In 2Mbps mode, you must use channels at least 2MHz appart to avoid overlap
+ // DEFAULT:
+ void set_channel(int Channel);
+
+ // PRECONDITION: Mode = Receive. True if a signal higher than -64bB is detected by the receiver
+ bool received_power_detector();
+
+ // set the transmit power in dB. Valid values are 0, -6, -12, -18
+ // DEFAULT: 0
+ void set_tx_power(int Power);
+
+
+ // enable or disable dynamic payload size on the given pipe
+ // DEFAULT:
+ void enable_dynamic_payload(int Pipe, bool Enable);
+
+ // Enable including a payload with ACK
+ // DEFAULT:
+ void enable_ack_payload(bool Enable);
+
+ // enable the write_tx_payload_no_ack() command
+ // DEFAULT: disabled
+ void enable_no_ack(bool Enable);
+
+ //
+ // receive functionality
+ //
+
+ // set the width in bytes for addresses. Valid values are 3,4,5
+ // DEFAULT: 5
+ void set_address_width(int Width);
+
+ // returns the width in bytes for addresses. Valid values are 3,4,5
+ int get_address_width();
+
+ // set the receive address of the given pipe. Pipes 0,1 have 3,4 or 5 byte addresses
+ // as specified by set_address_width(). Pipes 2,3,4,5 can only set the low order byte of the
+ // address, the other bytes are shared with pipe 1.
+
+ // Set the rx address for pipe 0 or 1
+ void set_rx_address(int Pipe, uint64_t Address);
+
+ // Set the low byte of the address for pipe 2,3,4,5
+ void set_rx_address_low(int Pipe, uint8_t Address);
+
+ // Set the payload size for the receive buffer for the given pipe
+ // (not used if dynamic payload size is used)
+ void set_rx_payload_bytes(int Pipe, int Bytes);
+
+ // returns true if the receive FIFO is full
+ bool is_rx_full();
+
+ // returns true if the receive FIFO is empty
+ bool is_rx_empty();
+
+ // receive packet status
+
+ // read the status register and return true if there is a packet ready to be received (RX_DR)
+ bool is_rx_ready();
+
+ // clear the RX_DR bit
+ void clear_rx_ready();
+
+ // if Enable, reflect RX_DR as active low on the INT line. The procedure to read a packet is:
+ // 1) Read payload through SPI, 2) clear_rc_ready(), read is_rx_ready() to see if there is another
+ // packet waiting
+ // DEFAULT: enabled
+ void set_interrupt_rx_ready(bool Enable);
+
+ // returns true if the transmit FIFO is full
+ bool is_tx_full();
+
+ // returns true if the transmit FIFO is empty
+ bool is_tx_empty();
+
+ // transmit packet status
+
+ // reads the status register and returns true if a packet has been transmitted. (TX_DS) If auto-acknowledge
+ // is set, then this is only asserted when an ack is received.
+ bool is_tx_sent();
+
+ // Clear the TX_DS bit
+ void clear_tx_sent();
+
+ // if Enable, reflect TX_DS as active low on the INT line
+ // DEFAULT: enabled
+ void set_interrupt_tx(bool Enable);
+
+ // retransmit behaviour
+
+ // set the auto-retransmit delay, in units of 250 microseconds.
+ // Valid input is 0,1,...,15 (for 250 .. 4000 us)
+ // DEFAULT:
+ void set_retransmit_delay(int Delay);
+
+ // set the number of auto-retransmit attempts, 0 .. 15
+ // DEFAULT:
+ void set_retransmit_attempts(int Attempts);
+
+ // returns true if we've hit the maximum number of restransmits
+ bool is_max_rt();
+
+ // clear the maximum number of retransmits flag.
+ void clear_max_rt();
+
+ // if Enable, reflect MAX_RT as active low on the INT line
+ // DEFAULT: enabled
+ void set_interrupt_max_rt(bool Enable);
+
+ // enable or disable the CRC check. Auto-acknowledge forces CRC enabled.
+ // DEFAULT:
+ void enable_crc(bool Enable);
+
+ // set the CRC width, either 1 byte or 2 bytes
+ // DEFAULT:
+ void set_crc_width(int width);
+
+ // set PWR_UP (move into standby mode)
+ void set_power_up();
+
+ // turn off power (PWR_UP=0)
+ void set_power_down();
+
+ // set as primary receiver (disables transmit mode)
+ void set_prx_mode();
+
+ // set as primary transmitter (disables receive mode)
+ void set_ptx_mode();
+
+ // Enable or disable receiving on the given pipe
+ // DEFAULT: Pipes 0,1 enabled, pipes 2,3,4,5 disabled.
+ void enable_rx_pipe(int Pipe, bool Enable);
+
+ // Enable or disable auto-acknowledge on the given pipe 0,1,2,3,4,5
+ // DEFAULT: Enabled on all pipes
+ void set_auto_acknowledge(int Pipe, bool Enable);
+
+ // Enable or disable RX addresses on the given pipe
+ void enable_receive_pipe(int Pipe, bool Enable);
+
+ // returns the pipe number for the payload available on the rx pipe, or -1 if the rx fifo is empty
+ int which_rx_pipe();
+
+ // returns true if the transmit fifo is full
+ bool tx_full();
+
+ // returns the number of transmitted but lost packets. Capped at 15, reset by writing the channel number.
+ int num_lost_packets();
+
+ // returns the number of times the current packet has been retransmitted. Reset when a new packet starts
+ int num_retransmitted_packets();
+
+
+ // Set the tx address. Used only for a PTX, set this the same as the rx_address of pipe 0 to enable
+ // auto-acknowledge with Enhanced ShockBurst(TM)
+ // DEFAULT:
+ void set_tx_address(uint64_t Address);
+
+ // commands
+
+ // read a byte from the given register
+ int read_register(int Register);
+
+ // read n bytes from the given register
+ int read_register_n(int Register, char* Buf, int Bytes);
+
+ // write one byte to the given register
+ int write_register(int Register, char x);
+
+ // write two bytes to a register
+ int write_register_16(int Register, uint16_t x);
+
+ // write five bytes to a register
+ int64_t write_register_40(int Register, uint64_t x);
+
+ // write some bytes to the given register
+ int write_register_bytes(int Register, char const* Buf, int Bytes);
+
+ // Write a transmit payload, 1-32 bytes
+ void write_tx_payload(char const* Buf, int Bytes);
+
+ // Write a transmit payload, 1-32 bytes, with ACK disabled.
+ // NOTE: enable_no_ack() must be enabled
+ void write_tx_payload_no_ack(char const* Buf, int Bytes);
+
+ // flush the transmit FIFO
+ void flush_tx_fifo();
+
+ // reuse the last transmitted payload. Payload reuse is activated until the next flush_tx_fifo() or write_tx_payload()
+ void reuse_tx_payload();
+
+ // returns the width of the receive payload. (If this isn't in the range 0..32 then the rx fifo should be flushed)
+ int rx_payload_width();
+
+ // read 1-32 bytes from the RX FIFO. The payload is deleted after it is read. The user must
+ // know how many bytes to read.
+ void read_rx_payload(char* Buf, int Bytes);
+
+ // this version reads the complete payload into Buf, and returns the number of bytes in the payload
+ int read_rx_payload(char* Buf);
+
+ // flush the receive FIFO
+ void flush_rx_fifo();
+
+ // set the ACK payload for the given pipe.
+ void write_ack_payload(int Pipe, char const* Buf, int Bytes);
+
+
+ private:
+ SPI Spi;
+ DigitalOut NCS;
+};
+
+#endif
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nRF24L01P_PRX.cpp Sun Aug 11 11:58:05 2013 +0000
@@ -0,0 +1,160 @@
+
+#include "nRF24L01P_PRX.h"
+
+// status
+#define STATUS_UNDEFINED 0
+#define STATUS_READY_INIT 1
+#define STATUS_POWER_DOWN 2
+#define STATUS_STARTUP_STANDBY 3
+#define STATUS_STANDBY 4
+#define STATUS_RECEIVE 5
+
+nRF24L01P_PRX::nRF24L01P_PRX(nRF24L01P& Device_, PinName CE_, PinName Int_)
+ : Device(Device_),
+ CE(CE_),
+ Int(Int_)
+{
+ CE = 0;
+ PayloadSize = 0;
+ Status = STATUS_UNDEFINED;
+ Int.mode(PullNone);
+ Int.fall(NULL);
+ InitializeTimer.attach_us(this, &nRF24L01P_PRX::ReadyInitialize, Tundef2pd_us);
+}
+
+void
+nRF24L01P_PRX::Initialize()
+{
+ while (Status == STATUS_UNDEFINED)
+ {
+ wait_us(1);
+ }
+ PowerOnTimer.detach();
+ CE = 0;
+ Device.reset();
+ Device.set_prx_mode();
+ Status = STATUS_POWER_DOWN;
+ PayloadSize = 0;
+ Int.fall(this, &nRF24L01P_PRX::IntHandler);
+}
+
+void
+nRF24L01P_PRX::SetChannel(int Channel)
+{
+ Device.set_channel(Channel);
+}
+
+void
+nRF24L01P_PRX::SetDataRate(int Rate)
+{
+ Device.set_air_data_rate(Rate);
+}
+
+void
+nRF24L01P_PRX::SetAddress(uint64_t Address)
+{
+ Device.set_rx_address(0, Address);
+}
+
+void
+nRF24L01P_PRX::SetPayloadSize(int Size)
+{
+ PayloadSize = Size;
+ Device.set_rx_payload_bytes(0, Size);
+}
+
+void
+nRF24L01P_PRX::PowerUp()
+{
+ if (Status != STATUS_POWER_DOWN)
+ {
+ error("nRF24L01P_PRX::PowerUp(): can only be called when device is powered down");
+ }
+ Status = STATUS_STARTUP_STANDBY;
+ Device.set_power_up();
+ PowerOnTimer.attach_us(this, &nRF24L01P_PRX::ReadyStandby, Tpd2stby_us);
+}
+
+void
+nRF24L01P_PRX::PowerDown()
+{
+ if (Status == STATUS_UNDEFINED || Status == STATUS_READY_INIT || Status == STATUS_POWER_DOWN)
+ {
+ error("nRF24L01P_PRX::PowerDown(): error: device is not powered up!");
+ }
+ PowerOnTimer.detach();
+ Device.set_power_down();
+ Status = STATUS_POWER_DOWN;
+}
+
+void
+nRF24L01P_PRX::StartReceive()
+{
+ if (Status == STATUS_UNDEFINED || Status == STATUS_READY_INIT || Status == STATUS_POWER_DOWN)
+ {
+ error("nRF24L01P_PRX::StartReceive(): error: device is not powered up!");
+ }
+ while (Status == STATUS_STARTUP_STANDBY)
+ {
+ wait_us(1);
+ }
+ CE = 1;
+ Status = STATUS_RECEIVE;
+}
+
+void
+nRF24L01P_PRX::StopReceive()
+{
+ if (Status != STATUS_RECEIVE)
+ {
+ error("nRF24L01P_PRX::StopReceive(): error: device is not receiving!");
+ }
+ CE = 0;
+ Status = STATUS_STANDBY;
+}
+
+bool
+nRF24L01P_PRX::IsPacketReady()
+{
+ return Device.is_rx_ready();
+}
+
+int
+nRF24L01P_PRX::ReadPacket(char* Buf)
+{
+ if (!this->IsPacketReady())
+ {
+ error("nRF24L01P_PRX::ReadPacket(): error: no packet to read!");
+ }
+
+ Device.read_rx_payload(Buf);
+ Device.clear_rx_ready();
+ return PayloadSize;
+}
+
+void
+nRF24L01P_PRX::IntHandler()
+{
+// here we do nothing, since we use polling instead
+/*
+ while (Device.is_rx_ready())
+ {
+ // read payload
+ Device.read_rx_payload(Buf);
+ Device.clear_rx_ready();
+ }
+*/
+}
+
+void
+nRF24L01P_PRX::ReadyInitialize()
+{
+ Status = STATUS_READY_INIT;
+}
+
+void
+nRF24L01P_PRX::ReadyStandby()
+{
+ if (Status == STATUS_STARTUP_STANDBY)
+ Status = STATUS_STANDBY;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nRF24L01P_PRX.h Sun Aug 11 11:58:05 2013 +0000
@@ -0,0 +1,66 @@
+// A simple PRX driver for the nRF24L01+
+// for polling mode with fixed payload length
+
+#ifndef NRF24L01P_PRX_H
+#define NRF24L01P_PRX_H
+
+#include "nRF24L01P.h"
+
+class nRF24L01P_PRX
+{
+ public:
+ nRF24L01P_PRX(nRF24L01P& Device_, PinName CE_, PinName Int_);
+
+ // Initialize the device for transmitting. There must be a delay of
+ // at least 100ms from initial power on before this function is called.
+ void Initialize();
+
+ // Set the channel number, 0 .. 125
+ void SetChannel(int Channel);
+
+ // sets the data rate in Kbps, valid values are 250 (nRF24L01+ only), 1000, 2000
+ void SetDataRate(int Rate);
+
+ // Set the 40-bit address
+ void SetAddress(uint64_t Address);
+
+ // Set the expected payload size
+ void SetPayloadSize(int Size);
+
+ // Power up ready to enter receive mode. There is a delay of Tpd2stby_us
+ // after PowerUp() before receiving can start.
+ void PowerUp();
+
+ // Powers down the device. PowerUp must be called before a packet can be transmitted.
+ void PowerDown();
+
+ // Start listening for packets.
+ void StartReceive();
+
+ // Stop listening for packets.
+ void StopReceive();
+
+ // returns true if there is a packet ready to read
+ bool IsPacketReady();
+
+ // PRECONDITION: IsPacketReady().
+ // Reads the packet into the given buffer.
+ // Returns the size of the packet.
+ int ReadPacket(char* Buf);
+
+ private:
+ void IntHandler();
+ void ReadyInitialize();
+ void ReadyStandby();
+
+ nRF24L01P& Device;
+ DigitalOut CE;
+ InterruptIn Int;
+ Timeout PowerOnTimer;
+ Timeout InitializeTimer;
+
+ int volatile Status;
+ int PayloadSize;
+};
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nRF24L01P_PTX.cpp Sun Aug 11 11:58:05 2013 +0000
@@ -0,0 +1,169 @@
+
+#include "nRF24L01P_PTX.h"
+
+// status
+#define STATUS_UNDEFINED 0
+#define STATUS_READY_INIT 1
+#define STATUS_POWER_DOWN 2
+#define STATUS_STARTUP_STANDBY 3
+#define STATUS_STANDBY 4
+#define STATUS_TRANSMITTING 5
+#define STATUS_PACKET_OK 6
+#define STATUS_PACKET_MAX_RT 7
+
+nRF24L01P_PTX::nRF24L01P_PTX(nRF24L01P& Device_, PinName CE_, PinName Int_)
+ : Device(Device_),
+ CE(CE_),
+ Int(Int_)
+{
+ CE = 0;
+ Status = STATUS_UNDEFINED;
+ Int.mode(PullNone);
+ Int.fall(NULL);
+ InitializeTimer.attach_us(this, &nRF24L01P_PTX::ReadyInitialize, Tundef2pd_us);
+}
+
+void
+nRF24L01P_PTX::Initialize()
+{
+ while (Status == STATUS_UNDEFINED)
+ {
+ wait_us(1);
+ }
+ PowerOnTimer.detach();
+ CE = 0;
+ Device.reset();
+ Device.set_ptx_mode();
+ Status = STATUS_POWER_DOWN;
+ Int.fall(this, &nRF24L01P_PTX::IntHandler);
+}
+
+void
+nRF24L01P_PTX::SetChannel(int Channel)
+{
+ Device.set_channel(Channel);
+}
+
+void
+nRF24L01P_PTX::SetDataRate(int Rate)
+{
+ Device.set_air_data_rate(Rate);
+}
+
+void
+nRF24L01P_PTX::SetTransmitPower(int Power)
+{
+ Device.set_tx_power(Power);
+}
+
+void
+nRF24L01P_PTX::SetDestinationAddress(uint64_t Address)
+{
+ Device.set_tx_address(Address);
+}
+
+void
+nRF24L01P_PTX::PowerUp()
+{
+ if (Status != STATUS_POWER_DOWN)
+ {
+ error("nRF24L01P_PTX::PowerUp(): can only be called when device is powered down");
+ }
+ Status = STATUS_STARTUP_STANDBY;
+ Device.set_power_up();
+ PowerOnTimer.attach_us(this, &nRF24L01P_PTX::ReadyStandby, Tpd2stby_us);
+}
+
+void
+nRF24L01P_PTX::PowerDown()
+{
+ if (Status == STATUS_UNDEFINED || Status == STATUS_READY_INIT)
+ {
+ error("nRF24L01P_PTX::PowerDown(): error: device is not initialized!");
+ }
+ // Although it is technically possible to turn the power off at any time,
+ // if we're currently processing a packet, wait until we've finished
+ while (Status == STATUS_TRANSMITTING || Status == STATUS_PACKET_OK || Status == STATUS_PACKET_MAX_RT)
+ {
+ wait_us(1);
+ }
+ PowerOnTimer.detach();
+ Device.set_power_down();
+ Status = STATUS_POWER_DOWN;
+}
+
+bool
+nRF24L01P_PTX::IsReadyTransmit()
+{
+ return (Status == STATUS_STANDBY);
+}
+
+int
+nRF24L01P_PTX::TransmitPacket(char* Buf, int Size)
+{
+ // If the device isn't powered up then there is a logic error
+ if (Status == STATUS_UNDEFINED || Status == STATUS_READY_INIT || Status == STATUS_POWER_DOWN)
+ {
+ error("nRF24L01P_PTX::TransmitPacket(): error: device power must be on!");
+ }
+ // Wait until the device is ready to transmit
+ while (Status != STATUS_STANDBY)
+ {
+ wait_us(1);
+ }
+ Device.write_tx_payload(Buf, Size);
+ Status = STATUS_TRANSMITTING;
+ CE = 1;
+ wait_us(Thce_us);
+ CE = 0;
+ // wait until the packet is transmitted (or some error)
+ while (Status == STATUS_TRANSMITTING)
+ {
+ wait_us(1);
+ }
+ int OldStatus = Status;
+ if (OldStatus == STATUS_PACKET_OK)
+ {
+ Status = STATUS_STANDBY;
+ return 0;
+ }
+ else if (OldStatus == STATUS_PACKET_MAX_RT)
+ {
+ Status = STATUS_STANDBY;
+ return -1;
+ }
+ // else the Status isn't what we expected, which
+ // shouldn't happen in blocking mode. Some interrupt must have
+ // reset Status. Bug out with an error.
+ return -1;
+}
+
+void
+nRF24L01P_PTX::IntHandler()
+{
+ if (Device.is_tx_sent())
+ {
+ // we successfully sent a packet
+ Status = STATUS_PACKET_OK;
+ Device.clear_tx_sent();
+ }
+ else if (Device.is_max_rt())
+ {
+ // we failed to send the packet
+ Status = STATUS_PACKET_MAX_RT;
+ Device.clear_max_rt();
+ }
+}
+
+void
+nRF24L01P_PTX::ReadyInitialize()
+{
+ Status = STATUS_READY_INIT;
+}
+
+void
+nRF24L01P_PTX::ReadyStandby()
+{
+ if (Status == STATUS_STARTUP_STANDBY)
+ Status = STATUS_STANDBY;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nRF24L01P_PTX.h Sun Aug 11 11:58:05 2013 +0000
@@ -0,0 +1,62 @@
+// A simple PTX driver for the nRF24L01+
+// with fixed payload length
+
+#ifndef NRF24L01P_PTX_H
+#define NRF24L01P_PTX_H
+
+#include "nRF24L01P.h"
+
+class nRF24L01P_PTX
+{
+ public:
+ nRF24L01P_PTX(nRF24L01P& Device_, PinName CE_, PinName Int_);
+
+ // Initialize the device for transmitting. There must be a delay of
+ // at least 100ms from initial power on before this function is called.
+ void Initialize();
+
+ // Set the channel number, 0 .. 125
+ void SetChannel(int Channel);
+
+ // sets the data rate in Kbps, valid values are 250 (nRF24L01+ only), 1000, 2000
+ void SetDataRate(int Rate);
+
+ // Set the transmitter power in dB. Valid values are -18, -12, -6, 0
+ void SetTransmitPower(int Power);
+
+ // Set the 40-bit destination address
+ void SetDestinationAddress(uint64_t Address);
+
+ // Power up ready to transmit. There is a delay of Tpd2stby_us
+ // after PowerUp() before a packet can be transmitted. This
+ // is handled automatically with a timer, so that TransmitPacket()
+ // will block until the device is ready.
+ void PowerUp();
+
+ // Powers down the device. PowerUp must be called before a packet can be transmitted.
+ void PowerDown();
+
+ // Returns true if the device is ready to transmit a packet, ie
+ // powered on and not busy
+ bool IsReadyTransmit();
+
+ // Does the actual transmit of a packet, in blocking mode.
+ // Returns 0 on success.
+ // Returns -1 if the packet wasn't successfully acknowledged.
+ int TransmitPacket(char* Buf, int Size);
+
+ private:
+ void IntHandler();
+ void ReadyInitialize();
+ void ReadyStandby();
+
+ nRF24L01P& Device;
+ DigitalOut CE;
+ InterruptIn Int;
+ Timeout PowerOnTimer;
+ Timeout InitializeTimer;
+
+ int volatile Status;
+};
+
+#endif