diff options
author | Daniel Friesel <daniel.friesel@uos.de> | 2019-06-24 13:51:17 +0200 |
---|---|---|
committer | Daniel Friesel <daniel.friesel@uos.de> | 2019-06-24 13:51:17 +0200 |
commit | 6bdbdaddc6d7629f51d5c12d7f3480afdf2234f5 (patch) | |
tree | d4100f944a447fdf74657f84801bcb4195a1a601 | |
parent | defe3e47dd837f9f2ae8447b7148893af8e8f1d0 (diff) |
RF24: Add functions required for reading
-rw-r--r-- | include/driver/nrf24l01.h | 159 | ||||
-rw-r--r-- | src/app/nrf24l01test/main.cc | 3 | ||||
-rw-r--r-- | src/driver/nrf24l01.cc | 101 |
3 files changed, 261 insertions, 2 deletions
diff --git a/include/driver/nrf24l01.h b/include/driver/nrf24l01.h index c10332d..44f8205 100644 --- a/include/driver/nrf24l01.h +++ b/include/driver/nrf24l01.h @@ -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() @@ -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. @@ -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(); }; diff --git a/src/app/nrf24l01test/main.cc b/src/app/nrf24l01test/main.cc index c12cbf5..ad1bc11 100644 --- a/src/app/nrf24l01test/main.cc +++ b/src/app/nrf24l01test/main.cc @@ -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) diff --git a/src/driver/nrf24l01.cc b/src/driver/nrf24l01.cc index ff19240..5992b17 100644 --- a/src/driver/nrf24l01.cc +++ b/src/driver/nrf24l01.cc @@ -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(); @@ -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) { @@ -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); |