[nRF24] Implemented basic functions

This commit is contained in:
jgromes 2019-06-01 20:30:16 +02:00
parent da5eb14867
commit 07637feef6
6 changed files with 723 additions and 147 deletions

View file

@ -0,0 +1,82 @@
/*
RadioLib nRF24 Receive Example
This example listens for FSK transmissions using nRF24 2.4 GHz radio module.
To successfully receive data, the following settings have to be the same
on both transmitter and receiver:
- carrier frequency
- data rate
- transmit pipe on transmitter must match receive pipe
on receiver
*/
// include the library
#include <RadioLib.h>
// nRF24 is in slot A on the shield
nRF24 nrf = RadioShield.ModuleA;
void setup() {
Serial.begin(9600);
// initialize nRF24
Serial.print(F("[nRF24] Initializing ... "));
// carrier frequency: 2400 MHz
// data rate: 1000 kbps
// output power: -12 dBm
// address width: 5 bytes
int state = nrf.begin();
if(state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while(true);
}
// set receive pipe 0 address
// NOTE: address width in bytes MUST be equal to the
// width set in begin() or setAddressWidth()
// methods (5 by default)
Serial.print(F("[nRF24] Setting address for receive pipe 0 ... "));
byte addr[] = {0x01, 0x23, 0x45, 0x67, 0x89};
state = nrf.setReceivePipe(0, addr);
if(state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while(true);
}
}
void loop() {
Serial.print(F("[nRF24] Waiting for incoming transmission ... "));
// you can receive data as an Arduino String
// NOTE: receive() is a blocking method!
// See example ReceiveInterrupt for details
// on non-blocking reception method.
String str;
int state = nrf.receive(str);
// you can also receive data as byte array
/*
byte byteArr[8];
int state = nrf.receive(byteArr, 8);
*/
if (state == ERR_NONE) {
// packet was successfully received
Serial.println(F("success!"));
// print the data of the packet
Serial.print(F("[nRF24] Data:\t\t"));
Serial.println(str);
} else if (state == ERR_RX_TIMEOUT) {
// timeout occurred while waiting for a packet
Serial.println(F("timeout!"));
}
}

View file

