RADIO nRF24L01

Dependents:   NRF24L01_receiver NRF24L01_sender G6-tim003-Projekat-Wireless Projekat_13_Grupa5_Bezicni_Chat ... more

Files at this revision

API Documentation at this revision

Comitter:
pabloamr
Date:
Thu Apr 21 23:14:43 2011 +0000
Commit message:

Changed in this revision

nRF24L01P.cpp Show annotated file Show diff for this revision Revisions of this file
nRF24L01P.h Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r 8d55f1f49a33 nRF24L01P.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nRF24L01P.cpp	Thu Apr 21 23:14:43 2011 +0000
@@ -0,0 +1,1029 @@
+/**
+ * @file nRF24L01P.cpp
+ *
+ * @author Owen Edwards
+ * 
+ * @section LICENSE
+ *
+ * Copyright (c) 2010 Owen Edwards
+ *
+ *    This program is free software: you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation, either version 3 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * @section DESCRIPTION
+ *
+ * nRF24L01+ Single Chip 2.4GHz Transceiver from Nordic Semiconductor.
+ *
+ * Datasheet:
+ *
+ * http://www.nordicsemi.no/files/Product/data_sheet/nRF24L01P_Product_Specification_1_0.pdf
+ */
+
+/**
+ * Includes
+ */
+#include "nRF24L01P.h"
+
+/**
+ * Defines
+ *
+ * (Note that all defines here start with an underscore, e.g. '_NRF24L01P_MODE_UNKNOWN',
+ *  and are local to this library.  The defines in the nRF24L01P.h file do not start
+ *  with the underscore, and can be used by code to access this library.)
+ */
+
+typedef enum {
+    _NRF24L01P_MODE_UNKNOWN,
+    _NRF24L01P_MODE_POWER_DOWN,
+    _NRF24L01P_MODE_STANDBY,
+    _NRF24L01P_MODE_RX,
+    _NRF24L01P_MODE_TX,
+} nRF24L01P_Mode_Type;
+
+/*
+ * The following FIFOs are present in nRF24L01+:
+ *   TX three level, 32 byte FIFO
+ *   RX three level, 32 byte FIFO
+ */
+#define _NRF24L01P_TX_FIFO_COUNT   33
+#define _NRF24L01P_RX_FIFO_COUNT   33
+
+#define _NRF24L01P_TX_FIFO_SIZE   32
+#define _NRF24L01P_RX_FIFO_SIZE   32
+
+#define _NRF24L01P_SPI_MAX_DATA_RATE     10000000
+
+#define _NRF24L01P_SPI_CMD_RD_REG            0x00
+#define _NRF24L01P_SPI_CMD_WR_REG            0x20
+#define _NRF24L01P_SPI_CMD_RD_RX_PAYLOAD     0x61   
+#define _NRF24L01P_SPI_CMD_WR_TX_PAYLOAD     0xa0
+#define _NRF24L01P_SPI_CMD_FLUSH_TX          0xe1
+#define _NRF24L01P_SPI_CMD_FLUSH_RX          0xe2
+#define _NRF24L01P_SPI_CMD_REUSE_TX_PL       0xe3
+#define _NRF24L01P_SPI_CMD_R_RX_PL_WID       0x60
+#define _NRF24L01P_SPI_CMD_W_ACK_PAYLOAD     0xa8
+#define _NRF24L01P_SPI_CMD_W_TX_PYLD_NO_ACK  0xb0
+#define _NRF24L01P_SPI_CMD_NOP               0xff
+
+
+#define _NRF24L01P_REG_CONFIG                0x00
+#define _NRF24L01P_REG_EN_AA                 0x01
+#define _NRF24L01P_REG_EN_RXADDR             0x02
+#define _NRF24L01P_REG_SETUP_AW              0x03
+#define _NRF24L01P_REG_SETUP_RETR            0x04
+#define _NRF24L01P_REG_RF_CH                 0x05
+#define _NRF24L01P_REG_RF_SETUP              0x06
+#define _NRF24L01P_REG_STATUS                0x07
+#define _NRF24L01P_REG_OBSERVE_TX            0x08
+#define _NRF24L01P_REG_RPD                   0x09
+#define _NRF24L01P_REG_RX_ADDR_P0            0x0a
+#define _NRF24L01P_REG_RX_ADDR_P1            0x0b
+#define _NRF24L01P_REG_RX_ADDR_P2            0x0c
+#define _NRF24L01P_REG_RX_ADDR_P3            0x0d
+#define _NRF24L01P_REG_RX_ADDR_P4            0x0e
+#define _NRF24L01P_REG_RX_ADDR_P5            0x0f
+#define _NRF24L01P_REG_TX_ADDR               0x10
+#define _NRF24L01P_REG_RX_PW_P0              0x11
+#define _NRF24L01P_REG_RX_PW_P1              0x12
+#define _NRF24L01P_REG_RX_PW_P2              0x13
+#define _NRF24L01P_REG_RX_PW_P3              0x14
+#define _NRF24L01P_REG_RX_PW_P4              0x15
+#define _NRF24L01P_REG_RX_PW_P5              0x16
+#define _NRF24L01P_REG_FIFO_STATUS           0x17
+#define _NRF24L01P_REG_DYNPD                 0x1c
+#define _NRF24L01P_REG_FEATURE               0x1d
+
+#define _NRF24L01P_REG_ADDRESS_MASK          0x1f
+
+// CONFIG register:
+#define _NRF24L01P_CONFIG_PRIM_RX        (1<<0)
+#define _NRF24L01P_CONFIG_PWR_UP         (1<<1)
+#define _NRF24L01P_CONFIG_CRC0           (1<<2)
+#define _NRF24L01P_CONFIG_EN_CRC         (1<<3)
+#define _NRF24L01P_CONFIG_MASK_MAX_RT    (1<<4)
+#define _NRF24L01P_CONFIG_MASK_TX_DS     (1<<5)
+#define _NRF24L01P_CONFIG_MASK_RX_DR     (1<<6)
+
+#define _NRF24L01P_CONFIG_CRC_MASK       (_NRF24L01P_CONFIG_EN_CRC|_NRF24L01P_CONFIG_CRC0)
+#define _NRF24L01P_CONFIG_CRC_NONE       (0)
+#define _NRF24L01P_CONFIG_CRC_8BIT       (_NRF24L01P_CONFIG_EN_CRC)
+#define _NRF24L01P_CONFIG_CRC_16BIT      (_NRF24L01P_CONFIG_EN_CRC|_NRF24L01P_CONFIG_CRC0)
+
+// EN_AA register:
+#define _NRF24L01P_EN_AA_NONE            0
+
+// EN_RXADDR register:
+#define _NRF24L01P_EN_RXADDR_NONE        0
+
+// SETUP_AW register:
+#define _NRF24L01P_SETUP_AW_AW_MASK      (0x3<<0)
+#define _NRF24L01P_SETUP_AW_AW_3BYTE     (0x1<<0)
+#define _NRF24L01P_SETUP_AW_AW_4BYTE     (0x2<<0)
+#define _NRF24L01P_SETUP_AW_AW_5BYTE     (0x3<<0)
+
+// SETUP_RETR register:
+#define _NRF24L01P_SETUP_RETR_NONE       0
+
+// RF_SETUP register:
+#define _NRF24L01P_RF_SETUP_RF_PWR_MASK          (0x3<<1)
+#define _NRF24L01P_RF_SETUP_RF_PWR_0DBM          (0x3<<1)
+#define _NRF24L01P_RF_SETUP_RF_PWR_MINUS_6DBM    (0x2<<1)
+#define _NRF24L01P_RF_SETUP_RF_PWR_MINUS_12DBM   (0x1<<1)
+#define _NRF24L01P_RF_SETUP_RF_PWR_MINUS_18DBM   (0x0<<1)
+
+#define _NRF24L01P_RF_SETUP_RF_DR_HIGH_BIT       (1 << 3)
+#define _NRF24L01P_RF_SETUP_RF_DR_LOW_BIT        (1 << 5)
+#define _NRF24L01P_RF_SETUP_RF_DR_MASK           (_NRF24L01P_RF_SETUP_RF_DR_LOW_BIT|_NRF24L01P_RF_SETUP_RF_DR_HIGH_BIT)
+#define _NRF24L01P_RF_SETUP_RF_DR_250KBPS        (_NRF24L01P_RF_SETUP_RF_DR_LOW_BIT)
+#define _NRF24L01P_RF_SETUP_RF_DR_1MBPS          (0)
+#define _NRF24L01P_RF_SETUP_RF_DR_2MBPS          (_NRF24L01P_RF_SETUP_RF_DR_HIGH_BIT)
+
+// STATUS register:
+#define _NRF24L01P_STATUS_TX_FULL        (1<<0)
+#define _NRF24L01P_STATUS_RX_P_NO        (0x7<<1)
+#define _NRF24L01P_STATUS_MAX_RT         (1<<4)
+#define _NRF24L01P_STATUS_TX_DS          (1<<5)
+#define _NRF24L01P_STATUS_RX_DR          (1<<6)
+
+// RX_PW_P0..RX_PW_P5 registers:
+#define _NRF24L01P_RX_PW_Px_MASK         0x3F
+
+#define _NRF24L01P_TIMING_Tundef2pd_us     100000   // 100mS
+#define _NRF24L01P_TIMING_Tstby2a_us          130   // 130uS
+#define _NRF24L01P_TIMING_Thce_us              10   //  10uS
+#define _NRF24L01P_TIMING_Tpd2stby_us        4500   // 4.5mS worst case
+#define _NRF24L01P_TIMING_Tpece2csn_us          4   //   4uS
+
+/**
+ * Methods
+ */
+
+nRF24L01P::nRF24L01P(PinName mosi, 
+                     PinName miso, 
+                     PinName sck, 
+                     PinName csn,
+                     PinName ce,
+                     PinName irq) : spi_(mosi, miso, sck), nCS_(csn), ce_(ce), nIRQ_(irq) {
+
+    mode = _NRF24L01P_MODE_UNKNOWN;
+
+    disable();
+
+    nCS_ = 1;
+
+    spi_.frequency(_NRF24L01P_SPI_MAX_DATA_RATE/5);     // 2Mbit, 1/5th the maximum transfer rate for the SPI bus
+    spi_.format(8,0);                                   // 8-bit, ClockPhase = 0, ClockPolarity = 0
+
+    wait_us(_NRF24L01P_TIMING_Tundef2pd_us);    // Wait for Power-on reset
+
+    setRegister(_NRF24L01P_REG_CONFIG, 0); // Power Down
+
+    setRegister(_NRF24L01P_REG_STATUS, _NRF24L01P_STATUS_MAX_RT|_NRF24L01P_STATUS_TX_DS|_NRF24L01P_STATUS_RX_DR);   // Clear any pending interrupts
+
+    //
+    // Setup default configuration
+    //
+    disableAllRxPipes();
+    setRfFrequency();
+    setRfOutputPower();
+    setAirDataRate();
+    setCrcWidth();
+    setTxAddress();
+    setRxAddress();
+    disableAutoAcknowledge();
+    disableAutoRetransmit();
+    setTransferSize();
+
+    mode = _NRF24L01P_MODE_POWER_DOWN;
+
+}
+
+
+void nRF24L01P::powerUp(void) {
+
+    int config = getRegister(_NRF24L01P_REG_CONFIG);
+
+    config |= _NRF24L01P_CONFIG_PWR_UP;
+
+    setRegister(_NRF24L01P_REG_CONFIG, config);
+
+    // Wait until the nRF24L01+ powers up
+    wait_us( _NRF24L01P_TIMING_Tpd2stby_us );
+
+    mode = _NRF24L01P_MODE_STANDBY;
+
+}
+
+
+void nRF24L01P::powerDown(void) {
+
+    int config = getRegister(_NRF24L01P_REG_CONFIG);
+
+    config &= ~_NRF24L01P_CONFIG_PWR_UP;
+
+    setRegister(_NRF24L01P_REG_CONFIG, config);
+
+    // Wait until the nRF24L01+ powers down
+    wait_us( _NRF24L01P_TIMING_Tpd2stby_us );    // This *may* not be necessary (no timing is shown in the Datasheet), but just to be safe
+
+    mode = _NRF24L01P_MODE_POWER_DOWN;
+
+}
+
+
+void nRF24L01P::setReceiveMode(void) {
+
+    if ( _NRF24L01P_MODE_POWER_DOWN == mode ) powerUp();
+
+    int config = getRegister(_NRF24L01P_REG_CONFIG);
+
+    config |= _NRF24L01P_CONFIG_PRIM_RX;
+
+    setRegister(_NRF24L01P_REG_CONFIG, config);
+
+    mode = _NRF24L01P_MODE_RX;
+
+}
+
+
+void nRF24L01P::setTransmitMode(void) {
+
+    if ( _NRF24L01P_MODE_POWER_DOWN == mode ) powerUp();
+
+    int config = getRegister(_NRF24L01P_REG_CONFIG);
+
+    config &= ~_NRF24L01P_CONFIG_PRIM_RX;
+
+    setRegister(_NRF24L01P_REG_CONFIG, config);
+
+    mode = _NRF24L01P_MODE_TX;
+
+}
+
+
+void nRF24L01P::enable(void) {
+
+    ce_ = 1;
+    wait_us( _NRF24L01P_TIMING_Tpece2csn_us );
+
+}
+
+
+void nRF24L01P::disable(void) {
+
+    ce_ = 0;
+
+}
+
+void nRF24L01P::setRfFrequency(int frequency) {
+
+    if ( ( frequency < NRF24L01P_MIN_RF_FREQUENCY ) || ( frequency > NRF24L01P_MAX_RF_FREQUENCY ) ) {
+
+        error( "nRF24L01P: Invalid RF Frequency setting %d\r\n", frequency );
+        return;
+
+    }
+
+    int channel = ( frequency - NRF24L01P_MIN_RF_FREQUENCY ) & 0x7F;
+
+    setRegister(_NRF24L01P_REG_RF_CH, channel);
+
+}
+
+
+int nRF24L01P::getRfFrequency(void) {
+
+    int channel = getRegister(_NRF24L01P_REG_RF_CH) & 0x7F;
+
+    return ( channel + NRF24L01P_MIN_RF_FREQUENCY );
+
+}
+
+
+void nRF24L01P::setRfOutputPower(int power) {
+
+    int rfSetup = getRegister(_NRF24L01P_REG_RF_SETUP) & ~_NRF24L01P_RF_SETUP_RF_PWR_MASK;
+
+    switch ( power ) {
+
+        case NRF24L01P_TX_PWR_ZERO_DB:
+            rfSetup |= _NRF24L01P_RF_SETUP_RF_PWR_0DBM;
+            break;
+
+        case NRF24L01P_TX_PWR_MINUS_6_DB:
+            rfSetup |= _NRF24L01P_RF_SETUP_RF_PWR_MINUS_6DBM;
+            break;
+
+        case NRF24L01P_TX_PWR_MINUS_12_DB:
+            rfSetup |= _NRF24L01P_RF_SETUP_RF_PWR_MINUS_12DBM;
+            break;
+
+        case NRF24L01P_TX_PWR_MINUS_18_DB:
+            rfSetup |= _NRF24L01P_RF_SETUP_RF_PWR_MINUS_18DBM;
+            break;
+
+        default:
+            error( "nRF24L01P: Invalid RF Output Power setting %d\r\n", power );
+            return;
+
+    }
+
+    setRegister(_NRF24L01P_REG_RF_SETUP, rfSetup);
+
+}
+
+
+int nRF24L01P::getRfOutputPower(void) {
+
+    int rfPwr = getRegister(_NRF24L01P_REG_RF_SETUP) & _NRF24L01P_RF_SETUP_RF_PWR_MASK;
+
+    switch ( rfPwr ) {
+
+        case _NRF24L01P_RF_SETUP_RF_PWR_0DBM:
+            return NRF24L01P_TX_PWR_ZERO_DB;
+
+        case _NRF24L01P_RF_SETUP_RF_PWR_MINUS_6DBM:
+            return NRF24L01P_TX_PWR_MINUS_6_DB;
+
+        case _NRF24L01P_RF_SETUP_RF_PWR_MINUS_12DBM:
+            return NRF24L01P_TX_PWR_MINUS_12_DB;
+
+        case _NRF24L01P_RF_SETUP_RF_PWR_MINUS_18DBM:
+            return NRF24L01P_TX_PWR_MINUS_18_DB;
+
+        default:
+            error( "nRF24L01P: Unknown RF Output Power value %d\r\n", rfPwr );
+            return 0;
+
+    }
+}
+
+
+void nRF24L01P::setAirDataRate(int rate) {
+
+    int rfSetup = getRegister(_NRF24L01P_REG_RF_SETUP) & ~_NRF24L01P_RF_SETUP_RF_DR_MASK;
+
+    switch ( rate ) {
+
+        case NRF24L01P_DATARATE_250_KBPS:
+            rfSetup |= _NRF24L01P_RF_SETUP_RF_DR_250KBPS;
+            break;
+
+        case NRF24L01P_DATARATE_1_MBPS:
+            rfSetup |= _NRF24L01P_RF_SETUP_RF_DR_1MBPS;
+            break;
+
+        case NRF24L01P_DATARATE_2_MBPS:
+            rfSetup |= _NRF24L01P_RF_SETUP_RF_DR_2MBPS;
+            break;
+
+        default:
+            error( "nRF24L01P: Invalid Air Data Rate setting %d\r\n", rate );
+            return;
+
+    }
+
+    setRegister(_NRF24L01P_REG_RF_SETUP, rfSetup);
+
+}
+
+
+int nRF24L01P::getAirDataRate(void) {
+
+    int rfDataRate = getRegister(_NRF24L01P_REG_RF_SETUP) & _NRF24L01P_RF_SETUP_RF_DR_MASK;
+
+    switch ( rfDataRate ) {
+
+        case _NRF24L01P_RF_SETUP_RF_DR_250KBPS:
+            return NRF24L01P_DATARATE_250_KBPS;
+
+        case _NRF24L01P_RF_SETUP_RF_DR_1MBPS:
+            return NRF24L01P_DATARATE_1_MBPS;
+
+        case _NRF24L01P_RF_SETUP_RF_DR_2MBPS:
+            return NRF24L01P_DATARATE_2_MBPS;
+
+        default:
+            error( "nRF24L01P: Unknown Air Data Rate value %d\r\n", rfDataRate );
+            return 0;
+
+    }
+}
+
+
+void nRF24L01P::setCrcWidth(int width) {
+
+    int config = getRegister(_NRF24L01P_REG_CONFIG) & ~_NRF24L01P_CONFIG_CRC_MASK;
+
+    switch ( width ) {
+
+        case NRF24L01P_CRC_NONE:
+            config |= _NRF24L01P_CONFIG_CRC_NONE;
+            break;
+
+        case NRF24L01P_CRC_8_BIT:
+            config |= _NRF24L01P_CONFIG_CRC_8BIT;
+            break;
+
+        case NRF24L01P_CRC_16_BIT:
+            config |= _NRF24L01P_CONFIG_CRC_16BIT;
+            break;
+
+        default:
+            error( "nRF24L01P: Invalid CRC Width setting %d\r\n", width );
+            return;
+
+    }
+
+    setRegister(_NRF24L01P_REG_CONFIG, config);
+
+}
+
+
+int nRF24L01P::getCrcWidth(void) {
+
+    int crcWidth = getRegister(_NRF24L01P_REG_CONFIG) & _NRF24L01P_CONFIG_CRC_MASK;
+
+    switch ( crcWidth ) {
+
+        case _NRF24L01P_CONFIG_CRC_NONE:
+            return NRF24L01P_CRC_NONE;
+
+        case _NRF24L01P_CONFIG_CRC_8BIT:
+            return NRF24L01P_CRC_8_BIT;
+
+        case _NRF24L01P_CONFIG_CRC_16BIT:
+            return NRF24L01P_CRC_16_BIT;
+
+        default:
+            error( "nRF24L01P: Unknown CRC Width value %d\r\n", crcWidth );
+            return 0;
+
+    }
+}
+
+
+void nRF24L01P::setTransferSize(int size, int pipe) {
+
+    if ( ( pipe < NRF24L01P_PIPE_P0 ) || ( pipe > NRF24L01P_PIPE_P5 ) ) {
+
+        error( "nRF24L01P: Invalid Transfer Size pipe number %d\r\n", pipe );
+        return;
+
+    }
+
+    if ( ( size < 0 ) || ( size > _NRF24L01P_RX_FIFO_SIZE ) ) {
+
+        error( "nRF24L01P: Invalid Transfer Size setting %d\r\n", size );
+        return;
+
+    }
+
+    int rxPwPxRegister = _NRF24L01P_REG_RX_PW_P0 + ( pipe - NRF24L01P_PIPE_P0 );
+
+    setRegister(rxPwPxRegister, ( size & _NRF24L01P_RX_PW_Px_MASK ) );
+
+}
+
+
+int nRF24L01P::getTransferSize(int pipe) {
+
+    if ( ( pipe < NRF24L01P_PIPE_P0 ) || ( pipe > NRF24L01P_PIPE_P5 ) ) {
+
+        error( "nRF24L01P: Invalid Transfer Size pipe number %d\r\n", pipe );
+        return 0;
+
+    }
+
+    int rxPwPxRegister = _NRF24L01P_REG_RX_PW_P0 + ( pipe - NRF24L01P_PIPE_P0 );
+
+    int size = getRegister(rxPwPxRegister);
+    
+    return ( size & _NRF24L01P_RX_PW_Px_MASK );
+
+}
+
+
+void nRF24L01P::disableAllRxPipes(void) {
+
+    setRegister(_NRF24L01P_REG_EN_RXADDR, _NRF24L01P_EN_RXADDR_NONE);
+
+}
+
+
+void nRF24L01P::disableAutoAcknowledge(void) {
+
+    setRegister(_NRF24L01P_REG_EN_AA, _NRF24L01P_EN_AA_NONE);
+
+}
+
+
+void nRF24L01P::enableAutoAcknowledge(int pipe) {
+
+    if ( ( pipe < NRF24L01P_PIPE_P0 ) || ( pipe > NRF24L01P_PIPE_P5 ) ) {
+
+        error( "nRF24L01P: Invalid Enable AutoAcknowledge pipe number %d\r\n", pipe );
+        return;
+
+    }
+
+    int enAA = getRegister(_NRF24L01P_REG_EN_AA);
+
+    enAA |= ( 1 << (pipe - NRF24L01P_PIPE_P0) );
+
+    setRegister(_NRF24L01P_REG_EN_AA, enAA);
+
+}
+
+
+void nRF24L01P::disableAutoRetransmit(void) {
+
+    setRegister(_NRF24L01P_REG_SETUP_RETR, _NRF24L01P_SETUP_RETR_NONE);
+
+}
+
+void nRF24L01P::setRxAddress(unsigned long long address, int width, int pipe) {
+
+    if ( ( pipe < NRF24L01P_PIPE_P0 ) || ( pipe > NRF24L01P_PIPE_P5 ) ) {
+
+        error( "nRF24L01P: Invalid setRxAddress pipe number %d\r\n", pipe );
+        return;
+
+    }
+
+    if ( ( pipe == NRF24L01P_PIPE_P0 ) || ( pipe == NRF24L01P_PIPE_P1 ) ) {
+
+        int setupAw = getRegister(_NRF24L01P_REG_SETUP_AW) & ~_NRF24L01P_SETUP_AW_AW_MASK;
+    
+        switch ( width ) {
+    
+            case 3:
+                setupAw |= _NRF24L01P_SETUP_AW_AW_3BYTE;
+                break;
+    
+            case 4:
+                setupAw |= _NRF24L01P_SETUP_AW_AW_4BYTE;
+                break;
+    
+            case 5:
+                setupAw |= _NRF24L01P_SETUP_AW_AW_5BYTE;
+                break;
+    
+            default:
+                error( "nRF24L01P: Invalid setRxAddress width setting %d\r\n", width );
+                return;
+    
+        }
+    
+        setRegister(_NRF24L01P_REG_SETUP_AW, setupAw);
+
+    } else {
+    
+        width = 1;
+    
+    }
+
+    int rxAddrPxRegister = _NRF24L01P_REG_RX_ADDR_P0 + ( pipe - NRF24L01P_PIPE_P0 );
+
+    int cn = (_NRF24L01P_SPI_CMD_WR_REG | (rxAddrPxRegister & _NRF24L01P_REG_ADDRESS_MASK));
+
+    nCS_ = 0;
+
+    int status = spi_.write(cn);
+
+    while ( width-- > 0 ) {
+
+        //
+        // LSByte first
+        //
+        spi_.write((int) (address & 0xFF));
+        address >>= 8;
+
+    }
+
+    nCS_ = 1;
+
+    int enRxAddr = getRegister(_NRF24L01P_REG_EN_RXADDR);
+
+    enRxAddr |= (1 << ( pipe - NRF24L01P_PIPE_P0 ) );
+
+    setRegister(_NRF24L01P_REG_EN_RXADDR, enRxAddr);
+}
+
+/*
+ * This version of setRxAddress is just a wrapper for the version that takes 'long long's,
+ *  in case the main code doesn't want to deal with long long's.
+ */
+void nRF24L01P::setRxAddress(unsigned long msb_address, unsigned long lsb_address, int width, int pipe) {
+
+    unsigned long long address = ( ( (unsigned long long) msb_address ) << 32 ) | ( ( (unsigned long long) lsb_address ) << 0 );
+
+    setRxAddress(address, width, pipe);
+
+}
+
+
+/*
+ * This version of setTxAddress is just a wrapper for the version that takes 'long long's,
+ *  in case the main code doesn't want to deal with long long's.
+ */
+void nRF24L01P::setTxAddress(unsigned long msb_address, unsigned long lsb_address, int width) {
+
+    unsigned long long address = ( ( (unsigned long long) msb_address ) << 32 ) | ( ( (unsigned long long) lsb_address ) << 0 );
+
+    setTxAddress(address, width);
+
+}
+
+
+void nRF24L01P::setTxAddress(unsigned long long address, int width) {
+
+    int setupAw = getRegister(_NRF24L01P_REG_SETUP_AW) & ~_NRF24L01P_SETUP_AW_AW_MASK;
+
+    switch ( width ) {
+
+        case 3:
+            setupAw |= _NRF24L01P_SETUP_AW_AW_3BYTE;
+            break;
+
+        case 4:
+            setupAw |= _NRF24L01P_SETUP_AW_AW_4BYTE;
+            break;
+
+        case 5:
+            setupAw |= _NRF24L01P_SETUP_AW_AW_5BYTE;
+            break;
+
+        default:
+            error( "nRF24L01P: Invalid setTxAddress width setting %d\r\n", width );
+            return;
+
+    }
+
+    setRegister(_NRF24L01P_REG_SETUP_AW, setupAw);
+
+    int cn = (_NRF24L01P_SPI_CMD_WR_REG | (_NRF24L01P_REG_TX_ADDR & _NRF24L01P_REG_ADDRESS_MASK));
+
+    nCS_ = 0;
+
+    int status = spi_.write(cn);
+
+    while ( width-- > 0 ) {
+
+        //
+        // LSByte first
+        //
+        spi_.write((int) (address & 0xFF));
+        address >>= 8;
+
+    }
+
+    nCS_ = 1;
+
+}
+
+
+unsigned long long nRF24L01P::getRxAddress(int pipe) {
+
+    if ( ( pipe < NRF24L01P_PIPE_P0 ) || ( pipe > NRF24L01P_PIPE_P5 ) ) {
+
+        error( "nRF24L01P: Invalid setRxAddress pipe number %d\r\n", pipe );
+        return 0;
+
+    }
+
+    int width;
+
+    if ( ( pipe == NRF24L01P_PIPE_P0 ) || ( pipe == NRF24L01P_PIPE_P1 ) ) {
+
+        int setupAw = getRegister(_NRF24L01P_REG_SETUP_AW) & _NRF24L01P_SETUP_AW_AW_MASK;
+
+        switch ( setupAw ) {
+
+            case _NRF24L01P_SETUP_AW_AW_3BYTE:
+                width = 3;
+                break;
+
+            case _NRF24L01P_SETUP_AW_AW_4BYTE:
+                width = 4;
+                break;
+
+            case _NRF24L01P_SETUP_AW_AW_5BYTE:
+                width = 5;
+                break;
+
+            default:
+                error( "nRF24L01P: Unknown getRxAddress width value %d\r\n", setupAw );
+                return 0;
+
+        }
+
+    } else {
+
+        width = 1;
+
+    }
+
+    int rxAddrPxRegister = _NRF24L01P_REG_RX_ADDR_P0 + ( pipe - NRF24L01P_PIPE_P0 );
+
+    int cn = (_NRF24L01P_SPI_CMD_RD_REG | (rxAddrPxRegister & _NRF24L01P_REG_ADDRESS_MASK));
+
+    unsigned long long address = 0;
+
+    nCS_ = 0;
+
+    int status = spi_.write(cn);
+
+    for ( int i=0; i<width; i++ ) {
+
+        //
+        // LSByte first
+        //
+        address |= ( ( (unsigned long long)( spi_.write(_NRF24L01P_SPI_CMD_NOP) & 0xFF ) ) << (i*8) );
+
+    }
+
+    nCS_ = 1;
+
+    if ( !( ( pipe == NRF24L01P_PIPE_P0 ) || ( pipe == NRF24L01P_PIPE_P1 ) ) ) {
+
+        address |= ( getRxAddress(NRF24L01P_PIPE_P1) & ~((unsigned long long) 0xFF) );
+
+    }
+
+    return address;
+
+}
+
+    
+unsigned long long nRF24L01P::getTxAddress(void) {
+
+    int setupAw = getRegister(_NRF24L01P_REG_SETUP_AW) & _NRF24L01P_SETUP_AW_AW_MASK;
+
+    int width;
+
+    switch ( setupAw ) {
+
+        case _NRF24L01P_SETUP_AW_AW_3BYTE:
+            width = 3;
+            break;
+
+        case _NRF24L01P_SETUP_AW_AW_4BYTE:
+            width = 4;
+            break;
+
+        case _NRF24L01P_SETUP_AW_AW_5BYTE:
+            width = 5;
+            break;
+
+        default:
+            error( "nRF24L01P: Unknown getTxAddress width value %d\r\n", setupAw );
+            return 0;
+
+    }
+
+    int cn = (_NRF24L01P_SPI_CMD_RD_REG | (_NRF24L01P_REG_TX_ADDR & _NRF24L01P_REG_ADDRESS_MASK));
+
+    unsigned long long address = 0;
+
+    nCS_ = 0;
+
+    int status = spi_.write(cn);
+
+    for ( int i=0; i<width; i++ ) {
+
+        //
+        // LSByte first
+        //
+        address |= ( ( (unsigned long long)( spi_.write(_NRF24L01P_SPI_CMD_NOP) & 0xFF ) ) << (i*8) );
+
+    }
+
+    nCS_ = 1;
+
+    return address;
+}
+
+
+bool nRF24L01P::readable(int pipe) {
+
+    if ( ( pipe < NRF24L01P_PIPE_P0 ) || ( pipe > NRF24L01P_PIPE_P5 ) ) {
+
+        error( "nRF24L01P: Invalid readable pipe number %d\r\n", pipe );
+        return false;
+
+    }
+
+    int status = getStatusRegister();
+
+    return ( ( status & _NRF24L01P_STATUS_RX_DR ) && ( ( ( status & _NRF24L01P_STATUS_RX_P_NO ) >> 1 ) == ( pipe & 0x7 ) ) );
+
+}
+
+
+int nRF24L01P::write(int pipe, char *data, int count) {
+
+    // Note: the pipe number is ignored in a Transmit / write
+
+    //
+    // Save the CE state
+    //
+    int originalCe = ce_;
+    disable();
+
+    if ( count <= 0 ) return 0;
+
+    if ( count > _NRF24L01P_TX_FIFO_SIZE ) count = _NRF24L01P_TX_FIFO_SIZE;
+
+    // Clear the Status bit
+    setRegister(_NRF24L01P_REG_STATUS, _NRF24L01P_STATUS_TX_DS);
+    
+    nCS_ = 0;
+
+    int status = spi_.write(_NRF24L01P_SPI_CMD_WR_TX_PAYLOAD);
+
+    for ( int i = 0; i < count; i++ ) {
+
+        spi_.write(*data++);
+
+    }
+
+    nCS_ = 1;
+
+    int originalMode = mode;
+    setTransmitMode();
+
+    enable();
+    wait_us(_NRF24L01P_TIMING_Thce_us);
+    disable();
+
+    while ( !( getStatusRegister() & _NRF24L01P_STATUS_TX_DS ) ) {
+
+        // Wait for the transfer to complete
+
+    }
+
+    // Clear the Status bit
+    setRegister(_NRF24L01P_REG_STATUS, _NRF24L01P_STATUS_TX_DS);
+
+    if ( originalMode == _NRF24L01P_MODE_RX ) {
+
+        setReceiveMode();
+
+    }
+
+    ce_ = originalCe;
+    wait_us( _NRF24L01P_TIMING_Tpece2csn_us );
+
+    return count;
+
+}
+
+
+int nRF24L01P::read(int pipe, char *data, int count) {
+
+    if ( ( pipe < NRF24L01P_PIPE_P0 ) || ( pipe > NRF24L01P_PIPE_P5 ) ) {
+
+        error( "nRF24L01P: Invalid read pipe number %d\r\n", pipe );
+        return -1;
+
+    }
+
+    if ( count <= 0 ) return 0;
+
+    if ( count > _NRF24L01P_RX_FIFO_SIZE ) count = _NRF24L01P_RX_FIFO_SIZE;
+
+    if ( readable(pipe) ) {
+
+        nCS_ = 0;
+
+        int status = spi_.write(_NRF24L01P_SPI_CMD_R_RX_PL_WID);
+
+        int rxPayloadWidth = spi_.write(_NRF24L01P_SPI_CMD_NOP);
+        
+        nCS_ = 1;
+
+        if ( ( rxPayloadWidth < 0 ) || ( rxPayloadWidth > _NRF24L01P_RX_FIFO_SIZE ) ) {
+    
+            // Received payload error: need to flush the FIFO
+
+            nCS_ = 0;
+    
+            int status = spi_.write(_NRF24L01P_SPI_CMD_FLUSH_RX);
+    
+            int rxPayloadWidth = spi_.write(_NRF24L01P_SPI_CMD_NOP);
+            
+            nCS_ = 1;
+            
+            //
+            // At this point, we should retry the reception,
+            //  but for now we'll just fall through...
+            //
+
+        } else {
+
+            if ( rxPayloadWidth < count ) count = rxPayloadWidth;
+
+            nCS_ = 0;
+        
+            int status = spi_.write(_NRF24L01P_SPI_CMD_RD_RX_PAYLOAD);
+        
+            for ( int i = 0; i < count; i++ ) {
+        
+                *data++ = spi_.write(_NRF24L01P_SPI_CMD_NOP);
+        
+            }
+
+            nCS_ = 1;
+
+            // Clear the Status bit
+            setRegister(_NRF24L01P_REG_STATUS, _NRF24L01P_STATUS_RX_DR);
+
+            return count;
+
+        }
+
+    } else {
+
+        //
+        // What should we do if there is no 'readable' data?
+        //  We could wait for data to arrive, but for now, we'll
+        //  just return with no data.
+        //
+        return 0;
+
+    }
+
+    //
+    // We get here because an error condition occured;
+    //  We could wait for data to arrive, but for now, we'll
+    //  just return with no data.
+    //
+    return -1;
+
+}
+
+void nRF24L01P::setRegister(int regAddress, int regData) {
+
+    //
+    // Save the CE state
+    //
+    int originalCe = ce_;
+    disable();
+
+    int cn = (_NRF24L01P_SPI_CMD_WR_REG | (regAddress & _NRF24L01P_REG_ADDRESS_MASK));
+
+    nCS_ = 0;
+
+    int status = spi_.write(cn);
+
+    spi_.write(regData & 0xFF);
+
+    nCS_ = 1;
+
+    ce_ = originalCe;
+    wait_us( _NRF24L01P_TIMING_Tpece2csn_us );
+
+}
+
+
+int nRF24L01P::getRegister(int regAddress) {
+
+    int cn = (_NRF24L01P_SPI_CMD_RD_REG | (regAddress & _NRF24L01P_REG_ADDRESS_MASK));
+
+    nCS_ = 0;
+
+    int status = spi_.write(cn);
+
+    int dn = spi_.write(_NRF24L01P_SPI_CMD_NOP);
+
+    nCS_ = 1;
+
+    return dn;
+
+}
+
+int nRF24L01P::getStatusRegister(void) {
+
+    nCS_ = 0;
+
+    int status = spi_.write(_NRF24L01P_SPI_CMD_NOP);
+
+    nCS_ = 1;
+
+    return status;
+
+}
diff -r 000000000000 -r 8d55f1f49a33 nRF24L01P.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nRF24L01P.h	Thu Apr 21 23:14:43 2011 +0000
@@ -0,0 +1,347 @@
+/**
+ * @file nRF24L01P.h
+ *
+ * @author Owen Edwards
+ * 
+ * @section LICENSE
+ *
+ * Copyright (c) 2010 Owen Edwards
+ *
+ *    This program is free software: you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation, either version 3 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * @section DESCRIPTION
+ *
+ * nRF24L01+ Single Chip 2.4GHz Transceiver from Nordic Semiconductor.
+ *
+ * Datasheet:
+ *
+ * http://www.nordicsemi.no/files/Product/data_sheet/nRF24L01P_Product_Specification_1_0.pdf
+ */
+
+#ifndef __NRF24L01P_H__
+#define __NRF24L01P_H__
+
+/**
+ * Includes
+ */
+#include "mbed.h"
+
+/**
+ * Defines
+ */
+#define NRF24L01P_TX_PWR_ZERO_DB         0
+#define NRF24L01P_TX_PWR_MINUS_6_DB     -6
+#define NRF24L01P_TX_PWR_MINUS_12_DB   -12
+#define NRF24L01P_TX_PWR_MINUS_18_DB   -18
+
+#define NRF24L01P_DATARATE_250_KBPS    250
+#define NRF24L01P_DATARATE_1_MBPS     1000
+#define NRF24L01P_DATARATE_2_MBPS     2000
+
+#define NRF24L01P_CRC_NONE               0
+#define NRF24L01P_CRC_8_BIT              8
+#define NRF24L01P_CRC_16_BIT            16
+
+#define NRF24L01P_MIN_RF_FREQUENCY    2400
+#define NRF24L01P_MAX_RF_FREQUENCY    2525
+
+#define NRF24L01P_PIPE_P0                0
+#define NRF24L01P_PIPE_P1                1
+#define NRF24L01P_PIPE_P2                2
+#define NRF24L01P_PIPE_P3                3
+#define NRF24L01P_PIPE_P4                4
+#define NRF24L01P_PIPE_P5                5
+
+/**
+* Default setup for the nRF24L01+, based on the Sparkfun "Nordic Serial Interface Board"
+*  for evaluation (http://www.sparkfun.com/products/9019)
+*/
+#define DEFAULT_NRF24L01P_ADDRESS       ((unsigned long long) 0xE7E7E7E7EE )
+#define DEFAULT_NRF24L01P_ADDRESS_WIDTH  5
+#define DEFAULT_NRF24L01P_CRC            NRF24L01P_CRC_16_BIT
+#define DEFAULT_NRF24L01P_RF_FREQUENCY  (NRF24L01P_MIN_RF_FREQUENCY + 2 )
+#define DEFAULT_NRF24L01P_DATARATE       NRF24L01P_DATARATE_1_MBPS
+#define DEFAULT_NRF24L01P_TX_PWR         NRF24L01P_TX_PWR_ZERO_DB
+#define DEFAULT_NRF24L01P_TRANSFER_SIZE  28
+
+/**
+ * nRF24L01+ Single Chip 2.4GHz Transceiver from Nordic Semiconductor.
+ */
+class nRF24L01P {
+
+public:
+
+    /**
+     * Constructor.
+     *
+     * @param mosi mbed pin to use for MOSI line of SPI interface.
+     * @param miso mbed pin to use for MISO line of SPI interface.
+     * @param sck mbed pin to use for SCK line of SPI interface.
+     * @param csn mbed pin to use for not chip select line of SPI interface.
+     * @param ce mbed pin to use for the chip enable line.
+     * @param irq mbed pin to use for the interrupt request line.
+     */
+    nRF24L01P(PinName mosi, PinName miso, PinName sck, PinName csn, PinName ce, PinName irq = NC);
+
+    /**
+     * Set the RF frequency.
+     *
+     * @param frequency the frequency of RF transmission in MHz (2400..2525).
+     */
+    void setRfFrequency(int frequency = DEFAULT_NRF24L01P_RF_FREQUENCY);
+
+    /**
+     * Get the RF frequency.
+     *
+     * @return the frequency of RF transmission in MHz (2400..2525).
+     */
+    int getRfFrequency(void);
+
+    /**
+     * Set the RF output power.
+     *
+     * @param power the RF output power in dBm (0, -6, -12 or -18).
+     */
+    void setRfOutputPower(int power = DEFAULT_NRF24L01P_TX_PWR);
+
+    /**
+     * Get the RF output power.
+     *
+     * @return the RF output power in dBm (0, -6, -12 or -18).
+     */
+    int getRfOutputPower(void);
+
+    /**
+     * Set the Air data rate.
+     *
+     * @param rate the air data rate in kbps (250, 1M or 2M).
+     */
+    void setAirDataRate(int rate = DEFAULT_NRF24L01P_DATARATE);
+
+    /**
+     * Get the Air data rate.
+     *
+     * @return the air data rate in kbps (250, 1M or 2M).
+     */
+    int getAirDataRate(void);
+
+    /**
+     * Set the CRC width.
+     *
+     * @param width the number of bits for the CRC (0, 8 or 16).
+     */
+    void setCrcWidth(int width = DEFAULT_NRF24L01P_CRC);
+
+    /**
+     * Get the CRC width.
+     *
+     * @return the number of bits for the CRC (0, 8 or 16).
+     */
+    int getCrcWidth(void);
+
+    /**
+     * Set the Receive address.
+     *
+     * @param address address associated with the particular pipe
+     * @param width width of the address in bytes (3..5)
+     * @param pipe pipe to associate the address with (0..5, default 0)
+     *
+     * Note that Pipes 0 & 1 have 3, 4 or 5 byte addresses,
+     *  while Pipes 2..5 only use the lowest byte (bits 7..0) of the
+     *  address provided here, and use 2, 3 or 4 bytes from Pipe 1's address.
+     *  The width parameter is ignored for Pipes 2..5.
+     */
+    void setRxAddress(unsigned long long address = DEFAULT_NRF24L01P_ADDRESS, int width = DEFAULT_NRF24L01P_ADDRESS_WIDTH, int pipe = NRF24L01P_PIPE_P0);
+
+    void setRxAddress(unsigned long msb_address, unsigned long lsb_address, int width, int pipe = NRF24L01P_PIPE_P0);
+
+    /**
+     * Set the Transmit address.
+     *
+     * @param address address for transmission
+     * @param width width of the address in bytes (3..5)
+     *
+     * Note that the address width is shared with the Receive pipes,
+     *  so a change to that address width affect transmissions.
+     */
+    void setTxAddress(unsigned long long address = DEFAULT_NRF24L01P_ADDRESS, int width = DEFAULT_NRF24L01P_ADDRESS_WIDTH);
+
+    void setTxAddress(unsigned long msb_address, unsigned long lsb_address, int width);
+
+    /**
+     * Get the Receive address.
+     *
+     * @param pipe pipe to get the address from (0..5, default 0)
+     * @return the address associated with the particular pipe
+     */
+    unsigned long long getRxAddress(int pipe = NRF24L01P_PIPE_P0);
+
+    /**
+     * Get the Transmit address.
+     *
+     * @return address address for transmission
+     */
+    unsigned long long getTxAddress(void);
+
+    /**
+     * Set the transfer size.
+     *
+     * @param size the size of the transfer, in bytes (1..32)
+     * @param pipe pipe for the transfer (0..5, default 0)
+     */
+    void setTransferSize(int size = DEFAULT_NRF24L01P_TRANSFER_SIZE, int pipe = NRF24L01P_PIPE_P0);
+
+    /**
+     * Get the transfer size.
+     *
+     * @return the size of the transfer, in bytes (1..32).
+     */
+    int getTransferSize(int pipe = NRF24L01P_PIPE_P0);
+
+
+    /**
+     * Get the RPD (Received Power Detector) state.
+     *
+     * @return true if the received power exceeded -64dBm
+     */
+    bool getRPD(void);
+
+    /**
+     * Put the nRF24L01+ into Receive mode
+     */
+    void setReceiveMode(void);
+
+    /**
+     * Put the nRF24L01+ into Transmit mode
+     */
+    void setTransmitMode(void);
+
+    /**
+     * Power up the nRF24L01+ into Standby mode
+     */
+    void powerUp(void);
+
+    /**
+     * Power down the nRF24L01+ into Power Down mode
+     */
+    void powerDown(void);
+
+    /**
+     * Enable the nRF24L01+ to Receive or Transmit (using the CE pin)
+     */
+    void enable(void);
+
+    /**
+     * Disable the nRF24L01+ to Receive or Transmit (using the CE pin)
+     */
+    void disable(void);
+
+    /**
+     * Transmit data
+     *
+     * @param pipe is ignored (included for consistency with file write routine)
+     * @param data pointer to an array of bytes to write
+     * @param count the number of bytes to send (1..32)
+     * @return the number of bytes actually written, or -1 for an error
+     */
+    int write(int pipe, char *data, int count);
+    
+    /**
+     * Receive data
+     *
+     * @param pipe the receive pipe to get data from
+     * @param data pointer to an array of bytes to store the received data
+     * @param count the number of bytes to receive (1..32)
+     * @return the number of bytes actually received, 0 if none are received, or -1 for an error
+     */
+    int read(int pipe, char *data, int count);
+
+    /**
+     * Determine if there is data available to read
+     *
+     * @param pipe the receive pipe to check for data
+     * @return true if the is data waiting in the given pipe
+     */
+    bool readable(int pipe = NRF24L01P_PIPE_P0);
+
+    /**
+     * Disable all receive pipes
+     *
+     * Note: receive pipes are enabled when their address is set.
+     */
+    void disableAllRxPipes(void);
+    
+    /**
+     * Disable AutoAcknowledge function
+     */
+    void disableAutoAcknowledge(void);
+    
+    /**
+     * Enable AutoAcknowledge function
+     *
+     * @param pipe the receive pipe
+     */
+    void enableAutoAcknowledge(int pipe = NRF24L01P_PIPE_P0);
+    
+    /**
+     * Disable AutoRetransmit function
+     */
+    void disableAutoRetransmit(void);
+    
+    /**
+     * Enable AutoRetransmit function
+     *
+     * @param delay the delay between restransmits, in uS (250uS..4000uS)
+     * @param count number of retransmits before generating an error (1..15)
+     */
+    void enableAutoRetransmit(int delay, int count);
+
+private:
+
+    /**
+     * Get the contents of an addressable register.
+     *
+     * @param regAddress address of the register
+     * @return the contents of the register
+     */
+    int getRegister(int regAddress);
+
+    /**
+     * Set the contents of an addressable register.
+     *
+     * @param regAddress address of the register
+     * @param regData data to write to the register
+     */
+    void setRegister(int regAddress, int regData);
+
+    /**
+     * Get the contents of the status register.
+     *
+     * @return the contents of the status register
+     */
+    int getStatusRegister(void);
+
+    SPI         spi_;
+    DigitalOut  nCS_;
+    DigitalOut  ce_;
+    InterruptIn nIRQ_;
+
+    int mode;
+
+};
+
+#endif /* __NRF24L01P_H__ */