Port of the nRF24l01+ library of these dudes. Not GPLed, so yeah, you can use it. Copyright (c) 2007 Stefan Engelke <mbox@stefanengelke.de> Some parts copyright (c) 2012 Eric Brundick <spirilis [at] linux dot com>
Revision 0:670ecbc1478a, committed 2013-05-28
- Comitter:
- heroic
- Date:
- Tue May 28 03:48:04 2013 +0000
- Commit message:
- Initial commit to mbedland: port of the Energia nRF24l01+ library as ported to mbed.; ; This is what happens if you use a GPLv3 license, guys: people who want to use the chip have to write their own, or port someone else's MIT licensed one.
Changed in this revision
diff -r 000000000000 -r 670ecbc1478a Enrf24.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Enrf24.cpp Tue May 28 03:48:04 2013 +0000 @@ -0,0 +1,556 @@ +/* nRF24L01+ I/O for mbed + * Ported by Jas Strong <jasmine@heroicrobotics.com> + * + * Copyright (c) 2013 Eric Brundick <spirilis [at] linux dot com> + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "mbed.h" +#include <stdint.h> +#include "Enrf24.h" + +/* Constructor */ +Enrf24::Enrf24(PinName cePin, PinName csnPin, PinName irqPin, PinName miso, PinName mosi, PinName sck) : + _cePin(cePin), + _csnPin(csnPin), + _irqPin(irqPin), + _miso(miso), + _mosi(mosi), + _sck(sck), + _spi(mosi, miso, sck) +{ + + rf_status = 0; + rf_addr_width = 5; + txbuf_len = 0; + readpending = 0; +} + +/* Initialization */ +void Enrf24::begin(uint32_t datarate, uint8_t channel) +{ + _cePin = 0; + _csnPin = 1; + + _spi.format(8,0); + _spi.frequency(2000000); + + _spi.write(0); // Strawman transfer, fixes USCI issue on G2553 + + // Is the transceiver present/alive? + if (!_isAlive()) + return; // Nothing more to do here... + + // Init certain registers + _writeReg(RF24_CONFIG, 0x00); // Deep power-down, everything disabled + _writeReg(RF24_EN_AA, 0x03); + _writeReg(RF24_EN_RXADDR, 0x03); + _writeReg(RF24_RF_SETUP, 0x00); + _writeReg(RF24_STATUS, ENRF24_IRQ_MASK); // Clear all IRQs + _writeReg(RF24_DYNPD, 0x03); + _writeReg(RF24_FEATURE, RF24_EN_DPL); // Dynamic payloads enabled by default + + // Set all parameters + if (channel > 125) + channel = 125; + deepsleep(); + _issueCmd(RF24_FLUSH_TX); + _issueCmd(RF24_FLUSH_RX); + readpending = 0; + _irq_clear(ENRF24_IRQ_MASK); + setChannel(channel); + setSpeed(datarate); + setTXpower(); + setAutoAckParams(); + setAddressLength(rf_addr_width); + setCRC(true); // Default = CRC on, 8-bit +} + +/* Formal shut-down/clearing of library state */ +void Enrf24::end() +{ + txbuf_len = 0; + rf_status = 0; + rf_addr_width = 5; + + if (!_isAlive()) + return; + deepsleep(); + _issueCmd(RF24_FLUSH_TX); + _issueCmd(RF24_FLUSH_RX); + readpending = 0; + _irq_clear(ENRF24_IRQ_MASK); + _cePin = 0; + _csnPin = 1; +} + +/* Basic SPI I/O */ +uint8_t Enrf24::_readReg(uint8_t addr) +{ + uint8_t result; + + _csnPin = 0; + rf_status = _spi.write(RF24_R_REGISTER | addr); + result = _spi.write(RF24_NOP); + _csnPin = 1; + return result; +} + +void Enrf24::_readRegMultiLSB(uint8_t addr, uint8_t *buf, size_t len) +{ + uint8_t i; + _csnPin = 0; + rf_status = _spi.write(RF24_R_REGISTER | addr); + for (i=0; i<len; i++) { + buf[len-i-1] = _spi.write(RF24_NOP); + } + _csnPin = 1; +} + +void Enrf24::_writeReg(uint8_t addr, uint8_t val) +{ + _csnPin=0; + rf_status = _spi.write(RF24_W_REGISTER | addr); + _spi.write(val); + _csnPin=1; +} + +void Enrf24::_writeRegMultiLSB(uint8_t addr, uint8_t *buf, size_t len) +{ + size_t i; + + _csnPin = 0; + rf_status = _spi.write(RF24_W_REGISTER | addr); + for (i=0; i<len; i++) { + _spi.write(buf[len-i-1]); + } + _csnPin = 1; +} + +void Enrf24::_issueCmd(uint8_t cmd) +{ + _csnPin=0; + rf_status = _spi.write(cmd); + _csnPin=1; +} + +void Enrf24::_issueCmdPayload(uint8_t cmd, uint8_t *buf, size_t len) +{ + size_t i; + + _csnPin = 0; + rf_status = _spi.write(cmd); + for (i=0; i<len; i++) { + _spi.write(buf[i]); + } + _csnPin = 1; +} + +void Enrf24::_readCmdPayload(uint8_t cmd, uint8_t *buf, size_t len, size_t maxlen) +{ + size_t i; + + _csnPin = 0; + rf_status = _spi.write(cmd); + for (i=0; i<len; i++) { + if (i < maxlen) { + buf[i] = _spi.write(RF24_NOP); + } else { + _spi.write(RF24_NOP); // Beyond maxlen bytes, just discard the remaining data. + } + } + _csnPin = 1; +} + +boolean Enrf24::_isAlive() +{ + uint8_t aw; + + aw = _readReg(RF24_SETUP_AW); + return ((aw & 0xFC) == 0x00 && (aw & 0x03) != 0x00); +} + +uint8_t Enrf24::_irq_getreason() +{ + lastirq = _readReg(RF24_STATUS) & ENRF24_IRQ_MASK; + return lastirq; +} + +// Get IRQ from last known rf_status update without querying module over SPI. +uint8_t Enrf24::_irq_derivereason() +{ + lastirq = rf_status & ENRF24_IRQ_MASK; + return lastirq; +} + +void Enrf24::_irq_clear(uint8_t irq) +{ + _writeReg(RF24_STATUS, irq & ENRF24_IRQ_MASK); +} + +#define ENRF24_CFGMASK_CRC(a) (a & (RF24_EN_CRC | RF24_CRCO)) + +void Enrf24::_readTXaddr(uint8_t *buf) +{ + _readRegMultiLSB(RF24_TX_ADDR, buf, rf_addr_width); +} + +void Enrf24::_writeRXaddrP0(uint8_t *buf) +{ + _writeRegMultiLSB(RF24_RX_ADDR_P0, buf, rf_addr_width); +} + + +/* nRF24 I/O maintenance--called as a "hook" inside other I/O functions to give + * the library a chance to take care of its buffers et al + */ +void Enrf24::_maintenanceHook() +{ + uint8_t i; + + _irq_getreason(); + + if (lastirq & ENRF24_IRQ_TXFAILED) { + lastTXfailed = true; + _issueCmd(RF24_FLUSH_TX); + _irq_clear(ENRF24_IRQ_TXFAILED); + } + + if (lastirq & ENRF24_IRQ_TX) { + lastTXfailed = false; + _irq_clear(ENRF24_IRQ_TX); + } + + if (lastirq & ENRF24_IRQ_RX) { + if ( !(_readReg(RF24_FIFO_STATUS) & RF24_RX_FULL) ) { /* Don't feel it's necessary + * to be notified of new + * incoming packets if the RX + * queue is full. + */ + _irq_clear(ENRF24_IRQ_RX); + } + + /* Check if RX payload is 0-byte or >32byte (erroneous conditions) + * Also check if data was received on pipe#0, which we are ignoring. + * The reason for this is pipe#0 is needed for receiving AutoACK acknowledgements, + * its address gets reset to the module's default and we do not care about data + * coming in to that address... + */ + _readCmdPayload(RF24_R_RX_PL_WID, &i, 1, 1); + if (i == 0 || i > 32 || ((rf_status & 0x0E) >> 1) == 0) { + /* Zero-width RX payload is an error that happens a lot + * with non-AutoAck, and must be cleared with FLUSH_RX. + * Erroneous >32byte packets are a similar phenomenon. + */ + _issueCmd(RF24_FLUSH_RX); + _irq_clear(ENRF24_IRQ_RX); + readpending = 0; + } else { + readpending = 1; + } + // Actual scavenging of RX queues is performed by user-directed use of read(). + } +} + + + +/* Public functions */ +boolean Enrf24::available(boolean checkIrq) +{ + if (checkIrq && _irqPin && readpending == 0) + return false; + _maintenanceHook(); + if ( !(_readReg(RF24_FIFO_STATUS) & RF24_RX_EMPTY) ) { + return true; + } + if (readpending) { + return true; + } + return false; +} + +size_t Enrf24::read(void *inbuf, uint8_t maxlen) +{ + uint8_t *buf = (uint8_t *)inbuf; + uint8_t plwidth; + + _maintenanceHook(); + readpending = 0; + if ((_readReg(RF24_FIFO_STATUS) & RF24_RX_EMPTY) || maxlen < 1) { + return 0; + } + _readCmdPayload(RF24_R_RX_PL_WID, &plwidth, 1, 1); + _readCmdPayload(RF24_R_RX_PAYLOAD, buf, plwidth, maxlen); + buf[plwidth] = '\0'; // Zero-terminate in case this is a string. + if (_irq_derivereason() & ENRF24_IRQ_RX) { + _irq_clear(ENRF24_IRQ_RX); + } + + return (size_t) plwidth; +} + +// Perform TX of current ring-buffer contents +void Enrf24::flush() +{ + uint8_t reg, addrbuf[5]; + boolean enaa=false, origrx=false; + + if (!txbuf_len) + return; // Zero-length buffer? Nothing to send! + + reg = _readReg(RF24_FIFO_STATUS); + if (reg & BIT5) { // RF24_TX_FULL #define is BIT0, which is not the correct bit for FIFO_STATUS. + return; // Should never happen, but nonetheless a precaution to take. + } + + _maintenanceHook(); + + if (reg & RF24_TX_REUSE) { + // If somehow TX_REUSE is enabled, we need to flush the TX queue before loading our new payload. + _issueCmd(RF24_FLUSH_TX); + } + + if (_readReg(RF24_EN_AA) & 0x01 && (_readReg(RF24_RF_SETUP) & 0x28) != 0x20) { + /* AutoACK enabled, must write TX addr to RX pipe#0 + * Note that 250Kbps doesn't support auto-ack, so we check RF24_RF_SETUP to verify that. + */ + enaa = true; + _readTXaddr(addrbuf); + _writeRXaddrP0(addrbuf); + } + + reg = _readReg(RF24_CONFIG); + if ( !(reg & RF24_PWR_UP) ) { + _writeReg(RF24_CONFIG, ENRF24_CFGMASK_IRQ | ENRF24_CFGMASK_CRC(reg) | RF24_PWR_UP); + wait_us(5000); // 5ms delay required for nRF24 oscillator start-up + } + if (reg & RF24_PRIM_RX) { + origrx=true; + _cePin = 0; + _writeReg(RF24_CONFIG, ENRF24_CFGMASK_IRQ | ENRF24_CFGMASK_CRC(reg) | RF24_PWR_UP); + } + + _issueCmdPayload(RF24_W_TX_PAYLOAD, txbuf, txbuf_len); + _cePin = 1; + wait_us(30); + _cePin = 0; + + txbuf_len = 0; // Reset TX ring buffer + + while (_irqPin) // Wait until IRQ fires + ; + // IRQ fired + _maintenanceHook(); // Handle/clear IRQ + + // Purge Pipe#0 address (set to module's power-up default) + if (enaa) { + addrbuf[0] = 0xE7; addrbuf[1] = 0xE7; addrbuf[2] = 0xE7; addrbuf[3] = 0xE7; addrbuf[4] = 0xE7; + _writeRXaddrP0(addrbuf); + } + + // If we were in RX mode before writing, return back to RX mode. + if (origrx) { + enableRX(); + } +} + +void Enrf24::purge() +{ + txbuf_len = 0; +} + +size_t Enrf24::write(uint8_t c) +{ + if (txbuf_len == 32) { // If we're trying to stuff an already-full buffer... + flush(); // Blocking OTA TX + } + + txbuf[txbuf_len] = c; + txbuf_len++; + + return 1; +} + +uint8_t Enrf24::radioState() +{ + uint8_t reg; + + if (!_isAlive()) + return ENRF24_STATE_NOTPRESENT; + + reg = _readReg(RF24_CONFIG); + if ( !(reg & RF24_PWR_UP) ) + return ENRF24_STATE_DEEPSLEEP; + + // At this point it's either Standby-I, II or PRX. + if (reg & RF24_PRIM_RX) { + if (_cePin) + return ENRF24_STATE_PRX; + // PRIM_RX=1 but CE=0 is a form of idle state. + return ENRF24_STATE_IDLE; + } + // Check if TX queue is empty, if so it's idle, if not it's PTX. + if (_readReg(RF24_FIFO_STATUS) & RF24_TX_EMPTY) + return ENRF24_STATE_IDLE; + return ENRF24_STATE_PTX; +} + +void Enrf24::deepsleep() +{ + uint8_t reg; + + reg = _readReg(RF24_CONFIG); + if (reg & (RF24_PWR_UP | RF24_PRIM_RX)) { + _writeReg(RF24_CONFIG, ENRF24_CFGMASK_IRQ | ENRF24_CFGMASK_CRC(reg)); + } + _cePin = 0; +} + +void Enrf24::enableRX() +{ + uint8_t reg; + + reg = _readReg(RF24_CONFIG); + _writeReg(RF24_CONFIG, ENRF24_CFGMASK_IRQ | ENRF24_CFGMASK_CRC(reg) | RF24_PWR_UP | RF24_PRIM_RX); + _cePin = 1; + + if ( !(reg & RF24_PWR_UP) ) { // Powering up from deep-sleep requires 5ms oscillator start delay + wait(5 / 1000); + } +} + +void Enrf24::disableRX() +{ + uint8_t reg; + + _cePin = 0; + + reg = _readReg(RF24_CONFIG); + if (reg & RF24_PWR_UP) { /* Keep us in standby-I if we're coming from RX mode, otherwise stay + * in deep-sleep if we call this while already in PWR_UP=0 mode. + */ + _writeReg(RF24_CONFIG, ENRF24_CFGMASK_IRQ | ENRF24_CFGMASK_CRC(reg) | RF24_PWR_UP); + } else { + _writeReg(RF24_CONFIG, ENRF24_CFGMASK_IRQ | ENRF24_CFGMASK_CRC(reg)); + } +} + +void Enrf24::autoAck(boolean onoff) +{ + uint8_t reg; + + reg = _readReg(RF24_EN_AA); + if (onoff) { + if ( !(reg & 0x01) || !(reg & 0x02) ) { + _writeReg(RF24_EN_AA, 0x03); + } + } else { + if (reg & 0x03) { + _writeReg(RF24_EN_AA, 0x00); + } + } +} + +void Enrf24::setChannel(uint8_t channel) +{ + if (channel > 125) + channel = 125; + _writeReg(RF24_RF_CH, channel); +} + +void Enrf24::setTXpower(int8_t dBm) +{ + uint8_t reg, pwr; + + reg = _readReg(RF24_RF_SETUP) & 0xF8; // preserve RF speed settings + pwr = 0x03; + if (dBm < 0) + pwr = 0x02; + if (dBm < -6) + pwr = 0x01; + if (dBm < -12) + pwr = 0x00; + _writeReg(RF24_RF_SETUP, reg | (pwr << 1)); +} + +void Enrf24::setSpeed(uint32_t rfspeed) +{ + uint8_t reg, spd; + + reg = _readReg(RF24_RF_SETUP) & 0xD7; // preserve RF power settings + spd = 0x01; + if (rfspeed < 2000000) + spd = 0x00; + if (rfspeed < 1000000) + spd = 0x04; + _writeReg(RF24_RF_SETUP, reg | (spd << 3)); +} + +void Enrf24::setCRC(boolean onoff, boolean crc16bit) +{ + uint8_t reg, crcbits=0; + + reg = _readReg(RF24_CONFIG) & 0xF3; // preserve IRQ mask, PWR_UP/PRIM_RX settings + if (onoff) + crcbits |= RF24_EN_CRC; + if (crc16bit) + crcbits |= RF24_CRCO; + _writeReg(RF24_CONFIG, reg | crcbits); +} + +void Enrf24::setAutoAckParams(uint8_t autoretry_count, uint16_t autoretry_timeout) +{ + uint8_t setup_retr=0; + + setup_retr = autoretry_count & 0x0F; + autoretry_timeout -= 250; + setup_retr |= ((autoretry_timeout / 250) & 0x0F) << 4; + _writeReg(RF24_SETUP_RETR, setup_retr); +} + +void Enrf24::setAddressLength(size_t len) +{ + if (len < 3) + len = 3; + if (len > 5) + len = 5; + + _writeReg(RF24_SETUP_AW, len-2); + rf_addr_width = len; +} + +void Enrf24::setRXaddress(void *rxaddr) +{ + _writeRegMultiLSB(RF24_RX_ADDR_P1, (uint8_t*)rxaddr, rf_addr_width); +} + +void Enrf24::setTXaddress(void *rxaddr) +{ + _writeRegMultiLSB(RF24_TX_ADDR, (uint8_t*)rxaddr, rf_addr_width); +} + +boolean Enrf24::rfSignalDetected() +{ + uint8_t rpd; + + rpd = _readReg(RF24_RPD); + return (boolean)rpd; +}
diff -r 000000000000 -r 670ecbc1478a Enrf24.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Enrf24.h Tue May 28 03:48:04 2013 +0000 @@ -0,0 +1,164 @@ +/* nRF24L01+ I/O for mbed + * Ported by Jas Strong <jasmine@heroicrobotics.com> + * + * Copyright (c) 2013 Eric Brundick <spirilis [at] linux dot com> + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef _ENRF24_H +#define _ENRF24_H + +#define ENRF24_LIBRARY_VERSION 1.5 + +#include "mbed.h" +#include <stdint.h> +#include "nRF24L01.h" + +#ifndef BITF + #define BIT0 (0x0001) + #define BIT1 (0x0002) + #define BIT2 (0x0004) + #define BIT3 (0x0008) + #define BIT4 (0x0010) + #define BIT5 (0x0020) + #define BIT6 (0x0040) + #define BIT7 (0x0080) + #define BIT8 (0x0100) + #define BIT9 (0x0200) + #define BITA (0x0400) + #define BITB (0x0800) + #define BITC (0x1000) + #define BITD (0x2000) + #define BITE (0x4000) + #define BITF (0x8000) +#endif + +/* Constants for speed, radio state */ +#define ENRF24_STATE_NOTPRESENT 0 +#define ENRF24_STATE_DEEPSLEEP 1 +#define ENRF24_STATE_IDLE 2 +#define ENRF24_STATE_PTX 3 +#define ENRF24_STATE_PRX 4 + +/* Internal IRQ handling */ +#define ENRF24_IRQ_TX 0x20 +#define ENRF24_IRQ_RX 0x40 +#define ENRF24_IRQ_TXFAILED 0x10 +#define ENRF24_IRQ_MASK 0x70 + +#define ENRF24_CFGMASK_IRQ 0 + +typedef uint8_t boolean; + + + +/* Class definition--inherits from Print so we have .print() functions */ +class Enrf24 { + public: + boolean lastTXfailed; + + Enrf24(PinName cePin, PinName csnPin, PinName irqPin, PinName miso, PinName mosi, PinName sck); + void begin(uint32_t datarate=1000000, uint8_t channel=0); // Specify bitrate & channel + void end(); // Shut it off, clear the library's state + + // I/O + boolean available(boolean checkIrq=false); // Check if incoming data is ready to be read + size_t read(void *inbuf, uint8_t maxlen=32); /* Read contents of RX buffer up to + * 'maxlen' bytes, return final length. + * 'inbuf' should be maxlen+1 since a + * null '\0' is tacked onto the end. + */ + virtual size_t write(uint8_t); // Single-byte write, implements TX ring-buffer & auto-send + //using Print::write; // Includes the multi-byte write for repeatedly hitting write(uint8_t) + void flush(); // Force transmission of TX ring buffer contents + void purge(); // Ignore TX ring buffer contents, return ring pointer to 0. + + // Power-state related stuff- + uint8_t radioState(); // Evaluate current state of the transceiver (see ENRF24_STATE_* defines) + void deepsleep(); // Enter POWERDOWN mode, ~0.9uA power consumption + void enableRX(); // Enter PRX mode (~14mA) + void disableRX(); /* Disable PRX mode (PRIM_RX bit in CONFIG register) + * Note this won't necessarily push the transceiver into deep sleep, but rather + * an idle standby mode where its internal oscillators are ready & running but + * the RF transceiver PLL is disabled. ~26uA power consumption. + */ + + // Custom tweaks to RF parameters, packet parameters + void autoAck(boolean onoff=true); // Enable/disable auto-acknowledgements (enabled by default) + void setChannel(uint8_t channel); + void setTXpower(int8_t dBm=0); // Only a few values supported by this (0, -6, -12, -18 dBm) + void setSpeed(uint32_t rfspeed); // Set 250000, 1000000, 2000000 speeds. + void setCRC(boolean onoff, boolean crc16bit=false); /* Enable/disable CRC usage inside nRF24's + * hardware packet engine, specify 8 or + * 16-bit CRC. + */ + // Set AutoACK retry count, timeout params (0-15, 250-4000 respectively) + void setAutoAckParams(uint8_t autoretry_count=15, uint16_t autoretry_timeout=2000); + + // Protocol addressing -- receive, transmit addresses + void setAddressLength(size_t len); // Valid parameters = 3, 4 or 5. Defaults to 5. + void setRXaddress(void *rxaddr); // 3-5 byte RX address loaded into pipe#1 + void setTXaddress(void *txaddr); // 3-5 byte TX address loaded into TXaddr register + + // Miscellaneous feature + boolean rfSignalDetected(); /* Read RPD register to determine if transceiver has presently detected an RF signal + * of -64dBm or greater. Only works in PRX (enableRX()) mode. + */ + + private: + uint8_t rf_status; + uint8_t rf_channel; + uint8_t rf_speed; // Stored in native RF_SETUP register format + uint8_t rf_addr_width; + uint8_t txbuf_len; + uint8_t txbuf[32]; + uint8_t lastirq, readpending; + DigitalOut _cePin, _csnPin, _mosi, _sck; + DigitalIn _miso, _irqPin; + SPI _spi; + + uint8_t _readReg(uint8_t addr); + void _readRegMultiLSB(uint8_t addr, uint8_t *buf, size_t len); + void _writeReg(uint8_t addr, uint8_t val); + void _writeRegMultiLSB(uint8_t addr, uint8_t *buf, size_t len); + void _issueCmd(uint8_t cmd); + void _readCmdPayload(uint8_t addr, uint8_t *buf, size_t len, size_t maxlen); + void _issueCmdPayload(uint8_t cmd, uint8_t *buf, size_t len); + uint8_t _irq_getreason(); + uint8_t _irq_derivereason(); // Get IRQ status from rf_status w/o querying module over SPI. + void _irq_clear(uint8_t irq); + boolean _isAlive(); + void _readTXaddr(uint8_t *buf); + void _writeRXaddrP0(uint8_t *buf); + void _maintenanceHook(); // Handles IRQs and purges RX queue when erroneous contents exist. + +/* Private planning: + Need to keep track of: + RF status (since we get it after every SPI communication, might as well store it) + RF channel (to refresh in order to reset PLOS_CNT) + RF speed (to determine if autoAck makes any sense, since it doesn't @ 250Kbps) + Address Length (to determine how many bytes to read out of set(RX|TX)address()) + 32-byte TX ring buffer + Ring buffer position + */ +}; + +#endif
diff -r 000000000000 -r 670ecbc1478a nRF24L01.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nRF24L01.h Tue May 28 03:48:04 2013 +0000 @@ -0,0 +1,121 @@ +/* nRF24L01.h + * Register definitions for manipulating the Nordic Semiconductor + * nRF24L01+ RF transceiver chipsets. + * + + Copyright (c) 2007 Stefan Engelke <mbox@stefanengelke.de> + Some parts copyright (c) 2012 Eric Brundick <spirilis [at] linux dot com> + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + */ +#ifndef _NRF24L01_H +#define _NRF24L01_H + +/* Register Map */ +#define RF24_CONFIG 0x00 +#define RF24_EN_AA 0x01 +#define RF24_EN_RXADDR 0x02 +#define RF24_SETUP_AW 0x03 +#define RF24_SETUP_RETR 0x04 +#define RF24_RF_CH 0x05 +#define RF24_RF_SETUP 0x06 +#define RF24_STATUS 0x07 +#define RF24_OBSERVE_TX 0x08 +#define RF24_CD 0x09 +#define RF24_RPD 0x09 +#define RF24_RX_ADDR_P0 0x0A +#define RF24_RX_ADDR_P1 0x0B +#define RF24_RX_ADDR_P2 0x0C +#define RF24_RX_ADDR_P3 0x0D +#define RF24_RX_ADDR_P4 0x0E +#define RF24_RX_ADDR_P5 0x0F +#define RF24_TX_ADDR 0x10 +#define RF24_RX_PW_P0 0x11 +#define RF24_RX_PW_P1 0x12 +#define RF24_RX_PW_P2 0x13 +#define RF24_RX_PW_P3 0x14 +#define RF24_RX_PW_P4 0x15 +#define RF24_RX_PW_P5 0x16 +#define RF24_FIFO_STATUS 0x17 +#define RF24_DYNPD 0x1C +#define RF24_FEATURE 0x1D + +/* Register Bits */ +#define RF24_MASK_RX_DR BIT6 +#define RF24_MASK_TX_DS BIT5 +#define RF24_MASK_MAX_RT BIT4 +#define RF24_EN_CRC BIT3 +#define RF24_CRCO BIT2 +#define RF24_PWR_UP BIT1 +#define RF24_PRIM_RX BIT0 +#define RF24_ENAA_P5 BIT5 +#define RF24_ENAA_P4 BIT4 +#define RF24_ENAA_P3 BIT3 +#define RF24_ENAA_P2 BIT2 +#define RF24_ENAA_P1 BIT1 +#define RF24_ENAA_P0 BIT0 +#define RF24_ERX_P5 BIT5 +#define RF24_ERX_P4 BIT4 +#define RF24_ERX_P3 BIT3 +#define RF24_ERX_P2 BIT2 +#define RF24_ERX_P1 BIT1 +#define RF24_ERX_P0 BIT0 +#define RF24_AW BIT0 +#define RF24_ARD BIT4 +#define RF24_ARC BIT0 +#define RF24_PLL_LOCK BIT4 +#define RF24_CONT_WAVE BIT7 +#define RF24_RF_DR BIT3 +#define RF24_RF_DR_LOW BIT5 +#define RF24_RF_DR_HIGH BIT3 +#define RF24_RF_PWR BIT1 +#define RF24_LNA_HCURR BIT0 +#define RF24_RX_DR BIT6 +#define RF24_TX_DS BIT5 +#define RF24_MAX_RT BIT4 +#define RF24_RX_P_NO BIT1 +#define RF24_TX_FULL BIT0 +#define RF24_PLOS_CNT BIT4 +#define RF24_ARC_CNT BIT0 +#define RF24_TX_REUSE BIT6 +#define RF24_FIFO_FULL BIT5 +#define RF24_TX_EMPTY BIT4 +#define RF24_RX_FULL BIT1 +#define RF24_RX_EMPTY BIT0 +#define RF24_EN_DPL BIT2 +#define RF24_EN_ACK_PAY BIT1 +#define RF24_EN_DYN_ACK BIT0 + +/* Instructions */ +#define RF24_R_REGISTER 0x00 +#define RF24_W_REGISTER 0x20 +#define RF24_REGISTER_MASK 0x1F +#define RF24_R_RX_PAYLOAD 0x61 +#define RF24_W_TX_PAYLOAD 0xA0 +#define RF24_FLUSH_TX 0xE1 +#define RF24_FLUSH_RX 0xE2 +#define RF24_REUSE_TX_PL 0xE3 +#define RF24_R_RX_PL_WID 0x60 +#define RF24_W_ACK_PAYLOAD 0xA8 +#define RF24_W_TX_PAYLOAD_NOACK 0xB0 +#define RF24_NOP 0xFF + +#endif