@ -1,5 +1,13 @@
/*
RadioLib nRF24 Transmit Example
This example transmits packets using nRF24 2.4 GHz radio module.
Each packet contains up to 32 bytes of data, in the form of:
- Arduino String
- null-terminated char array (C-string)
- arbitrary binary data (byte array)
Packet delivery is automatically acknowledged by the receiver.
*/
// include the library
@ -15,6 +23,7 @@ void setup() {
Serial.print(F("[nRF24] Initializing ... "));
// carrier frequency: 2400 MHz
// data rate: 1000 kbps
// output power: -12 dBm
// address width: 5 bytes
int state = nrf.begin();
if(state == ERR_NONE) {
@ -25,46 +34,13 @@ void setup() {
while(true);
}
// set receive pipe 0 address
// NOTE: address width in bytes MUST be equal to the
// set transmit address
// NOTE: address width in bytes MUST be equal to the
// width set in begin() or setAddressWidth()
// methods (5 by default)
Serial.print(F("[nRF24] Setting address for receive pipe 0 ... "));
byte receiveAddr0[] = {0x05, 0x06, 0x07, 0x08, 0x09};
state = nrf.setReceivePipe(0, receiveAddr0);
if(state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while(true);
}
// set receive pipe 1 - 5 address
// NOTE: unlike receive pipe 0, pipes 1 - 5 are only
// distinguished by their least significant byte,
// the upper bytes will be the same!
Serial.print(F("[nRF24] Setting addresses for receive pipes 1 - 5 ... "));
byte receiveAddr1[] = {0xAA, 0xBB, 0xCC, 0xDD, 0xE1};
// set pipe 1 address
state = nrf.setReceivePipe(1, receiveAddr1);
// set the addresses for rest of pipes
state |= nrf.setReceivePipe(2, 0xE2);
state |= nrf.setReceivePipe(3, 0xE3);
state |= nrf.setReceivePipe(4, 0xE4);
state |= nrf.setReceivePipe(5, 0xE5);
if(state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while(true);
}
// pipes 1 - 5 are automatically enabled upon address
// change, but can be disabled manually
Serial.print(F("[nRF24] Disabling pipes 2 - 5 ... "));
state = nrf.disablePipe(2);
byte addr[] = {0x01, 0x23, 0x45, 0x67, 0x89};
Serial.print(F("[nRF24] Setting transmit pipe ... "));
state = nrf.setTransmitPipe(addr);
if(state == ERR_NONE) {
Serial.println(F("success!"));
} else {
@ -77,23 +53,26 @@ void setup() {
void loop() {
Serial.print(F("[nRF24] Transmitting packet ... "));
// set transmit address
// NOTE: address width in bytes MUST be equal to the
// width set in begin() or setAddressWidth()
// methods (5 by default)
byte addr[] = {0x00, 0x01, 0x02, 0x03, 0x04};
// you can transmit C-string or Arduino string up to
// 32 characters long
int state = nrf.transmit("Hello World!", addr);
int state = nrf.transmit("Hello World!");
if (state == ERR_NONE) {
// the packet was successfully transmitted
Serial.println(" success!");
Serial.println(F("success!"));
} else if (state == ERR_PACKET_TOO_LONG) {
// the supplied packet was longer than 256 bytes
Serial.println(" too long!");
// the supplied packet was longer than 32 bytes
Serial.println(F("too long!"));
} else if (state == ERR_ACK_NOT_RECEIVED) {
// acknowledge from destination module
// was not received within 15 retries
Serial.println(F("ACK not received!"));
} else if (state == ERR_TX_TIMEOUT) {
// timed out while transmitting
Serial.println(F("timeout!"));
}

View file

@ -116,9 +116,11 @@ getPacketSource KEYWORD2
getPacketData KEYWORD2
# nRF24
setTransmitAddress KEYWORD2
setAddressWidth KEYWORD2
setTransmitPipe KEYWORD2
setReceivePipe KEYWORD2
disablePipe KEYWORD2
getStatus KEYWORD2
# HTTP
get KEYWORD2
@ -218,6 +220,7 @@ ERR_UNSUPPORTED_ENCODING LITERAL1
ERR_INVALID_DATA_RATE LITERAL1
ERR_INVALID_ADDRESS_WIDTH LITERAL1
ERR_INVALID_PIPE_NUMBER LITERAL1
ERR_ACK_NOT_RECEIVED LITERAL1
ERR_INVALID_NUM_BROAD_ADDRS LITERAL1

View file

@ -395,7 +395,7 @@
*/
#define ERR_UNSUPPORTED_ENCODING -402
// nRF24 status codes
// nRF24-specific status codes
/*!
\brief Supplied data rate is invalid.
@ -412,6 +412,11 @@
*/
#define ERR_INVALID_PIPE_NUMBER -503
/*!
\brief ACK packet from destination module was not received within 15 retries.
*/
#define ERR_ACK_NOT_RECEIVED -504
// CC1101-specific status codes
/*!

View file

@ -1,36 +1,66 @@
#include "nRF24.h"
nRF24::nRF24(Module* mod) {
nRF24::nRF24(Module* mod) : PhysicalLayer(NRF24_CRYSTAL_FREQ, NRF24_DIV_EXPONENT) {
_mod = mod;
}
int16_t nRF24::begin(int16_t freq, int16_t dataRate, uint8_t addrWidth) {
int16_t nRF24::begin(int16_t freq, int16_t dataRate, int8_t power, uint8_t addrWidth) {
// set module properties
_mod->SPIreadCommand = NRF24_CMD_READ;
_mod->SPIwriteCommand = NRF24_CMD_WRITE;
_mod->init(USE_SPI, INT_BOTH);
// override pin mode on INT0 (connected to nRF24 CE pin)
pinMode(_mod->getInt0(), OUTPUT);
// set frequency
int16_t state = setFrequency(freq);
digitalWrite(_mod->getInt0(), LOW);
// wait for minimum power-on reset duration
delay(100);
// check SPI connection
int16_t val = _mod->SPIgetRegValue(NRF24_REG_SETUP_AW);
if(!((val >= 1) && (val <= 3))) {
DEBUG_PRINTLN(F("No nRF24 found!"));
_mod->term();
return(ERR_CHIP_NOT_FOUND);
}
// configure settings inaccessible by public API
int16_t state = config();
if(state != ERR_NONE) {
return(state);
}
// set mode to standby
state = standby();
if(state != ERR_NONE) {
return(state);
}
// set frequency
state = setFrequency(freq);
if(state != ERR_NONE) {
return(state);
}
// set data rate
state = setDataRate(dataRate);
if(state != ERR_NONE) {
return(state);
}
// set output power
state = setOutputPower(power);
if(state != ERR_NONE) {
return(state);
}
// set address width
state = setAddressWidth(addrWidth);
if(state != ERR_NONE) {
return(state);
}
return(state);
}
@ -39,60 +69,198 @@ int16_t nRF24::sleep() {
}
int16_t nRF24::standby() {
// make sure carrier output is disabled
_mod->SPIsetRegValue(NRF24_REG_RF_SETUP, NRF24_CONT_WAVE_OFF, 7, 7);
_mod->SPIsetRegValue(NRF24_REG_RF_SETUP, NRF24_PLL_LOCK_OFF, 4, 4);
digitalWrite(_mod->getInt0(), LOW);
// use standby-1 mode
return(_mod->SPIsetRegValue(NRF24_REG_CONFIG, NRF24_POWER_UP, 1, 1));
}
int16_t nRF24::transmit(String& str, uint8_t* addr) {
return(nRF24::transmit(str.c_str(), addr));
int16_t nRF24::transmit(uint8_t* data, size_t len, uint8_t addr) {
// start transmission
int16_t state = startTransmit(data, len, addr);
if(state != ERR_NONE) {
return(state);
}
// wait until transmission is finished
uint32_t start = micros();
while(digitalRead(_mod->getInt1())) {
// check maximum number of retransmits
if(getStatus(NRF24_MAX_RT)) {
standby();
clearIRQ();
return(ERR_ACK_NOT_RECEIVED);
}
// check timeout: 15 retries * 4ms (max Tx time as per datasheet)
if(micros() - start >= 60000) {
standby();
clearIRQ();
return(ERR_TX_TIMEOUT);
}
}
// clear interrupts
clearIRQ();
return(state);
}
int16_t nRF24::transmit(const char* str, uint8_t* addr) {
return(nRF24::transmit((uint8_t*)str, strlen(str), addr));
int16_t nRF24::receive(uint8_t* data, size_t len) {
// start reception
int16_t state = startReceive();
if(state != ERR_NONE) {
return(state);
}
// wait for Rx_DataReady or timeout
uint32_t start = micros();
while(digitalRead(_mod->getInt1())) {
// check timeout: 15 retries * 4ms (max Tx time as per datasheet)
if(micros() - start >= 60000) {
standby();
clearIRQ();
return(ERR_RX_TIMEOUT);
}
}
// read the received data
return(readData(data, len));
}
int16_t nRF24::transmit(uint8_t* data, size_t len, uint8_t* addr) {
int16_t nRF24::transmitDirect(uint32_t frf) {
// set raw frequency value
if(frf != 0) {
uint8_t freqRaw = frf - 2400;
_mod->SPIwriteRegister(NRF24_REG_RF_CH, freqRaw & 0b01111111);
}
// output carrier
int16_t state = _mod->SPIsetRegValue(NRF24_REG_CONFIG, NRF24_PTX, 0, 0);
state |= _mod->SPIsetRegValue(NRF24_REG_RF_SETUP, NRF24_CONT_WAVE_ON, 7, 7);
state |= _mod->SPIsetRegValue(NRF24_REG_RF_SETUP, NRF24_PLL_LOCK_ON, 4, 4);
digitalWrite(_mod->getInt0(), HIGH);
return(state);
}
int16_t nRF24::receiveDirect() {
// nRF24 is unable to directly output demodulated data
// this method is implemented only for PhysicalLayer compatibility
return(ERR_NONE);
}
void nRF24::setIrqAction(void (*func)(void)) {
attachInterrupt(digitalPinToInterrupt(_mod->getInt1()), func, FALLING);
}
int16_t nRF24::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
// suppress unused variable warning
(void)addr;
// check packet length
if(len > 32) {
return(ERR_PACKET_TOO_LONG);
}
// set mode to standby
int16_t state = standby();
if(state != ERR_NONE) {
return(state);
}
// reverse address byte order (LSB must be written first)
uint8_t* addrReversed = new uint8_t[_addrWidth];
for(uint8_t i = 0; i < _addrWidth; i++) {
addrReversed[i] = addr[_addrWidth - 1 - i];
}
// set transmit address
_mod->SPIwriteRegisterBurst(NRF24_REG_TX_ADDR, addrReversed, _addrWidth);
// check packet length
if(len > 32) {
return(ERR_PACKET_TOO_LONG);
}
// enable Tx_DataSent interrupt
state = _mod->SPIsetRegValue(NRF24_REG_CONFIG, NRF24_MASK_RX_DR_IRQ_OFF | NRF24_MASK_TX_DS_IRQ_ON | NRF24_MASK_MAX_RT_IRQ_OFF, 6, 4);
// fill Tx FIFO
SPIwriteTxPayload(data, len);
// enable primary Tx mode
state |= _mod->SPIsetRegValue(NRF24_REG_CONFIG, NRF24_PTX, 0, 0);
state = _mod->SPIsetRegValue(NRF24_REG_CONFIG, NRF24_PTX, 0, 0);
// clear interrupts
clearIRQ();
// enable Tx_DataSent interrupt
state |= _mod->SPIsetRegValue(NRF24_REG_CONFIG, NRF24_MASK_TX_DS_IRQ_ON, 5, 5);
if(state != ERR_NONE) {
return(state);
}
// flush Tx FIFO
SPItransfer(NRF24_CMD_FLUSH_TX);
// fill Tx FIFO
uint8_t buff[32];
memset(buff, 0x00, 32);
memcpy(buff, data, len);
SPIwriteTxPayload(data, len);
// CE high to start transmitting
digitalWrite(_mod->getInt0(), HIGH);
// wait until transmission is finished
while(digitalRead(_mod->getInt1()));
// CE low
delayMicroseconds(10);
digitalWrite(_mod->getInt0(), LOW);
return(state);
}
int16_t nRF24::startReceive() {
// set mode to standby
int16_t state = standby();
if(state != ERR_NONE) {
return(state);
}
// enable primary Rx mode
state = _mod->SPIsetRegValue(NRF24_REG_CONFIG, NRF24_PRX, 0, 0);
if(state != ERR_NONE) {
return(state);
}
// enable Rx_DataReady interrupt
clearIRQ();
state |= _mod->SPIsetRegValue(NRF24_REG_CONFIG, NRF24_MASK_RX_DR_IRQ_ON, 6, 6);
if(state != ERR_NONE) {
return(state);
}
// flush Rx FIFO
SPItransfer(NRF24_CMD_FLUSH_RX);
// CE high to start receiving
digitalWrite(_mod->getInt0(), HIGH);
// wait to enter Rx state
delayMicroseconds(130);
return(state);
}
int16_t nRF24::readData(uint8_t* data, size_t len) {
// set mode to standby
int16_t state = standby();
if(state != ERR_NONE) {
return(state);
}
// read payload length
uint8_t buff[1];
SPItransfer(NRF24_CMD_READ_RX_PAYLOAD_WIDTH, false, NULL, buff, 1);
size_t length = buff[0];
// read packet data
if(len == 0) {
// argument 'len' equal to zero indicates String call, which means dynamically allocated data array
// dispose of the original and create a new one
delete[] data;
data = new uint8_t[length + 1];
}
SPIreadRxPayload(data, length);
// add terminating null
data[length] = 0;
// clear interrupt
clearIRQ();
return(state);
return(ERR_NONE);
}
int16_t nRF24::setFrequency(int16_t freq) {
@ -100,13 +268,13 @@ int16_t nRF24::setFrequency(int16_t freq) {
if(!((freq >= 2400) && (freq <= 2525))) {
return(ERR_INVALID_FREQUENCY);
}
// set mode to standby
int16_t state = standby();
if(state != ERR_NONE) {
return(state);
}
// set frequency
uint8_t freqRaw = freq - 2400;
state = _mod->SPIsetRegValue(NRF24_REG_RF_CH, freqRaw, 6, 0);
@ -119,7 +287,7 @@ int16_t nRF24::setDataRate(int16_t dataRate) {
if(state != ERR_NONE) {
return(state);
}
// set data rate
if(dataRate == 250) {
state = _mod->SPIsetRegValue(NRF24_REG_RF_SETUP, NRF24_DR_250_KBPS, 5, 5);
@ -133,7 +301,38 @@ int16_t nRF24::setDataRate(int16_t dataRate) {
} else {
return(ERR_INVALID_DATA_RATE);
}
return(state);
}
int16_t nRF24::setOutputPower(int8_t power) {
// set mode to standby
int16_t state = standby();
if(state != ERR_NONE) {
return(state);
}
// check allowed values
uint8_t powerRaw = 0;
switch(power) {
case -18:
powerRaw = NRF24_RF_PWR_18_DBM;
break;
case -12:
powerRaw = NRF24_RF_PWR_12_DBM;
break;
case -6:
powerRaw = NRF24_RF_PWR_6_DBM;
break;
case 0:
powerRaw = NRF24_RF_PWR_0_DBM;
break;
default:
return(ERR_INVALID_OUTPUT_POWER);
}
// write new register value
state = _mod->SPIsetRegValue(NRF24_REG_RF_SETUP, powerRaw, 2, 1);
return(state);
}
@ -143,7 +342,7 @@ int16_t nRF24::setAddressWidth(uint8_t addrWidth) {
if(state != ERR_NONE) {
return(state);
}
// set address width
switch(addrWidth) {
case 3:
@ -158,10 +357,26 @@ int16_t nRF24::setAddressWidth(uint8_t addrWidth) {
default:
return(ERR_INVALID_ADDRESS_WIDTH);
}
// save address width
_addrWidth = addrWidth;
return(state);
}
int16_t nRF24::setTransmitPipe(uint8_t* addr) {
// set mode to standby
int16_t state = standby();
if(state != ERR_NONE) {
return(state);
}
// set transmit address
_mod->SPIwriteRegisterBurst(NRF24_REG_TX_ADDR, addr, _addrWidth);
// set Rx pipe 0 address (for ACK)
_mod->SPIwriteRegisterBurst(NRF24_REG_RX_ADDR_P0, addr, _addrWidth);
return(state);
}
@ -171,26 +386,20 @@ int16_t nRF24::setReceivePipe(uint8_t pipeNum, uint8_t* addr) {
if(state != ERR_NONE) {
return(state);
}
// reverse byte order (LSB must be written first)
uint8_t* addrReversed = new uint8_t[_addrWidth];
for(uint8_t i = 0; i < _addrWidth; i++) {
addrReversed[i] = addr[_addrWidth - 1 - i];
}
// write full pipe 0 - 1 address and enable the pipe
switch(pipeNum) {
case 0:
_mod->SPIwriteRegisterBurst(NRF24_REG_RX_ADDR_P0, addrReversed, _addrWidth);
_mod->SPIwriteRegisterBurst(NRF24_REG_RX_ADDR_P0, addr, _addrWidth);
state |= _mod->SPIsetRegValue(NRF24_REG_EN_RXADDR, NRF24_P0_ON, 0, 0);
case 1:
_mod->SPIwriteRegisterBurst(NRF24_REG_RX_ADDR_P1, addrReversed, _addrWidth);
_mod->SPIwriteRegisterBurst(NRF24_REG_RX_ADDR_P1, addr, _addrWidth);
state |= _mod->SPIsetRegValue(NRF24_REG_EN_RXADDR, NRF24_P1_ON, 1, 1);
break;
default:
return(ERR_INVALID_PIPE_NUMBER);
}
return(state);
}
@ -200,7 +409,7 @@ int16_t nRF24::setReceivePipe(uint8_t pipeNum, uint8_t addrByte) {
if(state != ERR_NONE) {
return(state);
}
// write unique pipe 2 - 5 address and enable the pipe
switch(pipeNum) {
case 2:
@ -222,7 +431,7 @@ int16_t nRF24::setReceivePipe(uint8_t pipeNum, uint8_t addrByte) {
default:
return(ERR_INVALID_PIPE_NUMBER);
}
return(state);
}
@ -232,7 +441,7 @@ int16_t nRF24::disablePipe(uint8_t pipeNum) {
if(state != ERR_NONE) {
return(state);
}
switch(pipeNum) {
case 0:
state = _mod->SPIsetRegValue(NRF24_REG_EN_RXADDR, NRF24_P0_OFF, 0, 0);
@ -255,28 +464,103 @@ int16_t nRF24::disablePipe(uint8_t pipeNum) {
default:
return(ERR_INVALID_PIPE_NUMBER);
}
return(state);
}
void nRF24::SPIreadRxPayload(uint8_t numBytes, uint8_t* inBytes) {
digitalWrite(_mod->getCs(), LOW);
SPI.transfer(NRF24_CMD_READ_RX_PAYLOAD);
for(uint8_t i = 0; i < numBytes; i++) {
inBytes[i] = SPI.transfer(0x00);
}
digitalWrite(_mod->getCs(), HIGH);
int16_t nRF24::getStatus(uint8_t mask) {
return(_mod->SPIgetRegValue(NRF24_REG_STATUS) & mask);
}
void nRF24::SPIwriteTxPayload(uint8_t* data, uint8_t numBytes) {
digitalWrite(_mod->getCs(), LOW);
SPI.transfer(NRF24_CMD_WRITE_TX_PAYLOAD);
for(uint8_t i = 0; i < numBytes; i++) {
SPI.transfer(data[i]);
}
digitalWrite(_mod->getCs(), HIGH);
int16_t nRF24::setFrequencyDeviation(float freqDev) {
// nRF24 is unable to set frequency deviation
// this method is implemented only for PhysicalLayer compatibility
(void)freqDev;
return(ERR_NONE);
}
void nRF24::clearIRQ() {
// clear status bits
_mod->SPIsetRegValue(NRF24_REG_STATUS, NRF24_RX_DR | NRF24_TX_DS | NRF24_MAX_RT, 6, 4);
// disable interrupts
_mod->SPIsetRegValue(NRF24_REG_CONFIG, NRF24_MASK_RX_DR_IRQ_OFF | NRF24_MASK_TX_DS_IRQ_OFF | NRF24_MASK_MAX_RT_IRQ_OFF, 6, 4);
}
int16_t nRF24::config() {
// enable 16-bit CRC
int16_t state = _mod->SPIsetRegValue(NRF24_REG_CONFIG, NRF24_CRC_ON | NRF24_CRC_16, 3, 2);
if(state != ERR_NONE) {
return(state);
}
// set 15 retries and delay 1500 (5*250) us
_mod->SPIsetRegValue(NRF24_REG_SETUP_RETR, (5 << 4) | 5);
if(state != ERR_NONE) {
return(state);
}
// set features: dynamic payload on, payload with ACK packets off, dynamic ACK off
state = _mod->SPIsetRegValue(NRF24_REG_FEATURE, NRF24_DPL_ON | NRF24_ACK_PAY_OFF | NRF24_DYN_ACK_OFF, 2, 0);
if(state != ERR_NONE) {
return(state);
}
// enable dynamic payloads
state = _mod->SPIsetRegValue(NRF24_REG_DYNPD, NRF24_DPL_ALL_ON, 5, 0);
if(state != ERR_NONE) {
return(state);
}
// reset IRQ
clearIRQ();
// clear status
_mod->SPIsetRegValue(NRF24_REG_STATUS, NRF24_RX_DR | NRF24_TX_DS | NRF24_MAX_RT, 6, 4);
// flush FIFOs
SPItransfer(NRF24_CMD_FLUSH_TX);
SPItransfer(NRF24_CMD_FLUSH_RX);
// power up
_mod->SPIsetRegValue(NRF24_REG_CONFIG, NRF24_POWER_UP, 1, 1);
delay(5);
return(state);
}
void nRF24::SPIreadRxPayload(uint8_t* data, uint8_t numBytes) {
SPItransfer(NRF24_CMD_READ_RX_PAYLOAD, false, NULL, data, numBytes);
}
void nRF24::SPIwriteTxPayload(uint8_t* data, uint8_t numBytes) {
SPItransfer(NRF24_CMD_WRITE_TX_PAYLOAD, true, data, NULL, numBytes);
}
void nRF24::SPItransfer(uint8_t cmd, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes) {
// get pointer to used SPI interface and the settings
SPIClass* spi = _mod->getSpi();
SPISettings spiSettings = _mod->getSpiSettings();
// start transfer
digitalWrite(_mod->getCs(), LOW);
spi->beginTransaction(spiSettings);
// send command
spi->transfer(cmd);
// send data
if(write) {
for(uint8_t i = 0; i < numBytes; i++) {
spi->transfer(dataOut[i]);
}
} else {
for(uint8_t i = 0; i < numBytes; i++) {
dataIn[i] = spi->transfer(0x00);
}
}
// stop transfer
spi->endTransaction();
digitalWrite(_mod->getCs(), HIGH);
}

View file

@ -2,6 +2,13 @@
#define _RADIOLIB_NRF24_H
#include "Module.h"
#include "TypeDef.h"
#include "../protocols/PhysicalLayer.h"
// nRF24 physical layer properties (dummy only)
#define NRF24_CRYSTAL_FREQ 1.0
#define NRF24_DIV_EXPONENT 0
// nRF24 SPI commands
#define NRF24_CMD_READ 0b00000000
@ -107,6 +114,8 @@
#define NRF24_DR_250_KBPS 0b00100000 // 5 5 data rate: 250 kbps
#define NRF24_DR_1_MBPS 0b00000000 // 3 3 1 Mbps (default)
#define NRF24_DR_2_MBPS 0b00001000 // 3 3 2 Mbps
#define NRF24_PLL_LOCK_ON 0b00010000 // 4 4 force PLL lock: enabled
#define NRF24_PLL_LOCK_OFF 0b00000000 // 4 4 disabled (default)
#define NRF24_RF_PWR_18_DBM 0b00000000 // 2 1 output power: -18 dBm
#define NRF24_RF_PWR_12_DBM 0b00000010 // 2 1 -12 dBm
#define NRF24_RF_PWR_6_DBM 0b00000100 // 2 1 -6 dBm
@ -132,8 +141,8 @@
#define NRF24_TX_REUSE 0b01000000 // 6 6 reusing last transmitted payload
#define NRF24_TX_FIFO_FULL_FLAG 0b00100000 // 5 5 Tx FIFO is full
#define NRF24_TX_FIFO_EMPTY_FLAG 0b00010000 // 4 4 Tx FIFO is empty
#define NRF24_RX_FIFO_FULL_FLAG 0b00000010 // 5 5 Rx FIFO is full
#define NRF24_RX_FIFO_EMPTY_FLAG 0b00000001 // 4 4 Rx FIFO is empty
#define NRF24_RX_FIFO_FULL_FLAG 0b00000010 // 1 1 Rx FIFO is full
#define NRF24_RX_FIFO_EMPTY_FLAG 0b00000001 // 0 0 Rx FIFO is empty
// NRF24_REG_DYNPD
#define NRF24_DPL_P5_OFF 0b00000000 // 5 5 dynamic payload length on pipe 5: disabled (default)
@ -148,44 +157,258 @@
#define NRF24_DPL_P1_ON 0b00000010 // 1 1 enabled
#define NRF24_DPL_P0_OFF 0b00000000 // 0 0 dynamic payload length on pipe 0: disabled (default)
#define NRF24_DPL_P0_ON 0b00000001 // 0 0 enabled
#define NRF24_DPL_ALL_OFF 0b00000000 // 5 0 disable all dynamic payloads
#define NRF24_DPL_ALL_ON 0b00111111 // 5 0 enable all dynamic payloads
// NRF24_REG_FEATURE
#define NRF24_DPL_OFF 0b00000000 // 2 2 dynamic payload length: disabled (default)
#define NRF24_DPL_ON 0b00000100 // 2 2 enabled
#define NRF24_ACK_PAY_OFF 0b00000000 // 1 1 payload with ACK packets: disabled (default)
#define NRF24_ACK_PAY_ON 0b00000010 // 1 1 enabled
#define NRF24_DYN_ACK_OFF 0b00000000 // 0 0 payloads without ACK packets: disabled (default)
#define NRF24_DYN_ACK_ON 0b00000001 // 0 0 enabled
#define NRF24_DYN_ACK_OFF 0b00000000 // 0 0 payloads without ACK: disabled (default)
#define NRF24_DYN_ACK_ON 0b00000001 // 0 0 enabled
class nRF24 {
/*!
\class nRF24
\brief Control class for %nRF24 module.
*/
class nRF24: public PhysicalLayer {
public:
// constructor
// introduce PhysicalLayer overloads
using PhysicalLayer::transmit;
using PhysicalLayer::receive;
using PhysicalLayer::startTransmit;
using PhysicalLayer::readData;
/*!
\brief Default constructor.
\param mod Instance of Module that will be used to communicate with the radio.
*/
nRF24(Module* module);
// basic methods
int16_t begin(int16_t freq = 2400, int16_t dataRate = 1000, uint8_t addrWidth = 5);
/*!
\brief Initialization method.
\param freq Carrier frequency in MHz. Defaults to 2400 MHz.
\param dataRate Data rate to be used in kbps. Defaults to 1000 kbps.
\param power Output power in dBm. Defaults to -12 dBm.
\param addrWidth Address width in bytes. Defaults to 5 bytes.
\returns \ref status_codes
*/
int16_t begin(int16_t freq = 2400, int16_t dataRate = 1000, int8_t power = -12, uint8_t addrWidth = 5);
/*!
\brief Sets the module to sleep mode.
\returns \ref status_codes
*/
int16_t sleep();
/*!
\brief Sets the module to standby mode.
\returns \ref status_codes
*/
int16_t standby();
int16_t transmit(String& str, uint8_t* addr);
int16_t transmit(const char* str, uint8_t* addr);
int16_t transmit(uint8_t* data, size_t len, uint8_t* addr);
/*!
\brief Blocking binary transmit method.
Overloads for string-based transmissions are implemented in PhysicalLayer.
\param data Binary data to be sent.
\param len Number of bytes to send.
\param addr Dummy address parameter, to ensure PhysicalLayer compatibility.
\returns \ref status_codes
*/
int16_t transmit(uint8_t* data, size_t len, uint8_t addr);
/*!
\brief Blocking binary receive method.
Overloads for string-based transmissions are implemented in PhysicalLayer.
\param data Binary data to be sent.
\param len Number of bytes to send.
\returns \ref status_codes
*/
int16_t receive(uint8_t* data, size_t len);
/*!
\brief Starts direct mode transmission.
\param frf Raw RF frequency value. Defaults to 0, required for quick frequency shifts in RTTY.
\returns \ref status_codes
*/
int16_t transmitDirect(uint32_t frf = 0);
/*!
\brief Dummy direct mode reception method, to ensure PhysicalLayer compatibility.
\returns \ref status_codes
*/
int16_t receiveDirect();
// interrupt methods
/*!
\brief Sets interrupt service routine to call when IRQ activates.
\param func ISR to call.
*/
void setIrqAction(void (*func)(void));
/*!
\brief Interrupt-driven binary transmit method. IRQ will be activated when full packet is transmitted.
Overloads for string-based transmissions are implemented in PhysicalLayer.
\param data Binary data to be sent.
\param len Number of bytes to send.
\param addr Dummy address parameter, to ensure PhysicalLayer compatibility.
\returns \ref status_codes
*/
int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr);
/*!
\brief Interrupt-driven receive method. IRQ will be activated when full packet is received.
\returns \ref status_codes
*/
int16_t startReceive();
/*!
\brief Reads data received after calling startReceive method.
\param data Pointer to array to save the received binary data.
\param len Number of bytes that will be received. Must be known in advance for binary transmissions.
\returns \ref status_codes
*/
int16_t readData(uint8_t* data, size_t len);
// configuration methods
/*!
\brief Sets carrier frequency. Allowed values range from 2400 MHz to 2525 MHz.
\param freq Carrier frequency to be set in MHz.
\returns \ref status_codes
*/
int16_t setFrequency(int16_t freq);
/*!
\brief Sets data rate. Allowed values are 2000, 1000 or 250 kbps.
\param dataRate Data rate to be set in kbps.
\returns \ref status_codes
*/
int16_t setDataRate(int16_t dataRate);
/*!
\brief Sets output power. Allowed values are -18, -12, -6 or 0 dBm.
\param power Output power to be set in dBm.
\returns \ref status_codes
*/
int16_t setOutputPower(int8_t power);
/*!
\brief Sets address width of transmit and receive pipes in bytes. Allowed values are 3, 4 or 5 bytes.
\param addrWidth Address width to be set in bytes.
\returns \ref status_codes
*/
int16_t setAddressWidth(uint8_t addrWidth);
/*!
\brief Sets address of transmit pipe. The address width must be the same as the same as the configured in setAddressWidth.
\param addr Address to which the next packet shall be transmitted.
\returns \ref status_codes
*/
int16_t setTransmitPipe(uint8_t* addr);
/*!
\brief Sets address of receive pipes 0 or 1. The address width must be the same as the same as the configured in setAddressWidth.
\param pipeNum Number of pipe to which the address shall be set. Either 0 or 1, other pipes are handled using overloaded method.
\param addr Address from which %nRF24 shall receive new packets on the specified pipe.
\returns \ref status_codes
*/
int16_t setReceivePipe(uint8_t pipeNum, uint8_t* addr);
/*!
\brief Sets address of receive pipes 2 - 5. The first 2 - 4 address bytes for these pipes are the same as for address pipe 1, only the last byte can be set.
\param pipeNum Number of pipe to which the address shall be set. Allowed values range from 2 to 5.
\param addrByte LSB of address from which %nRF24 shall receive new packets on the specified pipe.
\returns \ref status_codes
*/
int16_t setReceivePipe(uint8_t pipeNum, uint8_t addrByte);
/*!
\brief Disables specified receive pipe.
\param pipeNum Receive pipe to be disabled.
\returns \ref status_codes
*/
int16_t disablePipe(uint8_t pipeNum);
/*!
\brief Gets nRF24 status register.
\param mask Bit mask to be used on the returned register value.
\returns Status register value or \ref status_codes
*/
int16_t getStatus(uint8_t mask = 0xFF);
/*!
\brief Dummy configuration method, to ensure PhysicalLayer compatibility.
\param freqDev Dummy frequency deviation parameter, no configuration will be changed.
\returns \ref status_codes
*/
int16_t setFrequencyDeviation(float freqDev);
private:
Module* _mod;
uint8_t _addrWidth;
void SPIreadRxPayload(uint8_t numBytes, uint8_t* inBytes);
void SPIwriteTxPayload(uint8_t* data, uint8_t numBytes);
int16_t config();
void clearIRQ();
void SPIreadRxPayload(uint8_t* data, uint8_t numBytes);
void SPIwriteTxPayload(uint8_t* data, uint8_t numBytes);
void SPItransfer(uint8_t cmd, bool write = false, uint8_t* dataOut = NULL, uint8_t* dataIn = NULL, uint8_t numBytes = 0);
};
#endif