RX TX Flush methods added
Fork of nRF24L01P by
Revision 1:054a50936ab6, committed 2013-03-07
- Comitter:
- Christilut
- Date:
- Thu Mar 07 09:28:09 2013 +0000
- Parent:
- 0:8ae48233b4e4
- Commit message:
- Added rx and tx buffer flush methods
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 8ae48233b4e4 -r 054a50936ab6 nRF24L01P.cpp --- a/nRF24L01P.cpp Wed Jan 19 22:59:48 2011 +0000 +++ b/nRF24L01P.cpp Thu Mar 07 09:28:09 2013 +0000 @@ -1,1029 +1,1091 @@ -/** - * @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 3 -#define _NRF24L01P_RX_FIFO_COUNT 3 - -#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; - -} +/** + * @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 3 +#define _NRF24L01P_RX_FIFO_COUNT 3 + +#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; + +} + +int nRF24L01P::flushRxBuffer(void) +{ + + nCS_ = 0; + + int status = spi_.write(_NRF24L01P_SPI_CMD_FLUSH_RX); + + int rxPayloadWidth = spi_.write(_NRF24L01P_SPI_CMD_NOP); + + nCS_ = 1; + + return status; + +} + +int nRF24L01P::flushTxBuffer(void) +{ + + nCS_ = 0; + + int status = spi_.write(_NRF24L01P_SPI_CMD_FLUSH_TX); + + int txPayloadWidth = spi_.write(_NRF24L01P_SPI_CMD_NOP); + + nCS_ = 1; + + return status; +} \ No newline at end of file
diff -r 8ae48233b4e4 -r 054a50936ab6 nRF24L01P.h --- a/nRF24L01P.h Wed Jan 19 22:59:48 2011 +0000 +++ b/nRF24L01P.h Thu Mar 07 09:28:09 2013 +0000 @@ -1,347 +1,353 @@ -/** - * @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) 0xE7E7E7E7E7 ) -#define DEFAULT_NRF24L01P_ADDRESS_WIDTH 5 -#define DEFAULT_NRF24L01P_CRC NRF24L01P_CRC_8_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 4 - -/** - * 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__ */ +/** + * @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) 0xE7E7E7E7E7 ) +#define DEFAULT_NRF24L01P_ADDRESS_WIDTH 5 +#define DEFAULT_NRF24L01P_CRC NRF24L01P_CRC_8_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 4 + +/** + * 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); + + int flushRxBuffer(void); + int flushTxBuffer(void); + +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__ */