[nRF24] Implemented basic functions
This commit is contained in:
parent
da5eb14867
commit
07637feef6
6 changed files with 723 additions and 147 deletions
82
examples/nRF24/nRF24_Receive/nRF24_Receive.ino
Normal file
82
examples/nRF24/nRF24_Receive/nRF24_Receive.ino
Normal 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!"));
|
||||
|
||||
}
|
||||
}
|
|
@ -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!"));
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
/*!
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue