Loading include/driver/nrf24l01.h +157 −2 Original line number Diff line number Diff line Loading @@ -22,8 +22,42 @@ private: uint8_t addr_width; /**< The address width to use - 3,4 or 5 bytes. */ uint32_t txRxDelay; /**< Var for adjusting delays depending on datarate */ /** * Write a single byte to a register * * @param reg Which register. Use constants from nRF24L01.h * @param value The new value to write * @return Current value of status register */ uint8_t writeRegister(uint8_t reg, uint8_t value); /** * Write a chunk of data to a register * * @param reg Which register. Use constants from nRF24L01.h * @param buf Where to get the data * @param len How many bytes of data to transfer * @return Current value of status register */ uint8_t writeRegister(uint8_t reg, const uint8_t *buf, uint8_t len); /** * Read single byte from a register * * @param reg Which register. Use constants from nRF24L01.h * @return Current value of register @p reg */ uint8_t readRegister(uint8_t reg); /** * Write the transmit payload * * The size of data written is the fixed payload size, see getPayloadSize() * * @param buf Where to get the data * @param len Number of bytes to be sent * @return Current value of status register */ uint8_t writePayload(const void *buf, uint8_t data_len, const uint8_t writeType); inline void csnHigh() Loading @@ -46,7 +80,7 @@ private: } public: Nrf24l01() : payload_size(32), dynamic_payloads_enabled(false), addr_width(5) {} Nrf24l01() : payload_size(32), dynamic_payloads_enabled(false), addr_width(5) { pipe0_reading_address[0] = 0; } /** * Power Amplifier level. Loading Loading @@ -231,9 +265,130 @@ public: * are enabled. See the datasheet for details. */ void toggleFeatures(void); /** * Be sure to call openWritingPipe() first to set the destination * of where to write to. * * This blocks until the message is successfully acknowledged by * the receiver or the timeout/retransmit maxima are reached. In * the current configuration, the max delay here is 60-70ms. * * The maximum size of data written is the fixed payload size, see * getPayloadSize(). However, you can write less, and the remainder * will just be filled with zeroes. * * TX/RX/RT interrupt flags will be cleared every time write is called * * @param buf Pointer to the data to be sent * @param len Number of bytes to be sent * * @code * radio.stopListening(); * radio.write(&data,sizeof(data)); * @endcode * @return True if the payload was delivered successfully false if not */ uint8_t write(const void *buf, uint8_t len, bool blocking); /** * Start listening on the pipes opened for reading. * * 1. Be sure to call openReadingPipe() first. * 2. Do not call write() while in this mode, without first calling stopListening(). * 3. Call available() to check for incoming traffic, and read() to get it. * * @code * Open reading pipe 1 using address CCCECCCECC * * byte address[] = { 0xCC,0xCE,0xCC,0xCE,0xCC }; * radio.openReadingPipe(1,address); * radio.startListening(); * @endcode */ void startListening(void); /** * Stop listening for incoming messages, and switch to transmit mode. * * Do this before calling write(). * @code * radio.stopListening(); * radio.write(&data,sizeof(data)); * @endcode */ void stopListening(void); /** * Check whether there are bytes available to be read * @code * if(radio.available()){ * radio.read(&data,sizeof(data)); * } * @endcode * @return True if there is a payload available, false if none is */ bool available(void); /** * Read the available payload * * The size of data read is the fixed payload size, see getPayloadSize() * * @note I specifically chose 'void*' as a data type to make it easier * for beginners to use. No casting needed. * * @note No longer boolean. Use available to determine if packets are * available. Interrupt flags are now cleared during reads instead of * when calling available(). * * @param buf Pointer to a buffer where the data should be written * @param len Maximum number of bytes to read into the buffer * * @code * if(radio.available()){ * radio.read(&data,sizeof(data)); * } * @endcode * @return No return value. Use available(). */ void read(void *buf, uint8_t len); /** * Open a pipe for reading * * Up to 6 pipes can be open for reading at once. Open all the required * reading pipes, and then call startListening(). * * @see openWritingPipe * @see setAddressWidth * * @note Pipes 0 and 1 will store a full 5-byte address. Pipes 2-5 will technically * only store a single byte, borrowing up to 4 additional bytes from pipe #1 per the * assigned address width. * @warning Pipes 1-5 should share the same address, except the first byte. * Only the first byte in the array should be unique, e.g. * @code * uint8_t addresses[][6] = {"1Node","2Node"}; * openReadingPipe(1,addresses[0]); * openReadingPipe(2,addresses[1]); * @endcode * * @warning Pipe 0 is also used by the writing pipe. So if you open * pipe 0 for reading, and then startListening(), it will overwrite the * writing pipe. Ergo, do an openWritingPipe() again before write(). * * @param number Which pipe# to open, 0-5. * @param address The 24, 32 or 40 bit address of the pipe to open. */ void openReadingPipe(uint8_t number, const uint8_t *address); /** * Close a pipe after it has been previously opened. * Can be safely called without having previously opened a pipe. * @param pipe Which pipe # to close, 0-5. */ void closeReadingPipe(uint8_t pipe); uint8_t getStatus(); }; Loading src/app/nrf24l01test/main.cc +3 −0 Original line number Diff line number Diff line Loading @@ -9,6 +9,9 @@ void loop(void) kout << "status: " << hex << nrf24l01.getStatus() << endl; kout << "write: "; kout << nrf24l01.write("foo", 3, true) << endl; nrf24l01.startListening(); arch.delay_ms(10); nrf24l01.stopListening(); } int main(void) Loading src/driver/nrf24l01.cc +101 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,16 @@ #error makeflag nrf24l01_cs_pin required #endif static const uint8_t child_pipe[] = { RX_ADDR_P0, RX_ADDR_P1, RX_ADDR_P2, RX_ADDR_P3, RX_ADDR_P4, RX_ADDR_P5}; static const uint8_t child_payload_size[] = { RX_PW_P0, RX_PW_P1, RX_PW_P2, RX_PW_P3, RX_PW_P4, RX_PW_P5}; static const uint8_t child_pipe_enable[] = { ERX_P0, ERX_P1, ERX_P2, ERX_P3, ERX_P4, ERX_P5}; void Nrf24l01::setup() { spi.setup(); Loading Loading @@ -181,6 +191,85 @@ uint8_t Nrf24l01::write(const void *buf, uint8_t len, bool blocking) return 1; } void Nrf24l01::startListening(void) { writeRegister(NRF_CONFIG, readRegister(NRF_CONFIG) | (1 << PRIM_RX)); writeRegister(NRF_STATUS, (1 << RX_DR) | (1 << TX_DS) | (1 << MAX_RT)); gpio.write(NRF24L01_EN_PIN, 1); // Restore the pipe0 adddress, if exists if (pipe0_reading_address[0] > 0) { writeRegister(RX_ADDR_P0, pipe0_reading_address, addr_width); } else { closeReadingPipe(0); } if (readRegister(FEATURE) & (1 << EN_ACK_PAY)) { flushTx(); } } void Nrf24l01::stopListening(void) { gpio.write(NRF24L01_EN_PIN, 0); arch.delay_us(txRxDelay); if (readRegister(FEATURE) & (1 << EN_ACK_PAY)) { arch.delay_us(txRxDelay); //200 flushTx(); } //flush_rx(); writeRegister(NRF_CONFIG, (readRegister(NRF_CONFIG)) & ~(1 << PRIM_RX)); writeRegister(EN_RXADDR, readRegister(EN_RXADDR) | (1 << child_pipe_enable[0])); // Enable RX on pipe0 } void Nrf24l01::openReadingPipe(uint8_t child, const uint8_t *address) { // If this is pipe 0, cache the address. This is needed because // openWritingPipe() will overwrite the pipe 0 address, so // startListening() will have to restore it. if (child == 0) { pipe0_reading_address[0] = address[0]; pipe0_reading_address[1] = address[1]; pipe0_reading_address[2] = address[2]; pipe0_reading_address[3] = address[3]; pipe0_reading_address[4] = address[4]; } if (child <= 6) { // For pipes 2-5, only write the LSB if (child < 2) { writeRegister(child_pipe[child], address, addr_width); } else { writeRegister(child_pipe[child], address, 1); } writeRegister(child_payload_size[child], payload_size); // Note it would be more efficient to set all of the bits for all open // pipes at once. However, I thought it would make the calling code // more simple to do it this way. writeRegister(EN_RXADDR, readRegister(EN_RXADDR) | (1 << child_pipe_enable[child])); } } /****************************************************************************/ void Nrf24l01::closeReadingPipe(uint8_t pipe) { writeRegister(EN_RXADDR, readRegister(EN_RXADDR) & ~(1 << child_pipe_enable[pipe])); } void Nrf24l01::maskIRQ(bool tx, bool fail, bool rx) { Loading Loading @@ -214,6 +303,18 @@ uint8_t Nrf24l01::readRegister(uint8_t reg) return rxbuf[1]; } uint8_t Nrf24l01::writeRegister(uint8_t reg, const uint8_t *buf, uint8_t len) { txbuf[0] = W_REGISTER | (REGISTER_MASK & reg); beginTransaction(); spi.xmit(1, txbuf, 1, rxbuf); spi.xmit(len, (unsigned char *)buf, 0, NULL); endTransaction(); return rxbuf[0]; } uint8_t Nrf24l01::writeRegister(uint8_t reg, uint8_t value) { txbuf[0] = W_REGISTER | (REGISTER_MASK & reg); Loading Loading
include/driver/nrf24l01.h +157 −2 Original line number Diff line number Diff line Loading @@ -22,8 +22,42 @@ private: uint8_t addr_width; /**< The address width to use - 3,4 or 5 bytes. */ uint32_t txRxDelay; /**< Var for adjusting delays depending on datarate */ /** * Write a single byte to a register * * @param reg Which register. Use constants from nRF24L01.h * @param value The new value to write * @return Current value of status register */ uint8_t writeRegister(uint8_t reg, uint8_t value); /** * Write a chunk of data to a register * * @param reg Which register. Use constants from nRF24L01.h * @param buf Where to get the data * @param len How many bytes of data to transfer * @return Current value of status register */ uint8_t writeRegister(uint8_t reg, const uint8_t *buf, uint8_t len); /** * Read single byte from a register * * @param reg Which register. Use constants from nRF24L01.h * @return Current value of register @p reg */ uint8_t readRegister(uint8_t reg); /** * Write the transmit payload * * The size of data written is the fixed payload size, see getPayloadSize() * * @param buf Where to get the data * @param len Number of bytes to be sent * @return Current value of status register */ uint8_t writePayload(const void *buf, uint8_t data_len, const uint8_t writeType); inline void csnHigh() Loading @@ -46,7 +80,7 @@ private: } public: Nrf24l01() : payload_size(32), dynamic_payloads_enabled(false), addr_width(5) {} Nrf24l01() : payload_size(32), dynamic_payloads_enabled(false), addr_width(5) { pipe0_reading_address[0] = 0; } /** * Power Amplifier level. Loading Loading @@ -231,9 +265,130 @@ public: * are enabled. See the datasheet for details. */ void toggleFeatures(void); /** * Be sure to call openWritingPipe() first to set the destination * of where to write to. * * This blocks until the message is successfully acknowledged by * the receiver or the timeout/retransmit maxima are reached. In * the current configuration, the max delay here is 60-70ms. * * The maximum size of data written is the fixed payload size, see * getPayloadSize(). However, you can write less, and the remainder * will just be filled with zeroes. * * TX/RX/RT interrupt flags will be cleared every time write is called * * @param buf Pointer to the data to be sent * @param len Number of bytes to be sent * * @code * radio.stopListening(); * radio.write(&data,sizeof(data)); * @endcode * @return True if the payload was delivered successfully false if not */ uint8_t write(const void *buf, uint8_t len, bool blocking); /** * Start listening on the pipes opened for reading. * * 1. Be sure to call openReadingPipe() first. * 2. Do not call write() while in this mode, without first calling stopListening(). * 3. Call available() to check for incoming traffic, and read() to get it. * * @code * Open reading pipe 1 using address CCCECCCECC * * byte address[] = { 0xCC,0xCE,0xCC,0xCE,0xCC }; * radio.openReadingPipe(1,address); * radio.startListening(); * @endcode */ void startListening(void); /** * Stop listening for incoming messages, and switch to transmit mode. * * Do this before calling write(). * @code * radio.stopListening(); * radio.write(&data,sizeof(data)); * @endcode */ void stopListening(void); /** * Check whether there are bytes available to be read * @code * if(radio.available()){ * radio.read(&data,sizeof(data)); * } * @endcode * @return True if there is a payload available, false if none is */ bool available(void); /** * Read the available payload * * The size of data read is the fixed payload size, see getPayloadSize() * * @note I specifically chose 'void*' as a data type to make it easier * for beginners to use. No casting needed. * * @note No longer boolean. Use available to determine if packets are * available. Interrupt flags are now cleared during reads instead of * when calling available(). * * @param buf Pointer to a buffer where the data should be written * @param len Maximum number of bytes to read into the buffer * * @code * if(radio.available()){ * radio.read(&data,sizeof(data)); * } * @endcode * @return No return value. Use available(). */ void read(void *buf, uint8_t len); /** * Open a pipe for reading * * Up to 6 pipes can be open for reading at once. Open all the required * reading pipes, and then call startListening(). * * @see openWritingPipe * @see setAddressWidth * * @note Pipes 0 and 1 will store a full 5-byte address. Pipes 2-5 will technically * only store a single byte, borrowing up to 4 additional bytes from pipe #1 per the * assigned address width. * @warning Pipes 1-5 should share the same address, except the first byte. * Only the first byte in the array should be unique, e.g. * @code * uint8_t addresses[][6] = {"1Node","2Node"}; * openReadingPipe(1,addresses[0]); * openReadingPipe(2,addresses[1]); * @endcode * * @warning Pipe 0 is also used by the writing pipe. So if you open * pipe 0 for reading, and then startListening(), it will overwrite the * writing pipe. Ergo, do an openWritingPipe() again before write(). * * @param number Which pipe# to open, 0-5. * @param address The 24, 32 or 40 bit address of the pipe to open. */ void openReadingPipe(uint8_t number, const uint8_t *address); /** * Close a pipe after it has been previously opened. * Can be safely called without having previously opened a pipe. * @param pipe Which pipe # to close, 0-5. */ void closeReadingPipe(uint8_t pipe); uint8_t getStatus(); }; Loading
src/app/nrf24l01test/main.cc +3 −0 Original line number Diff line number Diff line Loading @@ -9,6 +9,9 @@ void loop(void) kout << "status: " << hex << nrf24l01.getStatus() << endl; kout << "write: "; kout << nrf24l01.write("foo", 3, true) << endl; nrf24l01.startListening(); arch.delay_ms(10); nrf24l01.stopListening(); } int main(void) Loading
src/driver/nrf24l01.cc +101 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,16 @@ #error makeflag nrf24l01_cs_pin required #endif static const uint8_t child_pipe[] = { RX_ADDR_P0, RX_ADDR_P1, RX_ADDR_P2, RX_ADDR_P3, RX_ADDR_P4, RX_ADDR_P5}; static const uint8_t child_payload_size[] = { RX_PW_P0, RX_PW_P1, RX_PW_P2, RX_PW_P3, RX_PW_P4, RX_PW_P5}; static const uint8_t child_pipe_enable[] = { ERX_P0, ERX_P1, ERX_P2, ERX_P3, ERX_P4, ERX_P5}; void Nrf24l01::setup() { spi.setup(); Loading Loading @@ -181,6 +191,85 @@ uint8_t Nrf24l01::write(const void *buf, uint8_t len, bool blocking) return 1; } void Nrf24l01::startListening(void) { writeRegister(NRF_CONFIG, readRegister(NRF_CONFIG) | (1 << PRIM_RX)); writeRegister(NRF_STATUS, (1 << RX_DR) | (1 << TX_DS) | (1 << MAX_RT)); gpio.write(NRF24L01_EN_PIN, 1); // Restore the pipe0 adddress, if exists if (pipe0_reading_address[0] > 0) { writeRegister(RX_ADDR_P0, pipe0_reading_address, addr_width); } else { closeReadingPipe(0); } if (readRegister(FEATURE) & (1 << EN_ACK_PAY)) { flushTx(); } } void Nrf24l01::stopListening(void) { gpio.write(NRF24L01_EN_PIN, 0); arch.delay_us(txRxDelay); if (readRegister(FEATURE) & (1 << EN_ACK_PAY)) { arch.delay_us(txRxDelay); //200 flushTx(); } //flush_rx(); writeRegister(NRF_CONFIG, (readRegister(NRF_CONFIG)) & ~(1 << PRIM_RX)); writeRegister(EN_RXADDR, readRegister(EN_RXADDR) | (1 << child_pipe_enable[0])); // Enable RX on pipe0 } void Nrf24l01::openReadingPipe(uint8_t child, const uint8_t *address) { // If this is pipe 0, cache the address. This is needed because // openWritingPipe() will overwrite the pipe 0 address, so // startListening() will have to restore it. if (child == 0) { pipe0_reading_address[0] = address[0]; pipe0_reading_address[1] = address[1]; pipe0_reading_address[2] = address[2]; pipe0_reading_address[3] = address[3]; pipe0_reading_address[4] = address[4]; } if (child <= 6) { // For pipes 2-5, only write the LSB if (child < 2) { writeRegister(child_pipe[child], address, addr_width); } else { writeRegister(child_pipe[child], address, 1); } writeRegister(child_payload_size[child], payload_size); // Note it would be more efficient to set all of the bits for all open // pipes at once. However, I thought it would make the calling code // more simple to do it this way. writeRegister(EN_RXADDR, readRegister(EN_RXADDR) | (1 << child_pipe_enable[child])); } } /****************************************************************************/ void Nrf24l01::closeReadingPipe(uint8_t pipe) { writeRegister(EN_RXADDR, readRegister(EN_RXADDR) & ~(1 << child_pipe_enable[pipe])); } void Nrf24l01::maskIRQ(bool tx, bool fail, bool rx) { Loading Loading @@ -214,6 +303,18 @@ uint8_t Nrf24l01::readRegister(uint8_t reg) return rxbuf[1]; } uint8_t Nrf24l01::writeRegister(uint8_t reg, const uint8_t *buf, uint8_t len) { txbuf[0] = W_REGISTER | (REGISTER_MASK & reg); beginTransaction(); spi.xmit(1, txbuf, 1, rxbuf); spi.xmit(len, (unsigned char *)buf, 0, NULL); endTransaction(); return rxbuf[0]; } uint8_t Nrf24l01::writeRegister(uint8_t reg, uint8_t value) { txbuf[0] = W_REGISTER | (REGISTER_MASK & reg); Loading