diff --git a/.github/workflows/build_arduino.yml b/.github/workflows/build_arduino.yml new file mode 100644 index 000000000..c0da07b2e --- /dev/null +++ b/.github/workflows/build_arduino.yml @@ -0,0 +1,157 @@ +name: Arduino CLI build + +on: + pull_request: + paths: + - ".github/workflows/build_arduino.yml" + - "examples/**" + - "!examples/old_backups/recipes/pingpair_maple/**" + + push: + paths: + - ".github/workflows/build_arduino.yml" + - "examples/**" + - "!examples/old_backups/recipes/pingpair_maple/**" + +jobs: + check_formatting: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Check code formatting + uses: per1234/artistic-style-action@main + with: + options-file-path: ./examples/examples_formatter.conf + name-patterns: | + - '*.ino' + - '*.cpp' + - '*.hpp' + - '*.h' + target-paths: | + - examples + build: + needs: check_formatting + runs-on: ubuntu-latest + + strategy: + fail-fast: false + + matrix: + fqbn: + - "arduino:avr:yun" + - "arduino:avr:uno" + - "arduino:avr:diecimila" + - "arduino:avr:nano" + - "arduino:avr:mega" + - "arduino:avr:megaADK" + - "arduino:avr:leonardo" + - "arduino:avr:micro" + - "arduino:avr:esplora" + - "arduino:avr:mini" + - "arduino:avr:ethernet" + - "arduino:avr:fio" + - "arduino:avr:bt" + # - "arduino:avr:LilyPad" # board not found + - "arduino:avr:LilyPadUSB" + - "arduino:avr:pro" + - "arduino:avr:atmegang" + - "arduino:avr:robotControl" + - "arduino:avr:robotMotor" + # - "arduino:avr:gemma" # does not support SPI + - "arduino:avr:circuitplay32u4cat" + - "arduino:avr:yunmini" + - "arduino:avr:chiwawa" + - "arduino:avr:one" + - "arduino:avr:unowifi" + - "arduino:mbed:nano33ble" + # - "arduino:samd:mkr1000" # InterruptConfigure.ino uses pin 2 + # - "arduino:samd:mkrzero" # InterruptConfigure.ino uses pin 2 + # - "arduino:samd:mkrwifi1010" # InterruptConfigure.ino uses pin 2 + - "arduino:samd:nano_33_iot" + # - "arduino:samd:mkrfox1200" # InterruptConfigure.ino uses pin 2 + # - "arduino:samd:mkrwan1300" # InterruptConfigure.ino uses pin 2 + # - "arduino:samd:mkrwan1310" # InterruptConfigure.ino uses pin 2 + # - "arduino:samd:mkrgsm1400" # InterruptConfigure.ino uses pin 2 + # - "arduino:samd:mkrnb1500" # InterruptConfigure.ino uses pin 2 + # - "arduino:samd:mkrvidor4000" # InterruptConfigure.ino uses pin 2 + - "arduino:samd:adafruit_circuitplayground_m0" + - "arduino:samd:mzero_pro_bl" + - "arduino:samd:mzero_bl" + - "arduino:samd:tian" + - "arduino:megaavr:uno2018" + # - "arduino:megaavr:nano4809" # board not found + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Compile examples + uses: arduino/compile-sketches@main + with: + sketch-paths: | + - examples/GettingStarted + - examples/AcknowledgementPayloads + - examples/ManualAcknowledgements + - examples/StreamingData + - examples/MulticeiverDemo + - examples/InterruptConfigure + # - examples/old_backups/GettingStarted_HandlingFailures + # - examples/old_backups/pingpair_dyn + # - examples/old_backups/pingpair_irq + # - examples/old_backups/pingpair_multi_dyn + # - examples/old_backups/pingpair_sleepy + # - examples/old_backups/scanner + # - examples/old_backups/TransferTimeouts + # - examples/old_backups/recipes/led_remote + # - examples/old_backups/recipes/nordic_fob + # - examples/old_backups/recipes/pingpair_maple + fqbn: ${{ matrix.fqbn }} + attiny: + needs: check_formatting + runs-on: ubuntu-latest + + strategy: + fail-fast: false + + matrix: + fqbn: + - ATTinyCore:avr:attinyx4 + - ATTinyCore:avr:attinyx4opti + - ATTinyCore:avr:attinyx4micr + - ATTinyCore:avr:attinyx5 + - ATTinyCore:avr:attinyx5micr + - ATTinyCore:avr:attinyx8 + - ATTinyCore:avr:attinyx8opti + - ATTinyCore:avr:attinyx8micr + - ATTinyCore:avr:attinyx7 + - ATTinyCore:avr:attinyx7opti + - ATTinyCore:avr:attinyx7micr + - ATTinyCore:avr:attinyx61 + - ATTinyCore:avr:attinyx61opti + - ATTinyCore:avr:attinyx41 + - ATTinyCore:avr:attinyx41opti + - ATTinyCore:avr:attinyx41micr + # - ATTinyCore:avr:attiny43 # doesn't seem to support USI implementation of SPI + - ATTinyCore:avr:attiny828 + - ATTinyCore:avr:attiny828opti + - ATTinyCore:avr:attiny1634 + - ATTinyCore:avr:attiny1634opti + - ATTinyCore:avr:attinyx313 + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Compile examples + uses: arduino/compile-sketches@main + with: + platforms: | + - source-url: "http://drazzy.com/package_drazzy.com_index.json" + name: "ATTinyCore:avr" + - name: "arduino:avr" + sketch-paths: | + - examples/rf24_ATTiny/rf24ping85 + - examples/rf24_ATTiny/timingSearch3pin + fqbn: ${{ matrix.fqbn }} \ No newline at end of file diff --git a/.github/workflows/build_linux.yml b/.github/workflows/build_linux.yml index 90af69a33..61aab8ea2 100644 --- a/.github/workflows/build_linux.yml +++ b/.github/workflows/build_linux.yml @@ -1,64 +1,47 @@ -name: C/C++ CI +name: Linux build on: [push] jobs: - build-RPi-BCM2835: + build: runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v1 - - name: provide toolchain - run: | - sudo apt-get update && \ - sudo apt-get install binutils-arm-linux-gnueabi gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf && - arm-linux-gnueabihf-gcc -v && - arm-linux-gnueabihf-g++ -v - - name: configure - run: ./configure --soc=BCM2835 --driver=RPi - - name: make - run: make - - name: make - run: sudo make install + strategy: + fail-fast: false - build-RPi-BCM2836: - runs-on: ubuntu-latest + matrix: + config-options: + - "--soc=BCM2835 --driver=RPi" + - "--soc=BCM2836 --driver=RPi" + - "--soc=BCM2835 --driver=wiringPi --extra-cflags=-I/usr/local/include" + - "--driver=SPIDEV" steps: - uses: actions/checkout@v1 - name: provide toolchain run: | - sudo apt-get update && \ - sudo apt-get install binutils-arm-linux-gnueabi gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf && - arm-linux-gnueabihf-gcc -v && + sudo apt-get update + sudo apt-get install binutils-arm-linux-gnueabi gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf + arm-linux-gnueabihf-gcc -v arm-linux-gnueabihf-g++ -v - - name: configure - run: ./configure --soc=BCM2836 --driver=RPi - - name: make - run: make - - name: make - run: sudo make install - - build-wiringPi-BCM2835: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v1 - - name: provide toolchain - run: | - sudo apt-get update && \ - sudo apt-get install binutils-arm-linux-gnueabi gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf && - arm-linux-gnueabihf-gcc -v && - arm-linux-gnueabihf-g++ -v - - name: provide wiringPi + python3 --version + - name: provide WiringPi + if: ${{ matrix.config-options == '--soc=BCM2835 --driver=wiringPi --extra-cflags=-I/usr/local/include' }} run: | - git clone https://github.com/CoRfr/WiringPi && - cd WiringPi/wiringPi && - CC="arm-linux-gnueabihf-gcc -marm -mtune=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard" V=1 make -j5 && + git clone https://github.com/CoRfr/WiringPi + cd WiringPi/wiringPi + CC="arm-linux-gnueabihf-gcc -marm -mtune=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard" V=1 make -j5 sudo make install - - name: configure - run: ./configure --soc=BCM2835 --driver=wiringPi --extra-cflags=-I/usr/local/include - - name: make + - name: library configure + run: ./configure ${{ matrix.config-options }} + - name: library make run: make - - name: make + - name: library make install run: sudo make install + - name: make linux examples + # compiling examples for wiringPi is broken see nRF24#669 issue + if: ${{ matrix.config-options != '--soc=BCM2835 --driver=wiringPi --extra-cflags=-I/usr/local/include' }} + run: | + cd examples_linux + make + file ./gettingstarted diff --git a/.github/workflows/doxygen.yml b/.github/workflows/doxygen.yml new file mode 100644 index 000000000..6eec36501 --- /dev/null +++ b/.github/workflows/doxygen.yml @@ -0,0 +1,46 @@ +name: DoxyGen build + +on: + pull_request: + branches: + - master + push: + branches: + - master + release: + branches: + - master + types: + - published + - edited + +jobs: + build-doxygen: + runs-on: ubuntu-latest + + steps: + - name: get latest release version number + id: latest_ver + uses: pozetroninc/github-action-get-latest-release@master + with: + repository: nRF24/RF24 + - name: checkout + uses: actions/checkout@v2 + - name: overwrite doxygen tags + run: | + mkdir docs + touch doxygenAction + echo "PROJECT_NUMBER = ${{ steps.latest_ver.outputs.release }}" >> doxygenAction + echo "OUTPUT_DIRECTORY = ./docs" >> doxygenAction + echo "@INCLUDE = doxygenAction" >> Doxyfile + - name: build doxygen + uses: mattnotmitt/doxygen-action@v1 + with: + working-directory: '.' + doxyfile-path: './Doxyfile' + - name: upload to github pages + if: ${{ github.event_name == 'release'}} + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./docs/html \ No newline at end of file diff --git a/.gitignore b/.gitignore index c05f1977e..f4545a15f 100644 --- a/.gitignore +++ b/.gitignore @@ -20,7 +20,16 @@ Session.vim Makefile.inc utility/includes.h examples_linux/* -!examples_linux/**/ -!examples_linux/*.* +examples_linux/**/* +!examples_linux/*.cpp +!examples_linux/*.py +!examples_linux/**/*.cpp +!examples_linux/Makefile +!examples_linux/**/Makefile +*__pycache__/ .directory .idea +doxygenAction +.vscode/ +*venv +*.pyc \ No newline at end of file diff --git a/COMMON_ISSUES.md b/COMMON_ISSUES.md index 51ba65716..8767f057c 100644 --- a/COMMON_ISSUES.md +++ b/COMMON_ISSUES.md @@ -1,8 +1,48 @@ -# Here are the most common issues and their solutions. +# Common Issues -### I'm not receiving acks! -If you're not receiving acks correctly/reliably on data rates lower than 2MBPS, -try adding a big capacitor close to the module/chip. Example issues: [#264](https://github.com/nRF24/RF24/issues/264) [#211](https://github.com/nRF24/RF24/issues/211). +## Settings that must match +Before you report undesirable behavior, please make sure that the +following RF24 configurations match on both receiving and transmitting +nRF24L01 transceivers: +1. `RF24::setAddressWidth()` +2. `RF24::setChannel()` +3. `RF24::setDataRate()` +4. `RF24::setAutoAck()` +5. `RF24::enableDynamicPayloads()` or `RF24::disableDynamicPayloads()` +6. `RF24::enableAckPayload()` or `RF24::disableAckPayload()` (requires auto-ack and + dynamic payloads features) +7. `RF24::setPayloadSize()` (only if the dynamic payloads feature is disabled -- it is disabled by default) +8. `RF24::setCRCLength()` or `RF24::disableCRC()` (the auto-ack feature + automatically enables CRC because it is required) -For this application, please use Electrolytic or Tantalum capacitors. Ceramic capacitors will probably not be good enough. +Also, it helps to think of an address as a path (a commonly shared route) +instead of an identifying device destination. This means that addresses +have to match for a payload to travel from one transceiver to another. +However, the pipe numbers assigned with the matching address do not have +to match. You can think of pipes as parking spots for the packets, while +all packets' payloads live in a TX or RX FIFO buffer. Remember that the +TX FIFO buffers and the RX FIFO buffers both have a maximum occupancy of +3 payloads (regardless of the maximum 32-byte payload size). +## Here are the most common issues and their solutions. + +### write() always returns true after setAutoAck(false) +Don't disabled the auto-ack feature. RF24::write() has no reason to doubt +that the payload was delivered if the auto-ack feature is disabled. We +recommend you read the docs about RF24::setAutoAck() before disabling the +auto-ack feature. + +### write() returns false when the payload was received +If the settings match on both endpoint transceivers, then this can only +mean that the receiving nRF24L01 failed to send an acknowledgement (ACK) +packet back to the transmitting nRF24L01. Usually this is due to +instability (electric noise) in the power lines (VCC and GND) going to +the receiving nRF24L01. + +If you're not receiving ACK packets correctly/reliably on data rates +lower than 2MBPS, try adding a big capacitor close to the module/chip. +Example issues: [#264](https://github.com/nRF24/RF24/issues/264) +[#211](https://github.com/nRF24/RF24/issues/211). + +For reliability, please use Electrolytic or Tantalum capacitors. Ceramic +capacitors may not be good enough (depending on the manufacturing source). diff --git a/Doxyfile b/Doxyfile index dd1302557..acb0481a3 100644 --- a/Doxyfile +++ b/Doxyfile @@ -58,7 +58,7 @@ PROJECT_LOGO = # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. -OUTPUT_DIRECTORY = "../../ArduinoBuilds/RF24 Docs" +OUTPUT_DIRECTORY = ./docs # If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- # directories (in 2 levels) under the output directory of each output format and @@ -928,7 +928,8 @@ EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = bcm2835* \ readme* \ runtest* \ - tests* + tests* \ + README* # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the @@ -2582,3 +2583,4 @@ GENERATE_LEGEND = YES # This tag requires that the tag HAVE_DOT is set to YES. DOT_CLEANUP = YES + diff --git a/README.md b/README.md index d608c5bd5..438662a64 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,7 @@ +![Arduino CLI build](https://github.com/nRF24/RF24/workflows/Arduino%20CLI%20build/badge.svg) -# See http://tmrh20.github.io/RF24 for all documentation +![Linux build](https://github.com/nRF24/RF24/workflows/Linux%20build/badge.svg) + +# See http://nRF24.github.io/RF24 for all documentation ### Check our [contributing guidelines](CONTRIBUTING.md) before opening a pull request diff --git a/RF24.cpp b/RF24.cpp index f8ace8987..520d48a76 100644 --- a/RF24.cpp +++ b/RF24.cpp @@ -21,12 +21,12 @@ void RF24::csn(bool mode) } else { if (mode == HIGH) { - PORTB |= (1<CSN HIGH - delayMicroseconds(100); // allow csn to settle. + PORTB |= (1<CSN HIGH + delayMicroseconds(RF24_CSN_SETTLE_HIGH_DELAY); // allow csn to settle. } else { - PORTB &= ~(1<CSN LOW - delayMicroseconds(11); // allow csn to settle + PORTB &= ~(1<CSN LOW + delayMicroseconds(RF24_CSN_SETTLE_LOW_DELAY); // allow csn to settle } } // Return, CSN toggle complete @@ -103,21 +103,19 @@ inline void RF24::endTransaction() /****************************************************************************/ -uint8_t RF24::read_register(uint8_t reg, uint8_t* buf, uint8_t len) +void RF24::read_register(uint8_t reg, uint8_t* buf, uint8_t len) { - uint8_t status; - #if defined(RF24_LINUX) beginTransaction(); //configures the spi settings for RPi, locks mutex and setting csn low uint8_t * prx = spi_rxbuff; uint8_t * ptx = spi_txbuff; uint8_t size = len + 1; // Add register value to transmit buffer - *ptx++ = ( R_REGISTER | ( REGISTER_MASK & reg ) ); + *ptx++ = (R_REGISTER | reg); while (len--){ *ptx++ = RF24_NOP; } // Dummy operation, just for reading - _SPI.transfernb( (char *) spi_txbuff, (char *) spi_rxbuff, size); + _SPI.transfernb((char *)spi_txbuff, (char *)spi_rxbuff, size); status = *prx++; // status is 1st byte of receive buffer @@ -127,14 +125,12 @@ uint8_t RF24::read_register(uint8_t reg, uint8_t* buf, uint8_t len) #else // !defined(RF24_LINUX) beginTransaction(); - status = _SPI.transfer(R_REGISTER | (REGISTER_MASK & reg)); + status = _SPI.transfer(R_REGISTER | reg); while (len--) { - *buf++ = _SPI.transfer(0xff); + *buf++ = _SPI.transfer(0xFF); } endTransaction(); #endif // !defined(RF24_LINUX) - - return status; } /****************************************************************************/ @@ -148,17 +144,18 @@ uint8_t RF24::read_register(uint8_t reg) uint8_t * prx = spi_rxbuff; uint8_t * ptx = spi_txbuff; - *ptx++ = ( R_REGISTER | ( REGISTER_MASK & reg ) ); + *ptx++ = (R_REGISTER | reg); *ptx++ = RF24_NOP ; // Dummy operation, just for reading - _SPI.transfernb( (char *) spi_txbuff, (char *) spi_rxbuff, 2); + _SPI.transfernb((char *)spi_txbuff, (char *)spi_rxbuff, 2); + status = *prx; // status is 1st byte of receive buffer result = *++prx; // result is 2nd byte of receive buffer endTransaction(); #else // !defined(RF24_LINUX) beginTransaction(); - _SPI.transfer(R_REGISTER | (REGISTER_MASK & reg)); + status = _SPI.transfer(R_REGISTER | reg); result = _SPI.transfer(0xff); endTransaction(); @@ -169,10 +166,8 @@ uint8_t RF24::read_register(uint8_t reg) /****************************************************************************/ -uint8_t RF24::write_register(uint8_t reg, const uint8_t* buf, uint8_t len) +void RF24::write_register(uint8_t reg, const uint8_t* buf, uint8_t len) { - uint8_t status; - #if defined(RF24_LINUX) beginTransaction(); uint8_t * prx = spi_rxbuff; @@ -183,61 +178,68 @@ uint8_t RF24::write_register(uint8_t reg, const uint8_t* buf, uint8_t len) while ( len-- ) *ptx++ = *buf++; - _SPI.transfernb( (char *) spi_txbuff, (char *) spi_rxbuff, size); + _SPI.transfernb((char *)spi_txbuff, (char *)spi_rxbuff, size); status = *prx; // status is 1st byte of receive buffer endTransaction(); #else // !defined(RF24_LINUX) beginTransaction(); - status = _SPI.transfer(W_REGISTER | (REGISTER_MASK & reg)); + status = _SPI.transfer(W_REGISTER | reg); while (len--) { _SPI.transfer(*buf++); } endTransaction(); #endif // !defined(RF24_LINUX) - - return status; } /****************************************************************************/ -uint8_t RF24::write_register(uint8_t reg, uint8_t value) +void RF24::write_register(uint8_t reg, uint8_t value, bool is_cmd_only) { - uint8_t status; - - IF_SERIAL_DEBUG(printf_P(PSTR("write_register(%02x,%02x)\r\n"), reg, value)); - - #if defined(RF24_LINUX) - beginTransaction(); - uint8_t * prx = spi_rxbuff; - uint8_t * ptx = spi_txbuff; - *ptx++ = ( W_REGISTER | ( REGISTER_MASK & reg ) ); - *ptx = value ; - - _SPI.transfernb( (char *) spi_txbuff, (char *) spi_rxbuff, 2); - status = *prx++; // status is 1st byte of receive buffer - endTransaction(); - #else // !defined(RF24_LINUX) - - beginTransaction(); - status = _SPI.transfer(W_REGISTER | (REGISTER_MASK & reg)); - _SPI.transfer(value); - endTransaction(); - - #endif // !defined(RF24_LINUX) - - return status; + if (is_cmd_only) { + if (reg != RF24_NOP) { // don't print the get_status() operation + IF_SERIAL_DEBUG(printf_P(PSTR("write_register(%02x)\r\n"), reg)); + } + beginTransaction(); + status = _SPI.transfer(W_REGISTER | reg); + endTransaction(); + } + else { + IF_SERIAL_DEBUG(printf_P(PSTR("write_register(%02x,%02x)\r\n"), reg, value)); + #if defined(RF24_LINUX) + beginTransaction(); + uint8_t * prx = spi_rxbuff; + uint8_t * ptx = spi_txbuff; + *ptx++ = (W_REGISTER | reg); + *ptx = value; + + _SPI.transfernb((char *)spi_txbuff, (char *)spi_rxbuff, 2); + status = *prx++; // status is 1st byte of receive buffer + endTransaction(); + #else // !defined(RF24_LINUX) + + beginTransaction(); + status = _SPI.transfer(W_REGISTER | reg); + _SPI.transfer(value); + endTransaction(); + #endif // !defined(RF24_LINUX) + } } /****************************************************************************/ -uint8_t RF24::write_payload(const void* buf, uint8_t data_len, const uint8_t writeType) +void RF24::write_payload(const void* buf, uint8_t data_len, const uint8_t writeType) { - uint8_t status; const uint8_t* current = reinterpret_cast(buf); - data_len = rf24_min(data_len, payload_size); - uint8_t blank_len = dynamic_payloads_enabled ? 0 : payload_size - data_len; + uint8_t blank_len = !data_len ? 1 : 0; + if (!dynamic_payloads_enabled) { + data_len = rf24_min(data_len, payload_size); + blank_len = payload_size - data_len; + } + else { + data_len = rf24_min(data_len, 32); + } //printf("[Writing %u bytes %u blanks]",data_len,blank_len); IF_SERIAL_DEBUG(printf("[Writing %u bytes %u blanks]\n", data_len, blank_len); ); @@ -255,7 +257,7 @@ uint8_t RF24::write_payload(const void* buf, uint8_t data_len, const uint8_t wri while ( blank_len-- ) *ptx++ = 0; - _SPI.transfernb( (char *) spi_txbuff, (char *) spi_rxbuff, size); + _SPI.transfernb((char *)spi_txbuff, (char *)spi_rxbuff, size); status = *prx; // status is 1st byte of receive buffer endTransaction(); @@ -272,21 +274,22 @@ uint8_t RF24::write_payload(const void* buf, uint8_t data_len, const uint8_t wri endTransaction(); #endif // !defined(RF24_LINUX) - - return status; } /****************************************************************************/ -uint8_t RF24::read_payload(void* buf, uint8_t data_len) +void RF24::read_payload(void* buf, uint8_t data_len) { - uint8_t status; uint8_t* current = reinterpret_cast(buf); - if (data_len > payload_size) { - data_len = payload_size; + uint8_t blank_len = 0; + if (!dynamic_payloads_enabled) { + data_len = rf24_min(data_len, payload_size); + blank_len = payload_size - data_len; + } + else { + data_len = rf24_min(data_len, 32); } - uint8_t blank_len = dynamic_payloads_enabled ? 0 : payload_size - data_len; //printf("[Reading %u bytes %u blanks]",data_len,blank_len); @@ -305,7 +308,7 @@ uint8_t RF24::read_payload(void* buf, uint8_t data_len) size = data_len + blank_len + 1; // Size has been lost during while, re affect - _SPI.transfernb( (char *) spi_txbuff, (char *) spi_rxbuff, size); + _SPI.transfernb((char *)spi_txbuff, (char *)spi_rxbuff, size); status = *prx++; // 1st byte is status @@ -329,35 +332,21 @@ uint8_t RF24::read_payload(void* buf, uint8_t data_len) endTransaction(); #endif // !defined(RF24_LINUX) - - return status; } /****************************************************************************/ uint8_t RF24::flush_rx(void) { - return spiTrans(FLUSH_RX); + write_register(FLUSH_RX, RF24_NOP, true); + return status; } /****************************************************************************/ uint8_t RF24::flush_tx(void) { - return spiTrans(FLUSH_TX); -} - -/****************************************************************************/ - -uint8_t RF24::spiTrans(uint8_t cmd) -{ - - uint8_t status; - - beginTransaction(); - status = _SPI.transfer(cmd); - endTransaction(); - + write_register(FLUSH_TX, RF24_NOP, true); return status; } @@ -365,20 +354,22 @@ uint8_t RF24::spiTrans(uint8_t cmd) uint8_t RF24::get_status(void) { - return spiTrans(RF24_NOP); + write_register(RF24_NOP, RF24_NOP, true); + return status; } /****************************************************************************/ #if !defined(MINIMAL) -void RF24::print_status(uint8_t status) +void RF24::print_status(uint8_t _status) { - printf_P(PSTR("STATUS\t\t = 0x%02x RX_DR=%x TX_DS=%x MAX_RT=%x RX_P_NO=%x TX_FULL=%x\r\n"), status, (status & _BV(RX_DR)) ? 1 : 0, - (status & _BV(TX_DS)) ? 1 : 0, (status & _BV(MAX_RT)) ? 1 : 0, ((status >> RX_P_NO) & 0x07), (status & _BV(TX_FULL)) ? 1 : 0); + printf_P(PSTR("STATUS\t\t= 0x%02x RX_DR=%x TX_DS=%x MAX_RT=%x RX_P_NO=%x TX_FULL=%x\r\n"), _status, (_status & _BV(RX_DR)) ? 1 : 0, + (_status & _BV(TX_DS)) ? 1 : 0, (_status & _BV(MAX_RT)) ? 1 : 0, ((_status >> RX_P_NO) & 0x07), (_status & _BV(TX_FULL)) ? 1 : 0); } /****************************************************************************/ + void RF24::print_observe_tx(uint8_t value) { printf_P(PSTR("OBSERVE_TX=%02x: POLS_CNT=%x ARC_CNT=%x\r\n"), value, (value >> PLOS_CNT) & 0x0F, (value >> ARC_CNT) & 0x0F); @@ -391,10 +382,9 @@ void RF24::print_byte_register(const char* name, uint8_t reg, uint8_t qty) //char extra_tab = strlen_P(name) < 8 ? '\t' : 0; //printf_P(PSTR(PRIPSTR"\t%c ="),name,extra_tab); #if defined(RF24_LINUX) - printf("%s\t =", name); + printf("%s\t=", name); #else // !defined(RF24_LINUX) - printf_P(PSTR(PRIPSTR - "\t ="),name); + printf_P(PSTR(PRIPSTR"\t="),name); #endif // !defined(RF24_LINUX) while (qty--) { printf_P(PSTR(" 0x%02x"), read_register(reg++)); @@ -408,16 +398,16 @@ void RF24::print_address_register(const char* name, uint8_t reg, uint8_t qty) { #if defined(RF24_LINUX) - printf("%s\t =",name); + printf("%s\t=", name); #else // !defined(RF24_LINUX) - printf_P(PSTR(PRIPSTR"\t ="),name); + printf_P(PSTR(PRIPSTR"\t="), name); #endif // !defined(RF24_LINUX) while (qty--) { uint8_t buffer[addr_width]; - read_register(reg++, buffer, sizeof buffer); + read_register(reg++ & REGISTER_MASK, buffer, sizeof(buffer)); printf_P(PSTR(" 0x")); - uint8_t* bufptr = buffer + sizeof buffer; + uint8_t* bufptr = buffer + sizeof(buffer); while (--bufptr >= buffer) { printf_P(PSTR("%02x"), *bufptr); } @@ -431,8 +421,8 @@ void RF24::print_address_register(const char* name, uint8_t reg, uint8_t qty) /****************************************************************************/ RF24::RF24(uint16_t _cepin, uint16_t _cspin, uint32_t _spi_speed) - :ce_pin(_cepin), csn_pin(_cspin),spi_speed(_spi_speed), payload_size(32), dynamic_payloads_enabled(false), addr_width(5), - csDelay(5)//,pipe0_reading_address(0) + :ce_pin(_cepin), csn_pin(_cspin),spi_speed(_spi_speed), payload_size(32), dynamic_payloads_enabled(true), addr_width(5), _is_p_variant(false), + csDelay(5) { pipe0_reading_address[0] = 0; if(spi_speed <= 35000){ //Handle old BCM2835 speed constants, default to RF24_SPI_SPEED @@ -458,7 +448,12 @@ uint8_t RF24::getChannel() void RF24::setPayloadSize(uint8_t size) { - payload_size = rf24_min(size, 32); + // payload size must be in range [1, 32] + payload_size = rf24_max(1, rf24_min(32, size)); + + // write static payload size setting for all pipes + for (uint8_t i = 0; i < 6; ++i) + write_register(RX_PW_P0 + i, payload_size); } /****************************************************************************/ @@ -472,9 +467,9 @@ uint8_t RF24::getPayloadSize(void) #if !defined(MINIMAL) -static const PROGMEM char rf24_datarate_e_str_0[] = "1MBPS"; -static const PROGMEM char rf24_datarate_e_str_1[] = "2MBPS"; -static const PROGMEM char rf24_datarate_e_str_2[] = "250KBPS"; +static const PROGMEM char rf24_datarate_e_str_0[] = "= 1 MBPS"; +static const PROGMEM char rf24_datarate_e_str_1[] = "= 2 MBPS"; +static const PROGMEM char rf24_datarate_e_str_2[] = "= 250 KBPS"; static const PROGMEM char * const rf24_datarate_e_str_P[] = { rf24_datarate_e_str_0, rf24_datarate_e_str_1, @@ -486,18 +481,18 @@ static const PROGMEM char * const rf24_model_e_str_P[] = { rf24_model_e_str_0, rf24_model_e_str_1, }; -static const PROGMEM char rf24_crclength_e_str_0[] = "Disabled"; -static const PROGMEM char rf24_crclength_e_str_1[] = "8 bits"; -static const PROGMEM char rf24_crclength_e_str_2[] = "16 bits" ; +static const PROGMEM char rf24_crclength_e_str_0[] = "= Disabled"; +static const PROGMEM char rf24_crclength_e_str_1[] = "= 8 bits"; +static const PROGMEM char rf24_crclength_e_str_2[] = "= 16 bits" ; static const PROGMEM char * const rf24_crclength_e_str_P[] = { rf24_crclength_e_str_0, rf24_crclength_e_str_1, rf24_crclength_e_str_2, }; -static const PROGMEM char rf24_pa_dbm_e_str_0[] = "PA_MIN"; -static const PROGMEM char rf24_pa_dbm_e_str_1[] = "PA_LOW"; -static const PROGMEM char rf24_pa_dbm_e_str_2[] = "PA_HIGH"; -static const PROGMEM char rf24_pa_dbm_e_str_3[] = "PA_MAX"; +static const PROGMEM char rf24_pa_dbm_e_str_0[] = "= PA_MIN"; +static const PROGMEM char rf24_pa_dbm_e_str_1[] = "= PA_LOW"; +static const PROGMEM char rf24_pa_dbm_e_str_2[] = "= PA_HIGH"; +static const PROGMEM char rf24_pa_dbm_e_str_3[] = "= PA_MAX"; static const PROGMEM char * const rf24_pa_dbm_e_str_P[] = { rf24_pa_dbm_e_str_0, rf24_pa_dbm_e_str_1, @@ -518,15 +513,29 @@ static const char * const rf24_csn_e_str_P[] = { }; #endif // defined(RF24_LINUX) +static const PROGMEM char rf24_feature_e_str_on[] = "= Enabled"; +static const PROGMEM char rf24_feature_e_str_allowed[] = "= Allowed"; +static const PROGMEM char rf24_feature_e_str_open[] = " open "; +static const PROGMEM char rf24_feature_e_str_closed[] = "closed"; +static const PROGMEM char * const rf24_feature_e_str_P[] = { + rf24_crclength_e_str_0, + rf24_feature_e_str_on, + rf24_feature_e_str_allowed, + rf24_feature_e_str_closed, + rf24_feature_e_str_open +}; + void RF24::printDetails(void) { #if defined(RF24_LINUX) printf("================ SPI Configuration ================\n" ); - printf("CSN Pin \t = %d\n", csn_pin); - printf("CE Pin \t = Custom GPIO%d\n", ce_pin ); + uint8_t bus_ce = csn_pin % 10; + uint8_t bus_numb = (csn_pin - bus_ce) / 10; + printf("CSN Pin\t\t= /dev/spidev%d.%d\n", bus_numb, bus_ce); + printf("CE Pin\t\t= Custom GPIO%d\n", ce_pin); #endif - printf_P(PSTR("SPI Speedz\t = %d Mhz\n"),(uint8_t)(spi_speed/1000000)); //Print the SPI speed on non-Linux devices + printf_P(PSTR("SPI Speedz\t= %d Mhz\n"),(uint8_t)(spi_speed/1000000)); //Print the SPI speed on non-Linux devices #if defined(RF24_LINUX) printf("================ NRF Configuration ================\n"); #endif // defined(RF24_LINUX) @@ -545,21 +554,97 @@ void RF24::printDetails(void) print_byte_register(PSTR("CONFIG\t"), NRF_CONFIG); print_byte_register(PSTR("DYNPD/FEATURE"), DYNPD, 2); - printf_P(PSTR("Data Rate\t = " + printf_P(PSTR("Data Rate\t" PRIPSTR "\r\n"),(char*)pgm_read_ptr(&rf24_datarate_e_str_P[getDataRate()])); - printf_P(PSTR("Model\t\t = " + printf_P(PSTR("Model\t\t= " PRIPSTR "\r\n"),(char*)pgm_read_ptr(&rf24_model_e_str_P[isPVariant()])); - printf_P(PSTR("CRC Length\t = " + printf_P(PSTR("CRC Length\t" PRIPSTR "\r\n"),(char*)pgm_read_ptr(&rf24_crclength_e_str_P[getCRCLength()])); - printf_P(PSTR("PA Power\t = " + printf_P(PSTR("PA Power\t" PRIPSTR "\r\n"),(char*)pgm_read_ptr(&rf24_pa_dbm_e_str_P[getPALevel()])); - printf_P(PSTR("ARC\t\t = %d\r\n"), getARC()); + printf_P(PSTR("ARC\t\t= %d\r\n"), getARC()); } +void RF24::printPrettyDetails(void) { + + #if defined(RF24_LINUX) + printf("================ SPI Configuration ================\n"); + uint8_t bus_ce = csn_pin % 10; + uint8_t bus_numb = (csn_pin - bus_ce) / 10; + printf("CSN Pin\t\t\t= /dev/spidev%d.%d\n", bus_numb, bus_ce); + printf("CE Pin\t\t\t= Custom GPIO%d\n", ce_pin); + #endif + printf_P(PSTR("SPI Frequency\t\t= %d Mhz\n"), (uint8_t)(spi_speed / 1000000)); //Print the SPI speed on non-Linux devices + #if defined(RF24_LINUX) + printf("================ NRF Configuration ================\n"); + #endif // defined(RF24_LINUX) + + uint8_t channel = getChannel(); + uint16_t frequency = (uint16_t)channel + 2400; + printf_P(PSTR("Channel\t\t\t= %u (~ %u MHz)\r\n"), channel, frequency); + + printf_P(PSTR("RF Data Rate\t\t" + PRIPSTR + "\r\n"), (char*)pgm_read_ptr(&rf24_datarate_e_str_P[getDataRate()])); + printf_P(PSTR("RF Power Amplifier\t" + PRIPSTR + "\r\n"), (char*)pgm_read_ptr(&rf24_pa_dbm_e_str_P[getPALevel()])); + printf_P(PSTR("RF Low Noise Amplifier\t" + PRIPSTR + "\r\n"), (char*)pgm_read_ptr(&rf24_feature_e_str_P[(bool)(read_register(RF_SETUP) & 1) * 1])); + printf_P(PSTR("CRC Length\t\t" + PRIPSTR + "\r\n"), (char*)pgm_read_ptr(&rf24_crclength_e_str_P[getCRCLength()])); + printf_P(PSTR("Address Length\t\t= %d bytes\r\n"), (read_register(SETUP_AW) & 3) + 2); + printf_P(PSTR("Static Payload Length\t= %d bytes\r\n"), getPayloadSize()); + + uint8_t setupRetry = read_register(SETUP_RETR); + printf_P(PSTR("Auto Retry Delay\t= %d microseconds\r\n"), (uint16_t)(setupRetry >> ARD) * 250 + 250); + printf_P(PSTR("Auto Retry Attempts\t= %d maximum\r\n"), setupRetry & 0x0F); + + uint8_t observeTx = read_register(OBSERVE_TX); + printf_P(PSTR("Packets lost on\n current channel\t= %d\r\n"), observeTx >> 4); + printf_P(PSTR("Retry attempts made for\n last transmission\t= %d\r\n"), observeTx & 0x0F); + + uint8_t features = read_register(FEATURE); + printf_P(PSTR("Multicast\t\t" + PRIPSTR + "\r\n"), (char*)pgm_read_ptr(&rf24_feature_e_str_P[(bool)(features & _BV(EN_DYN_ACK)) * 2])); + printf_P(PSTR("Custom ACK Payload\t" + PRIPSTR + "\r\n"), (char*)pgm_read_ptr(&rf24_feature_e_str_P[(bool)(features & _BV(EN_ACK_PAY)) * 1])); + + uint8_t dynPl = read_register(DYNPD); + uint8_t autoAck = read_register(EN_AA); + printf_P(PSTR("Dynamic Payloads\t" + PRIPSTR + "\r\n"), (char*)pgm_read_ptr(&rf24_feature_e_str_P[(dynPl && (features &_BV(EN_DPL))) * 1])); + printf_P(PSTR("Auto Acknowledgment\t" + PRIPSTR + "\r\n"), (char*)pgm_read_ptr(&rf24_feature_e_str_P[(bool)(autoAck & 1) * 1])); + + config_reg = read_register(NRF_CONFIG); + printf_P(PSTR("Primary Mode\t\t= %cX\r\n"), config_reg & _BV(PWR_UP) ? 'T' : 'R'); + print_address_register(PSTR("TX address\t"), TX_ADDR); + + uint8_t openPipes = read_register(EN_RXADDR); + for (uint8_t i = 0; i < 6; ++i) { + bool isOpen = openPipes & _BV(i); + printf_P(PSTR("pipe %u (" + PRIPSTR + ") bound"), i, (char*)pgm_read_ptr(&rf24_feature_e_str_P[isOpen + 3])); + if (i < 2) { + print_address_register(PSTR(""), RX_ADDR_P0 + i); + } + else { + print_byte_register(PSTR(""), RX_ADDR_P0 + i); + } + } +} #endif // !defined(MINIMAL) /****************************************************************************/ @@ -571,7 +656,7 @@ bool RF24::begin(void) #if defined(MRAA) GPIO(); - gpio.begin(ce_pin,csn_pin); + gpio.begin(ce_pin, csn_pin); #endif #if defined(RF24_RPi) @@ -632,37 +717,56 @@ bool RF24::begin(void) // Set 1500uS (minimum for 32B payload in ESB@250KBPS) timeouts, to make testing a little easier // WARNING: If this is ever lowered, either 250KBS mode with AA is broken or maximum packet - // sizes must never be used. See documentation for a more complete explanation. - setRetries(5, 15); - + // sizes must never be used. See datasheet for a more complete explanation. + setRetries(5, 15); + // Then set the data rate to the slowest (and most reliable) speed supported by all // hardware. setDataRate(RF24_1MBPS); - // Disable dynamic payloads, to match dynamic_payloads_enabled setting - Reset value is 0 + // detect if is a plus variant & use old toggle features command accordingly + uint8_t before_toggle = read_register(FEATURE); toggle_features(); - write_register(FEATURE, 0); - write_register(DYNPD, 0); + uint8_t after_toggle = read_register(FEATURE); + _is_p_variant = before_toggle == after_toggle; + if (after_toggle){ + if (_is_p_variant){ + // module did not experience power-on-reset (#401) + toggle_features(); + } + // allow use of multicast parameter and dynamic payloads by default + write_register(FEATURE, 0); + } + ack_payloads_enabled = false; // ack payloads disabled by default + write_register(DYNPD, 0); // disable dynamic payloads by default (for all pipes) dynamic_payloads_enabled = false; - ack_payloads_enabled = false; - - // Reset current status - // Notice reset and flush is the last thing we do - write_register(NRF_STATUS, _BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT)); + write_register(EN_AA, 0x3F); // enable auto-ack on all pipes + write_register(EN_RXADDR, 0); // close all RX pipes + setPayloadSize(32); // set static payload size to 32 (max) bytes by default + setAddressWidth(5); // set default address length to (max) 5 bytes // Set up default configuration. Callers can always change it later. // This channel should be universally safe and not bleed over into adjacent // spectrum. setChannel(76); + // Reset current status + // Notice reset and flush is the last thing we do + write_register(NRF_STATUS, _BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT)); + + // Flush buffers flush_rx(); flush_tx(); - // Clear CONFIG register, Enable PTX, Power Up & 16-bit CRC + // Clear CONFIG register: + // Reflect all IRQ events on IRQ pin + // Enable PTX + // Power Up + // 16-bit CRC (CRC required by auto-ack) // Do not write CE high so radio will remain in standby I mode // PTX should use only 22uA of power - write_register(NRF_CONFIG, (_BV(EN_CRC) | _BV(CRCO)) ); + write_register(NRF_CONFIG, (_BV(EN_CRC) | _BV(CRCO)) ); config_reg = read_register(NRF_CONFIG); powerUp(); @@ -690,26 +794,17 @@ void RF24::startListening(void) #if !defined(RF24_TINY) && !defined(LITTLEWIRE) powerUp(); #endif - /* Notes Once ready for next release - * 1. Can update stopListening() to use config_reg var and ack_payloads_enabled var instead of SPI rx/tx - * 2. Update txDelay defaults: 240 for 2MBPS, 280 for 1MBPS, 505 for 250KBPS per initial testing - * 3. Allows time for slower devices to update with the faster startListening() function prior to updating stopListening() & adjusting txDelay - */ config_reg |= _BV(PRIM_RX); - write_register(NRF_CONFIG,config_reg); + write_register(NRF_CONFIG, config_reg); write_register(NRF_STATUS, _BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT)); ce(HIGH); - // Restore the pipe0 adddress, if exists + + // Restore the pipe0 address, if exists if (pipe0_reading_address[0] > 0) { write_register(RX_ADDR_P0, pipe0_reading_address, addr_width); } else { closeReadingPipe(0); } - - if(ack_payloads_enabled){ - flush_tx(); - } - } /****************************************************************************/ @@ -720,15 +815,14 @@ void RF24::stopListening(void) { ce(LOW); + //delayMicroseconds(100); delayMicroseconds(txDelay); - - if (read_register(FEATURE) & _BV(EN_ACK_PAY)) { - delayMicroseconds(txDelay); //200 + if (ack_payloads_enabled){ flush_tx(); } - //flush_rx(); + config_reg &= ~_BV(PRIM_RX); - write_register(NRF_CONFIG,config_reg); + write_register(NRF_CONFIG, config_reg); #if defined(RF24_TINY) || defined(LITTLEWIRE) // for 3 pins solution TX mode is only left with additonal powerDown/powerUp cycle @@ -738,9 +832,6 @@ void RF24::stopListening(void) } #endif write_register(EN_RXADDR, read_register(EN_RXADDR) | _BV(pgm_read_byte(&child_pipe_enable[0]))); // Enable RX on pipe0 - - //delayMicroseconds(100); - } /****************************************************************************/ @@ -813,11 +904,11 @@ bool RF24::write(const void* buf, uint8_t len, const bool multicast) ce(LOW); - uint8_t status = write_register(NRF_STATUS, _BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT)); + write_register(NRF_STATUS, _BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT)); //Max retries exceeded if (status & _BV(MAX_RT)) { - flush_tx(); //Only going to be 1 packet int the FIFO at a time using this method, so just flush + flush_tx(); // Only going to be 1 packet in the FIFO at a time using this method, so just flush return 0; } //TX OK 1 or 0 @@ -838,16 +929,15 @@ bool RF24::writeBlocking(const void* buf, uint8_t len, uint32_t timeout) //This way the FIFO will fill up and allow blocking until packets go through //The radio will auto-clear everything in the FIFO as long as CE remains high - uint32_t timer = millis(); //Get the time that the payload transmission started + uint32_t timer = millis(); // Get the time that the payload transmission started - while ((get_status() - & (_BV(TX_FULL)))) { //Blocking only if FIFO is full. This will loop and block until TX is successful or timeout + while ((get_status() & (_BV(TX_FULL)))) { // Blocking only if FIFO is full. This will loop and block until TX is successful or timeout - if (get_status() & _BV(MAX_RT)) { //If MAX Retries have been reached - reUseTX(); //Set re-transmit and clear the MAX_RT interrupt flag + if (status & _BV(MAX_RT)) { // If MAX Retries have been reached + reUseTX(); // Set re-transmit and clear the MAX_RT interrupt flag if (millis() - timer > timeout) { - return 0; - } //If this payload has exceeded the user-defined timeout, exit and return 0 + return 0; // If this payload has exceeded the user-defined timeout, exit and return 0 + } } #if defined(FAILURE_HANDLING) || defined(RF24_LINUX) if (millis() - timer > (timeout + 95)) { @@ -861,18 +951,18 @@ bool RF24::writeBlocking(const void* buf, uint8_t len, uint32_t timeout) } //Start Writing - startFastWrite(buf, len, 0); //Write the payload if a buffer is clear + startFastWrite(buf, len, 0); // Write the payload if a buffer is clear - return 1; //Return 1 to indicate successful transmission + return 1; // Return 1 to indicate successful transmission } /****************************************************************************/ void RF24::reUseTX() { - write_register(NRF_STATUS, _BV(MAX_RT)); //Clear max retry flag - spiTrans(REUSE_TX_PL); - ce(LOW); //Re-Transfer packet + write_register(NRF_STATUS, _BV(MAX_RT)); //Clear max retry flag + write_register(REUSE_TX_PL, RF24_NOP, true); + ce(LOW); //Re-Transfer packet ce(HIGH); } @@ -891,8 +981,8 @@ bool RF24::writeFast(const void* buf, uint8_t len, const bool multicast) //Blocking only if FIFO is full. This will loop and block until TX is successful or fail while ((get_status() & (_BV(TX_FULL)))) { - if (get_status() & _BV(MAX_RT)) { - return 0; //Return 0. The previous payload has been retransmitted + if (status & _BV(MAX_RT)) { + return 0; //Return 0. The previous payload has not been retransmitted // From the user perspective, if you get a 0, just keep trying to send the same payload } #if defined(FAILURE_HANDLING) || defined(RF24_LINUX) @@ -904,8 +994,7 @@ bool RF24::writeFast(const void* buf, uint8_t len, const bool multicast) } #endif } - //Start Writing - startFastWrite(buf, len, multicast); + startFastWrite(buf, len, multicast); // Start Writing return 1; } @@ -925,30 +1014,27 @@ bool RF24::writeFast(const void* buf, uint8_t len) void RF24::startFastWrite(const void* buf, uint8_t len, const bool multicast, bool startTx) { //TMRh20 - //write_payload( buf,len); write_payload(buf, len, multicast ? W_TX_PAYLOAD_NO_ACK : W_TX_PAYLOAD); if (startTx) { ce(HIGH); } - } /****************************************************************************/ //Added the original startWrite back in so users can still use interrupts, ack payloads, etc //Allows the library to pass all tests -void RF24::startWrite(const void* buf, uint8_t len, const bool multicast) +bool RF24::startWrite(const void* buf, uint8_t len, const bool multicast) { // Send the payload - - //write_payload( buf, len ); write_payload(buf, len, multicast ? W_TX_PAYLOAD_NO_ACK : W_TX_PAYLOAD); ce(HIGH); #if !defined(F_CPU) || F_CPU > 20000000 delayMicroseconds(10); #endif ce(LOW); + return !(status & _BV(TX_FULL)); } /****************************************************************************/ @@ -967,7 +1053,7 @@ bool RF24::txStandBy() uint32_t timeout = millis(); #endif while (!(read_register(FIFO_STATUS) & _BV(TX_EMPTY))) { - if (get_status() & _BV(MAX_RT)) { + if (status & _BV(MAX_RT)) { write_register(NRF_STATUS, _BV(MAX_RT)); ce(LOW); flush_tx(); //Non blocking, flush the data @@ -999,7 +1085,7 @@ bool RF24::txStandBy(uint32_t timeout, bool startTx) uint32_t start = millis(); while (!(read_register(FIFO_STATUS) & _BV(TX_EMPTY))) { - if (get_status() & _BV(MAX_RT)) { + if (status & _BV(MAX_RT)) { write_register(NRF_STATUS, _BV(MAX_RT)); ce(LOW); // Set re-transmit ce(HIGH); @@ -1027,7 +1113,7 @@ bool RF24::txStandBy(uint32_t timeout, bool startTx) /****************************************************************************/ void RF24::maskIRQ(bool tx, bool fail, bool rx) -{ +{ /* clear the interrupt flags */ config_reg &= ~(1 << MASK_MAX_RT | 1 << MASK_TX_DS | 1 << MASK_RX_DR); /* set the specified interrupt flags */ @@ -1039,21 +1125,7 @@ void RF24::maskIRQ(bool tx, bool fail, bool rx) uint8_t RF24::getDynamicPayloadSize(void) { - uint8_t result = 0; - - #if defined(RF24_LINUX) - spi_txbuff[0] = R_RX_PL_WID; - spi_txbuff[1] = 0xff; - beginTransaction(); - _SPI.transfernb( (char *) spi_txbuff, (char *) spi_rxbuff, 2); - result = spi_rxbuff[1]; - endTransaction(); - #else - beginTransaction(); - _SPI.transfer(R_RX_PL_WID); - result = _SPI.transfer(0xff); - endTransaction(); - #endif + uint8_t result = read_register(R_RX_PL_WID); if (result > 32) { flush_rx(); @@ -1094,8 +1166,8 @@ void RF24::read(void* buf, uint8_t len) // Fetch the payload read_payload(buf, len); - //Clear the two possible interrupt flags with one command - write_register(NRF_STATUS, _BV(RX_DR) | _BV(MAX_RT) | _BV(TX_DS)); + //Clear the only applicable interrupt flags + write_register(NRF_STATUS, _BV(RX_DR)); } @@ -1105,7 +1177,7 @@ void RF24::whatHappened(bool& tx_ok, bool& tx_fail, bool& rx_ready) { // Read the status & reset the status in one easy call // Or is that such a good idea? - uint8_t status = write_register(NRF_STATUS, _BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT)); + write_register(NRF_STATUS, _BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT)); // Report to the user what happened tx_ok = status & _BV(TX_DS); @@ -1122,11 +1194,6 @@ void RF24::openWritingPipe(uint64_t value) write_register(RX_ADDR_P0, reinterpret_cast(&value), addr_width); write_register(TX_ADDR, reinterpret_cast(&value), addr_width); - - - //const uint8_t max_payload_size = 32; - //write_register(RX_PW_P0,rf24_min(payload_size,max_payload_size)); - write_register(RX_PW_P0, payload_size); } /****************************************************************************/ @@ -1136,17 +1203,11 @@ void RF24::openWritingPipe(const uint8_t* address) // expects it LSB first too, so we're good. write_register(RX_ADDR_P0, address, addr_width); write_register(TX_ADDR, address, addr_width); - - //const uint8_t max_payload_size = 32; - //write_register(RX_PW_P0,rf24_min(payload_size,max_payload_size)); - write_register(RX_PW_P0, payload_size); } /****************************************************************************/ static const PROGMEM uint8_t child_pipe[] = {RX_ADDR_P0, RX_ADDR_P1, RX_ADDR_P2, RX_ADDR_P3, RX_ADDR_P4, RX_ADDR_P5}; -static const PROGMEM uint8_t child_payload_size[] = {RX_PW_P0, RX_PW_P1, RX_PW_P2, - RX_PW_P3, RX_PW_P4, RX_PW_P5}; void RF24::openReadingPipe(uint8_t child, uint64_t address) { @@ -1165,8 +1226,6 @@ void RF24::openReadingPipe(uint8_t child, uint64_t address) write_register(pgm_read_byte(&child_pipe[child]), reinterpret_cast(&address), 1); } - write_register(pgm_read_byte(&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. @@ -1205,7 +1264,6 @@ void RF24::openReadingPipe(uint8_t child, const uint8_t* address) } else { write_register(pgm_read_byte(&child_pipe[child]), address, 1); } - write_register(pgm_read_byte(&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 @@ -1227,7 +1285,7 @@ void RF24::closeReadingPipe(uint8_t pipe) void RF24::toggle_features(void) { beginTransaction(); - _SPI.transfer(ACTIVATE); + status = _SPI.transfer(ACTIVATE); _SPI.transfer(0x73); endTransaction(); } @@ -1276,21 +1334,32 @@ void RF24::disableDynamicPayloads(void) void RF24::enableAckPayload(void) { - // - // enable ack payload and dynamic payload features - // + // enable ack payloads and dynamic payload features - //toggle_features(); - write_register(FEATURE, read_register(FEATURE) | _BV(EN_ACK_PAY) | _BV(EN_DPL)); + if (!ack_payloads_enabled){ + write_register(FEATURE, read_register(FEATURE) | _BV(EN_ACK_PAY) | _BV(EN_DPL)); - IF_SERIAL_DEBUG(printf("FEATURE=%i\r\n", read_register(FEATURE))); + IF_SERIAL_DEBUG(printf("FEATURE=%i\r\n", read_register(FEATURE))); - // - // Enable dynamic payload on pipes 0 & 1 - // - write_register(DYNPD, read_register(DYNPD) | _BV(DPL_P1) | _BV(DPL_P0)); - dynamic_payloads_enabled = true; - ack_payloads_enabled = true; + // Enable dynamic payload on pipes 0 + write_register(DYNPD, read_register(DYNPD) | _BV(DPL_P0)); + dynamic_payloads_enabled = true; + ack_payloads_enabled = true; + } +} + +/****************************************************************************/ + +void RF24::disableAckPayload(void) +{ + // disable ack payloads (leave dynamic payload features as is) + if (ack_payloads_enabled){ + write_register(FEATURE, read_register(FEATURE) | ~_BV(EN_ACK_PAY)); + + IF_SERIAL_DEBUG(printf("FEATURE=%i\r\n", read_register(FEATURE))); + + ack_payloads_enabled = false; + } } /****************************************************************************/ @@ -1304,40 +1373,19 @@ void RF24::enableDynamicAck(void) write_register(FEATURE, read_register(FEATURE) | _BV(EN_DYN_ACK)); IF_SERIAL_DEBUG(printf("FEATURE=%i\r\n", read_register(FEATURE))); - - } /****************************************************************************/ -void RF24::writeAckPayload(uint8_t pipe, const void* buf, uint8_t len) +bool RF24::writeAckPayload(uint8_t pipe, const void* buf, uint8_t len) { - const uint8_t* current = reinterpret_cast(buf); + if (ack_payloads_enabled){ + const uint8_t* current = reinterpret_cast(buf); - uint8_t data_len = rf24_min(len, 32); - - #if defined(RF24_LINUX) - beginTransaction(); - uint8_t * ptx = spi_txbuff; - uint8_t size = data_len + 1 ; // Add register value to transmit buffer - *ptx++ = W_ACK_PAYLOAD | ( pipe & 0x07 ); - while ( data_len-- ){ - *ptx++ = *current++; + write_payload(current, len, W_ACK_PAYLOAD | (pipe & 0x07)); + return !(status & _BV(TX_FULL)); } - - _SPI.transfern( (char *) spi_txbuff, size); - endTransaction(); - #else - beginTransaction(); - _SPI.transfer(W_ACK_PAYLOAD | (pipe & 0x07)); - - while (data_len--) { - _SPI.transfer(*current++); - } - endTransaction(); - - #endif - + return 0; } /****************************************************************************/ @@ -1351,20 +1399,21 @@ bool RF24::isAckPayloadAvailable(void) bool RF24::isPVariant(void) { - rf24_datarate_e dR = getDataRate(); - bool result = setDataRate(RF24_250KBPS); - setDataRate(dR); - return result; + return _is_p_variant; } /****************************************************************************/ void RF24::setAutoAck(bool enable) { - if (enable) { + if (enable){ write_register(EN_AA, 0x3F); - } else { + }else{ write_register(EN_AA, 0); + // accomodate ACK payloads feature + if (ack_payloads_enabled){ + disableAckPayload(); + } } } @@ -1372,12 +1421,15 @@ void RF24::setAutoAck(bool enable) void RF24::setAutoAck(uint8_t pipe, bool enable) { - if (pipe <= 6) { + if (pipe < 6) { uint8_t en_aa = read_register(EN_AA); if (enable) { en_aa |= _BV(pipe); - } else { + }else{ en_aa &= ~_BV(pipe); + if (ack_payloads_enabled && !pipe){ + disableAckPayload(); + } } write_register(EN_AA, en_aa); } @@ -1404,13 +1456,13 @@ void RF24::setPALevel(uint8_t level, bool lnaEnable) uint8_t setup = read_register(RF_SETUP) & 0xF8; - if (level > 3) { // If invalid level, go to max PA - level = (RF24_PA_MAX << 1) + lnaEnable; // +1 to support the SI24R1 chip extra bit + if (level > 3) { // If invalid level, go to max PA + level = (RF24_PA_MAX << 1) + lnaEnable; // +1 to support the SI24R1 chip extra bit } else { - level = (level << 1) + lnaEnable; // Else set level as requested + level = (level << 1) + lnaEnable; // Else set level as requested } - write_register(RF_SETUP, setup |= level); // Write it to the chip + write_register(RF_SETUP, setup |= level); // Write it to the chip } /****************************************************************************/ @@ -1521,7 +1573,7 @@ rf24_crclength_e RF24::getCRCLength(void) rf24_crclength_e result = RF24_CRC_DISABLED; uint8_t AA = read_register(EN_AA); config_reg = read_register(NRF_CONFIG); - + if (config_reg & _BV(EN_CRC) || AA) { if (config_reg & _BV(CRCO)) { result = RF24_CRC_16; @@ -1548,20 +1600,49 @@ void RF24::setRetries(uint8_t delay, uint8_t count) } /****************************************************************************/ -void RF24::startConstCarrier(rf24_pa_dbm_e level, uint8_t channel ) +void RF24::startConstCarrier(rf24_pa_dbm_e level, uint8_t channel) { - write_register(RF_SETUP, (read_register(RF_SETUP)) | _BV(CONT_WAVE)); - write_register(RF_SETUP, (read_register(RF_SETUP)) | _BV(PLL_LOCK)); + stopListening(); + write_register(RF_SETUP, read_register(RF_SETUP) | _BV(CONT_WAVE) | _BV(PLL_LOCK)); + if (isPVariant()){ + setAutoAck(0); + setRetries(0, 0); + uint8_t dummy_buf[32]; + for (uint8_t i = 0; i < 32; ++i) + dummy_buf[i] = 0xFF; + + // use write_register() instead of openWritingPipe() to bypass + // truncation of the address with the current RF24::addr_width value + write_register(TX_ADDR, reinterpret_cast(&dummy_buf), 5); + flush_tx(); // so we can write to top level + + // use write_register() instead of write_payload() to bypass + // truncation of the payload with the current RF24::payload_size value + write_register(W_TX_PAYLOAD, reinterpret_cast(&dummy_buf), 32); + + disableCRC(); + } setPALevel(level); setChannel(channel); - IF_SERIAL_DEBUG( printf_P(PSTR("RF_SETUP=%02x\r\n"), read_register(RF_SETUP) ) ); + IF_SERIAL_DEBUG(printf_P(PSTR("RF_SETUP=%02x\r\n"), read_register(RF_SETUP))); ce(HIGH); + if (isPVariant()){ + delay(1); // datasheet says 1 ms is ok in this instance + ce(LOW); + reUseTX(); + } } /****************************************************************************/ void RF24::stopConstCarrier() -{ - write_register(RF_SETUP, (read_register(RF_SETUP)) & ~_BV(CONT_WAVE)); - write_register(RF_SETUP, (read_register(RF_SETUP)) & ~_BV(PLL_LOCK)); +{ + /* + * A note from the datasheet: + * Do not use REUSE_TX_PL together with CONT_WAVE=1. When both these + * registers are set the chip does not react when setting CE low. If + * however, both registers are set PWR_UP = 0 will turn TX mode off. + */ + powerDown(); // per datasheet recommendation (just to be safe) + write_register(RF_SETUP, read_register(RF_SETUP) & ~_BV(CONT_WAVE) & ~_BV(PLL_LOCK)); ce(LOW); } diff --git a/RF24.h b/RF24.h index 442431d58..de67fc89c 100644 --- a/RF24.h +++ b/RF24.h @@ -23,43 +23,89 @@ #include #endif + /** - * Power Amplifier level. - * - * For use with setPALevel() + * @defgroup PALevel Power Amplifier level + * Power Amplifier level. The units dBm (decibel-milliwatts or dBmW) + * represents a logarithmic signal loss. + * @see RF24::setPALevel() + * @see RF24::getPALevel() + * @{ */ typedef enum { + /** + * (0) represents: + * nRF24L01 | Si24R1 with
lnaEnabled = 1 | Si24R1 with
lnaEnabled = 0 + * :-------:|:-----------------------------:|:----------------------------: + * -18 dBm | -6 dBm | -12 dBm + */ RF24_PA_MIN = 0, + /** + * (1) represents: + * nRF24L01 | Si24R1 with
lnaEnabled = 1 | Si24R1 with
lnaEnabled = 0 + * :-------:|:-----------------------------:|:----------------------------: + * -12 dBm | 0 dBm | -4 dBm + */ RF24_PA_LOW, + /** + * (2) represents: + * nRF24L01 | Si24R1 with
lnaEnabled = 1 | Si24R1 with
lnaEnabled = 0 + * :-------:|:-----------------------------:|:----------------------------: + * -6 dBm | 3 dBm | 1 dBm + */ RF24_PA_HIGH, + /** + * (3) represents: + * nRF24L01 | Si24R1 with
lnaEnabled = 1 | Si24R1 with
lnaEnabled = 0 + * :-------:|:-----------------------------:|:----------------------------: + * 0 dBm | 7 dBm | 4 dBm + */ RF24_PA_MAX, + /** + * (4) This should not be used and remains for backward compatibility. + */ RF24_PA_ERROR } rf24_pa_dbm_e; /** - * Data rate. How fast data moves through the air. - * - * For use with setDataRate() + * @} + * @defgroup Datarate datarate + * How fast data moves through the air. Units are in bits per second (bps). + * @see RF24::setDataRate() + * @see RF24::getDataRate() + * @{ */ typedef enum { + /** (0) represents 1 Mbps */ RF24_1MBPS = 0, + /** (1) represents 2 Mbps */ RF24_2MBPS, + /** (2) represents 250 kbps */ RF24_250KBPS } rf24_datarate_e; /** - * CRC Length. How big (if any) of a CRC is included. - * - * For use with setCRCLength() + * @} + * @defgroup CRCLength CRC length + * The length of a CRC checksum that is used (if any).
Cyclical Redundancy + * Checking (CRC) is commonly used to ensure data integrity. + * @see RF24::setCRCLength() + * @see RF24::getCRCLength() + * @see RF24::disableCRC() + * @{ */ typedef enum { + /** (0) represents no CRC checksum is used */ RF24_CRC_DISABLED = 0, + /** (1) represents CRC 8 bit checksum is used */ RF24_CRC_8, + /** (2) represents CRC 16 bit checksum is used */ RF24_CRC_16 } rf24_crclength_e; /** - * Driver for nRF24L01(+) 2.4GHz Wireless Transceiver + * @} + * @brief Driver class for nRF24L01(+) 2.4GHz Wireless Transceiver */ class RF24 { @@ -84,12 +130,14 @@ class RF24 { uint8_t spi_rxbuff[32+1] ; //SPI receive buffer (payload max 32 bytes) uint8_t spi_txbuff[32+1] ; //SPI transmit buffer (payload max 32 bytes + 1 byte for the command) #endif + uint8_t status; /** The status byte returned from every SPI transaction */ uint8_t payload_size; /**< Fixed size of payloads */ bool dynamic_payloads_enabled; /**< Whether dynamic payloads are enabled. */ bool ack_payloads_enabled; /**< Whether ack payloads are enabled. */ uint8_t pipe0_reading_address[5]; /**< Last address set on pipe 0 for reading. */ uint8_t addr_width; /**< The address width to use - 3,4 or 5 bytes. */ uint8_t config_reg; /**< For storing the value of the NRF_CONFIG register */ + bool _is_p_variant; /** For storing the result of testing the toggleFeatures() affect */ protected: @@ -118,7 +166,7 @@ class RF24 { * Creates a new instance of this driver. Before using, you create an instance * and send in the unique pins that this chip is connected to. * - * See http://tmrh20.github.io/RF24/pages.html for device specific information
+ * See [Related Pages](pages.html) for device specific information
* * @note Users can specify default SPI speed by modifying `#define RF24_SPI_SPEED` in RF24_config.h
* For Arduino, SPI speed will only be properly configured this way on devices supporting SPI TRANSACTIONS
@@ -155,13 +203,18 @@ class RF24 { * 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. * + * Open reading pipe 1 using address `0xCCCECCCECC` * @code - * Open reading pipe 1 using address CCCECCCECC - * - * byte address[] = { 0xCC,0xCE,0xCC,0xCE,0xCC }; + * byte address[] = {0xCC, 0xCE, 0xCC, 0xCE, 0xCC}; * radio.openReadingPipe(1,address); * radio.startListening(); * @endcode + * + * @note If there was a call to openReadingPipe() about pipe 0 prior to + * calling this function, then this function will re-write the address + * that was last set to reading pipe 0. This is because openWritingPipe() + * will overwrite the address to reading pipe 0 for proper auto-ack + * functionality. */ void startListening(void); @@ -171,8 +224,12 @@ class RF24 { * Do this before calling write(). * @code * radio.stopListening(); - * radio.write(&data,sizeof(data)); + * radio.write(&data, sizeof(data)); * @endcode + * + * @note When the ACK payloads feature is enabled, the TX FIFO buffers are + * flushed when calling this function. This is meant to discard any ACK + * payloads that were not appended to acknowledgment packets. */ void stopListening(void); @@ -183,50 +240,85 @@ class RF24 { * radio.read(&data,sizeof(data)); * } * @endcode + * + * @see available(uint8_t*) + * * @return True if there is a payload available, false if none is + * + * @warning This function relies on the information about the pipe number + * that received the next available payload. According to the datasheet, + * the data about the pipe number that received the next available payload + * is "unreliable" during a FALLING transition on the IRQ pin. This means + * you should call whatHappened() before calling this function + * during an ISR (Interrupt Service Routine).
For example: + * @code + * void isrCallbackFunction() { + * bool tx_ds, tx_df, rx_dr; + * radio.whatHappened(tx_ds, tx_df, rx_dr); // resets the IRQ pin to HIGH + * radio.available(); // returned data should now be reliable + * } + * + * void setup() { + * pinMode(IRQ_PIN, INPUT); + * attachInterrupt(digitalPinToInterrupt(IRQ_PIN), isrCallbackFunction, FALLING); + * } + * @endcode */ bool available(void); /** - * Read from the available payload + * Read payload data from the RX FIFO buffer(s). * - * The length of data read should the next available payload's length - * @sa getPayloadSize(), getDynamicPayloadSize() + * The length of data read is usually the next available payload's length + * @see getPayloadSize() + * @see getDynamicPayloadSize() * - * @note I specifically chose 'void*' as a data type to make it easier + * @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. This * value should match the length of the object referenced using the - * `buf` parameter. There is no bounds checking implemented here. - * - * @code - * if(radio.available()){ - * radio.read(&data,sizeof(data)); - * } - * @endcode - * @return No return value. Use available(). + * `buf` parameter. The absolute maximum number of bytes that can be read + * in one call is 32 (for dynamic payload lengths) or whatever number was + * previously passed to setPayloadSize() (for static payload lengths). * @remark Remember that each call to read() fetches data from the * RX FIFO beginning with the first byte from the first available * payload. A payload is not removed from the RX FIFO until it's * entire length (or more) is fetched using read(). * @remarks - * - If `len` parameter's value is less than the available payload's + * - If @a len parameter's value is less than the available payload's * length, then the payload remains in the RX FIFO. - * - If `len` parameter's value is greater than the first of multiple - * available payloads, then the data returned to the `buf` + * - If @a len parameter's value is greater than the first of multiple + * available payloads, then the data saved to the @a buf * parameter's object will be supplemented with data from the next * available payload. - * - If `len` parameter's value is greater than the last available + * - If @a len parameter's value is greater than the last available * payload's length, then the last byte in the payload is used as - * padding for the data returned to the `buf` parameter's object. - * The nRF24L01 will continue returning the last byte from the last + * padding for the data saved to the @a buf parameter's object. + * The nRF24L01 will repeatedly use the last byte from the last * payload even when read() is called with an empty RX FIFO. + * + * @note To use this function in the python wrapper, remember that + * only the @a len parameter is required because this function (in the + * python wrapper) returns the payload data as a buffer protocol object + * (bytearray object). + * @code{.py} + * # let `radio` be the instantiated RF24 object + * if radio.available(): + * length = radio.getDynamicPayloadSize() # or radio.getPayloadSize() for static payload sizes + * received_payload = radio.read(length) + * @endcode + * + * @return No return value. Use available(). + * @note This function no longer returns a boolean. Use available to + * determine if packets are available. The `RX_DR` Interrupt flag is now + * cleared with this function instead of when calling available(). + * @code + * if(radio.available()) { + * radio.read(&data, sizeof(data)); + * } + * @endcode */ void read(void* buf, uint8_t len); @@ -251,7 +343,24 @@ class RF24 { * radio.stopListening(); * radio.write(&data,sizeof(data)); * @endcode - * @return True if the payload was delivered successfully and an ACK was received, or upon successfull transmission if auto-ack is disabled. + * + * @note The @a len parameter must be omitted when using the python + * wrapper because the length of the payload is determined automatically. + *
To use this function in the python wrapper: + * @code{.py} + * # let `radio` be the instantiated RF24 object + * buffer = b"Hello World" # a `bytes` object + * radio.write(buffer) + * @endcode + * + * @return + * - `true` if the payload was delivered successfully and an acknowledgement + * (ACK packet) was received. If auto-ack is disabled, then any attempt + * to transmit will also return true (even if the payload was not + * received). + * - `false` if the payload was sent but was not acknowledged with an ACK + * packet. This condition can only be reported if the auto-ack feature + * is on. */ bool write(const void* buf, uint8_t len); @@ -259,25 +368,41 @@ class RF24 { * New: Open a pipe for writing via byte array. Old addressing format retained * for compatibility. * - * Only one writing pipe can be open at once, but you can change the address - * you'll write to. Call stopListening() first. + * Only one writing pipe can be opened at once, but this function changes + * the address that is used to transmit (ACK payloads/packets do not apply + * here). Be sure to call stopListening() prior to calling this function. * * Addresses are assigned via a byte array, default is 5 byte address length - s * + * * @code - * uint8_t addresses[][6] = {"1Node","2Node"}; + * uint8_t addresses[][6] = {"1Node", "2Node"}; * radio.openWritingPipe(addresses[0]); * @endcode * @code - * uint8_t address[] = { 0xCC,0xCE,0xCC,0xCE,0xCC }; + * uint8_t address[] = { 0xCC, 0xCE, 0xCC, 0xCE, 0xCC }; * radio.openWritingPipe(address); * address[0] = 0x33; - * radio.openReadingPipe(1,address); + * radio.openReadingPipe(1, address); * @endcode - * @see setAddressWidth * - * @param address The address of the pipe to open. Coordinate these pipe - * addresses amongst nodes on the network. + * @warning This function will overwrite the address set to reading pipe 0 + * as stipulated by the datasheet for proper auto-ack functionality in TX + * mode. Use this function to ensure proper transmission acknowledgement + * when the address set to reading pipe 0 (via openReadingPipe()) does not + * match the address passed to this function. If the auto-ack feature is + * disabled, then this function will still overwrite the address for + * reading pipe 0 regardless. + * + * @see setAddressWidth() + * @see startListening() + * + * @param address The address to be used for outgoing transmissions (uses + * pipe 0). Coordinate this address amongst other receiving nodes (the + * pipe numbers don't need to match). + * + * @remark There is no address length parameter because this function will + * always write the number of bytes that the radio addresses are configured + * to use (set with setAddressWidth()). */ void openWritingPipe(const uint8_t* address); @@ -288,26 +413,38 @@ class RF24 { * 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 + * @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 store a single byte, borrowing up to 4 additional bytes from pipe 1 per the + * assigned address width.
+ * 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]); + * uint8_t addresses[][6] = {"Prime", "2Node", "3xxxx", "4xxxx"}; + * openReadingPipe(0, addresses[0]); // address used is "Prime" + * openReadingPipe(1, addresses[1]); // address used is "2Node" + * openReadingPipe(2, addresses[2]); // address used is "3Node" + * openReadingPipe(3, addresses[3]); // address used is "4Node" * @endcode * - * @warning Pipe 0 is also used by the writing pipe so should typically be avoided as a reading pipe.
- * If used, the reading pipe 0 address needs to be restored at avery call to startListening(), and the address
- * is ONLY restored if the LSB is a non-zero value.
See http://maniacalbits.blogspot.com/2013/04/rf24-addressing-nrf24l01-radios-require.html - * - * @param number Which pipe# to open, 0-5. + * @warning If the reading pipe 0 is opened by this function, the address + * passed to this function (for pipe 0) will be restored at every call to + * startListening(), but the address for pipe 0 is ONLY restored if the LSB is a + * non-zero value.
Read + * http://maniacalbits.blogspot.com/2013/04/rf24-addressing-nrf24l01-radios-require.html + * to understand how to avoid using malformed addresses. This address + * restoration is implemented because of the underlying neccessary + * functionality of openWritingPipe(). + * + * @param number Which pipe to open. Only pipe numbers 0-5 are available, + * an address assigned to any pipe number not in that range will be ignored. * @param address The 24, 32 or 40 bit address of the pipe to open. + * + * @remark There is no address length parameter because this function will + * always write the number of bytes (for pipes 0 and 1) that the radio + * addresses are configured to use (set with setAddressWidth()). */ void openReadingPipe(uint8_t number, const uint8_t* address); @@ -337,26 +474,94 @@ class RF24 { void printDetails(void); /** - * Test whether there are bytes available to be read in the + * Print a giant block of debugging information to stdout. This function + * differs from printDetails() because it makes the information more + * understandable without having to look up the datasheet or convert + * hexadecimal to binary. Only use this function if your application can + * spare a few extra bytes of memory. + * + * @warning Does nothing if stdout is not defined. See fdevopen in stdio.h + * The printf.h file is included with the library for Arduino. + * @code + * #include + * setup(){ + * Serial.begin(115200); + * printf_begin(); + * ... + * } + * @endcode + */ + void printPrettyDetails(void); + + /** + * Test whether there are bytes available to be read from the * FIFO buffers. * - * @param[out] pipe_num Which pipe has the payload available + * @note This function is named `available_pipe()` in the python wrapper. + * Additionally, the `available_pipe()` function (which + * takes no arguments) returns a 2 item tuple containing (ordered by + * tuple's indices): + * - A boolean describing if there is a payload available to read from + * the RX FIFO buffers. + * - The pipe number that received the next available payload in the RX + * FIFO buffers. If the item at the tuple's index 0 is `False`, then + * this pipe number is invalid. + * @note To use this function in python: + * @code{.py} + * # let `radio` be the instatiated RF24 object + * has_payload, pipe_number = radio.available_pipe() # expand the tuple to 2 variables + * if has_payload: + * print("Received a payload with pipe", pipe_number) + * @endcode * + * @param[out] pipe_num Which pipe has the payload available * @code * uint8_t pipeNum; * if(radio.available(&pipeNum)){ - * radio.read(&data,sizeof(data)); - * Serial.print("Got data on pipe"); + * radio.read(&data, sizeof(data)); + * Serial.print("Received data on pipe "); * Serial.println(pipeNum); * } * @endcode - * @return True if there is a payload available, false if none is + * + * @warning According to the datasheet, the data saved to @a pipe_num is + * "unreliable" during a FALLING transition on the IRQ pin. This means you + * should call whatHappened() before calling this function during + * an ISR (Interrupt Service Routine).
For example: + * @code + * void isrCallbackFunction() { + * bool tx_ds, tx_df, rx_dr; + * radio.whatHappened(tx_ds, tx_df, rx_dr); // resets the IRQ pin to HIGH + * uint8_t pipe; // initialize pipe data + * radio.available(&pipe); // pipe data should now be reliable + * } + * + * void setup() { + * pinMode(IRQ_PIN, INPUT); + * attachInterrupt(digitalPinToInterrupt(IRQ_PIN), isrCallbackFunction, FALLING); + * } + * @endcode + * + * @return + * - `true` if there is a payload available in the top (first out) + * level RX FIFO. + * - `false` if there is nothing available in the RX FIFO because it is + * empty. */ bool available(uint8_t* pipe_num); /** - * Check if the radio needs to be read. Can be used to prevent data loss - * @return True if all three 32-byte radio buffers are full + * Use this function to check if the radio's RX FIFO levels are all + * occupied. This can be used to prevent data loss because any incoming + * transmissions are rejected if there is no unoccupied levels in the RX + * FIFO to store the incoming payload. Remember that each level can hold + * up to a maximum of 32 bytes. + * @return + * - `true` if all three 3 levels of the RX FIFO buffers are occupied. + * - `false` if there is one or more levels available in the RX FIFO + * buffers. Remember that this does not always mean that the RX FIFO + * buffers are empty; use available() to see if the RX FIFO buffers are + * empty or not. */ bool rxFifoFull(); @@ -388,19 +593,37 @@ class RF24 { void powerUp(void); /** - * Write for single NOACK writes. Optionally disables acknowledgements/autoretries for a single write. - * - * @note enableDynamicAck() must be called to enable this feature - * - * Can be used with enableAckPayload() to request a response - * @see enableDynamicAck() - * @see setAutoAck() - * @see write() - * - * @param buf Pointer to the data to be sent - * @param len Number of bytes to be sent - * @param multicast Request ACK (0), NOACK (1) - */ + * Write for single NOACK writes. Optionally disable + * acknowledgements/auto-retries for a single payload using the + * multicast parameter set to true. + * + * Can be used with enableAckPayload() to request a response + * @see setAutoAck() + * @see write() + * + * @param buf Pointer to the data to be sent + * @param len Number of bytes to be sent + * @param multicast Request ACK response (false), or no ACK response + * (true). Be sure to have called enableDynamicAck() at least once before + * setting this parameter. + * @return + * - `true` if the payload was delivered successfully and an acknowledgement + * (ACK packet) was received. If auto-ack is disabled, then any attempt + * to transmit will also return true (even if the payload was not + * received). + * - `false` if the payload was sent but was not acknowledged with an ACK + * packet. This condition can only be reported if the auto-ack feature + * is on. + * + * @note The @a len parameter must be omitted when using the python + * wrapper because the length of the payload is determined automatically. + *
To use this function in the python wrapper: + * @code{.py} + * # let `radio` be the instantiated RF24 object + * buffer = b"Hello World" # a `bytes` object + * radio.write(buffer, False) # False = the multicast parameter + * @endcode + */ bool write(const void* buf, uint8_t len, const bool multicast); /** @@ -429,21 +652,54 @@ class RF24 { * * @param buf Pointer to the data to be sent * @param len Number of bytes to be sent - * @return True if the payload was delivered successfully false if not + * @return + * - `true` if the payload was delivered successfully and an acknowledgement + * (ACK packet) was received. If auto-ack is disabled, then any attempt + * to transmit will also return true (even if the payload was not + * received). + * - `false` if the payload was sent but was not acknowledged with an ACK + * packet. This condition can only be reported if the auto-ack feature + * is on. + * + * @note The @a len parameter must be omitted when using the python + * wrapper because the length of the payload is determined automatically. + *
To use this function in the python wrapper: + * @code{.py} + * # let `radio` be the instantiated RF24 object + * buffer = b"Hello World" # a `bytes` object + * radio.writeFast(buffer) + * @endcode */ bool writeFast(const void* buf, uint8_t len); /** - * WriteFast for single NOACK writes. Disables acknowledgements/autoretries for a single write. - * - * @note enableDynamicAck() must be called to enable this feature - * @see enableDynamicAck() - * @see setAutoAck() - * - * @param buf Pointer to the data to be sent - * @param len Number of bytes to be sent - * @param multicast Request ACK (0) or NOACK (1) - */ + * WriteFast for single NOACK writes. Optionally disable + * acknowledgements/auto-retries for a single payload using the + * multicast parameter set to true. + * + * @see setAutoAck() + * + * @param buf Pointer to the data to be sent + * @param len Number of bytes to be sent + * @param multicast Request ACK response (false), or no ACK response + * (true). Be sure to have called enableDynamicAck() at least once before + * setting this parameter. + * @return + * - `true` if the payload passed to @a buf was loaded in the TX FIFO. + * - `false` if the payload passed to @a buf was not loaded in the TX FIFO + * because a previous payload already in the TX FIFO failed to + * transmit. This condition can only be reported if the auto-ack feature + * is on. + * + * @note The @a len parameter must be omitted when using the python + * wrapper because the length of the payload is determined automatically. + *
To use this function in the python wrapper: + * @code{.py} + * # let `radio` be the instantiated RF24 object + * buffer = b"Hello World" # a `bytes` object + * radio.writeFast(buffer, False) # False = the multicast parameter + * @endcode + */ bool writeFast(const void* buf, uint8_t len, const bool multicast); /** @@ -455,12 +711,11 @@ class RF24 { * retransmit is enabled, the nRF24L01 is never in TX mode long enough to disobey this rule. Allow the FIFO * to clear by issuing txStandBy() or ensure appropriate time between transmissions. * - * @code * Example (Full blocking): - * - * radio.writeBlocking(&buf,32,1000); //Wait up to 1 second to write 1 payload to the buffers - * txStandBy(1000); //Wait up to 1 second for the payload to send. Return 1 if ok, 0 if failed. - * //Blocks only until user timeout or success. Data flushed on fail. + * @code + * radio.writeBlocking(&buf, sizeof(buf), 1000); // Wait up to 1 second to write 1 payload to the buffers + * radio.txStandBy(1000); // Wait up to 1 second for the payload to send. Return 1 if ok, 0 if failed. + * // Blocks only until user timeout or success. Data flushed on fail. * @endcode * @note If used from within an interrupt, the interrupt should be disabled until completion, and sei(); called to enable millis(). * @see txStandBy() @@ -470,7 +725,22 @@ class RF24 { * @param buf Pointer to the data to be sent * @param len Number of bytes to be sent * @param timeout User defined timeout in milliseconds. - * @return True if the payload was loaded into the buffer successfully false if not + * + * @note The @a len parameter must be omitted when using the python + * wrapper because the length of the payload is determined automatically. + *
To use this function in the python wrapper: + * @code{.py} + * # let `radio` be the instantiated RF24 object + * buffer = b"Hello World" # a `bytes` object + * radio.writeBlocking(buffer, 1000) # 1000 means wait at most 1 second + * @endcode + * + * @return + * - `true` if the payload passed to @a buf was loaded in the TX FIFO. + * - `false` if the payload passed to @a buf was not loaded in the TX FIFO + * because a previous payload already in the TX FIFO failed to + * transmit. This condition can only be reported if the auto-ack feature + * is on. */ bool writeBlocking(const void* buf, uint8_t len, uint32_t timeout); @@ -487,81 +757,127 @@ class RF24 { * * Relies on built-in auto retry functionality. * - * @code * Example (Partial blocking): - * - * radio.writeFast(&buf,32); - * radio.writeFast(&buf,32); - * radio.writeFast(&buf,32); //Fills the FIFO buffers up - * bool ok = txStandBy(); //Returns 0 if failed. 1 if success. - * //Blocks only until MAX_RT timeout or success. Data flushed on fail. + * @code + * radio.writeFast(&buf,32); + * radio.writeFast(&buf,32); + * radio.writeFast(&buf,32); //Fills the FIFO buffers up + * bool ok = txStandBy(); //Returns 0 if failed. 1 if success. + * //Blocks only until MAX_RT timeout or success. Data flushed on fail. * @endcode * @see txStandBy(unsigned long timeout) - * @return True if transmission is successful - * + * @return + * - `true` if all payloads in the TX FIFO were delivered successfully and + * an acknowledgement (ACK packet) was received for each. If auto-ack is + * disabled, then any attempt to transmit will also return true (even if + * the payload was not received). + * - `false` if a payload was sent but was not acknowledged with an ACK + * packet. This condition can only be reported if the auto-ack feature + * is on. */ bool txStandBy(); /** * This function allows extended blocking and auto-retries per a user defined timeout - * @code - * Fully Blocking Example: * - * radio.writeFast(&buf,32); - * radio.writeFast(&buf,32); - * radio.writeFast(&buf,32); //Fills the FIFO buffers up - * bool ok = txStandBy(1000); //Returns 0 if failed after 1 second of retries. 1 if success. - * //Blocks only until user defined timeout or success. Data flushed on fail. + * Fully Blocking Example: + * @code + * radio.writeFast(&buf,32); + * radio.writeFast(&buf,32); + * radio.writeFast(&buf,32); //Fills the FIFO buffers up + * bool ok = txStandBy(1000); //Returns 0 if failed after 1 second of retries. 1 if success. + * //Blocks only until user defined timeout or success. Data flushed on fail. * @endcode * @note If used from within an interrupt, the interrupt should be disabled until completion, and sei(); called to enable millis(). * @param timeout Number of milliseconds to retry failed payloads * @param startTx If this is set to `true`, then this function puts the nRF24L01 * in TX Mode. `false` leaves the primary mode (TX or RX) as it is, which can * prevent the mandatory wait time to change modes. - * @return True if transmission is successful - * + * @return + * - `true` if all payloads in the TX FIFO were delivered successfully and + * an acknowledgement (ACK packet) was received for each. If auto-ack is + * disabled, then any attempt to transmit will also return true (even if + * the payload was not received). + * - `false` if a payload was sent but was not acknowledged with an ACK + * packet. This condition can only be reported if the auto-ack feature + * is on. */ bool txStandBy(uint32_t timeout, bool startTx = 0); /** - * Write an ack payload for the specified pipe + * Write an acknowledgement (ACK) payload for the specified pipe + * + * The next time a message is received on a specified @a pipe, the data in + * @a buf will be sent back in the ACK payload. * - * The next time a message is received on @p pipe, the data in @p buf will - * be sent back in the acknowledgement. * @see enableAckPayload() * @see enableDynamicPayloads() - * @warning Only three of these can be pending at any time as there are only 3 FIFO buffers.
Dynamic payloads must be enabled. - * @note Ack payloads are handled automatically by the radio chip when a payload is received. Users should generally - * write an ack payload as soon as startListening() is called, so one is available when a regular payload is received. - * @note Ack payloads are dynamic payloads. This only works on pipes 0&1 by default. Call - * enableDynamicPayloads() to enable on all pipes. + * + * @note ACK payloads are handled automatically by the radio chip when a + * regular payload is received. It is important to discard regular payloads + * in the TX FIFO (using flush_tx()) before loading the first ACK payload + * into the TX FIFO. This function can be called before and after calling + * startListening(). + * + * @warning Only three of these can be pending at any time as there are + * only 3 FIFO buffers.
Dynamic payloads must be enabled. + * + * @note ACK payloads are dynamic payloads. Calling enableAckPayload() + * will automatically enable dynamic payloads on pipe 0 (required for TX + * mode when expecting ACK payloads). To use ACK payloads on any other + * pipe in RX mode, call enableDynamicPayloads(). * * @param pipe Which pipe# (typically 1-5) will get this response. * @param buf Pointer to data that is sent * @param len Length of the data to send, up to 32 bytes max. Not affected * by the static payload set by setPayloadSize(). - */ - void writeAckPayload(uint8_t pipe, const void* buf, uint8_t len); - - /** - * Determine if an ack payload was received in the most recent call to - * write(). The regular available() can also be used. - * - * Call read() to retrieve the ack payload. - * - * @return True if an ack payload is available. - */ - bool isAckPayloadAvailable(void); - - /** - * Call this when you get an interrupt to find out why * - * Tells you what caused the interrupt, and clears the state of - * interrupts. + * @note The @a len parameter must be omitted when using the python + * wrapper because the length of the payload is determined automatically. + *
To use this function in the python wrapper: + * @code{.py} + * # let `radio` be the instantiated RF24 object + * buffer = b"Hello World" # a `bytes` object + * radio.writeAckPayload(1, buffer) # load an ACK payload for response on pipe 1 + * @endcode * - * @param[out] tx_ok The send was successful (TX_DS) - * @param[out] tx_fail The send failed, too many retries (MAX_RT) - * @param[out] rx_ready There is a message waiting to be read (RX_DS) + * @return + * - `true` if the payload was loaded into the TX FIFO. + * - `false` if the payload wasn't loaded into the TX FIFO because it is + * already full or the ACK payload feature is not enabled using + * enableAckPayload(). + */ + bool writeAckPayload(uint8_t pipe, const void* buf, uint8_t len); + + /** + * Call this when you get an Interrupt Request (IRQ) to find out why + * + * This function describes what event triggered the IRQ pin to go active + * LOW and clears the status of all events. + * + * @see maskIRQ() + * + * @param[out] tx_ok The transmission attempt completed (TX_DS). This does + * not imply that the transmitted data was received by another radio, rather + * this only reports if the attempt to send was completed. This will + * always be `true` when the auto-ack feature is disabled. + * @param[out] tx_fail The transmission failed to be acknowledged, meaning + * too many retries (MAX_RT) were made while expecting an ACK packet. This + * event is only triggered when auto-ack feature is enabled. + * @param[out] rx_ready There is a newly received payload (RX_DR) saved to + * RX FIFO buffers. Remember that the RX FIFO can only hold up to 3 + * payloads. Once the RX FIFO is full, all further received transmissions + * are rejected until there is space to save new data in the RX FIFO + * buffers. + * + * @note This function expects no parameters in the python wrapper. + * Instead, this function returns a 3 item tuple describing the IRQ + * events' status.
To use this function in the python wrapper: + * @code{.py} + * # let`radio` be the instantiated RF24 object + * tx_ds, tx_df, rx_dr = radio.whatHappened() # get IRQ status flags + * print("tx_ds: {}, tx_df: {}, rx_dr: {}".format(tx_ds, tx_df, rx_dr)) + * @endcode */ void whatHappened(bool& tx_ok, bool& tx_fail, bool& rx_ready); @@ -580,17 +896,29 @@ class RF24 { * @see startWrite() * @see writeBlocking() * - * For single noAck writes see: - * @see enableDynamicAck() + * For single noAck writes: * @see setAutoAck() * * @param buf Pointer to the data to be sent * @param len Number of bytes to be sent - * @param multicast Request ACK (0) or NOACK (1) + * @param multicast Request ACK response (false), or no ACK response + * (true). Be sure to have called enableDynamicAck() at least once before + * setting this parameter. * @param startTx If this is set to `true`, then this function sets the * nRF24L01's CE pin to active (enabling TX transmissions). `false` has no - * effect on the nRF24L01's CE pin. - * @return True if the payload was delivered successfully false if not + * effect on the nRF24L01's CE pin and simply loads the payload into the + * TX FIFO. + * + * @note The @a len parameter must be omitted when using the python + * wrapper because the length of the payload is determined automatically. + *
To use this function in the python wrapper: + * @code{.py} + * # let `radio` be the instantiated RF24 object + * buffer = b"Hello World" # a `bytes` object + * radio.startFastWrite(buffer, False, True) # 3rd parameter is optional + * # False means expecting ACK response (multicast parameter) + * # True means initiate transmission (startTx parameter) + * @endcode */ void startFastWrite(const void* buf, uint8_t len, const bool multicast, bool startTx = 1); @@ -606,41 +934,78 @@ class RF24 { * @see whatHappened() * * For single noAck writes see: - * @see enableDynamicAck() * @see setAutoAck() * * @param buf Pointer to the data to be sent * @param len Number of bytes to be sent - * @param multicast Request ACK (0) or NOACK (1) - * + * @param multicast Request ACK response (false), or no ACK response + * (true). Be sure to have called enableDynamicAck() at least once before + * setting this parameter. + * + * @return + * - `true` if payload was written to the TX FIFO buffers and the + * transmission was started. + * - `false` if the TX FIFO is full and the payload could not be written. In + * this condition, the transmission process is restarted. + * @note The @a len parameter must be omitted when using the python + * wrapper because the length of the payload is determined automatically. + *
To use this function in the python wrapper: + * @code{.py} + * # let `radio` be the instantiated RF24 object + * buffer = b"Hello World" # a `bytes` object + * radio.startWrite(buffer, False) # False = the multicast parameter + * @endcode */ - void startWrite(const void* buf, uint8_t len, const bool multicast); + bool startWrite(const void* buf, uint8_t len, const bool multicast); /** - * This function is mainly used internally to take advantage of the auto payload - * re-use functionality of the chip, but can be beneficial to users as well. + * The function will instruct the radio to re-use the payload in the + * top level (first out) of the TX FIFO buffers. This is used internally + * by writeBlocking() to initiate retries when a TX failure + * occurs. Retries are automatically initiated except with the standard + * write(). This way, data is not flushed from the buffer until calling + * flush_tx(). If the TX FIFO has only the one payload (in the top level), + * the re-used payload can be overwritten by using write(), writeFast(), + * writeBlocking(), startWrite(), or startFastWrite(). If the TX FIFO has + * other payloads enqueued, then the aforementioned functions will attempt + * to enqueue the a new payload in the TX FIFO (does not overwrite the top + * level of the TX FIFO). Currently, stopListening() also calls flush_tx() + * when ACK payloads are enabled (via enableAckPayload()). * - * The function will instruct the radio to re-use the data in the FIFO buffers, - * and instructs the radio to re-send once the timeout limit has been reached. - * Used by writeFast and writeBlocking to initiate retries when a TX failure - * occurs. Retries are automatically initiated except with the standard write(). - * This way, data is not flushed from the buffer until switching between modes. + * Upon exiting, this function will set the CE pin HIGH to initiate the + * re-transmission process. If only 1 re-transmission is desired, then the + * CE pin should be set to LOW after the mandatory minumum pulse duration + * of 10 microseconds. + * + * @remark This function only applies when taking advantage of the + * auto-retry feature. See setAutoAck() and setRetries() to configure the + * auto-retry feature. * * @note This is to be used AFTER auto-retry fails if wanting to resend - * using the built-in payload reuse features. - * After issuing reUseTX(), it will keep reending the same payload forever or until - * a payload is written to the FIFO, or a flush_tx command is given. + * using the built-in payload reuse feature. After issuing reUseTX(), it + * will keep resending the same payload until a transmission failure + * occurs or the CE pin is set to LOW (whichever comes first). In the + * event of a re-transmission failure, simply call this function again to + * resume re-transmission of the same payload. */ void reUseTX(); /** - * Empty the transmit buffer. This is generally not required in standard operation. - * May be required in specific cases after stopListening() , if operating at 250KBPS data rate. + * Empty all 3 of the TX (transmit) FIFO buffers. This is automatically + * called by stopListening() if ACK payloads are enabled. However, + * startListening() does not call this function. * * @return Current value of status register */ uint8_t flush_tx(void); + /** + * Empty all 3 of the RX (receive) FIFO buffers. + * + * @return Current value of status register + */ + uint8_t flush_rx(void); + /** * Test whether there was a carrier on the line for the * previous listening period. @@ -666,7 +1031,8 @@ class RF24 { * radio.read(0,0); * } * @endcode - * @return true if signal => -64dBm, false if not + * @return true if a signal less than or equal to -64dBm was detected, + * false if not. */ bool testRPD(void); @@ -683,41 +1049,42 @@ class RF24 { } /** - * 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. - */ + * Close a pipe after it has been previously opened. + * Can be safely called without having previously opened a pipe. + * @param pipe Which pipe number to close, any integer not in range [0, 5] + * is ignored. + */ void closeReadingPipe(uint8_t pipe); /** - * - * If a failure has been detected, it usually indicates a hardware issue. By default the library - * will cease operation when a failure is detected. - * This should allow advanced users to detect and resolve intermittent hardware issues. - * - * In most cases, the radio must be re-enabled via radio.begin(); and the appropriate settings - * applied after a failure occurs, if wanting to re-enable the device immediately. - * - * The three main failure modes of the radio include: - * - * Writing to radio: Radio unresponsive - Fixed internally by adding a timeout to the internal write functions in RF24 (failure handling) - * - * Reading from radio: Available returns true always - Fixed by adding a timeout to available functions by the user. This is implemented internally in RF24Network. - * - * Radio configuration settings are lost - Fixed by monitoring a value that is different from the default, and re-configuring the radio if this setting reverts to the default. - * - * See the included example, GettingStarted_HandlingFailures - * - * @code - * if(radio.failureDetected){ - * radio.begin(); // Attempt to re-configure the radio with defaults - * radio.failureDetected = 0; // Reset the detection value - * radio.openWritingPipe(addresses[1]); // Re-configure pipe addresses - * radio.openReadingPipe(1,addresses[0]); - * report_failure(); // Blink leds, send a message, etc. to indicate failure - * } - * @endcode - */ + * + * If a failure has been detected, it usually indicates a hardware issue. By default the library + * will cease operation when a failure is detected. + * This should allow advanced users to detect and resolve intermittent hardware issues. + * + * In most cases, the radio must be re-enabled via radio.begin(); and the appropriate settings + * applied after a failure occurs, if wanting to re-enable the device immediately. + * + * The three main failure modes of the radio include: + * + * Writing to radio: Radio unresponsive - Fixed internally by adding a timeout to the internal write functions in RF24 (failure handling) + * + * Reading from radio: Available returns true always - Fixed by adding a timeout to available functions by the user. This is implemented internally in RF24Network. + * + * Radio configuration settings are lost - Fixed by monitoring a value that is different from the default, and re-configuring the radio if this setting reverts to the default. + * + * See the included example, GettingStarted_HandlingFailures + * + * @code + * if(radio.failureDetected){ + * radio.begin(); // Attempt to re-configure the radio with defaults + * radio.failureDetected = 0; // Reset the detection value + * radio.openWritingPipe(addresses[1]); // Re-configure pipe addresses + * radio.openReadingPipe(1,addresses[0]); + * report_failure(); // Blink leds, send a message, etc. to indicate failure + * } + * @endcode + */ //#if defined (FAILURE_HANDLING) bool failureDetected; //#endif @@ -733,34 +1100,60 @@ class RF24 { /**@{*/ /** - * Set the address width from 3 to 5 bytes (24, 32 or 40 bit) - * - * @param a_width The address width to use: 3,4 or 5 - */ - + * Set the address width from 3 to 5 bytes (24, 32 or 40 bit) + * + * @param a_width The address width (in bytes) to use; this can be 3, 4 or + * 5. + */ void setAddressWidth(uint8_t a_width); /** - * Set the number and delay of retries upon failed submit + * Set the number of retry attempts and delay between retry attempts when + * transmitting a payload. The radio is waiting for an acknowledgement + * (ACK) packet during the delay between retry attempts. + * + * @param delay How long to wait between each retry, in multiples of + * 250 us. The minumum of 0 means 250 us, and the maximum of 15 means + * 4000 us. The default value of 5 means 1500us (5 * 250 + 250). + * @param count How many retries before giving up. The default/maximum is 15. Use + * 0 to disable the auto-retry feature all together. * - * @param delay How long to wait between each retry, in multiples of 250us, - * max is 15. 0 means 250us, 15 means 4000us. - * @param count How many retries before giving up, max 15 + * @note Disable the auto-retry feature on a transmitter still uses the + * auto-ack feature (if enabled), except it will not retry to transmit if + * the payload was not acknowledged on the first attempt. */ void setRetries(uint8_t delay, uint8_t count); /** - * Set RF communication channel + * Set RF communication channel. The frequency used by a channel is + * calculated as: + * @verbatim 2400 MHz + @endverbatim + * Meaning the default channel of 76 uses the approximate frequency of + * 2476 MHz. + * + * @note In the python wrapper, this function is the setter of the + * `channel` attribute.
To use this function in the python wrapper: + * @code{.py} + * # let `radio` be the instantiated RF24 object + * radio.channel = 2 # set the channel to 2 (2402 MHz) + * @endcode * * @param channel Which RF channel to communicate on, 0-125 */ void setChannel(uint8_t channel); /** - * Get RF communication channel - * - * @return The currently configured RF Channel - */ + * Get RF communication channel + * + * @note In the python wrapper, this function is the getter of the + * `channel` attribute.
To use this function in the python wrapper: + * @code{.py} + * # let `radio` be the instantiated RF24 object + * chn = radio.channel # get the channel + * @endcode + * + * @return The currently configured RF Channel + */ uint8_t getChannel(void); /** @@ -771,7 +1164,12 @@ class RF24 { * transmit the maximum payload size (32 bytes), no matter how much * was sent to write(). * - * @todo Implement variable-sized payloads feature + * @note In the python wrapper, this function is the setter of the + * `payloadSize` attribute.
To use this function in the python wrapper: + * @code{.py} + * # let `radio` be the instantiated RF24 object + * radio.payloadSize = 16 # set the static payload size to 16 bytes + * @endcode * * @param size The number of bytes in the payload */ @@ -780,6 +1178,13 @@ class RF24 { /** * Get Static Payload Size * + * @note In the python wrapper, this function is the getter of the + * `payloadSize` attribute.
To use this function in the python wrapper: + * @code{.py} + * # let `radio` be the instantiated RF24 object + * pl_size = radio.payloadSize # get the static payload size + * @endcode + * * @see setPayloadSize() * * @return The number of bytes in the payload @@ -809,16 +1214,33 @@ class RF24 { uint8_t getDynamicPayloadSize(void); /** - * Enable custom payloads on the acknowledge packets + * Enable custom payloads in the acknowledge packets * - * Ack payloads are a handy way to return data back to senders without + * ACK payloads are a handy way to return data back to senders without * manually changing the radio modes on both units. * - * @note Ack payloads are dynamic payloads. This only works on pipes 0&1 by default. Call - * enableDynamicPayloads() to enable on all pipes. + * @remarks The ACK payload feature requires the auto-ack feature to be + * enabled for any pipe using ACK payloads. This function does not + * automatically enable the auto-ack feature on pipe 0 since the auto-ack + * feature is enabled for all pipes by default. + * + * @see setAutoAck() + * + * @note ACK payloads are dynamic payloads. This function automatically + * enables dynamic payloads on pipe 0 by default. Call + * enableDynamicPayloads() to enable on all pipes (especially for RX nodes + * that use pipes other than pipe 0 to receive transmissions expecting + * responses with ACK payloads). */ void enableAckPayload(void); + /** + * Disable custom payloads on the ackowledge packets + * + * @see enableAckPayload() + */ + void disableAckPayload(void); + /** * Enable dynamically-sized payloads * @@ -840,15 +1262,20 @@ class RF24 { void disableDynamicPayloads(void); /** - * Enable dynamic ACKs (single write multicast or unicast) for chosen messages + * Enable dynamic ACKs (single write multicast or unicast) for chosen + * messages. * - * @note To enable full multicast or per-pipe multicast, use setAutoAck() + * @note This function must be called once before using the multicast + * parameter for any functions that offer it. To use multicast behavior + * about all outgoing payloads (using pipe 0) or incoming payloads + * (concerning all RX pipes), use setAutoAck() + * + * @see setAutoAck() for all pipes + * @see setAutoAck(uint8_t, bool) for individual pipes * - * @warning This MUST be called prior to attempting single write NOACK calls * @code - * radio.enableDynamicAck(); - * radio.write(&data,32,1); // Sends a payload with no acknowledgement requested - * radio.write(&data,32,0); // Sends a payload using auto-retry/autoACK + * radio.write(&data, 32, 1); // Sends a payload with no acknowledgement requested + * radio.write(&data, 32, 0); // Sends a payload using auto-retry/autoACK * @endcode */ void enableDynamicAck(); @@ -862,48 +1289,99 @@ class RF24 { bool isPVariant(void); /** - * Enable or disable auto-acknowlede packets + * Enable or disable the auto-acknowledgement feature for all pipes. This + * feature is enabled by default. Auto-acknowledgement responds to every + * recieved payload with an empty ACK packet. These ACK packets get sent + * from the receiving radio back to the transmitting radio. To attach an + * ACK payload to a ACK packet, use writeAckPayload(). + * + * If this feature is disabled on a transmitting radio, then the + * transmitting radio will always report that the payload was recieved + * (even if it was not). Please remember that this feature's configuration + * needs to match for transmitting and receiving radios. + * + * @warning When using the `multicast` parameter to write(), this feature + * can be disabled for an individual payload. However, if this feature is + * disabled, then the `multicast` parameter will have no effect. * - * This is enabled by default, so it's only needed if you want to turn - * it off for some reason. + * @note If disabling auto-acknowledgment packets, the ACK payloads + * feature is also disabled as this feature is required to send ACK + * payloads. * - * @param enable Whether to enable (true) or disable (false) auto-acks + * @see write() + * @see writeFast() + * @see startFastWrite() + * @see startWrite() + * @see writeAckPayload() + * + * @param enable Whether to enable (true) or disable (false) the + * auto-acknowledgment feature for all pipes */ void setAutoAck(bool enable); /** - * Enable or disable auto-acknowlede packets on a per pipeline basis. + * Enable or disable the auto-acknowledgement feature for a specific pipe. + * This feature is enabled by default for all pipes. Auto-acknowledgement + * responds to every recieved payload with an empty ACK packet. These ACK + * packets get sent from the receiving radio back to the transmitting + * radio. To attach an ACK payload to a ACK packet, use writeAckPayload(). + * + * Pipe 0 is used for TX operations, which include sending ACK packets. If + * using this feature on both TX & RX nodes, then pipe 0 must have this + * feature enabled for the RX & TX operations. If this feature is disabled + * on a transmitting radio's pipe 0, then the transmitting radio will + * always report that the payload was recieved (even if it was not). + * Remember to also enable this feature for any pipe that is openly + * listening to a transmitting radio with this feature enabled. * - * AA is enabled by default, so it's only needed if you want to turn - * it off/on for some reason on a per pipeline basis. + * @warning If this feature is enabled for pipe 0, then the `multicast` + * parameter to write() can be used to disable this feature for an + * individual payload. However, if this feature is disabled for pipe 0, + * then the `multicast` parameter will have no effect. * - * @param pipe Which pipeline to modify - * @param enable Whether to enable (true) or disable (false) auto-acks + * @note If disabling auto-acknowledgment packets on pipe 0, the ACK + * payloads feature is also disabled as this feature is required on pipe 0 + * to send ACK payloads. + * + * @see write() + * @see writeFast() + * @see startFastWrite() + * @see startWrite() + * @see writeAckPayload() + * @see enableAckPayloads() + * @see disableAckPayloads() + * + * @param pipe Which pipe to configure. This number should be in range + * [0, 5]. + * @param enable Whether to enable (true) or disable (false) the + * auto-acknowledgment feature for the specified pipe */ void setAutoAck(uint8_t pipe, bool enable); /** - * Set Power Amplifier (PA) level to one of four levels: - * RF24_PA_MIN, RF24_PA_LOW, RF24_PA_HIGH and RF24_PA_MAX + * Set Power Amplifier (PA) level and Low Noise Amplifier (LNA) state * - * The power levels correspond to the following output levels respectively: - * NRF24L01: -18dBm, -12dBm,-6dBM, and 0dBm, lnaEnable affects modules with LNA + * @param level The desired @ref PALevel as defined by @ref rf24_pa_dbm_e. + * @param lnaEnable Enable or Disable the LNA (Low Noise Amplifier) Gain. + * See table for Si24R1 modules below.
@p lnaEnable only affects + * nRF24L01 modules with an LNA chip. * - * SI24R1: -6dBm, 0dBm, 3dBm and 7dBm with lnaEnable = 1 - * -12dBm,-4dBm, 1dBm and 4dBm with lnaEnable = 0 + * | @p level (enum value) | nRF24L01
description | Si24R1
description when
@p lnaEnable = 1 | Si24R1
description when
@p lnaEnable = 0 | + * |:---------------------:|:-------:|:--------:|:-------:| + * | @ref RF24_PA_MIN (0) | -18 dBm | -6 dBm | -12 dBm | + * | @ref RF24_PA_LOW (1) | -12 dBm | -0 dBm | -4 dBm | + * | @ref RF24_PA_HIGH (2) | -6 dBm | 3 dBm | 1 dBm | + * | @ref RF24_PA_MAX (3) | 0 dBm | 7 dBm | 4 dBm | * - * @param level Desired PA level. - * @param lnaEnable En/Disable LNA Gain + * @note The getPALevel() function does not care what was passed @p lnaEnable parameter. */ void setPALevel(uint8_t level, bool lnaEnable = 1); /** - * Fetches the current PA level. - * - * NRF24L01: -18dBm, -12dBm, -6dBm and 0dBm - * SI24R1: -6dBm, 0dBm, 3dBm, 7dBm + * Fetches the current @ref PALevel. * - * @return Returns values 0 to 3 representing the PA Level. + * @return One of the values defined by @ref rf24_pa_dbm_e.
+ * See tables in @ref rf24_pa_dbm_e or setPALevel() */ uint8_t getPALevel(void); @@ -917,35 +1395,48 @@ class RF24 { uint8_t getARC(void); /** - * Set the transmission data rate - * - * @warning setting RF24_250KBPS will fail for non-plus units - * - * @param speed RF24_250KBPS for 250kbs, RF24_1MBPS for 1Mbps, or RF24_2MBPS for 2Mbps - * @return true if the change was successful - */ + * Set the transmission @ref Datarate + * + * @warning setting @ref RF24_250KBPS will fail for non-plus modules (when + * isPVariant() returns false). + * + * @param speed Specify one of the following values (as defined by + * @ref rf24_datarate_e): + * | @p speed (enum value) | description | + * |:---------------------:|:-----------:| + * | @ref RF24_1MBPS (0) | for 1 Mbps | + * | @ref RF24_2MBPS (1) | for 2 Mbps | + * | @ref RF24_250KBPS (2) | for 250 kbs | + * + * @return true if the change was successful + */ bool setDataRate(rf24_datarate_e speed); /** - * Fetches the transmission data rate + * Fetches the currently configured transmission @ref Datarate * - * @return Returns the hardware's currently configured datarate. The value - * is one of 250kbs, RF24_1MBPS for 1Mbps, or RF24_2MBPS, as defined in the - * rf24_datarate_e enum. + * @return One of the values defined by @ref rf24_datarate_e.
+ * See table in @ref rf24_datarate_e or setDataRate() */ rf24_datarate_e getDataRate(void); /** - * Set the CRC length - *
CRC checking cannot be disabled if auto-ack is enabled - * @param length RF24_CRC_8 for 8-bit or RF24_CRC_16 for 16-bit + * Set the @ref CRCLength (in bits) + *
CRC cannot be disabled if auto-ack is enabled + * @param length Specify one of the values (as defined by @ref rf24_crclength_e) + * | @p length (enum value) | description | + * |:--------------------------:|:------------------------------:| + * | @ref RF24_CRC_DISABLED (0) | to disable using CRC checksums | + * | @ref RF24_CRC_8 (1) | to use 8-bit checksums | + * | @ref RF24_CRC_16 (2) | to use 16-bit checksums | */ void setCRCLength(rf24_crclength_e length); /** - * Get the CRC length + * Get the @ref CRCLength (in bits) *
CRC checking cannot be disabled if auto-ack is enabled - * @return RF24_CRC_DISABLED if disabled or RF24_CRC_8 for 8-bit or RF24_CRC_16 for 16-bit + * @return One of the values defined by @ref rf24_crclength_e.
+ * See table in @ref rf24_crclength_e or setCRCLength() */ rf24_crclength_e getCRCLength(void); @@ -957,58 +1448,90 @@ class RF24 { void disableCRC(void); /** - * The radio will generate interrupt signals when a transmission is complete, - * a transmission fails, or a payload is received. This allows users to mask - * those interrupts to prevent them from generating a signal on the interrupt - * pin. Interrupts are enabled on the radio chip by default. - * - * @code - * Mask all interrupts except the receive interrupt: - * - * radio.maskIRQ(1,1,0); - * @endcode - * - * @param tx_ok Mask transmission complete interrupts - * @param tx_fail Mask transmit failure interrupts - * @param rx_ready Mask payload received interrupts - */ + * This function is used to configure what events will trigger the Interrupt + * Request (IRQ) pin active LOW. + * The following events can be configured: + * 1. "data sent": This does not mean that the data transmitted was + * recieved, only that the attempt to send it was complete. + * 2. "data failed": This means the data being sent was not recieved. This + * event is only triggered when the auto-ack feature is enabled. + * 3. "data received": This means that data from a receiving payload has + * been loaded into the RX FIFO buffers. Remember that there are only 3 + * levels available in the RX FIFO buffers. + * + * By default, all events are configured to trigger the IRQ pin active LOW. + * When the IRQ pin is active, use whatHappened() to determine what events + * triggered it. Remeber that calling whatHappened() also clears these + * events' status, and the IRQ pin will then be reset to inactive HIGH. + * + * The following code configures the IRQ pin to only reflect the "data received" + * event: + * @code + * radio.maskIRQ(1, 1, 0); + * @endcode + * + * @param tx_ok `true` ignores the "data sent" event, `false` reflects the + * "data sent" event on the IRQ pin. + * @param tx_fail `true` ignores the "data failed" event, `false` reflects the + * "data failed" event on the IRQ pin. + * @param rx_ready `true` ignores the "data received" event, `false` reflects the + * "data received" event on the IRQ pin. + */ void maskIRQ(bool tx_ok, bool tx_fail, bool rx_ready); /** - * - * The driver will delay for this duration when stopListening() is called - * - * When responding to payloads, faster devices like ARM(RPi) are much faster than Arduino: - * 1. Arduino sends data to RPi, switches to RX mode - * 2. The RPi receives the data, switches to TX mode and sends before the Arduino radio is in RX mode - * 3. If AutoACK is disabled, this can be set as low as 0. If AA/ESB enabled, set to 100uS minimum on RPi - * - * @warning If set to 0, ensure 130uS delay after stopListening() and before any sends - */ - + * + * The driver will delay for this duration when stopListening() is called + * + * When responding to payloads, faster devices like ARM(RPi) are much faster than Arduino: + * 1. Arduino sends data to RPi, switches to RX mode + * 2. The RPi receives the data, switches to TX mode and sends before the Arduino radio is in RX mode + * 3. If AutoACK is disabled, this can be set as low as 0. If AA/ESB enabled, set to 100uS minimum on RPi + * + * @warning If set to 0, ensure 130uS delay after stopListening() and before any sends + */ uint32_t txDelay; /** - * - * On all devices but Linux and ATTiny, a small delay is added to the CSN toggling function - * - * This is intended to minimise the speed of SPI polling due to radio commands - * - * If using interrupts or timed requests, this can be set to 0 Default:5 - */ - + * + * On all devices but Linux and ATTiny, a small delay is added to the CSN toggling function + * + * This is intended to minimise the speed of SPI polling due to radio commands + * + * If using interrupts or timed requests, this can be set to 0 Default:5 + */ uint32_t csDelay; /** * Transmission of constant carrier wave with defined frequency and output power - * + * * @param level Output power to use * @param channel The channel to use - */ + * + * @warning If isPVariant() returns true, then this function takes extra + * measures that alter some settings. These settings alterations include: + * - setAutoAck() to false (for all pipes) + * - setRetries() to retry `0` times with a delay of 250 microseconds + * - set the TX address to 5 bytes of `0xFF` + * - flush_tx() + * - load a 32 byte payload of `0xFF` into the TX FIFO's top level + * - disableCRC() + */ void startConstCarrier(rf24_pa_dbm_e level, uint8_t channel); /** - * Stop transmission of constant wave and reset PLL and CONT registers + * Stop transmission of constant wave and reset PLL and CONT registers + * + * @warning this function will powerDown() the radio per recommendation of + * datasheet. + * @note If isPVariant() returns true, please remember to re-configure the radio's settings + * @code + * // re-establish default settings + * setCRCLength(RF24_CRC_16); + * setAutoAck(true); + * setRetries(5, 15); + * @endcode + * @see startConstCarrier() */ void stopConstCarrier(void); @@ -1023,13 +1546,14 @@ class RF24 { /** * Open a pipe for reading - * @note For compatibility with old code only, see new function + * @deprecated For compatibility with old code only, see newer function + * openReadingPipe() * * @warning Pipes 1-5 should share the first 32 bits. * Only the least significant byte should be unique, e.g. * @code - * openReadingPipe(1,0xF0F0F0F0AA); - * openReadingPipe(2,0xF0F0F0F066); + * openReadingPipe(1, 0xF0F0F0F0AA); + * openReadingPipe(2, 0xF0F0F0F066); * @endcode * * @warning Pipe 0 is also used by the writing pipe so should typically be avoided as a reading pipe.
@@ -1043,7 +1567,8 @@ class RF24 { /** * Open a pipe for writing - * @note For compatibility with old code only, see new function + * @deprecated For compatibility with old code only, see newer function + * openWritingPipe() * * Addresses are 40-bit hex values, e.g.: * @@ -1056,14 +1581,18 @@ class RF24 { void openWritingPipe(uint64_t address); /** - * Empty the receive buffer + * Determine if an ack payload was received in the most recent call to + * write(). The regular available() can also be used. * - * @return Current value of status register + * @deprecated Call read() to retrieve the ack payload. + * + * @return True if an ack payload is available. */ - uint8_t flush_rx(void); + bool isAckPayloadAvailable(void); private: + /**@}*/ /** * @name Low-level internal interface. * @@ -1099,9 +1628,10 @@ class RF24 { * @param reg Which register. Use constants from nRF24L01.h * @param buf Where to put the data * @param len How many bytes of data to transfer - * @return Current value of status register + * @return Nothing. Older versions of this function returned the status + * byte, but that it now saved to a private member on all SPI transactions. */ - uint8_t read_register(uint8_t reg, uint8_t* buf, uint8_t len); + void read_register(uint8_t reg, uint8_t* buf, uint8_t len); /** * Read single byte from a register @@ -1117,18 +1647,20 @@ class RF24 { * @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 + * @return Nothing. Older versions of this function returned the status + * byte, but that it now saved to a private member on all SPI transactions. */ - uint8_t write_register(uint8_t reg, const uint8_t* buf, uint8_t len); + void write_register(uint8_t reg, const uint8_t* buf, uint8_t len); /** * 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 + * @return Nothing. Older versions of this function returned the status + * byte, but that it now saved to a private member on all SPI transactions. */ - uint8_t write_register(uint8_t reg, uint8_t value); + void write_register(uint8_t reg, uint8_t value, bool is_cmd_only = false); /** * Write the transmit payload @@ -1137,9 +1669,10 @@ class RF24 { * * @param buf Where to get the data * @param len Number of bytes to be sent - * @return Current value of status register + * @return Nothing. Older versions of this function returned the status + * byte, but that it now saved to a private member on all SPI transactions. */ - uint8_t write_payload(const void* buf, uint8_t len, const uint8_t writeType); + void write_payload(const void* buf, uint8_t len, const uint8_t writeType); /** * Read the receive payload @@ -1148,9 +1681,10 @@ class RF24 { * * @param buf Where to put the data * @param len Maximum number of bytes to read - * @return Current value of status register + * @return Nothing. Older versions of this function returned the status + * byte, but that it now saved to a private member on all SPI transactions. */ - uint8_t read_payload(void* buf, uint8_t len); + void read_payload(void* buf, uint8_t len); /** * Retrieve the current status of the chip @@ -1215,12 +1749,6 @@ class RF24 { */ void toggle_features(void); - /** - * Built in spi transfer function to simplify repeating code repeating code - */ - - uint8_t spiTrans(uint8_t cmd); - #if defined (FAILURE_HANDLING) || defined (RF24_LINUX) void errNotify(void); @@ -1233,97 +1761,93 @@ class RF24 { /** - * @example GettingStarted.ino - * For Arduino
- * Updated: TMRh20 2014
- * - * This is an example of how to use the RF24 class to communicate on a basic level. Configure and write this sketch to two - * different nodes. Put one of the nodes into 'transmit' mode by connecting with the serial monitor and
- * sending a 'T'. The ping node sends the current time to the pong node, which responds by sending the value - * back. The ping node can then see how long the whole cycle took.
- * @note For a more efficient call-response scenario see the GettingStarted_CallResponse.ino example. - * @note When switching between sketches, the radio may need to be powered down to clear settings that are not "un-set" otherwise + * @example{lineno} examples/GettingStarted/GettingStarted.ino + * Written by [2bndy5](http://github.com/2bndy5) in 2020 + * + * A simple example of sending data from 1 nRF24L01 transceiver to another. + * + * This example was written to be used on 2 devices acting as "nodes". + * Use the Serial Monitor to change each node's behavior. */ /** -* @example gettingstarted.cpp -* For Linux
-* Updated: TMRh20 2014
-* -* This is an example of how to use the RF24 class to communicate on a basic level. Configure and write this sketch to two -* different nodes. Put one of the nodes into 'transmit' mode by connecting with the serial monitor and
-* sending a 'T'. The ping node sends the current time to the pong node, which responds by sending the value -* back. The ping node can then see how long the whole cycle took.
-* @note For a more efficient call-response scenario see the GettingStarted_CallResponse.ino example. -*/ - -/** - * @example GettingStarted_CallResponse.ino - * For Arduino
- * New: TMRh20 2014
- * - * This example continues to make use of all the normal functionality of the radios including - * the auto-ack and auto-retry features, but allows ack-payloads to be written optionlly as well.
- * This allows very fast call-response communication, with the responding radio never having to - * switch out of Primary Receiver mode to send back a payload, but having the option to switch to
- * primary transmitter if wanting to initiate communication instead of respond to a commmunication. + * @example{lineno} examples/AcknowledgementPayloads/AcknowledgementPayloads.ino + * Written by [2bndy5](http://github.com/2bndy5) in 2020 + * + * A simple example of sending data from 1 nRF24L01 transceiver to another + * with Acknowledgement (ACK) payloads attached to ACK packets. + * + * This example was written to be used on 2 devices acting as "nodes". + * Use the Serial Monitor to change each node's behavior. */ /** -* @example gettingstarted_call_response.cpp -* For Linux
-* New: TMRh20 2014
-* -* This example continues to make use of all the normal functionality of the radios including -* the auto-ack and auto-retry features, but allows ack-payloads to be written optionlly as well.
-* This allows very fast call-response communication, with the responding radio never having to -* switch out of Primary Receiver mode to send back a payload, but having the option to switch to
-* primary transmitter if wanting to initiate communication instead of respond to a commmunication. -*/ + * @example{lineno} examples/ManualAcknowledgements/ManualAcknowledgements.ino + * Written by [2bndy5](http://github.com/2bndy5) in 2020 + * + * A simple example of sending data from 1 nRF24L01 transceiver to another + * with manually transmitted (non-automatic) Acknowledgement (ACK) payloads. + * This example still uses ACK packets, but they have no payloads. Instead the + * acknowledging response is sent with `write()`. This tactic allows for more + * updated acknowledgement payload data, where actual ACK payloads' data are + * outdated by 1 transmission because they have to loaded before receiving a + * transmission. + * + * This example was written to be used on 2 devices acting as "nodes". + * Use the Serial Monitor to change each node's behavior. + */ /** -* @example GettingStarted_HandlingData.ino -* Dec 2014 - TMRh20
-* -* This example demonstrates how to send multiple variables in a single payload and work with data. As usual, it is -* generally important to include an incrementing value like millis() in the payloads to prevent errors. -*/ + * @example{lineno} examples/StreamingData/StreamingData.ino + * Written by [2bndy5](http://github.com/2bndy5) in 2020 + * + * A simple example of streaming data from 1 nRF24L01 transceiver to another. + * + * This example was written to be used on 2 devices acting as "nodes". + * Use the Serial Monitor to change each node's behavior. + */ /** -* @example GettingStarted_HandlingFailures.ino -* -* This example demonstrates the basic getting started functionality, but with failure handling for the radio chip. -* Addresses random radio failures etc, potentially due to loose wiring on breadboards etc. -*/ - + * @example{lineno} examples/MulticeiverDemo/MulticeiverDemo.ino + * Written by [2bndy5](http://github.com/2bndy5) in 2020 + * + * A simple example of sending data from as many as 6 nRF24L01 transceivers to + * 1 receiving transceiver. This technique is trademarked by + * Nordic Semiconductors as "MultiCeiver". + * + * This example was written to be used on up to 6 devices acting as TX nodes & + * only 1 device acting as the RX node (that's a maximum of 7 devices). + * Use the Serial Monitor to change each node's behavior. + */ /** - * @example Transfer.ino - * For Arduino
- * This example demonstrates half-rate transfer using the FIFO buffers
- * - * It is an example of how to use the RF24 class. Write this sketch to two - * different nodes. Put one of the nodes into 'transmit' mode by connecting
- * with the serial monitor and sending a 'T'. The data transfer will begin, - * with the receiver displaying the payload count. (32Byte Payloads)
+ * @example{lineno} examples/InterruptConfigure/InterruptConfigure.ino + * Written by [2bndy5](http://github.com/2bndy5) in 2020 + * + * This example uses Acknowledgement (ACK) payloads attached to ACK packets to + * demonstrate how the nRF24L01's IRQ (Interrupt Request) pin can be + * configured to detect when data is received, or when data has transmitted + * successfully, or when data has failed to transmit. + * + * This example was written to be used on 2 devices acting as "nodes". + * Use the Serial Monitor to change each node's behavior. */ /** -* @example transfer.cpp -* For Linux
-* This example demonstrates half-rate transfer using the FIFO buffers
-* -* It is an example of how to use the RF24 class. Write this sketch to two -* different nodes. Put one of the nodes into 'transmit' mode by connecting
-* with the serial monitor and sending a 'T'. The data transfer will begin, -* with the receiver displaying the payload count. (32Byte Payloads)
-*/ + * @example{lineno} examples/old_backups/GettingStarted_HandlingFailures/GettingStarted_HandlingFailures.ino + * Written by [TMRh20](http://github.com/TMRh20) in 2019 + * + * This example demonstrates the basic getting started functionality, but with + * failure handling for the radio chip. Addresses random radio failures etc, + * potentially due to loose wiring on breadboards etc. + */ /** - * @example TransferTimeouts.ino - * New: TMRh20
+ * @example{lineno} examples/old_backups/TransferTimeouts/TransferTimeouts.ino + * Written by [TMRh20](https://github.com/TMRh20) + * * This example demonstrates the use of and extended timeout period and - * auto-retries/auto-reUse to increase reliability in noisy or low signal scenarios.
+ * auto-retries/auto-reUse to increase reliability in noisy or low signal scenarios. * * Write this sketch to two different nodes. Put one of the nodes into 'transmit' * mode by connecting with the serial monitor and sending a 'T'. The data
@@ -1332,33 +1856,9 @@ class RF24 { */ /** - * @example starping.pde - * - * This sketch is a more complex example of using the RF24 library for Arduino. - * Deploy this on up to six nodes. Set one as the 'pong receiver' by tying the - * role_pin low, and the others will be 'ping transmit' units. The ping units - * unit will send out the value of millis() once a second. The pong unit will - * respond back with a copy of the value. Each ping unit can get that response - * back, and determine how long the whole cycle took. - * - * This example requires a bit more complexity to determine which unit is which. - * The pong receiver is identified by having its role_pin tied to ground. - * The ping senders are further differentiated by a byte in eeprom. - */ - -/** - * @example pingpair_ack.ino - * Update: TMRh20
- * This example continues to make use of all the normal functionality of the radios including - * the auto-ack and auto-retry features, but allows ack-payloads to be written optionlly as well.
- * This allows very fast call-response communication, with the responding radio never having to - * switch out of Primary Receiver mode to send back a payload, but having the option to if wanting
- * to initiate communication instead of respond to a commmunication. - */ - -/** - * @example pingpair_irq.ino - * Update: TMRh20
+ * @example{lineno} examples/old_backups/pingpair_irq/pingpair_irq.ino + * Updated by [TMRh20](https://github.com/TMRh20) + * * This is an example of how to user interrupts to interact with the radio, and a demonstration * of how to use them to sleep when receiving, and not miss any payloads.
* The pingpair_sleepy example expands on sleep functionality with a timed sleep option for the transmitter. @@ -1366,14 +1866,9 @@ class RF24 { */ /** -* @example pingpair_irq_simple.ino -* Dec 2014 - TMRh20
-* This is an example of how to user interrupts to interact with the radio, with bidirectional communication. -*/ - -/** - * @example pingpair_sleepy.ino - * Update: TMRh20
+ * @example{lineno} examples/old_backups/pingpair_sleepy/pingpair_sleepy.ino + * Updated by [TMRh20](https://github.com/TMRh20) + * * This is an example of how to use the RF24 class to create a battery- * efficient system. It is just like the GettingStarted_CallResponse example, but the
* ping node powers down the radio and sleeps the MCU after every @@ -1381,37 +1876,155 @@ class RF24 { */ /** -* @example rf24ping85.ino -* New: Contributed by https://github.com/tong67
-* This is an example of how to use the RF24 class to communicate with ATtiny85 and other node.
-*/ + * @example{lineno} examples/rf24_ATTiny/rf24ping85/rf24ping85.ino + * 2014 Contribution by [tong67](https://github.com/tong67)
+ * Updated 2020 by [2bndy5](http://github.com/2bndy5) for the + * [SpenceKonde ATTinyCore](https://github.com/SpenceKonde/ATTinyCore)
+ * The RF24 library uses the [ATTinyCore by + * SpenceKonde](https://github.com/SpenceKonde/ATTinyCore) + * + * This sketch is a duplicate of the ManualAcknowledgements.ino example + * (without all the Serial input/output code), and it demonstrates + * a ATTiny25/45/85 or ATTiny24/44/84 driving the nRF24L01 transceiver using + * the RF24 class to communicate with another node. + * + * A simple example of sending data from 1 nRF24L01 transceiver to another + * with manually transmitted (non-automatic) Acknowledgement (ACK) payloads. + * This example still uses ACK packets, but they have no payloads. Instead the + * acknowledging response is sent with `write()`. This tactic allows for more + * updated acknowledgement payload data, where actual ACK payloads' data are + * outdated by 1 transmission because they have to loaded before receiving a + * transmission. + * + * This example was written to be used on 2 devices acting as "nodes". + */ /** -* @example timingSearch3pin.ino -* New: Contributed by https://github.com/tong67
-* This is an example of how to determine the correct timing for ATtiny when using only 3-pins -*/ + * @example{lineno} examples/rf24_ATTiny/timingSearch3pin/timingSearch3pin.ino + * 2014 Contribution by [tong67](https://github.com/tong67)
+ * Updated 2020 by [2bndy5](http://github.com/2bndy5) for the + * [SpenceKonde ATTinyCore](https://github.com/SpenceKonde/ATTinyCore)
+ * The RF24 library uses the [ATTinyCore by + * SpenceKonde](https://github.com/SpenceKonde/ATTinyCore) + * + * This sketch can be used to determine the best settle time values to use for + * RF24::csDelay in RF24::csn() (private function). + * @see RF24::csDelay + * + * The settle time values used here are 100/20. However, these values depend + * on the actual used RC combiniation and voltage drop by LED. The + * intermediate results are written to TX (PB3, pin 2 -- using Serial). + * + * For schematic details, see introductory comment block in the rf24ping85.ino sketch. + */ /** - * @example pingpair_dyn.ino + * @example{lineno} examples/old_backups/pingpair_dyn/pingpair_dyn.ino * * This is an example of how to use payloads of a varying (dynamic) size on Arduino. */ /** -* @example pingpair_dyn.cpp -* -* This is an example of how to use payloads of a varying (dynamic) size on Linux. -*/ + * @example{lineno} examples_linux/getting_started.py + * Written by [2bndy5](http://github.com/2bndy5) in 2020 + * + * This is a simple example of using the RF24 class on a Raspberry Pi. + * + * Remember to install the Python wrapper, then + * navigate to the "RF24/examples_linux" folder. + *
To run this example, enter + * @code{.sh}python3 getting_started.py @endcode and follow the prompts. + * + * @note this example requires python v3.7 or newer because it measures + * transmission time with `time.monotonic_ns()`. + */ + +/** + * @example{lineno} examples_linux/acknowledgement_payloads.py + * Written by [2bndy5](http://github.com/2bndy5) in 2020 + * + * This is a simple example of using the RF24 class on a Raspberry Pi to + * transmit and retrieve custom automatic acknowledgment payloads. + * + * Remember to install the Python wrapper, then + * navigate to the "RF24/examples_linux" folder. + *
To run this example, enter + * @code{.sh}python3 acknowledgement_payloads.py @endcode and follow the prompts. + * + * @note this example requires python v3.7 or newer because it measures + * transmission time with `time.monotonic_ns()`. + */ + +/** + * @example{lineno} examples_linux/manual_acknowledgements.py + * Written by [2bndy5](http://github.com/2bndy5) in 2020 + * + * This is a simple example of using the RF24 class on a Raspberry Pi to + * transmit and respond with acknowledgment (ACK) transmissions. Notice that + * the auto-ack feature is enabled, but this example doesn't use automatic ACK + * payloads because automatic ACK payloads' data will always be outdated by 1 + * transmission. Instead, this example uses a call and response paradigm. + * + * Remember to install the Python wrapper, then + * navigate to the "RF24/examples_linux" folder. + *
To run this example, enter + * @code{.sh}python3 manual_acknowledgements.py @endcode and follow the prompts. + * + * @note this example requires python v3.7 or newer because it measures + * transmission time with `time.monotonic_ns()`. + */ + +/** + * @example{lineno} examples_linux/streaming_data.py + * Written by [2bndy5](http://github.com/2bndy5) in 2020 + * + * This is a simple example of using the RF24 class on a Raspberry Pi for + * streaming multiple payloads. + * + * Remember to install the Python wrapper, then + * navigate to the "RF24/examples_linux" folder. + *
To run this example, enter + * @code{.sh}python3 streaming_data.py @endcode and follow the prompts. + * + * @note this example requires python v3.7 or newer because it measures + * transmission time with `time.monotonic_ns()`. + */ /** - * @example pingpair_dyn.py + * @example{lineno} examples_linux/interrupt_configure.py + * Written by [2bndy5](http://github.com/2bndy5) in 2020 + * + * This is a simple example of using the RF24 class on a Raspberry Pi to + * detecting (and verifying) the IRQ (interrupt) pin on the nRF24L01. + * + * Remember to install the Python wrapper, then + * navigate to the "RF24/examples_linux" folder. + *
To run this example, enter + * @code{.sh}python3 interrupt_configure.py @endcode and follow the prompts. * - * This is a python example for RPi of how to use payloads of a varying (dynamic) size. + * @note this example requires python v3.7 or newer because it measures + * transmission time with `time.monotonic_ns()`. */ /** - * @example scanner.ino + * @example{lineno} examples_linux/multiceiver_demo.py + * Written by [2bndy5](http://github.com/2bndy5) in 2020 + * + * This is a simple example of using the RF24 class on a Raspberry Pi for + * using 1 nRF24L01 to receive data from up to 6 other transceivers. This + * technique is called "multiceiver" in the datasheet. + * + * Remember to install the Python wrapper, then + * navigate to the "RF24/examples_linux" folder. + *
To run this example, enter + * @code{.sh}python3 multiceiver_demo.py @endcode and follow the prompts. + * + * @note this example requires python v3.7 or newer because it measures + * transmission time with `time.monotonic_ns()`. + */ + +/** + * @example{lineno} examples/old_backups/scanner/scanner.ino * * Example to detect interference on the various channels available. * This is a good diagnostic tool to check whether you're picking a @@ -1421,6 +2034,68 @@ class RF24 { * See http://arduino.cc/forum/index.php/topic,54795.0.html */ +/** + * @example{lineno} examples_linux/gettingstarted.cpp + * Written by [2bndy5](http://github.com/2bndy5) in 2020 + * + * A simple example of sending data from 1 nRF24L01 transceiver to another. + * + * This example was written * This example was written to be used on up to 6 devices acting as TX nodes & + * only 1 device acting as the RX node (that's a maximum of 7 devices). + acting as "nodes". + * Use `ctrl+c` to quit at any time. + */ + +/** + * @example{lineno} examples_linux/acknowledgementPayloads.cpp + * Written by [2bndy5](http://github.com/2bndy5) in 2020 + * + * A simple example of sending data from 1 nRF24L01 transceiver to another + * with Acknowledgement (ACK) payloads attached to ACK packets. + * + * This example was written to be used on 2 devices acting as "nodes". + * Use `ctrl+c` to quit at any time. + */ + +/** + * @example{lineno} examples_linux/manualAcknowledgements.cpp + * Written by [2bndy5](http://github.com/2bndy5) in 2020 + * + * A simple example of sending data from 1 nRF24L01 transceiver to another + * with manually transmitted (non-automatic) Acknowledgement (ACK) payloads. + * This example still uses ACK packets, but they have no payloads. Instead the + * acknowledging response is sent with `write()`. This tactic allows for more + * updated acknowledgement payload data, where actual ACK payloads' data are + * outdated by 1 transmission because they have to loaded before receiving a + * transmission. + * + * This example was written to be used on 2 devices acting as "nodes". + * Use `ctrl+c` to quit at any time. + */ + +/** + * @example{lineno} examples_linux/streamingData.cpp + * Written by [2bndy5](http://github.com/2bndy5) in 2020 + * + * A simple example of sending data from 1 nRF24L01 transceiver to another. + * + * This example was written to be used on 2 devices acting as "nodes". + * Use `ctrl+c` to quit at any time. + */ + +/** + * @example{lineno} examples_linux/multiceiverDemo.cpp + * Written by [2bndy5](http://github.com/2bndy5) in 2020 + * + * A simple example of sending data from as many as 6 nRF24L01 transceivers to + * 1 receiving transceiver. This technique is trademarked by + * Nordic Semiconductors as "MultiCeiver". + * + * This example was written to be used on up to 6 devices acting as TX nodes & + * only 1 device acting as the RX node (that's a maximum of 7 devices). + * Use `ctrl+c` to quit at any time. + */ + /** * @mainpage Optimized High Speed Driver for nRF24L01(+) 2.4GHz Wireless Transceiver * @@ -1437,20 +2112,22 @@ class RF24 { * @section News News * * **Aug 2020**
+ * v1.3.9 + * - Fix broken compilation for some devices due to recent changes * v1.3.8 - * - Introduces change that mainly reduces the time required to call startListening(), powerUp(), and powerDown() + * - Introduces change that mainly reduces the time required to call RF24::startListening(), RF24::powerUp(), and RF24::powerDown() * - Affects speed of switching from TX->RX. Users might consider starting updates of slower devices with this
* release to prevent missed packets when similar changes are introduced, affecting switching from RX->TX - * - Clean up begin() function (reduce program size) + * - Clean up RF24::begin() function (reduce program size) * * v1.3.7 - * - Bug fix for writeFast() function affecting RF24 stack (all RF24 libraries) + * - Bug fix for RF24::writeFast() function affecting RF24 stack (all RF24 libraries) * - Unify Arduino & Linux constructor. Accept SPI speed in Hz as optional parameter * - Removal of BCM2835 SPI speed constants due to removal from BCM library * - Update to latest BCM2835 driver * - Bug fix for RPi millis() code * - Added Constant Carrier Wave functionality & added to scanner example - * - Modify setPALevel() to allow setting LNA gain via optional parameter + * - Modify RF24::setPALevel() to allow setting LNA gain via optional parameter * - Cleanup of warnings, errors and old files * * **March-July 2020** @@ -1460,24 +2137,24 @@ class RF24 { * - Minor fixes & changes * * - * + * * @section Useful Useful References * * - * @li RF24 Class Documentation - * @li Support & Configuration - * @li Source Code - * @li nrf24L01 v2.0 Datasheet - * @li nrf24L01+ v1.0 Datasheet + * @li RF24 Class Documentation + * @li Support & Configuration + * @li Source Code + * @li nRF24L01 v2.0 Datasheet + * @li nRF24L01+ v1.0 Datasheet * * **Additional Information and Add-ons** * - * @li RF24Network: OSI Network Layer for multi-device communication. Create a home sensor network. - * @li RF24Mesh: Dynamic Mesh Layer for RF24Network - * @li RF24Ethernet: TCP/IP Radio Mesh Networking (shares Arduino Ethernet API) - * @li RF24Audio: Realtime Wireless Audio streaming - * @li My Blog: RF24 Optimization Overview - * @li My Blog: RPi/Linux w/RF24Gateway + * @li RF24Network: OSI Network Layer for multi-device communication. Create a home sensor network. + * @li RF24Mesh: Dynamic Mesh Layer for RF24Network + * @li RF24Ethernet: TCP/IP Radio Mesh Networking (shares Arduino Ethernet API) + * @li RF24Audio: Realtime Wireless Audio streaming + * @li My Blog: RF24 Optimization Overview + * @li My Blog: RPi/Linux w/RF24Gateway * @li All TMRh20 Documentation Main Page * * **More Information** @@ -1517,27 +2194,27 @@ class RF24 { * * @li [0] https://learn.sparkfun.com/tutorials/tiny-avr-programmer-hookup-guide/attiny85-use-hints * @li [1] http://highlowtech.org/?p=1695 - * @li [2] http://littlewire.cc/ + * @li [2] http://littlewire.cc/ *


* * * * * @page Arduino Arduino - * + * * RF24 is fully compatible with Arduino boards
* See http://www.arduino.cc/en/Reference/Board and http://arduino.cc/en/Reference/SPI for more information - * + * * RF24 makes use of the standard hardware SPI pins (MISO,MOSI,SCK) and requires two additional pins, to control * the chip-select and chip-enable functions.
- * These pins must be chosen and designated by the user, in RF24 radio(ce_pin,cs_pin); and can use any + * These pins must be chosen and designated by the user, in RF24 radio(ce_pin,cs_pin); and can use any * available pins. - * + * *
* @section Alternate_SPI Alternate SPI Support * * RF24 supports alternate SPI methods, in case the standard hardware SPI pins are otherwise unavailable. - * + * *
* **Software Driven SPI** * @@ -1545,8 +2222,8 @@ class RF24 { * * Setup:
* 1. Install the digitalIO library
- * 2. Open RF24_config.h in a text editor. - Uncomment the line + * 2. Open RF24_config.h in a text editor. + Uncomment the line @code #define SOFTSPI @endcode @@ -1571,11 +2248,11 @@ class RF24 { *
* **Alternate Hardware (UART) Driven SPI** * - * The Serial Port (UART) on Arduino can also function in SPI mode, and can double-buffer data, while the + * The Serial Port (UART) on Arduino can also function in SPI mode, and can double-buffer data, while the * default SPI hardware cannot. * * The SPI_UART library is available at https://github.com/TMRh20/Sketches/tree/master/SPI_UART - * + * * Enabling: * 1. Install the SPI_UART library * 2. Edit RF24_config.h and uncomment `#define SPI_UART` @@ -1593,12 +2270,13 @@ class RF24 { * * @note SPI_UART on Mega boards requires soldering to an unused pin on the chip.
See * https://github.com/TMRh20/RF24/issues/24 for more information on SPI_UART. - * + * * @page ATTiny ATTiny * - * ATTiny support is built into the library, so users are not required to include SPI.h in their sketches
+ * ATTiny support for this library relys on the SpenceKonde ATTinyCore. Be sure to have added this core to the Arduino Boards Manager with the following guide:
+ * http://highlowtech.org/?p=1695
* See the included rf24ping85 example for pin info and usage - * + * * Some versions of Arduino IDE may require a patch to allow use of the full program space on ATTiny
* See https://github.com/TCWORLD/ATTinyCore/tree/master/PCREL%20Patch%20for%20GCC for ATTiny patch * @@ -1606,7 +2284,7 @@ class RF24 { * * @section Hardware Hardware Configuration * By tong67 ( https://github.com/tong67 ) - * + * * **ATtiny25/45/85 Pin map with CE_PIN 3 and CSN_PIN 4** * @code * +-\/-+ @@ -1614,7 +2292,7 @@ class RF24 { * nRF24L01 CE, pin3 --- PB3 2| |7 PB2 --- nRF24L01 SCK, pin5 * nRF24L01 CSN, pin4 --- PB4 3| |6 PB1 --- nRF24L01 MOSI, pin6 * nRF24L01 GND, pin1 --- GND 4| |5 PB0 --- nRF24L01 MISO, pin7 - * +----+ + * +----+ * @endcode * *
@@ -1625,22 +2303,22 @@ class RF24 { * This configuration is enabled when CE_PIN and CSN_PIN are equal, e.g. both 3
* Because CE is always high the power consumption is higher than for 5 pins solution
* @code - * ^^ - * +-\/-+ nRF24L01 CE, pin3 ------| // - * PB5 1|o |8 Vcc --- nRF24L01 VCC, pin2 ------x----------x--|<|-- 5V - * NC PB3 2| |7 PB2 --- nRF24L01 SCK, pin5 --|<|---x-[22k]--| LED - * NC PB4 3| |6 PB1 --- nRF24L01 MOSI, pin6 1n4148 | - * nRF24L01 GND, pin1 -x- GND 4| |5 PB0 --- nRF24L01 MISO, pin7 | - * | +----+ | - * |-----------------------------------------------||----x-- nRF24L01 CSN, pin4 - * 10nF + * ^^ + * +-\/-+ nRF24L01 CE, pin3 ------| // + * PB5 1|o |8 Vcc --- nRF24L01 VCC, pin2 ------x----------x--|<|-- 5V + * NC PB3 2| |7 PB2 --- nRF24L01 SCK, pin5 --|<|---x-[22k]--| LED + * NC PB4 3| |6 PB1 --- nRF24L01 MOSI, pin6 1n4148 | + * nRF24L01 GND, pin1 -x- GND 4| |5 PB0 --- nRF24L01 MISO, pin7 | + * | +----+ | + * |-----------------------------------------------||----x-- nRF24L01 CSN, pin4 + * 10nF * @endcode * *
* **ATtiny24/44/84 Pin map with CE_PIN 8 and CSN_PIN 7**
* Schematic provided and successfully tested by Carmine Pastore (https://github.com/Carminepz)
* @code - * +-\/-+ + * +-\/-+ * nRF24L01 VCC, pin2 --- VCC 1|o |14 GND --- nRF24L01 GND, pin1 * PB0 2| |13 AREF * PB1 3| |12 PA1 @@ -1649,12 +2327,12 @@ class RF24 { * PA7 6| |9 PA4 --- nRF24L01 SCK, pin5 * nRF24L01 MISO, pin7 --- PA6 7| |8 PA5 --- nRF24L01 MOSI, pin6 * +----+ - * @endcode - * + * @endcode + * *
* **ATtiny2313/4313 Pin map with CE_PIN 12 and CSN_PIN 13**
* @code - * +-\/-+ + * +-\/-+ * PA2 1|o |20 VCC --- nRF24L01 VCC, pin2 * PD0 2| |19 PB7 --- nRF24L01 SCK, pin5 * PD1 3| |18 PB6 --- nRF24L01 MOSI, pin6 @@ -1666,13 +2344,13 @@ class RF24 { * PD5 9| |12 PB0 * nRF24L01 GND, pin1 --- GND 10| |11 PD6 * +----+ - * @endcode + * @endcode * *


* * - * - * + * + * * * * @page Linux Linux Installation @@ -1682,10 +2360,10 @@ class RF24 { * @note The SPIDEV option should work with most Linux systems supporting spi userspace device.
* *
- * @section AutoInstall Automated Install + * @section AutoInstall Automated Install *(**Designed & Tested on RPi** - Defaults to SPIDEV on devices supporting it) * - * + * * 1. Install prerequisites if there are any (MRAA, LittleWire libraries, setup SPI device etc) * 2. Download the install.sh file from http://tmrh20.github.io/RF24Installer/RPi/install.sh * @code wget http://tmrh20.github.io/RF24Installer/RPi/install.sh @endcode @@ -1694,13 +2372,13 @@ class RF24 { * 4. Run it and choose your options * @code ./install.sh @endcode * 5. Run an example from one of the libraries - * @code - * cd rf24libs/RF24/examples_linux + * @code + * cd rf24libs/RF24/examples_linux * @endcode * Edit the gettingstarted example, to set your pin configuration * @code nano gettingstarted.cpp - * make - * sudo ./gettingstarted + * make + * sudo ./gettingstarted * @endcode * *
@@ -1709,7 +2387,7 @@ class RF24 { * @note See the MRAA documentation for more info on installing MRAA
* 2. Make a directory to contain the RF24 and possibly RF24Network lib and enter it * @code - * mkdir ~/rf24libs + * mkdir ~/rf24libs * cd ~/rf24libs * @endcode * 3. Clone the RF24 repo @@ -1720,11 +2398,11 @@ class RF24 { * 6. Build the library, and run an example file * @code make; sudo make install @endcode * @code - * cd examples_linux + * cd examples_linux * @endcode * Edit the gettingstarted example, to set your pin configuration - * @code nano gettingstarted.cpp - * make + * @code nano gettingstarted.cpp + * make * sudo ./gettingstarted * @endcode * @@ -1738,9 +2416,9 @@ class RF24 { * @endcode * 3. See the gettingstarted example for an example of pin configuration *

- * + * * @page MRAA MRAA - * + * * MRAA is a Low Level Skeleton Library for Communication on GNU/Linux platforms
* See http://iotdk.intel.com/docs/master/mraa/index.html for more information * @@ -1768,20 +2446,20 @@ class RF24 { * Run @code sudo ldconfig @endcode * * 3. Install RF24, using MRAA - * See http://tmrh20.github.io/RF24/Linux.html + * See http://nRF24.github.io/RF24/Linux.html * * *


* - * * * - * @page RPi Linux General/Raspberry Pi + * + * @page RPi Linux General/Raspberry Pi * * RF24 supports a variety of Linux based devices via various drivers. Some boards like RPi can utilize multiple methods * to drive the GPIO and SPI functionality. * - * + * * @section PreConfig Potential PreConfiguration * * If SPI is not already enabled, load it on boot: @@ -1790,7 +2468,7 @@ class RF24 { * B. Select **Advanced** and **enable the SPI kernel module**
* C. Update other software and libraries * @code sudo apt-get update @endcode - * @code sudo apt-get upgrade @endcode + * @code sudo apt-get upgrade @endcode *
* * @section Build Build Options @@ -1807,11 +2485,11 @@ class RF24 { * Using pin 15/GPIO 22 for CE, pin 24/GPIO8 (CE0) for CSN * * Can use any available SPI BUS for CSN.
- * In general, use @code RF24 radio(, *10+); @endcode for proper constructor to - * address correct spi device at /dev/spidev\.\ + * In general, use @code RF24 radio(, *10+); @endcode for proper constructor to + * address correct spi device at /dev/spidev\.\ *
* Choose any GPIO output pin for radio CE pin. - * + * * **General:** * @code RF24 radio(22,0); @endcode * @@ -1824,11 +2502,11 @@ class RF24 { * **SPI_DEV Constructor** * * @code RF24 radio(22,0); @endcode - * + * * * https://www.raspberrypi.org/documentation/usage/gpio/ * - * **Pins:** + * **Pins:** * * | PIN | NRF24L01 | RPI | RPi -P1 Connector | * |-----|----------|------------|-------------------| @@ -1840,29 +2518,29 @@ class RF24 { * | 6 | MOSI | rpi-mosi | (19) | * | 7 | MISO | rpi-miso | (21) | * | 8 | IRQ | - | - | - * - * - * - * + * + * + * + * *

**************** - * + * * Based on the arduino lib from J. Coliz
- * the library was berryfied by Purinda Gunasekara
+ * the library was berryfied by Purinda Gunasekara
* then forked from github stanleyseow/RF24 to https://github.com/jscrane/RF24-rpi
* Network lib also based on https://github.com/farconada/RF24Network * - * * - * + * + * *


- * * - * + * + * * @page Python Python Wrapper (by https://github.com/mz-fuzzy) * * @section Prerequisites Prerequisites - * + * * Python2: * * @code sudo apt-get install python-dev libboost-python-dev python-setuptools python-rpi.gpio @endcode @@ -1887,19 +2565,19 @@ class RF24 { * 3. Install the library * @code sudo ./setup.py install @endcode or @code sudo python3 setup.py install @endcode * See the additional
Platform Support pages for information on connecting your hardware
- * See the included example for usage information. - * + * See the included example for usage information. + * * 5. Running the Example:
- * Edit the pingpair_dyn.py example to configure the appropriate pins per the above documentation: + * Edit the pingpair_dyn.py example to configure the appropriate pins per the above documentation: * @code nano pingpair_dyn.py @endcode * Configure another device, Arduino or RPi with the pingpair_dyn example
- * Run the example + * Run the example * @code sudo ./pingpair_dyn.py @endcode or @code sudo python3 pingpair_dyn.py @endcode * *


* * @page CrossCompile Linux cross-compilation - * + * * RF24 library supports cross-compilation. Advantages of cross-compilation: * - development tools don't have to be installed on target machine * - resources of target machine don't have to be sufficient for compilation @@ -1972,16 +2650,16 @@ class RF24 { *


* * @page ATXMEGA ATXMEGA - * + * * The RF24 driver can be build as a static library with Atmel Studio 7 in order to be included as any other library in another program for the XMEGA family. * * Currently only the ATXMEGA D3 family is implemented. - * - * @section Preparation - * + * + * @section Preparation + * * Create an empty GCC Static Library project in AS7.
* As not all files are required, copy the following directory structure in the project: - * + * * @code * utility\ * ATXMegaD3\ @@ -2001,38 +2679,38 @@ class RF24 { * RF24.h * RF24_config.h * @endcode - * + * * @section Usage - * + * * Add the library to your project!
* In the file where the **main()** is put the following in order to update the millisecond functionality: - * + * * @code * ISR(TCE0_OVF_vect) * { * update_milisec(); * } * @endcode - * + * * Declare the rf24 radio with **RF24 radio(XMEGA_PORTC_PIN3, XMEGA_SPI_PORT_C);** - * + * * First parameter is the CE pin which can be any available pin on the uC. - * - * Second parameter is the CS which can be on port C (**XMEGA_SPI_PORT_C**) or on port D (**XMEGA_SPI_PORT_D**). - * + * + * Second parameter is the CS which can be on port C (**XMEGA_SPI_PORT_C**) or on port D (**XMEGA_SPI_PORT_D**). + * * Call the **__start_timer()** to start the millisecond timer. - * + * * @note Note about the millisecond functionality:
- * + * * The millisecond functionality is based on the TCE0 so don't use these pins as IO.
- * The operating frequency of the uC is 32MHz. If you have other frequency change the TCE0 registers appropriatly in function **__start_timer()** in **compatibility.c** file for your frequency. + * The operating frequency of the uC is 32MHz. If you have other frequency change the TCE0 registers appropriatly in function **__start_timer()** in **compatibility.c** file for your frequency. * * @page Portability RF24 Portability * * The RF24 radio driver mainly utilizes the Arduino API for GPIO, SPI, and timing functions, which are easily replicated - * on various platforms.
Support files for these platforms are stored under RF24/utility, and can be modified to provide + * on various platforms.
Support files for these platforms are stored under RF24/utility, and can be modified to provide * the required functionality. - * + * *
* @section Hardware_Templates Basic Hardware Template * @@ -2041,18 +2719,18 @@ class RF24 { * The RF24 library now includes a basic hardware template to assist in porting to various platforms.
The following files can be included * to replicate standard Arduino functions as needed, allowing devices from ATTiny to Raspberry Pi to utilize the same core RF24 driver. * - * | File | Purpose | - * |--------------------|------------------------------------------------------------------------------| - * | RF24_arch_config.h | Basic Arduino/AVR compatibility, includes for remaining support files, etc | - * | includes.h | Linux only. Defines specific platform, include correct RF24_arch_config file | - * | spi.h | Provides standardized SPI ( transfer() ) methods | - * | gpio.h | Provides standardized GPIO ( digitalWrite() ) methods | - * | compatibility.h | Provides standardized timing (millis(), delay()) methods | - * | your_custom_file.h | Provides access to custom drivers for spi,gpio, etc | + * | File | Purpose | + * |--------------------|------------------------------------------------------------------------------| + * | RF24_arch_config.h | Basic Arduino/AVR compatibility, includes for remaining support files, etc | + * | includes.h | Linux only. Defines specific platform, include correct RF24_arch_config file | + * | spi.h | Provides standardized SPI ( transfer() ) methods | + * | gpio.h | Provides standardized GPIO ( digitalWrite() ) methods | + * | compatibility.h | Provides standardized timing (millis(), delay()) methods | + * | your_custom_file.h | Provides access to custom drivers for spi,gpio, etc | * *
* Examples are provided via the included hardware support templates in **RF24/utility**
- * See the modules page for examples of class declarations + * See the modules page for examples of class declarations * *
* @section Device_Detection Device Detection @@ -2064,7 +2742,7 @@ class RF24 { *
* @section Ported_Code Code * To have your ported code included in this library, or for assistance in porting, create a pull request or open an issue at https://github.com/TMRh20/RF24 - * + * * *


*/ diff --git a/RF24_config.h b/RF24_config.h index b142af195..361e70486 100644 --- a/RF24_config.h +++ b/RF24_config.h @@ -1,6 +1,6 @@ /* - Copyright (C) + Copyright (C) 2011 J. Coliz 2015-2019 TMRh20 2015 spaniakos @@ -9,7 +9,7 @@ 2016 akatran 2017-2019 Avamander 2019 IkpeohaGodson - + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. @@ -24,7 +24,7 @@ //#define MINIMAL //#define SPI_UART // Requires library from https://github.com/TMRh20/Sketches/tree/master/SPI_UART //#define SOFTSPI // Requires library from https://github.com/greiman/DigitalIO - + /** * User access to internally used delay time (in microseconds) during RF24::powerUp() * @warning This default value compensates for all supported hardware. Only adjust this if you @@ -35,11 +35,11 @@ #endif /**********************/ -#define rf24_max(a,b) (a>b?a:b) -#define rf24_min(a,b) (ab?a:b) +#define rf24_min(a, b) (a - + #if defined (ARDUINO) && !defined (__arm__) && !defined (__ARDUINO_X86__) #if defined SPI_UART @@ -88,7 +88,7 @@ const uint8_t SPI_MODE = 0; #define _SPI spi - + #else // !defined (SPI_UART) && !defined (SOFTSPI) #include #define _SPI SPI @@ -114,7 +114,7 @@ extern HardwareSPI SPI; #endif // !defined(__arm__) && !defined (__ARDUINO_X86__) - + #ifndef _BV #define _BV(x) (1<<(x)) #endif @@ -129,13 +129,13 @@ #endif // defined(RF24_TINY) #endif // SERIAL_DEBUG - + #if defined (__ARDUINO_X86__) #define printf_P printf #define _BV(bit) (1<<(bit)) #endif // defined (__ARDUINO_X86__) - + // Progmem is Arduino-specific // Arduino DUE is arm and does not include avr/pgmspace #if defined (ARDUINO_ARCH_ESP8266) || defined (ESP32) @@ -158,7 +158,7 @@ #endif #ifndef pgm_read_byte #define pgm_read_byte(addr) (*(const unsigned char *)(addr)) - #endif + #endif #endif // !defined (ARDUINO) #ifndef prog_uint16_t @@ -188,7 +188,7 @@ #endif // !defined (ARDUINO) || defined (ESP_PLATFORM) || defined (__arm__) || defined (__ARDUINO_X86__) && !defined (XMEGA) #endif //Everything else - + #if defined (SPI_HAS_TRANSACTION) && !defined (SPI_UART) && !defined (SOFTSPI) #define RF24_SPI_TRANSACTIONS #endif // defined (SPI_HAS_TRANSACTION) && !defined (SPI_UART) && !defined (SOFTSPI) diff --git a/datasheets/nRF24L01P_datasheet_v1.pdf b/datasheets/nRF24L01P_datasheet_v1.pdf new file mode 100644 index 000000000..f8d77a456 Binary files /dev/null and b/datasheets/nRF24L01P_datasheet_v1.pdf differ diff --git a/datasheets/nRF24L01_datasheet_v2.pdf b/datasheets/nRF24L01_datasheet_v2.pdf new file mode 100644 index 000000000..b35803355 Binary files /dev/null and b/datasheets/nRF24L01_datasheet_v2.pdf differ diff --git a/doxygen-custom.css b/doxygen-custom.css index 9491c0d72..236f3e3b9 100644 --- a/doxygen-custom.css +++ b/doxygen-custom.css @@ -801,4 +801,15 @@ dl.bug { .caption { font-weight: bold; } +td.fielddoc +th.markdownTableHeadLeft, +th.markdownTableHeadRight, +th.markdownTableHeadCenter, +th.markdownTableHeadNone { + background-image: none; + border-radius: unset; +} +td.fielddoc tr:last-child { + border-bottom: 1px solid #2D4068; +} diff --git a/examples/AcknowledgementPayloads/AcknowledgementPayloads.ino b/examples/AcknowledgementPayloads/AcknowledgementPayloads.ino new file mode 100644 index 000000000..72be79232 --- /dev/null +++ b/examples/AcknowledgementPayloads/AcknowledgementPayloads.ino @@ -0,0 +1,208 @@ +/* + * See documentation at https://nRF24.github.io/RF24 + * See License information at root directory of this library + * Author: Brendan Doherty (2bndy5) + */ + +/** + * A simple example of sending data from 1 nRF24L01 transceiver to another + * with Acknowledgement (ACK) payloads attached to ACK packets. + * + * This example was written to be used on 2 devices acting as "nodes". + * Use the Serial Monitor to change each node's behavior. + */ +#include +#include "printf.h" +#include "RF24.h" + +// instantiate an object for the nRF24L01 transceiver +RF24 radio(7, 8); // using pin 7 for the CE pin, and pin 8 for the CSN pin + +// an identifying device destination +// Let these addresses be used for the pair +uint8_t address[][6] = {"1Node", "2Node"}; +// It is very helpful to think of an address as a path instead of as +// an identifying device destination +// to use different addresses on a pair of radios, we need a variable to + +// uniquely identify which address this radio will use to transmit +bool radioNumber = 1; // 0 uses address[0] to transmit, 1 uses address[1] to transmit + +// Used to control whether this node is sending or receiving +bool role = false; // true = TX role, false = RX role + +// For this example, we'll be using a payload containing +// a string & an integer number that will be incremented +// on every successful transmission. +// Make a data structure to store the entire payload of different datatypes +struct PayloadStruct { + char message[7]; // only using 6 characters for TX & ACK payloads + uint8_t counter; +}; +PayloadStruct payload; + +void setup() { + + Serial.begin(115200); + while (!Serial) { + // some boards need to wait to ensure access to serial over USB + } + + // initialize the transceiver on the SPI bus + if (!radio.begin()) { + Serial.println(F("radio hardware is not responding!!")); + while (1) {} // hold in infinite loop + } + + // print example's introductory prompt + Serial.println(F("RF24/examples/AcknowledgementPayloads")); + + // To set the radioNumber via the Serial monitor on startup + Serial.println(F("Which radio is this? Enter '0' or '1'. Defaults to '0'")); + while (!Serial.available()) { + // wait for user input + } + char input = Serial.parseInt(); + radioNumber = input == 1; + Serial.print(F("radioNumber = ")); + Serial.println((int)radioNumber); + + // role variable is hardcoded to RX behavior, inform the user of this + Serial.println(F("*** PRESS 'T' to begin transmitting to the other node")); + + // Set the PA Level low to try preventing power supply related problems + // because these examples are likely run with nodes in close proximity to + // each other. + radio.setPALevel(RF24_PA_LOW); // RF24_PA_MAX is default. + + // to use ACK payloads, we need to enable dynamic payload lengths (for all nodes) + radio.enableDynamicPayloads(); // ACK payloads are dynamically sized + + // Acknowledgement packets have no payloads by default. We need to enable + // this feature for all nodes (TX & RX) to use ACK payloads. + radio.enableAckPayload(); + + // set the TX address of the RX node into the TX pipe + radio.openWritingPipe(address[radioNumber]); // always uses pipe 0 + + // set the RX address of the TX node into a RX pipe + radio.openReadingPipe(1, address[!radioNumber]); // using pipe 1 + + // additional setup specific to the node's role + if (role) { + // setup the TX payload + + memcpy(payload.message, "Hello ", 6); // set the payload message + radio.stopListening(); // put radio in TX mode + } else { + // setup the ACK payload & load the first response into the FIFO + + memcpy(payload.message, "World ", 6); // set the payload message + // load the payload for the first received transmission on pipe 0 + radio.writeAckPayload(1, &payload, sizeof(PayloadStruct)); + + radio.startListening(); // put radio in RX mode + } + + // For debugging info + // printf_begin(); // needed only once for printing details + // radio.printDetails(); // (smaller) function that prints raw register values + // radio.printPrettyDetails(); // (larger) function that prints human readable data + +} + +void loop() { + + if (role) { + // This device is a TX node + + unsigned long start_timer = micros(); // start the timer + bool report = radio.write(&payload, sizeof(payload)); // transmit & save the report + unsigned long end_timer = micros(); // end the timer + + if (report) { + Serial.print(F("Transmission successful! ")); // payload was delivered + Serial.print(F("Time to transmit = ")); + Serial.print(end_timer - start_timer); // print the timer result + Serial.print(F(" us. Sent: ")); + Serial.print(payload.message); // print the outgoing message + Serial.print(payload.counter); // print the outgoing counter + uint8_t pipe; + if (radio.available(&pipe)) { // is there an ACK payload? grab the pipe number that received it + PayloadStruct received; + radio.read(&received, sizeof(received)); // get incoming ACK payload + Serial.print(F(" Recieved ")); + Serial.print(radio.getDynamicPayloadSize()); // print incoming payload size + Serial.print(F(" bytes on pipe ")); + Serial.print(pipe); // print pipe number that received the ACK + Serial.print(F(": ")); + Serial.print(received.message); // print incoming message + Serial.println(received.counter); // print incoming counter + + // save incoming counter & increment for next outgoing + payload.counter = received.counter + 1; + + } else { + Serial.println(F(" Recieved: an empty ACK packet")); // empty ACK packet received + } + + + } else { + Serial.println(F("Transmission failed or timed out")); // payload was not delivered + } + + // to make this example readable in the serial monitor + delay(1000); // slow transmissions down by 1 second + + } else { + // This device is a RX node + + uint8_t pipe; + if (radio.available(&pipe)) { // is there a payload? get the pipe number that recieved it + uint8_t bytes = radio.getDynamicPayloadSize(); // get the size of the payload + PayloadStruct received; + radio.read(&received, sizeof(received)); // get incoming payload + Serial.print(F("Received ")); + Serial.print(bytes); // print the size of the payload + Serial.print(F(" bytes on pipe ")); + Serial.print(pipe); // print the pipe number + Serial.print(F(": ")); + Serial.print(received.message); // print incoming message + Serial.print(received.counter); // print incoming counter + Serial.print(F(" Sent: ")); + Serial.print(payload.message); // print outgoing message + Serial.println(payload.counter); // print outgoing counter + + // save incoming counter & increment for next outgoing + payload.counter = received.counter + 1; + // load the payload for the first received transmission on pipe 0 + radio.writeAckPayload(1, &payload, sizeof(payload)); + } + } // role + + if (Serial.available()) { + // change the role via the serial monitor + + char c = toupper(Serial.read()); + if (c == 'T' && !role) { + // Become the TX node + + role = true; + Serial.println(F("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK")); + + memcpy(payload.message, "Hello ", 6); // change payload message + radio.stopListening(); // this also discards any unused ACK payloads + + } else if (c == 'R' && role) { + // Become the RX node + + role = false; + Serial.println(F("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK")); + memcpy(payload.message, "World ", 6); // change payload message + + // load the payload for the first received transmission on pipe 0 + radio.writeAckPayload(1, &payload, sizeof(PayloadStruct)); + radio.startListening(); + } + } +} // loop \ No newline at end of file diff --git a/examples/GettingStarted/GettingStarted.ino b/examples/GettingStarted/GettingStarted.ino index 5f7a2c501..c89058c93 100644 --- a/examples/GettingStarted/GettingStarted.ino +++ b/examples/GettingStarted/GettingStarted.ino @@ -1,142 +1,154 @@ - -/* -* Getting Started example sketch for nRF24L01+ radios -* This is a very basic example of how to send data from one node to another -* Updated: Dec 2014 by TMRh20 -*/ - -#include -#include "RF24.h" - -/****************** User Config ***************************/ -/*** Set this radio as radio number 0 or 1 ***/ -bool radioNumber = 0; - -/* Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins 7 & 8 */ -RF24 radio(7,8); -/**********************************************************/ - -byte addresses[][6] = {"1Node","2Node"}; - -// Used to control whether this node is sending or receiving -bool role = 0; - -void setup() { - Serial.begin(115200); - Serial.println(F("RF24/examples/GettingStarted")); - Serial.println(F("*** PRESS 'T' to begin transmitting to the other node")); - - radio.begin(); - - // Set the PA Level low to prevent power supply related issues since this is a - // getting_started sketch, and the likelihood of close proximity of the devices. RF24_PA_MAX is default. - radio.setPALevel(RF24_PA_LOW); - - // Open a writing and reading pipe on each radio, with opposite addresses - if(radioNumber){ - radio.openWritingPipe(addresses[1]); - radio.openReadingPipe(1,addresses[0]); - }else{ - radio.openWritingPipe(addresses[0]); - radio.openReadingPipe(1,addresses[1]); - } - - // Start the radio listening for data - radio.startListening(); -} - -void loop() { - - -/****************** Ping Out Role ***************************/ -if (role == 1) { - - radio.stopListening(); // First, stop listening so we can talk. - - - Serial.println(F("Now sending")); - - unsigned long start_time = micros(); // Take the time, and send it. This will block until complete - if (!radio.write( &start_time, sizeof(unsigned long) )){ - Serial.println(F("failed")); - } - - radio.startListening(); // Now, continue listening - - unsigned long started_waiting_at = micros(); // Set up a timeout period, get the current microseconds - boolean timeout = false; // Set up a variable to indicate if a response was received or not - - while ( ! radio.available() ){ // While nothing is received - if (micros() - started_waiting_at > 200000 ){ // If waited longer than 200ms, indicate timeout and exit while loop - timeout = true; - break; - } - } - - if ( timeout ){ // Describe the results - Serial.println(F("Failed, response timed out.")); - }else{ - unsigned long got_time; // Grab the response, compare, and send to debugging spew - radio.read( &got_time, sizeof(unsigned long) ); - unsigned long end_time = micros(); - - // Spew it - Serial.print(F("Sent ")); - Serial.print(start_time); - Serial.print(F(", Got response ")); - Serial.print(got_time); - Serial.print(F(", Round-trip delay ")); - Serial.print(end_time-start_time); - Serial.println(F(" microseconds")); - } - - // Try again 1s later - delay(1000); - } - - - -/****************** Pong Back Role ***************************/ - - if ( role == 0 ) - { - unsigned long got_time; - - if( radio.available()){ - // Variable for the received timestamp - while (radio.available()) { // While there is data ready - radio.read( &got_time, sizeof(unsigned long) ); // Get the payload - } - - radio.stopListening(); // First, stop listening so we can talk - radio.write( &got_time, sizeof(unsigned long) ); // Send the final one back. - radio.startListening(); // Now, resume listening so we catch the next packets. - Serial.print(F("Sent response ")); - Serial.println(got_time); - } - } - - - - -/****************** Change Roles via Serial Commands ***************************/ - - if ( Serial.available() ) - { - char c = toupper(Serial.read()); - if ( c == 'T' && role == 0 ){ - Serial.println(F("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK")); - role = 1; // Become the primary transmitter (ping out) - - }else - if ( c == 'R' && role == 1 ){ - Serial.println(F("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK")); - role = 0; // Become the primary receiver (pong back) - radio.startListening(); - - } - } - - -} // Loop - +/* + * See documentation at https://nRF24.github.io/RF24 + * See License information at root directory of this library + * Author: Brendan Doherty (2bndy5) + */ + +/** + * A simple example of sending data from 1 nRF24L01 transceiver to another. + * + * This example was written to be used on 2 devices acting as "nodes". + * Use the Serial Monitor to change each node's behavior. + */ +#include +#include "printf.h" +#include "RF24.h" + +// instantiate an object for the nRF24L01 transceiver +RF24 radio(7, 8); // using pin 7 for the CE pin, and pin 8 for the CSN pin + +// Let these addresses be used for the pair +uint8_t address[][6] = {"1Node", "2Node"}; +// It is very helpful to think of an address as a path instead of as +// an identifying device destination + +// to use different addresses on a pair of radios, we need a variable to +// uniquely identify which address this radio will use to transmit +bool radioNumber = 1; // 0 uses address[0] to transmit, 1 uses address[1] to transmit + +// Used to control whether this node is sending or receiving +bool role = false; // true = TX role, false = RX role + +// For this example, we'll be using a payload containing +// a single float number that will be incremented +// on every successful transmission +float payload = 0.0; + +void setup() { + + Serial.begin(115200); + while (!Serial) { + // some boards need to wait to ensure access to serial over USB + } + + // initialize the transceiver on the SPI bus + if (!radio.begin()) { + Serial.println(F("radio hardware is not responding!!")); + while (1) {} // hold in infinite loop + } + + // print example's introductory prompt + Serial.println(F("RF24/examples/GettingStarted")); + + // To set the radioNumber via the Serial monitor on startup + Serial.println(F("Which radio is this? Enter '0' or '1'. Defaults to '0'")); + while (!Serial.available()) { + // wait for user input + } + char input = Serial.parseInt(); + radioNumber = input == 1; + Serial.print(F("radioNumber = ")); + Serial.println((int)radioNumber); + + // role variable is hardcoded to RX behavior, inform the user of this + Serial.println(F("*** PRESS 'T' to begin transmitting to the other node")); + + // Set the PA Level low to try preventing power supply related problems + // because these examples are likely run with nodes in close proximity to + // each other. + radio.setPALevel(RF24_PA_LOW); // RF24_PA_MAX is default. + + // save on transmission time by setting the radio to only transmit the + // number of bytes we need to transmit a float + radio.setPayloadSize(sizeof(payload)); // float datatype occupies 4 bytes + + // set the TX address of the RX node into the TX pipe + radio.openWritingPipe(address[radioNumber]); // always uses pipe 0 + + // set the RX address of the TX node into a RX pipe + radio.openReadingPipe(1, address[!radioNumber]); // using pipe 1 + + // additional setup specific to the node's role + if (role) { + radio.stopListening(); // put radio in TX mode + } else { + radio.startListening(); // put radio in RX mode + } + + // For debugging info + // printf_begin(); // needed only once for printing details + // radio.printDetails(); // (smaller) function that prints raw register values + // radio.printPrettyDetails(); // (larger) function that prints human readable data + +} // setup + +void loop() { + + if (role) { + // This device is a TX node + + unsigned long start_timer = micros(); // start the timer + bool report = radio.write(&payload, sizeof(float)); // transmit & save the report + unsigned long end_timer = micros(); // end the timer + + if (report) { + Serial.print(F("Transmission successful! ")); // payload was delivered + Serial.print(F("Time to transmit = ")); + Serial.print(end_timer - start_timer); // print the timer result + Serial.print(F(" us. Sent: ")); + Serial.println(payload); // print payload sent + payload += 0.01; // increment float payload + } else { + Serial.println(F("Transmission failed or timed out")); // payload was not delivered + } + + // to make this example readable in the serial monitor + delay(1000); // slow transmissions down by 1 second + + } else { + // This device is a RX node + + uint8_t pipe; + if (radio.available(&pipe)) { // is there a payload? get the pipe number that recieved it + uint8_t bytes = radio.getDynamicPayloadSize(); // get the size of the payload + radio.read(&payload, bytes); // fetch payload from FIFO + Serial.print(F("Received ")); + Serial.print(bytes); // print the size of the payload + Serial.print(F(" bytes on pipe ")); + Serial.print(pipe); // print the pipe number + Serial.print(F(": ")); + Serial.println(payload); // print the payload's value + } + } // role + + if (Serial.available()) { + // change the role via the serial monitor + + char c = toupper(Serial.read()); + if (c == 'T' && !role) { + // Become the TX node + + role = true; + Serial.println(F("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK")); + radio.stopListening(); + + } else if (c == 'R' && role) { + // Become the RX node + + role = false; + Serial.println(F("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK")); + radio.startListening(); + } + } + +} // loop \ No newline at end of file diff --git a/examples/GettingStarted_CallResponse/GettingStarted_CallResponse.ino b/examples/GettingStarted_CallResponse/GettingStarted_CallResponse.ino deleted file mode 100644 index d93bcf6f8..000000000 --- a/examples/GettingStarted_CallResponse/GettingStarted_CallResponse.ino +++ /dev/null @@ -1,142 +0,0 @@ -/* - Dec 2014 - TMRh20 - Updated - Derived from examples by J. Coliz -*/ -/** - * Example for efficient call-response using ack-payloads - * - * This example continues to make use of all the normal functionality of the radios including - * the auto-ack and auto-retry features, but allows ack-payloads to be written optionlly as well. - * This allows very fast call-response communication, with the responding radio never having to - * switch out of Primary Receiver mode to send back a payload, but having the option to switch to - * primary transmitter if wanting to initiate communication instead of respond to a commmunication. - */ - -#include -#include "RF24.h" - -// You must include printf and run printf_begin() if you wish to use radio.printDetails(); -//#include "printf.h" - -/****************** User Config ***************************/ -/*** Set this radio as radio number 0 or 1 ***/ -bool radioNumber = 0; - -/* Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins 7 & 8 */ -RF24 radio(7,8); -/**********************************************************/ - // Topology -byte addresses[][6] = {"1Node","2Node"}; // Radio pipe addresses for the 2 nodes to communicate. - -// Role management: Set up role. This sketch uses the same software for all the nodes -// in this system. Doing so greatly simplifies testing. -typedef enum { role_ping_out = 1, role_pong_back } role_e; // The various roles supported by this sketch -const char* role_friendly_name[] = { "invalid", "Ping out", "Pong back"}; // The debug-friendly names of those roles -role_e role = role_pong_back; // The role of the current running sketch - -byte counter = 1; // A single byte to keep track of the data being sent back and forth - - -void setup(){ - - Serial.begin(115200); - // printf_begin(); // This is for initializing printf that is used by printDetails() - Serial.println(F("RF24/examples/GettingStarted_CallResponse")); - Serial.println(F("*** PRESS 'T' to begin transmitting to the other node")); - - // Setup and configure radio - - radio.begin(); - - radio.enableAckPayload(); // Allow optional ack payloads - radio.enableDynamicPayloads(); // Ack payloads are dynamic payloads - - if(radioNumber){ - radio.openWritingPipe(addresses[1]); // Both radios listen on the same pipes by default, but opposite addresses - radio.openReadingPipe(1,addresses[0]); // Open a reading pipe on address 0, pipe 1 - }else{ - radio.openWritingPipe(addresses[0]); - radio.openReadingPipe(1,addresses[1]); - } - radio.startListening(); // Start listening - - radio.writeAckPayload(1,&counter,1); // Pre-load an ack-paylod into the FIFO buffer for pipe 1 - //radio.printDetails(); -} - -void loop(void) { - - -/****************** Ping Out Role ***************************/ - - if (role == role_ping_out){ // Radio is in ping mode - - byte gotByte; // Initialize a variable for the incoming response - - radio.stopListening(); // First, stop listening so we can talk. - Serial.print(F("Now sending ")); // Use a simple byte counter as payload - Serial.println(counter); - - unsigned long time = micros(); // Record the current microsecond count - - if ( radio.write(&counter,1) ){ // Send the counter variable to the other radio - if(!radio.available()){ // If nothing in the buffer, we got an ack but it is blank - Serial.print(F("Got blank response. round-trip delay: ")); - Serial.print(micros()-time); - Serial.println(F(" microseconds")); - }else{ - while(radio.available() ){ // If an ack with payload was received - radio.read( &gotByte, 1 ); // Read it, and display the response time - unsigned long timer = micros(); - - Serial.print(F("Got response ")); - Serial.print(gotByte); - Serial.print(F(" round-trip delay: ")); - Serial.print(timer-time); - Serial.println(F(" microseconds")); - counter++; // Increment the counter variable - } - } - - }else{ Serial.println(F("Sending failed.")); } // If no ack response, sending failed - - delay(1000); // Try again later - } - - -/****************** Pong Back Role ***************************/ - - if ( role == role_pong_back ) { - byte pipeNo, gotByte; // Declare variables for the pipe and the byte received - while( radio.available(&pipeNo)){ // Read all available payloads - radio.read( &gotByte, 1 ); - // Since this is a call-response. Respond directly with an ack payload. - gotByte += 1; // Ack payloads are much more efficient than switching to transmit mode to respond to a call - radio.writeAckPayload(pipeNo,&gotByte, 1 ); // This can be commented out to send empty payloads. - Serial.print(F("Loaded next response ")); - Serial.println(gotByte); - } - } - - - -/****************** Change Roles via Serial Commands ***************************/ - - if ( Serial.available() ) - { - char c = toupper(Serial.read()); - if ( c == 'T' && role == role_pong_back ){ - Serial.println(F("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK")); - role = role_ping_out; // Become the primary transmitter (ping out) - counter = 1; - }else - if ( c == 'R' && role == role_ping_out ){ - Serial.println(F("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK")); - role = role_pong_back; // Become the primary receiver (pong back) - radio.startListening(); - counter = 1; - radio.writeAckPayload(1,&counter,1); - - } - } -} diff --git a/examples/GettingStarted_HandlingData/GettingStarted_HandlingData.ino b/examples/GettingStarted_HandlingData/GettingStarted_HandlingData.ino deleted file mode 100755 index d2efcb9c8..000000000 --- a/examples/GettingStarted_HandlingData/GettingStarted_HandlingData.ino +++ /dev/null @@ -1,161 +0,0 @@ - -/* -* Getting Started example sketch for nRF24L01+ radios -* This is an example of how to send data from one node to another using data structures -* Updated: Dec 2014 by TMRh20 -*/ - -#include -#include "RF24.h" - -byte addresses[][6] = {"1Node","2Node"}; - - -/****************** User Config ***************************/ -/*** Set this radio as radio number 0 or 1 ***/ -bool radioNumber = 1; - -/* Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins 7 & 8 */ -RF24 radio(7,8); -/**********************************************************/ - - -// Used to control whether this node is sending or receiving -bool role = 0; - -/** -* Create a data structure for transmitting and receiving data -* This allows many variables to be easily sent and received in a single transmission -* See http://www.cplusplus.com/doc/tutorial/structures/ -*/ -struct dataStruct{ - unsigned long _micros; - float value; -}myData; - -void setup() { - - Serial.begin(115200); - Serial.println(F("RF24/examples/GettingStarted_HandlingData")); - Serial.println(F("*** PRESS 'T' to begin transmitting to the other node")); - - radio.begin(); - - // Set the PA Level low to prevent power supply related issues since this is a - // getting_started sketch, and the likelihood of close proximity of the devices. RF24_PA_MAX is default. - radio.setPALevel(RF24_PA_LOW); - - // Open a writing and reading pipe on each radio, with opposite addresses - if(radioNumber){ - radio.openWritingPipe(addresses[1]); - radio.openReadingPipe(1,addresses[0]); - }else{ - radio.openWritingPipe(addresses[0]); - radio.openReadingPipe(1,addresses[1]); - } - - myData.value = 1.22; - // Start the radio listening for data - radio.startListening(); -} - - - - -void loop() { - - -/****************** Ping Out Role ***************************/ -if (role == 1) { - - radio.stopListening(); // First, stop listening so we can talk. - - - Serial.println(F("Now sending")); - - myData._micros = micros(); - if (!radio.write( &myData, sizeof(myData) )){ - Serial.println(F("failed")); - } - - radio.startListening(); // Now, continue listening - - unsigned long started_waiting_at = micros(); // Set up a timeout period, get the current microseconds - boolean timeout = false; // Set up a variable to indicate if a response was received or not - - while ( ! radio.available() ){ // While nothing is received - if (micros() - started_waiting_at > 200000 ){ // If waited longer than 200ms, indicate timeout and exit while loop - timeout = true; - break; - } - } - - if ( timeout ){ // Describe the results - Serial.println(F("Failed, response timed out.")); - }else{ - // Grab the response, compare, and send to debugging spew - radio.read( &myData, sizeof(myData) ); - unsigned long time = micros(); - - // Spew it - Serial.print(F("Sent ")); - Serial.print(time); - Serial.print(F(", Got response ")); - Serial.print(myData._micros); - Serial.print(F(", Round-trip delay ")); - Serial.print(time-myData._micros); - Serial.print(F(" microseconds Value ")); - Serial.println(myData.value); - } - - // Try again 1s later - delay(1000); - } - - - -/****************** Pong Back Role ***************************/ - - if ( role == 0 ) - { - - if( radio.available()){ - // Variable for the received timestamp - while (radio.available()) { // While there is data ready - radio.read( &myData, sizeof(myData) ); // Get the payload - } - - radio.stopListening(); // First, stop listening so we can talk - myData.value += 0.01; // Increment the float value - radio.write( &myData, sizeof(myData) ); // Send the final one back. - radio.startListening(); // Now, resume listening so we catch the next packets. - Serial.print(F("Sent response ")); - Serial.print(myData._micros); - Serial.print(F(" : ")); - Serial.println(myData.value); - } - } - - - - -/****************** Change Roles via Serial Commands ***************************/ - - if ( Serial.available() ) - { - char c = toupper(Serial.read()); - if ( c == 'T' && role == 0 ){ - Serial.print(F("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK")); - role = 1; // Become the primary transmitter (ping out) - - }else - if ( c == 'R' && role == 1 ){ - Serial.println(F("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK")); - role = 0; // Become the primary receiver (pong back) - radio.startListening(); - - } - } - - -} // Loop diff --git a/examples/GettingStarted_HandlingFailures/GettingStarted_HandlingFailures.ino b/examples/GettingStarted_HandlingFailures/GettingStarted_HandlingFailures.ino deleted file mode 100644 index 10d1092c2..000000000 --- a/examples/GettingStarted_HandlingFailures/GettingStarted_HandlingFailures.ino +++ /dev/null @@ -1,218 +0,0 @@ - -/* -* Getting Started example sketch for nRF24L01+ radios -* This is a very basic example of how to send data from one node to another -* but modified to include failure handling. -* -* The nrf24l01+ radios are fairly reliable devices, but on breadboards etc, with inconsistent wiring, failures may -* occur randomly after many hours to days or weeks. This sketch demonstrates how to handle the various failures and -* keep the radio operational. -* -* The three main failure modes of the radio include: -* Writing to radio: Radio unresponsive - Fixed internally by adding a timeout to the internal write functions in RF24 (failure handling) -* Reading from radio: Available returns true always - Fixed by adding a timeout to available functions by the user. This is implemented internally in RF24Network. -* Radio configuration settings are lost - Fixed by monitoring a value that is different from the default, and re-configuring the radio if this setting reverts to the default. -* -* The printDetails output should appear as follows for radio #0: -* -* STATUS = 0x0e RX_DR=0 TX_DS=0 MAX_RT=0 RX_P_NO=7 TX_FULL=0 -* RX_ADDR_P0-1 = 0x65646f4e31 0x65646f4e32 -* RX_ADDR_P2-5 = 0xc3 0xc4 0xc5 0xc6 -* TX_ADDR = 0x65646f4e31 -* RX_PW_P0-6 = 0x20 0x20 0x00 0x00 0x00 0x00 -* EN_AA = 0x3f -* EN_RXADDR = 0x02 -* RF_CH = 0x4c -* RF_SETUP = 0x03 -* CONFIG = 0x0f -* DYNPD/FEATURE = 0x00 0x00 -* Data Rate = 1MBPS -* Model = nRF24L01+ -* CRC Length = 16 bits -* PA Power = PA_LOW -* -*Users can use this sketch to troubleshoot radio module wiring etc. as it makes the radios hot-swapable -* -* Updated: 2019 by TMRh20 -*/ - -#include -#include "RF24.h" -#include "printf.h" - -/****************** User Config ***************************/ -/*** Set this radio as radio number 0 or 1 ***/ -bool radioNumber = 0; - -/* Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins 7 & 8 */ -RF24 radio(7,8); -/**********************************************************/ - -byte addresses[][6] = {"1Node","2Node"}; - -// Used to control whether this node is sending or receiving -bool role = 0; - -/**********************************************************/ -//Function to configure the radio -void configureRadio(){ - - radio.begin(); - - // Set the PA Level low to prevent power supply related issues since this is a - // getting_started sketch, and the likelihood of close proximity of the devices. RF24_PA_MAX is default. - radio.setPALevel(RF24_PA_LOW); - - // Open a writing and reading pipe on each radio, with opposite addresses - if(radioNumber){ - radio.openWritingPipe(addresses[1]); - radio.openReadingPipe(1,addresses[0]); - }else{ - radio.openWritingPipe(addresses[0]); - radio.openReadingPipe(1,addresses[1]); - } - - // Start the radio listening for data - radio.startListening(); - radio.printDetails(); -} - -/**********************************************************/ - -void setup() { - Serial.begin(115200); - Serial.println(F("RF24/examples/GettingStarted")); - Serial.println(F("*** PRESS 'T' to begin transmitting to the other node")); - - printf_begin(); - - configureRadio(); -} - -uint32_t configTimer = millis(); - -void loop() { - - if(radio.failureDetected){ - radio.failureDetected = false; - delay(250); - Serial.println("Radio failure detected, restarting radio"); - configureRadio(); - } - //Every 5 seconds, verify the configuration of the radio. This can be done using any - //setting that is different from the radio defaults. - if(millis() - configTimer > 5000){ - configTimer = millis(); - if(radio.getDataRate() != RF24_1MBPS){ - radio.failureDetected = true; - Serial.print("Radio configuration error detected"); - } - } - -/****************** Ping Out Role ***************************/ -if (role == 1) { - - radio.stopListening(); // First, stop listening so we can talk. - - - Serial.println(F("Now sending")); - - unsigned long start_time = micros(); // Take the time, and send it. This will block until complete - if (!radio.write( &start_time, sizeof(unsigned long) )){ - Serial.println(F("failed")); - } - - radio.startListening(); // Now, continue listening - - unsigned long started_waiting_at = micros(); // Set up a timeout period, get the current microseconds - boolean timeout = false; // Set up a variable to indicate if a response was received or not - - while ( ! radio.available() ){ // While nothing is received - if (micros() - started_waiting_at > 200000 ){ // If waited longer than 200ms, indicate timeout and exit while loop - timeout = true; - break; - } - } - - if ( timeout ){ // Describe the results - Serial.println(F("Failed, response timed out.")); - }else{ - unsigned long got_time; // Grab the response, compare, and send to debugging spew - - //Failure Handling: - uint32_t failTimer = millis(); - while(radio.available()){ //If available always returns true, there is a problem - if(millis() - failTimer > 250){ - radio.failureDetected = true; - Serial.println("Radio available failure detected"); - break; - } - radio.read( &got_time, sizeof(unsigned long) ); - } - unsigned long end_time = micros(); - - // Spew it - Serial.print(F("Sent ")); - Serial.print(start_time); - Serial.print(F(", Got response ")); - Serial.print(got_time); - Serial.print(F(", Round-trip delay ")); - Serial.print(end_time-start_time); - Serial.println(F(" microseconds")); - } - - // Try again 1s later - delay(1000); - } - - - -/****************** Pong Back Role ***************************/ - - if ( role == 0 ) - { - unsigned long got_time; - - if( radio.available()){ - - uint32_t failTimer = millis(); // Variable for the received timestamp - while (radio.available()) { // While there is data ready - if(millis()-failTimer > 500){ - Serial.println("Radio available failure detected"); - radio.failureDetected = true; - break; - } - radio.read( &got_time, sizeof(unsigned long) ); // Get the payload - } - - radio.stopListening(); // First, stop listening so we can talk - radio.write( &got_time, sizeof(unsigned long) ); // Send the final one back. - radio.startListening(); // Now, resume listening so we catch the next packets. - Serial.print(F("Sent response ")); - Serial.println(got_time); - } - } - - - - -/****************** Change Roles via Serial Commands ***************************/ - - if ( Serial.available() ) - { - char c = toupper(Serial.read()); - if ( c == 'T' && role == 0 ){ - Serial.println(F("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK")); - role = 1; // Become the primary transmitter (ping out) - - }else - if ( c == 'R' && role == 1 ){ - Serial.println(F("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK")); - role = 0; // Become the primary receiver (pong back) - radio.startListening(); - - } - } - - -} // Loop diff --git a/examples/InterruptConfigure/InterruptConfigure.ino b/examples/InterruptConfigure/InterruptConfigure.ino new file mode 100644 index 000000000..5d616edba --- /dev/null +++ b/examples/InterruptConfigure/InterruptConfigure.ino @@ -0,0 +1,346 @@ +/* + * See documentation at https://nRF24.github.io/RF24 + * See License information at root directory of this library + * Author: Brendan Doherty (2bndy5) + */ + +/** + * This example uses Acknowledgement (ACK) payloads attached to ACK packets to + * demonstrate how the nRF24L01's IRQ (Interrupt Request) pin can be + * configured to detect when data is received, or when data has transmitted + * successfully, or when data has failed to transmit. + * + * This example was written to be used on 2 devices acting as "nodes". + * Use the Serial Monitor to change each node's behavior. + */ +#include +#include "printf.h" +#include "RF24.h" + +// We will be using the nRF24L01's IRQ pin for this example +#define IRQ_PIN 2 // this needs to be a digital input capable pin +volatile bool wait_for_event = false; // used to wait for an IRQ event to trigger + +// instantiate an object for the nRF24L01 transceiver +RF24 radio(7, 8); // using pin 7 for the CE pin, and pin 8 for the CSN pin + +// Let these addresses be used for the pair +uint8_t address[][6] = {"1Node", "2Node"}; +// It is very helpful to think of an address as a path instead of as +// an identifying device destination + +// to use different addresses on a pair of radios, we need a variable to +// uniquely identify which address this radio will use to transmit +bool radioNumber = 1; // 0 uses address[0] to transmit, 1 uses address[1] to transmit + +// Used to control whether this node is sending or receiving +bool role = false; // true = TX node, false = RX node + +// For this example, we'll be using a payload containing +// a string that changes on every transmission. (successful or not) +// Make a couple arrays of payloads & an iterator to traverse them +const uint8_t tx_pl_size = 5; +const uint8_t ack_pl_size = 4; +uint8_t pl_iterator = 0; +// The " + 1" compensates for the c-string's NULL terminating 0 +char tx_payloads[][tx_pl_size + 1] = {"Ping ", "Pong ", "Radio", "1FAIL"}; +char ack_payloads[][ack_pl_size + 1] = {"Yak ", "Back", " ACK"}; + +void interruptHandler(); // prototype to handle IRQ events +void printRxFifo(); // prototype to print RX FIFO with 1 buffer + + +void setup() { + Serial.begin(115200); + while (!Serial) { + // some boards need to wait to ensure access to serial over USB + } + + // initialize the transceiver on the SPI bus + if (!radio.begin()) { + Serial.println(F("radio hardware is not responding!!")); + while (1) {} // hold in infinite loop + } + + // print example's introductory prompt + Serial.println(F("RF24/examples/InterruptConfigure")); + + // To set the radioNumber via the Serial monitor on startup + Serial.println(F("Which radio is this? Enter '0' or '1'. Defaults to '0'")); + while (!Serial.available()) { + // wait for user input + } + char input = Serial.parseInt(); + radioNumber = input == 1; + Serial.print(F("radioNumber = ")); + Serial.println((int)radioNumber); + + // role variable is hardcoded to RX behavior, inform the user of this + Serial.println(F("*** PRESS 'T' to begin transmitting to the other node")); + + // setup the IRQ_PIN + pinMode(IRQ_PIN, INPUT); + attachInterrupt(digitalPinToInterrupt(IRQ_PIN), interruptHandler, FALLING); + // IMPORTANT: do not call radio.available() before calling + // radio.whatHappened() when the interruptHandler() is triggered by the + // IRQ pin FALLING event. According to the datasheet, the pipe information + // is unreliable during the IRQ pin FALLING transition. + + // Set the PA Level low to try preventing power supply related problems + // because these examples are likely run with nodes in close proximity to + // each other. + radio.setPALevel(RF24_PA_LOW); // RF24_PA_MAX is default. + + // For this example we use acknowledgment (ACK) payloads to trigger the + // IRQ pin when data is received on the TX node. + // to use ACK payloads, we need to enable dynamic payload lengths + radio.enableDynamicPayloads(); // ACK payloads are dynamically sized + + // Acknowledgement packets have no payloads by default. We need to enable + // this feature for all nodes (TX & RX) to use ACK payloads. + radio.enableAckPayload(); + // Fot this example, we use the same address to send data back and forth + + // set the TX address of the RX node into the TX pipe + radio.openWritingPipe(address[radioNumber]); // always uses pipe 0 + + // set the RX address of the TX node into a RX pipe + radio.openReadingPipe(1, address[!radioNumber]); // using pipe 1 + + // additional setup specific to the node's role + if (role) { + // setup for TX mode + radio.stopListening(); // put radio in TX mode + + } else { + // setup for RX mode + + // let IRQ pin only trigger on "data ready" event in RX mode + radio.maskIRQ(1, 1, 0); // args = "data_sent", "data_fail", "data_ready" + + // Fill the TX FIFO with 3 ACK payloads for the first 3 received + // transmissions on pipe 1 + radio.writeAckPayload(1, &ack_payloads[0], ack_pl_size); + radio.writeAckPayload(1, &ack_payloads[1], ack_pl_size); + radio.writeAckPayload(1, &ack_payloads[2], ack_pl_size); + + radio.startListening(); // put radio in RX mode + } + + // For debugging info + // printf_begin(); // needed only once for printing details + // radio.printDetails(); // (smaller) function that prints raw register values + // radio.printPrettyDetails(); // (larger) function that prints human readable data + +} + +void loop() { + if (role && !wait_for_event) { + + // delay(1); // wait for IRQ pin to fully RISE + + // This device is a TX node. This if block is only triggered when + // NOT waiting for an IRQ event to happen + + if (pl_iterator == 0) { + // Test the "data ready" event with the IRQ pin + + Serial.println(F("\nConfiguring IRQ pin to ignore the 'data sent' event")); + radio.maskIRQ(true, false, false); // args = "data_sent", "data_fail", "data_ready" + Serial.println(F(" Pinging RX node for 'data ready' event...")); + + } else if (pl_iterator == 1) { + // Test the "data sent" event with the IRQ pin + + Serial.println(F("\nConfiguring IRQ pin to ignore the 'data ready' event")); + radio.maskIRQ(false, false, true); // args = "data_sent", "data_fail", "data_ready" + Serial.println(F(" Pinging RX node for 'data sent' event...")); + + } else if (pl_iterator == 2) { + // Use this iteration to fill the RX node's FIFO which sets us up for the next test. + + // write() uses virtual interrupt flags that work despite the masking of the IRQ pin + radio.maskIRQ(1, 1, 1); // disable IRQ masking for this step + + Serial.println(F("\nSending 1 payload to fill RX node's FIFO. IRQ pin is neglected.")); + // write() will call flush_tx() on 'data fail' events + if (radio.write(&tx_payloads[pl_iterator], tx_pl_size)) { + if (radio.rxFifoFull()) { + Serial.println(F("RX node's FIFO is full; it is not listening any more")); + } else { + Serial.println("Transmission successful, but the RX node might still be listening."); + } + } else { + Serial.println(F("Transmission failed or timed out. Continuing anyway.")); + radio.flush_tx(); // discard payload(s) that failed to transmit + } + + } else if (pl_iterator == 3) { + // test the "data fail" event with the IRQ pin + + Serial.println(F("\nConfiguring IRQ pin to reflect all events")); + radio.maskIRQ(0, 0, 0); // args = "data_sent", "data_fail", "data_ready" + Serial.println(F(" Pinging inactive RX node for 'data fail' event...")); + } + + if (pl_iterator < 4 && pl_iterator != 2) { + + // IRQ pin is LOW when activated. Otherwise it is always HIGH + // Wait until IRQ pin is activated. + wait_for_event = true; + + // use the non-blocking call to write a payload and begin transmission + // the "false" argument means we are expecting an ACK packet response + radio.startFastWrite(tx_payloads[pl_iterator++], tx_pl_size, false); + + // In this example, the "data fail" event is always configured to + // trigger the IRQ pin active. Because the auto-ACK feature is on by + // default, we don't need a timeout check to prevent an infinite loop. + + } else if (pl_iterator == 4) { + // all IRQ tests are done; flush_tx() and print the ACK payloads for fun + + // CE pin is still HIGH which consumes more power. Example is now idling so... + radio.stopListening(); // ensure CE pin is LOW + // stopListening() also calls flush_tx() when ACK payloads are enabled + + printRxFifo(); + pl_iterator++; + + + // inform user what to do next + Serial.println(F("\n*** PRESS 'T' to restart the transmissions")); + Serial.println(F("*** PRESS 'R' to change to Receive role\n")); + + + } else if (pl_iterator == 2) { + pl_iterator++; // proceed from step 3 to last step (stop at step 4 for readability) + } + + } else if (!role) { + // This device is a RX node + + if (radio.rxFifoFull()) { + // wait until RX FIFO is full then stop listening + + delay(100); // let ACK payload finish transmitting + radio.stopListening(); // also discards unused ACK payloads + printRxFifo(); // flush the RX FIFO + + // Fill the TX FIFO with 3 ACK payloads for the first 3 received + // transmissions on pipe 1. + radio.writeAckPayload(1, &ack_payloads[0], ack_pl_size); + radio.writeAckPayload(1, &ack_payloads[1], ack_pl_size); + radio.writeAckPayload(1, &ack_payloads[2], ack_pl_size); + + delay(100); // let TX node finish its role + radio.startListening(); // We're ready to start over. Begin listening. + } + + } // role + + if (Serial.available()) { + // change the role via the serial monitor + + char c = toupper(Serial.read()); + if (c == 'T') { + // Become the TX node + if (!role) + Serial.println(F("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK")); + else + Serial.println(F("*** RESTARTING IRQ PIN TEST ***")); + + role = true; + wait_for_event = false; + pl_iterator = 0; // reset the iterator + radio.flush_tx(); // discard any payloads in the TX FIFO + + // startListening() clears the IRQ masks also. This is required for + // continued TX operations when a transmission fails. + radio.stopListening(); // this also discards any unused ACK payloads + + } else if (c == 'R' && role) { + // Become the RX node + Serial.println(F("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK")); + + role = false; + + radio.maskIRQ(0, 0, 0); // the IRQ pin should only trigger on "data ready" event + + // Fill the TX FIFO with 3 ACK payloads for the first 3 received + // transmissions on pipe 1 + radio.flush_tx(); // make sure there is room for 3 new ACK payloads + radio.writeAckPayload(1, &ack_payloads[0], ack_pl_size); + radio.writeAckPayload(1, &ack_payloads[1], ack_pl_size); + radio.writeAckPayload(1, &ack_payloads[2], ack_pl_size); + radio.startListening(); + } + } // Serial.available() +} // loop + + +/** + * when the IRQ pin goes active LOW, call this fuction print out why + */ +void interruptHandler() { + // print IRQ status and all masking flags' states + + Serial.println(F("\tIRQ pin is actively LOW")); // show that this function was called + delayMicroseconds(250); + bool tx_ds, tx_df, rx_dr; // declare variables for IRQ masks + radio.whatHappened(tx_ds, tx_df, rx_dr); // get values for IRQ masks + // whatHappened() clears the IRQ masks also. This is required for + // continued TX operations when a transmission fails. + // clearing the IRQ masks resets the IRQ pin to its inactive state (HIGH) + + Serial.print(F("\tdata_sent: ")); + Serial.print(tx_ds); // print "data sent" mask state + Serial.print(F(", data_fail: ")); + Serial.print(tx_df); // print "data fail" mask state + Serial.print(F(", data_ready: ")); + Serial.println(rx_dr); // print "data ready" mask state + + if (tx_df) // if TX payload failed + radio.flush_tx(); // clear all payloads from the TX FIFO + + // print if test passed or failed. Unintentional fails mean the RX node was not listening. + // pl_iterator has already been incremented by now + if (pl_iterator <= 1) { + Serial.print(F(" 'Data Ready' event test ")); + Serial.println(rx_dr ? F("passed") : F("failed")); + } else if (pl_iterator == 2) { + Serial.print(F(" 'Data Sent' event test ")); + Serial.println(tx_ds ? F("passed") : F("failed")); + } else if (pl_iterator == 4) { + Serial.print(F(" 'Data Fail' event test ")); + Serial.println(tx_df ? F("passed") : F("failed")); + } + wait_for_event = false; // ready to continue with loop() operations +} // interruptHandler + + +/** + * Print the entire RX FIFO with one buffer. This will also flush the RX FIFO. + * Remember that the payload sizes are declared as tx_pl_size and ack_pl_size. + */ +void printRxFifo() { + if (radio.available()) { // if there is data in the RX FIFO + // to flush the data from the RX FIFO, we'll fetch it all using 1 buffer + + uint8_t pl_size = !role ? tx_pl_size : ack_pl_size; + char rx_fifo[pl_size * 3 + 1]; // RX FIFO is full & we know ACK payloads' size + if (radio.rxFifoFull()) { + rx_fifo[pl_size * 3] = 0; // add a NULL terminating char to use as a c-string + radio.read(&rx_fifo, pl_size * 3); // this clears the RX FIFO (for this example) + } else { + uint8_t i = 0; + while (radio.available()) { + radio.read(&rx_fifo + (i * pl_size), pl_size); + i++; + } + rx_fifo[i * pl_size] = 0; // add a NULL terminating char to use as a c-string + } + Serial.print(F("Complete RX FIFO: ")); + Serial.println(rx_fifo); // print the entire RX FIFO with 1 buffer + } +} \ No newline at end of file diff --git a/examples/ManualAcknowledgements/ManualAcknowledgements.ino b/examples/ManualAcknowledgements/ManualAcknowledgements.ino new file mode 100644 index 000000000..17d45933b --- /dev/null +++ b/examples/ManualAcknowledgements/ManualAcknowledgements.ino @@ -0,0 +1,220 @@ +/* + * See documentation at https://nRF24.github.io/RF24 + * See License information at root directory of this library + * Author: Brendan Doherty (2bndy5) + */ + +/** + * A simple example of sending data from 1 nRF24L01 transceiver to another + * with manually transmitted (non-automatic) Acknowledgement (ACK) payloads. + * This example still uses ACK packets, but they have no payloads. Instead the + * acknowledging response is sent with `write()`. This tactic allows for more + * updated acknowledgement payload data, where actual ACK payloads' data are + * outdated by 1 transmission because they have to loaded before receiving a + * transmission. + * + * This example was written to be used on 2 devices acting as "nodes". + * Use the Serial Monitor to change each node's behavior. + */ +#include +#include "printf.h" +#include "RF24.h" + +// instantiate an object for the nRF24L01 transceiver +RF24 radio(7, 8); // using pin 7 for the CE pin, and pin 8 for the CSN pin + +// Let these addresses be used for the pair +uint8_t address[][6] = {"1Node", "2Node"}; +// It is very helpful to think of an address as a path instead of as +// an identifying device destination + +// to use different addresses on a pair of radios, we need a variable to +// uniquely identify which address this radio will use to transmit +bool radioNumber = 1; // 0 uses address[0] to transmit, 1 uses address[1] to transmit + +// Used to control whether this node is sending or receiving +bool role = false; // true = TX node, false = RX node + +// For this example, we'll be using a payload containing +// a string & an integer number that will be incremented +// on every successful transmission. +// Make a data structure to store the entire payload of different datatypes +struct PayloadStruct { + char message[7]; // only using 6 characters for TX & RX payloads + uint8_t counter; +}; +PayloadStruct payload; + +void setup() { + + // append a NULL terminating character for printing as a c-string + payload.message[6] = 0; + + Serial.begin(115200); + while (!Serial) { + // some boards need to wait to ensure access to serial over USB + } + + // initialize the transceiver on the SPI bus + if (!radio.begin()) { + Serial.println(F("radio hardware is not responding!!")); + while (1) {} // hold in infinite loop + } + + // print example's introductory prompt + Serial.println(F("RF24/examples/ManualAcknowledgements")); + + // To set the radioNumber via the Serial monitor on startup + Serial.println(F("Which radio is this? Enter '0' or '1'. Defaults to '0'")); + while (!Serial.available()) { + // wait for user input + } + char input = Serial.parseInt(); + radioNumber = input == 1; + Serial.print(F("radioNumber = ")); + Serial.println((int)radioNumber); + + // role variable is hardcoded to RX behavior, inform the user of this + Serial.println(F("*** PRESS 'T' to begin transmitting to the other node")); + + // Set the PA Level low to try preventing power supply related problems + // because these examples are likely run with nodes in close proximity to + // each other. + radio.setPALevel(RF24_PA_LOW); // RF24_PA_MAX is default. + + // save on transmission time by setting the radio to only transmit the + // number of bytes we need to transmit a float + radio.setPayloadSize(sizeof(payload)); // char[7] & uint8_t datatypes occupy 8 bytes + + // set the TX address of the RX node into the TX pipe + radio.openWritingPipe(address[radioNumber]); // always uses pipe 0 + + // set the RX address of the TX node into a RX pipe + radio.openReadingPipe(1, address[!radioNumber]); // using pipe 1 + + if (role) { + // setup the TX node + + memcpy(payload.message, "Hello ", 6); // set the outgoing message + radio.stopListening(); // put radio in TX mode + } else { + // setup the RX node + + memcpy(payload.message, "World ", 6); // set the outgoing message + radio.startListening(); // put radio in RX mode + } + + // For debugging info + // printf_begin(); // needed only once for printing details + // radio.printDetails(); // (smaller) function that prints raw register values + // radio.printPrettyDetails(); // (larger) function that prints human readable data + +} // setup() + +void loop() { + + if (role) { + // This device is a TX node + + unsigned long start_timer = micros(); // start the timer + bool report = radio.write(&payload, sizeof(payload)); // transmit & save the report + + if (report) { + // transmission successful; wait for response and print results + + radio.startListening(); // put in RX mode + unsigned long start_timeout = millis(); // timer to detect timeout + while (!radio.available()) { // wait for response + if (millis() - start_timeout > 200) // only wait 200 ms + break; + } + unsigned long end_timer = micros(); // end the timer + radio.stopListening(); // put back in TX mode + + // print summary of transactions + Serial.print(F("Transmission successful!")); // payload was delivered + uint8_t pipe; + if (radio.available(&pipe)) { // is there a payload received + Serial.print(F(" Round-trip delay: ")); + Serial.print(end_timer - start_timer); // print the timer result + Serial.print(F(" us. Sent: ")); + Serial.print(payload.message); // print the outgoing payload's message + Serial.print(payload.counter); // print outgoing payload's counter + PayloadStruct received; + radio.read(&received, sizeof(received)); // get payload from RX FIFO + Serial.print(F(" Received ")); + Serial.print(radio.getPayloadSize()); // print the size of the payload + Serial.print(F(" bytes on pipe ")); + Serial.print(pipe); // print the pipe number + Serial.print(F(": ")); + Serial.print(received.message); // print the incoming payload's message + Serial.println(received.counter); // print the incoming payload's counter + payload.counter = received.counter; // save incoming counter for next outgoing counter + } else { + Serial.println(F(" Recieved no response.")); // no response received + } + } else { + Serial.println(F("Transmission failed or timed out")); // payload was not delivered + } // report + + // to make this example readable in the serial monitor + delay(1000); // slow transmissions down by 1 second + + } else { + // This device is a RX node + + uint8_t pipe; + if (radio.available(&pipe)) { // is there a payload? get the pipe number that recieved it + PayloadStruct received; + radio.read(&received, sizeof(received)); // get incoming payload + payload.counter = received.counter + 1; // increment incoming counter for next outgoing response + + // transmit response & save result to `report` + radio.stopListening(); // put in TX mode + + radio.writeFast(&payload, sizeof(payload)); // load response to TX FIFO + bool report = radio.txStandBy(150); // keep retrying for 150 ms + + radio.startListening(); // put back in RX mode + + // print summary of transactions + Serial.print(F("Received ")); + Serial.print(radio.getPayloadSize()); // print the size of the payload + Serial.print(F(" bytes on pipe ")); + Serial.print(pipe); // print the pipe number + Serial.print(F(": ")); + Serial.print(received.message); // print incoming message + Serial.print(received.counter); // print incoming counter + + if (report) { + Serial.print(F(" Sent: ")); + Serial.print(payload.message); // print outgoing message + Serial.println(payload.counter); // print outgoing counter + } else { + Serial.println(" Response failed."); // failed to send response + } + } + } // role + + if (Serial.available()) { + // change the role via the serial monitor + + char c = toupper(Serial.read()); + if (c == 'T' && !role) { + // Become the TX node + + role = true; + memcpy(payload.message, "Hello ", 6); // set the outgoing message + Serial.println(F("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK")); + radio.stopListening(); // put in TX mode + + } else if (c == 'R' && role) { + // Become the RX node + + role = false; + memcpy(payload.message, "World ", 6); // set the response message + Serial.println(F("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK")); + radio.startListening(); // put in RX mode + } + } +} // loop \ No newline at end of file diff --git a/examples/MulticeiverDemo/MulticeiverDemo.ino b/examples/MulticeiverDemo/MulticeiverDemo.ino new file mode 100644 index 000000000..cce3a89fc --- /dev/null +++ b/examples/MulticeiverDemo/MulticeiverDemo.ino @@ -0,0 +1,198 @@ +/* + * See documentation at https://nRF24.github.io/RF24 + * See License information at root directory of this library + * Author: Brendan Doherty 2bndy5 + */ + +/** + * A simple example of sending data from as many as 6 nRF24L01 transceivers to + * 1 receiving transceiver. This technique is trademarked by + * Nordic Semiconductors as "MultiCeiver". + * + * This example was written to be used on up to 6 devices acting as TX nodes & + * only 1 device acting as the RX node (that's a maximum of 7 devices). + * Use the Serial Monitor to change each node's behavior. + */ +#include +#include "printf.h" +#include "RF24.h" + +// instantiate an object for the nRF24L01 transceiver +RF24 radio(7, 8); // using pin 7 for the CE pin, and pin 8 for the CSN pin + +// For this example, we'll be using 6 addresses; 1 for each TX node +// It is very helpful to think of an address as a path instead of as +// an identifying device destination +// Notice that the last byte is the only byte that changes in the last 5 +// addresses. This is a limitation of the nRF24L01 transceiver for pipes 2-5 +// because they use the same first 4 bytes from pipe 1. +uint64_t address[6] = {0x7878787878LL, + 0xB3B4B5B6F1LL, + 0xB3B4B5B6CDLL, + 0xB3B4B5B6A3LL, + 0xB3B4B5B60FLL, + 0xB3B4B5B605LL + }; + +// Because this example allow up to 6 nodes (specified by numbers 0-5) to +// transmit and only 1 node to receive, we will use a negative value in our +// role variable to signify this node is a receiver. +// role variable is used to control whether this node is sending or receiving +char role = 'R'; // 0-5 = TX node; any negative number = RX node + +// For this example, we'll be using a payload containing +// a node ID number and a single integer number that will be incremented +// on every successful transmission. +// Make a data structure to use as a payload. +struct PayloadStruct +{ + unsigned long nodeID; + unsigned long payloadID; +}; +PayloadStruct payload; + +// This example uses all 6 pipes to receive while TX nodes only use 2 pipes +// To make this easier we'll use a function to manage the addresses, and the +// payload's nodeID +void setRole(); // declare a prototype; definition is found after the loop() + +void setup() { + + Serial.begin(115200); + while (!Serial) { + // some boards need to wait to ensure access to serial over USB + } + + // initialize the transceiver on the SPI bus + if (!radio.begin()) { + Serial.println(F("radio hardware is not responding!!")); + while (1) {} // hold in infinite loop + } + + // print example's introductory prompt + Serial.println(F("RF24/examples/MulticeiverDemo")); + Serial.println(F("*** Enter a number between 0 and 5 (inclusive) to change")); + Serial.println(F(" the identifying node number that transmits.")); + + // Set the PA Level low to try preventing power supply related problems + // because these examples are likely run with nodes in close proximity of + // each other. + radio.setPALevel(RF24_PA_LOW); // RF24_PA_MAX is default. + + // save on transmission time by setting the radio to only transmit the + // number of bytes we need to transmit a float + radio.setPayloadSize(sizeof(payload)); // 2x int datatype occupy 8 bytes + + // Set the pipe addresses accordingly. This function additionally also + // calls startListening() or stopListening() and sets the payload's nodeID + setRole(); + + // For debugging info + // printf_begin(); // needed only once for printing details + // radio.printDetails(); // (smaller) function that prints raw register values + // radio.printPrettyDetails(); // (larger) function that prints human readable data + +} // setup() + +void loop() { + + if (role <= 53) { + // This device is a TX node + + unsigned long start_timer = micros(); // start the timer + bool report = radio.write(&payload, sizeof(payload)); // transmit & save the report + unsigned long end_timer = micros(); // end the timer + + if (report) { + // payload was delivered + + Serial.print(F("Transmission of payloadID ")); + Serial.print(payload.payloadID); // print payloadID + Serial.print(F(" as node ")); + Serial.print(payload.nodeID); // print nodeID + Serial.print(F(" successful!")); + Serial.print(F(" Time to transmit: ")); + Serial.print(end_timer - start_timer); // print the timer result + Serial.println(F(" us")); + } else { + Serial.println(F("Transmission failed or timed out")); // payload was not delivered + } + payload.payloadID++; // increment payload number + + // to make this example readable in the serial monitor + delay(500); // slow transmissions down by 1 second + + } else if (role == 'R') { + // This device is the RX node + + uint8_t pipe; + if (radio.available(&pipe)) { // is there a payload? get the pipe number that recieved it + uint8_t bytes = radio.getPayloadSize(); // get the size of the payload + radio.read(&payload, bytes); // fetch payload from FIFO + Serial.print(F("Received ")); + Serial.print(bytes); // print the size of the payload + Serial.print(F(" bytes on pipe ")); + Serial.print(pipe); // print the pipe number + Serial.print(F(" from node ")); + Serial.print(payload.nodeID); // print the payload's origin + Serial.print(F(". PayloadID: ")); + Serial.println(payload.payloadID); // print the payload's number + } + } // role + + if (Serial.available()) { + // change the role via the serial monitor + + char c = Serial.read(); + if (toupper(c) == 'R' && role <= 53) { + // Become the RX node + + role = 'R'; + Serial.println(F("*** CHANGING ROLE TO RECEIVER ***")); + Serial.println(F("--- Enter a number between 0 and 5 (inclusive) to act as")); + Serial.println(F(" a unique node number that transmits to the RX node.")); + setRole(); // change address on all pipes to TX nodes + + } else if (c >= 48 && c <= 53 && c != role) { + // Become a TX node with identifier 'c' + + role = c - 48; + Serial.print(F("*** CHANGING ROLE TO NODE ")); + Serial.print(c); + Serial.println(F(" ***")); + Serial.println(F("--- Enter a number between 0 and 5 (inclusive) to change")); + Serial.println(F(" the identifying node number that transmits.")); + Serial.println(F("--- PRESS 'R' to act as the RX node.")); + setRole(); // change address on pipe 0 to the RX node + } + } + +} // loop + +void setRole() { + if (role == 'R') { + // For the RX node + + // Set the addresses for all pipes to TX nodes + for (uint8_t i = 0; i < 6; ++i) + radio.openReadingPipe(i, address[i]); + + radio.startListening(); // put radio in RX mode + + } else { + // For the TX node + + // set the payload's nodeID & reset the payload's identifying number + payload.nodeID = role; + payload.payloadID = 0; + + // Set the address on pipe 0 to the RX node. + radio.stopListening(); // put radio in TX mode + radio.openWritingPipe(address[role]); + + // According to the datasheet, the auto-retry features's delay value should + // be "skewed" to allow the RX node to receive 1 transmission at a time. + // So, use varying delay between retry attempts and 15 (at most) retry attempts + radio.setRetries(((role * 3) % 12) + 3, 15); // maximum value is 15 for both args + } +} // setRole \ No newline at end of file diff --git a/examples/StreamingData/StreamingData.ino b/examples/StreamingData/StreamingData.ino new file mode 100644 index 000000000..e17d9b509 --- /dev/null +++ b/examples/StreamingData/StreamingData.ino @@ -0,0 +1,185 @@ +/* + * See documentation at https://nRF24.github.io/RF24 + * See License information at root directory of this library + * Author: Brendan Doherty 2bndy5 + */ + +/** + * A simple example of streaming data from 1 nRF24L01 transceiver to another. + * + * This example was written to be used on 2 devices acting as "nodes". + * Use the Serial Monitor to change each node's behavior. + */ +#include +#include "printf.h" +#include "RF24.h" + +// instantiate an object for the nRF24L01 transceiver +RF24 radio(7, 8); // using pin 7 for the CE pin, and pin 8 for the CSN pin + +// Let these addresses be used for the pair +uint8_t address[][6] = {"1Node", "2Node"}; +// It is very helpful to think of an address as a path instead of as +// an identifying device destination + +// to use different addresses on a pair of radios, we need a variable to +// uniquely identify which address this radio will use to transmit +bool radioNumber; // 0 uses address[0] to transmit, 1 uses address[1] to transmit + +// Used to control whether this node is sending or receiving +bool role = false; // true = TX node, false = RX node + +// For this example, we'll be sending 32 payloads each containing +// 32 bytes of data that looks like ASCII art when printed to the serial +// monitor. The TX node and RX node needs only a single 32 byte buffer. +#define SIZE 32 // this is the maximum for this example. (minimum is 1) +char buffer[SIZE + 1]; // for the RX node +uint8_t counter = 0; // for counting the number of received payloads +void makePayload(uint8_t); // prototype to construct a payload dynamically + + +void setup() { + + buffer[SIZE] = 0; // add a NULL terminating character (for easy printing) + + Serial.begin(115200); + while (!Serial) { + // some boards need to wait to ensure access to serial over USB + } + + // initialize the transceiver on the SPI bus + if (!radio.begin()) { + Serial.println(F("radio hardware is not responding!!")); + while (1) {} // hold in infinite loop + } + + // print example's introductory prompt + Serial.println(F("RF24/examples/StreamingData")); + + // To set the radioNumber via the Serial monitor on startup + Serial.println(F("Which radio is this? Enter '0' or '1'. Defaults to '0'")); + while (!Serial.available()) { + // wait for user input + } + char input = Serial.parseInt(); + radioNumber = input == 1; + Serial.print(F("radioNumber = ")); + Serial.println((int)radioNumber); + + // role variable is hardcoded to RX behavior, inform the user of this + Serial.println(F("*** PRESS 'T' to begin transmitting to the other node")); + + // Set the PA Level low to try preventing power supply related problems + // because these examples are likely run with nodes in close proximity to + // each other. + radio.setPALevel(RF24_PA_LOW); // RF24_PA_MAX is default. + + // save on transmission time by setting the radio to only transmit the + // number of bytes we need to transmit + radio.setPayloadSize(SIZE); // default value is the maximum 32 bytes + + // set the TX address of the RX node into the TX pipe + radio.openWritingPipe(address[radioNumber]); // always uses pipe 0 + + // set the RX address of the TX node into a RX pipe + radio.openReadingPipe(1, address[!radioNumber]); // using pipe 1 + + // additional setup specific to the node's role + if (role) { + radio.stopListening(); // put radio in TX mode + } else { + radio.startListening(); // put radio in RX mode + } + + // For debugging info + // printf_begin(); // needed only once for printing details + // radio.printDetails(); // (smaller) function that prints raw register values + // radio.printPrettyDetails(); // (larger) function that prints human readable data + +} // setup() + + +void loop() { + + if (role) { + // This device is a TX node + + radio.flush_tx(); + uint8_t i = 0; + uint8_t failures = 0; + unsigned long start_timer = micros(); // start the timer + while (i < SIZE) { + makePayload(i); // make the payload + if (!radio.writeFast(&buffer, SIZE)) { + failures++; + radio.reUseTX(); + } else { + i++; + } + + if (failures >= 100) { + Serial.print(F("Too many failures detected. Aborting at payload ")); + Serial.println(buffer[0]); + break; + } + } + unsigned long end_timer = micros(); // end the timer + + Serial.print(F("Time to transmit = ")); + Serial.print(end_timer - start_timer); // print the timer result + Serial.print(F(" us with ")); + Serial.print(failures); // print failures detected + Serial.println(F(" failures detected")); + + // to make this example readable in the serial monitor + delay(1000); // slow transmissions down by 1 second + + } else { + // This device is a RX node + + if (radio.available()) { // is there a payload? + radio.read(&buffer, SIZE); // fetch payload from FIFO + Serial.print(F("Received: ")); + Serial.print(buffer); // print the payload's value + Serial.print(F(" - ")); + Serial.println(counter++); // print the received counter + } + } // role + + if (Serial.available()) { + // change the role via the serial monitor + + char c = toupper(Serial.read()); + if (c == 'T' && !role) { + // Become the TX node + + role = true; + counter = 0; //reset the RX node's counter + Serial.println(F("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK")); + radio.stopListening(); + + } else if (c == 'R' && role) { + // Become the RX node + + role = false; + Serial.println(F("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK")); + radio.startListening(); + } + } + +} // loop + + +void makePayload(uint8_t i) { + // Make a single payload based on position in stream. + // This example employs function to save memory on certain boards. + + // let the first character be an identifying alphanumeric prefix + // this lets us see which payload didn't get received + buffer[0] = i + (i < 26 ? 65 : 71); + for (uint8_t j = 0; j < SIZE - 1; ++j) { + char chr = j >= (SIZE - 1) / 2 + abs((SIZE - 1) / 2 - i); + chr |= j < (SIZE - 1) / 2 - abs((SIZE - 1) / 2 - i); + buffer[j + 1] = chr + 48; + } +} \ No newline at end of file diff --git a/examples/Transfer/Transfer.ino b/examples/Transfer/Transfer.ino deleted file mode 100644 index 249ee6bd6..000000000 --- a/examples/Transfer/Transfer.ino +++ /dev/null @@ -1,146 +0,0 @@ -/* - TMRh20 2014 - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. -*/ - -/* - General Data Transfer Rate Test - - This example demonstrates basic data transfer functionality with the - updated library. This example will display the transfer rates acheived - using the slower form of high-speed transfer using blocking-writes. -*/ - - -#include -#include "RF24.h" -#include "printf.h" - -/************* USER Configuration *****************************/ -// Hardware configuration -RF24 radio(7, 8); // Set up nRF24L01 radio on SPI bus plus pins 7 & 8 - -/***************************************************************/ - -const uint64_t pipes[2] = { 0xABCDABCD71LL, 0x544d52687CLL }; // Radio pipe addresses for the 2 nodes to communicate. - -byte data[32]; //Data buffer for testing data transfer speeds - -unsigned long counter, rxTimer; //Counter and timer for keeping track transfer info -unsigned long startTime, stopTime; -bool TX = 1, RX = 0, role = 0; - -void setup(void) { - Serial.begin(115200); - printf_begin(); - - radio.begin(); // Setup and configure rf radio - radio.setChannel(1); - radio.setPALevel(RF24_PA_LOW); // If you want to save power use "RF24_PA_MIN" but keep in mind that reduces the module's range - radio.setDataRate(RF24_2MBPS); - radio.setAutoAck(1); // Ensure autoACK is enabled - radio.setRetries(2, 15); // Optionally, increase the delay between retries & # of retries - - radio.setCRCLength(RF24_CRC_8); // Use 8-bit CRC for performance - radio.openWritingPipe(pipes[0]); - radio.openReadingPipe(1, pipes[1]); - - radio.startListening(); // Start listening - radio.printDetails(); // Dump the configuration of the rf unit for debugging - - Serial.println(F("\n\rRF24/examples/Transfer/")); - Serial.println(F("*** PRESS 'T' to begin transmitting to the other node")); - - randomSeed(analogRead(0)); //Seed for random number generation - - for (int i = 0; i < 32; i++) { - data[i] = random(255); //Load the buffer with random data - } - radio.powerUp(); //Power up the radio -} - -void loop(void) { - if (role == TX) { - delay(2000); - - Serial.println(F("Initiating Basic Data Transfer")); - - unsigned long cycles = 10000; //Change this to a higher or lower number. - - startTime = millis(); - unsigned long pauseTime = millis(); - - for (int i = 0; i < cycles; i++) { //Loop through a number of cycles - data[0] = i; //Change the first byte of the payload for identification - if (!radio.writeFast(&data, 32)) { //Write to the FIFO buffers - counter++; //Keep count of failed payloads - } - - //This is only required when NO ACK ( enableAutoAck(0) ) payloads are used - // if(millis() - pauseTime > 3){ - // pauseTime = millis(); - // radio.txStandBy(); // Need to drop out of TX mode every 4ms if sending a steady stream of multicast data - // //delayMicroseconds(130); // This gives the PLL time to sync back up - // } - - } - - stopTime = millis(); - //This should be called to wait for completion and put the radio in standby mode after transmission, returns 0 if data still in FIFO (timed out), 1 if success - if (!radio.txStandBy()) { - counter += 3; //Standby, block only until FIFO empty or auto-retry timeout. Flush TX FIFO if failed - } - //radio.txStandBy(1000); //Standby, using extended timeout period of 1 second - - float numBytes = cycles * 32; - float rate = numBytes / (stopTime - startTime); - - Serial.print("Transfer complete at "); Serial.print(rate); Serial.println(" KB/s"); - Serial.print(counter); Serial.print(" of "); Serial.print(cycles); Serial.println(" Packets Failed to Send"); - counter = 0; - - } - - - - if (role == RX) { - while (radio.available()) { - radio.read(&data, 32); - counter++; - } - if (millis() - rxTimer > 1000) { - rxTimer = millis(); - unsigned long numBytes = counter * 32; - Serial.print(F("Rate: ")); - //Prevent dividing into 0, which will cause issues over a period of time - Serial.println(numBytes > 0 ? numBytes / 1000.0 : 0); - Serial.print(F("Payload Count: ")); - Serial.println(counter); - counter = 0; - } - } - // - // Change roles - // - - if ( Serial.available()) { - char c = toupper(Serial.read()); - if (c == 'T' && role == RX) { - Serial.println(F("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK")); - delay(10); - radio.openWritingPipe(pipes[1]); - radio.openReadingPipe(1, pipes[0]); - radio.stopListening(); - role = TX; // Become the primary transmitter (ping out) - } else if (c == 'R' && role == TX) { - radio.openWritingPipe(pipes[0]); - radio.openReadingPipe(1, pipes[1]); - radio.startListening(); - Serial.println(F("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK")); - role = RX; // Become the primary receiver (pong back) - } - } -} diff --git a/examples/TransferTimeouts/TransferTimeouts.ino b/examples/TransferTimeouts/TransferTimeouts.ino deleted file mode 100644 index 95d765761..000000000 --- a/examples/TransferTimeouts/TransferTimeouts.ino +++ /dev/null @@ -1,189 +0,0 @@ -/* -TMRh20 2014 - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -/** Reliably transmitting large volumes of data with a low signal or in noisy environments - * This example demonstrates data transfer functionality with the use of auto-retry - and auto-reUse functionality enabled. This sketch demonstrates how a user can extend - the auto-retry functionality to any chosen time period, preventing data loss and ensuring - the consistency of data. - - This sketh demonstrates use of the writeBlocking() functionality, and extends the standard - retry functionality of the radio. Payloads will be auto-retried until successful or the - extended timeout period is reached. - */ - - - -#include -#include "nRF24L01.h" -#include "RF24.h" -#include "printf.h" - -/************* USER Configuration *****************************/ - -RF24 radio(7,8); // Set up nRF24L01 radio on SPI bus plus pins 7 & 8 -unsigned long timeoutPeriod = 3000; // Set a user-defined timeout period. With auto-retransmit set to (15,15) retransmission will take up to 60ms and as little as 7.5ms with it set to (1,15). - // With a timeout period of 1000, the radio will retry each payload for up to 1 second before giving up on the transmission and starting over - -/***************************************************************/ - -const uint64_t pipes[2] = { 0xABCDABCD71LL, 0x544d52687CLL }; // Radio pipe addresses for the 2 nodes to communicate. - -byte data[32]; //Data buffer - -volatile unsigned long counter; -unsigned long rxTimer,startTime, stopTime, payloads = 0; -bool TX=1,RX=0,role=0, transferInProgress = 0; - - -void setup(void) { - - Serial.begin(115200); - printf_begin(); - - radio.begin(); // Setup and configure rf radio - radio.setChannel(1); // Set the channel - radio.setPALevel(RF24_PA_LOW); // Set PA LOW for this demonstration. We want the radio to be as lossy as possible for this example. - radio.setDataRate(RF24_1MBPS); // Raise the data rate to reduce transmission distance and increase lossiness - radio.setAutoAck(1); // Ensure autoACK is enabled - radio.setRetries(2,15); // Optionally, increase the delay between retries. Want the number of auto-retries as high as possible (15) - radio.setCRCLength(RF24_CRC_16); // Set CRC length to 16-bit to ensure quality of data - radio.openWritingPipe(pipes[0]); // Open the default reading and writing pipe - radio.openReadingPipe(1,pipes[1]); - - radio.startListening(); // Start listening - radio.printDetails(); // Dump the configuration of the rf unit for debugging - - printf("\n\rRF24/examples/Transfer Rates/\n\r"); - printf("*** PRESS 'T' to begin transmitting to the other node\n\r"); - - randomSeed(analogRead(0)); //Seed for random number generation - for(int i=0; i<32; i++){ - data[i] = random(255); //Load the buffer with random data - } - radio.powerUp(); //Power up the radio - - -} - - - -void loop(void){ - - - if(role == TX){ - delay(2000); // Pause for a couple seconds between transfers - printf("Initiating Extended Timeout Data Transfer\n\r"); - - unsigned long cycles = 1000; // Change this to a higher or lower number. This is the number of payloads that will be sent. - - unsigned long transferCMD[] = {'H','S',cycles }; // Indicate to the other radio that we are starting, and provide the number of payloads that will be sent - radio.writeFast(&transferCMD,12); // Send the transfer command - if(radio.txStandBy(timeoutPeriod)){ // If transfer initiation was successful, do the following - - startTime = millis(); // For calculating transfer rate - boolean timedOut = 0; // Boolean for keeping track of failures - - for(int i=0; i timeoutPeriod){ // If no data available, check the timeout period - Serial.println("Transfer Failed"); // If per-payload timeout exceeeded, end the transfer - transferInProgress = 0; - }else - if(counter >= payloads){ // If the specified number of payloads is reached, transfer is completed - startTime = millis() - startTime; // Calculate the total time spent during transfer - float numBytes = counter*32; // Calculate the number of bytes transferred - Serial.print("Rate: "); // Print the transfer rate and number of payloads - Serial.print(numBytes/startTime); - Serial.println(" KB/s"); - printf("Payload Count: %d \n\r", counter); - transferInProgress = 0; // End the transfer as complete - } - } - - - } - - // - // Change roles - // - - if ( Serial.available() ) - { - char c = toupper(Serial.read()); - if ( c == 'T' && role == RX ) - { - printf("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK\n\r"); - radio.openWritingPipe(pipes[1]); - radio.openReadingPipe(1,pipes[0]); - radio.stopListening(); - role = TX; // Become the primary transmitter (ping out) - } - else if ( c == 'R' && role == TX ) - { - radio.openWritingPipe(pipes[0]); - radio.openReadingPipe(1,pipes[1]); - radio.startListening(); - printf("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK\n\r"); - role = RX; // Become the primary receiver (pong back) - } - } -} - - diff --git a/examples/Usage/led_remote/Jamfile b/examples/Usage/led_remote/Jamfile deleted file mode 100644 index 901f8da8c..000000000 --- a/examples/Usage/led_remote/Jamfile +++ /dev/null @@ -1,206 +0,0 @@ -PROJECT_NAME = $(PWD:B) ; -PROJECT_DIR = . ; -PROJECT_LIBS = SPI RF24 ; - -OUT_DIR = ojam ; -F_CPU = 16000000 ; -MCU = atmega328p ; -PORTS = /dev/tty.usbserial-A600eHIs /dev/tty.usbserial-A40081RP /dev/tty.usbserial-A9007LmI ; - -UPLOAD_RATE = 57600 ; -AVRDUDE_PROTOCOL = stk500v1 ; -COM = 33 ; - -# Host-specific overrides for locations -if $(OS) = MACOSX -{ -ARDUINO_VERSION = 22 ; -OLD_DIR = /opt/arduino-0021 ; -AVR_TOOLS_PATH = $(OLD_DIR)/hardware/tools/avr/bin ; -AVRDUDECONFIG_PATH = $(OLD_DIR)/hardware/tools/avr/etc ; -ARDUINO_DIR = /opt/Arduino ; -ARDUINO_AVR = /usr/lib/avr/include ; -} - -# Where is everything? -ARDUINO_VERSION ?= 22 ; -AVR_TOOLS_PATH ?= /usr/bin ; -ARDUINO_DIR ?= /opt/arduino-00$(ARDUINO_VERSION) ; -ARDUINO_AVR ?= $(ARDUINO_DIR)/hardware/tools/avr/avr/include/avr ; -AVRDUDECONFIG_PATH ?= $(ARDUINO_DIR)/hardware/tools ; -ARDUINO_CORE = $(ARDUINO_DIR)/hardware/arduino/cores/arduino ; -ARDUINO_LIB = $(ARDUINO_DIR)/libraries ; -SKETCH_LIB = $(HOME)/Source/Arduino/libraries ; -AVR_CC = $(AVR_TOOLS_PATH)/avr-gcc ; -AVR_CXX = $(AVR_TOOLS_PATH)/avr-g++ ; -AVR_LD = $(AVR_TOOLS_PATH)/avr-gcc ; -AVR_OBJCOPY = $(AVR_TOOLS_PATH)/avr-objcopy ; -AVRDUDE = $(AVR_TOOLS_PATH)/avrdude ; - -DEFINES = F_CPU=$(F_CPU)L ARDUINO=$(ARDUINO_VERSION) VERSION_H ; -CTUNING = -ffunction-sections -fdata-sections ; -CXXTUNING = -fno-exceptions -fno-strict-aliasing ; -CFLAGS = -Os -Wall -Wextra -mmcu=$(MCU) $(CTUNING) ; -CXXFLAGS = $(CFLAGS) $(CXXTUNING) ; -LDFLAGS = -Os -lm -Wl,--gc-sections -mmcu=atmega328p ; - -# Search everywhere for headers -HDRS = $(PROJECT_DIR) $(ARDUINO_AVR) $(ARDUINO_CORE) [ GLOB $(ARDUINO_LIB) $(SKETCH_LIB) : [^.]* ] ; - -# Grab everything from the core directory -CORE_MODULES = [ GLOB $(ARDUINO_CORE) : *.c *.cpp ] ; - -# Grab everything from libraries. To avoid this "grab everything" behaviour, you -# can specify specific modules to pick up in PROJECT_MODULES -LIB_MODULES = [ GLOB $(ARDUINO_LIB)/$(PROJECT_LIBS) $(SKETCH_LIB)/$(PROJECT_LIBS) : *.cpp ] ; - -# In addition to explicitly-specified program modules, pick up anything from the current -# dir. -PROJECT_MODULES += [ GLOB $(PROJECT_DIR) : *.c *.cpp *.pde ] ; - -# Shortcut for the out files -OUT = $(OUT_DIR)/$(PROJECT_NAME) ; - -# AvrDude setup -AVRDUDE_FLAGS = -V -F -D -C $(AVRDUDECONFIG_PATH)/avrdude.conf -p $(MCU) -c $(AVRDUDE_PROTOCOL) -b $(UPLOAD_RATE) ; - -rule GitVersion -{ - Always $(<) ; - Depends all : $(<) ; -} - -actions GitVersion -{ - echo "const char program_version[] = \"\\" > $(<) - git log -1 --pretty=format:%h >> $(<) - echo "\";" >> $(<) -} - -GitVersion version.h ; - -rule AvrCc -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - Clean clean : $(<) ; - - CCHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] ; - CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ; -} - -actions AvrCc -{ - $(AVR_CC) -c -o $(<) $(CCHDRS) $(CCDEFS) $(CFLAGS) $(>) -} - -rule AvrC++ -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - Clean clean : $(<) ; - - CCHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] ; - CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ; -} - -actions AvrC++ -{ - $(AVR_CXX) -c -o $(<) $(CCHDRS) $(CCDEFS) $(CXXFLAGS) $(>) -} - -rule Pde -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - Clean clean : $(<) ; - -} - -actions Pde -{ - echo "#include " > $(<) - echo "#line 1 \"$(>)\"" >> $(<) - cat $(>) >> $(<) -} - -rule AvrPde -{ - local _CPP = $(OUT_DIR)/$(_I:B).cpp ; - Pde $(_CPP) : $(>) ; - AvrC++ $(<) : $(_CPP) ; -} - -rule AvrObject -{ - switch $(>:S) - { - case .c : AvrCc $(<) : $(>) ; - case .cpp : AvrC++ $(<) : $(>) ; - case .pde : AvrPde $(<) : $(>) ; - } -} - -rule AvrObjects -{ - for _I in $(<) - { - AvrObject $(OUT_DIR)/$(_I:B).o : $(_I) ; - } -} - -rule AvrMainFromObjects -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - MkDir $(<:D) ; - Depends all : $(<) ; - Clean clean : $(<) ; -} - -actions AvrMainFromObjects -{ - $(AVR_LD) $(LDFLAGS) -o $(<) $(>) -} - -rule AvrMain -{ - AvrMainFromObjects $(<) : $(OUT_DIR)/$(>:B).o ; - AvrObjects $(>) ; -} - -rule AvrHex -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - Depends hex : $(<) ; - Clean clean : $(<) ; -} - -actions AvrHex -{ - $(AVR_OBJCOPY) -O ihex -R .eeprom $(>) $(<) -} - -rule AvrUpload -{ - Depends $(1) : $(2) ; - Depends $(2) : $(3) ; - NotFile $(1) ; - Always $(1) ; - Always $(2) ; - AvrUploadAction $(2) : $(3) ; -} - -actions AvrUploadAction -{ - $(AVRDUDE) $(AVRDUDE_FLAGS) -P $(<) $(AVRDUDE_WRITE_FLASH) -U flash:w:$(>):i -} - -AvrMain $(OUT).elf : $(CORE_MODULES) $(LIB_MODULES) $(PROJECT_MODULES) ; -AvrHex $(OUT).hex : $(OUT).elf ; - -AvrUpload p6 : /dev/tty.usbserial-A600eHIs : $(OUT).hex ; -AvrUpload p4 : /dev/tty.usbserial-A40081RP : $(OUT).hex ; -AvrUpload p9 : /dev/tty.usbserial-A9007LmI : $(OUT).hex ; - diff --git a/examples/Usage/nordic_fob/Jamfile b/examples/Usage/nordic_fob/Jamfile deleted file mode 100644 index ec519f7c5..000000000 --- a/examples/Usage/nordic_fob/Jamfile +++ /dev/null @@ -1,219 +0,0 @@ -# (1) Project Information - -PROJECT_LIBS = RF24 SPI ; -PROJECT_DIRS = $(PWD) ; - -# (2) Board Information - -UPLOAD_PROTOCOL ?= stk500v1 ; -UPLOAD_SPEED ?= 115200 ; -MCU ?= atmega328p ; -F_CPU ?= 16000000 ; -CORE ?= arduino ; -VARIANT ?= standard ; -ARDUINO_VERSION ?= 100 ; - -# (3) USB Ports - -PORTS = p4 p6 p9 u0 u1 u2 ; -PORT_p6 = /dev/tty.usbserial-A600eHIs ; -PORT_p4 = /dev/tty.usbserial-A40081RP ; -PORT_p9 = /dev/tty.usbserial-A9007LmI ; -PORT_u0 = /dev/ttyUSB0 ; -PORT_u1 = /dev/ttyUSB1 ; -PORT_u2 = /dev/ttyUSB2 ; - -# (4) Location of AVR tools -# -# This configuration assumes using avr-tools that were obtained separate from the Arduino -# distribution. - -if $(OS) = MACOSX -{ - AVR_BIN = /usr/local/avrtools/bin ; - AVR_ETC = /usr/local/avrtools/etc ; - AVR_INCLUDE = /usr/local/avrtools/include ; -} -else -{ - AVR_BIN = /usr/bin ; - AVR_INCLUDE = /usr/lib/avr/include ; - AVR_ETC = /etc ; -} - -# (5) Directories where Arduino core and libraries are located - -ARDUINO_DIR ?= /opt/Arduino ; -ARDUINO_CORE = $(ARDUINO_DIR)/hardware/arduino/cores/$(CORE) $(ARDUINO_DIR)/hardware/arduino/variants/$(VARIANT) ; -ARDUINO_LIB = $(ARDUINO_DIR)/libraries ; -SKETCH_LIB = $(HOME)/Source/Arduino/libraries ; - -# -# -------------------------------------------------- -# Below this line usually never needs to be modified -# - -# Tool locations - -CC = $(AVR_BIN)/avr-gcc ; -C++ = $(AVR_BIN)/avr-g++ ; -LINK = $(AVR_BIN)/avr-gcc ; -AR = $(AVR_BIN)/avr-ar rcs ; -RANLIB = ; -OBJCOPY = $(AVR_BIN)/avr-objcopy ; -AVRDUDE = $(AVR_BIN)/avrdude ; - -# Flags - -DEFINES += F_CPU=$(F_CPU)L ARDUINO=$(ARDUINO_VERSION) VERSION_H ; -OPTIM = -Os ; -CCFLAGS = -Wall -Wextra -Wno-strict-aliasing -mmcu=$(MCU) -ffunction-sections -fdata-sections ; -C++FLAGS = $(CCFLAGS) -fno-exceptions -fno-strict-aliasing ; -LINKFLAGS = $(OPTIM) -lm -Wl,--gc-sections -mmcu=$(MCU) ; -AVRDUDEFLAGS = -V -F -D -C $(AVR_ETC)/avrdude.conf -p $(MCU) -c $(UPLOAD_PROTOCOL) -b $(UPLOAD_SPEED) ; - -# Search everywhere for headers - -HDRS = $(PROJECT_DIRS) $(AVR_INCLUDE) $(ARDUINO_CORE) $(ARDUINO_LIB)/$(PROJECT_LIBS) $(ARDUINO_LIB)/$(PROJECT_LIBS)/utility $(SKETCH_LIB)/$(PROJECT_LIBS) ; - -# Output locations - -LOCATE_TARGET = $(F_CPU) ; -LOCATE_SOURCE = $(F_CPU) ; - -# -# Custom rules -# - -rule GitVersion -{ - Always $(<) ; - Depends all : $(<) ; -} - -actions GitVersion -{ - echo "const char program_version[] = \"\\" > $(<) - git log -1 --pretty=format:%h >> $(<) - echo "\";" >> $(<) -} - -GitVersion version.h ; - -rule Pde -{ - Depends $(<) : $(>) ; - MakeLocate $(<) : $(LOCATE_SOURCE) ; - Clean clean : $(<) ; -} - -if ( $(ARDUINO_VERSION) < 100 ) -{ - ARDUINO_H = WProgram.h ; -} -else -{ - ARDUINO_H = Arduino.h ; -} - -actions Pde -{ - echo "#include <$(ARDUINO_H)>" > $(<) - echo "#line 1 \"$(>)\"" >> $(<) - cat $(>) >> $(<) -} - -rule C++Pde -{ - local _CPP = $(>:B).cpp ; - Pde $(_CPP) : $(>) ; - C++ $(<) : $(_CPP) ; -} - -rule UserObject -{ - switch $(>:S) - { - case .ino : C++Pde $(<) : $(>) ; - case .pde : C++Pde $(<) : $(>) ; - } -} - -rule Objects -{ - local _i ; - - for _i in [ FGristFiles $(<) ] - { - local _b = $(_i:B)$(SUFOBJ) ; - local _o = $(_b:G=$(SOURCE_GRIST:E)) ; - Object $(_o) : $(_i) ; - Depends obj : $(_o) ; - } -} - -rule Library -{ - LibraryFromObjects $(<) : $(>:B)$(SUFOBJ) ; - Objects $(>) ; -} - -rule Main -{ - MainFromObjects $(<) : $(>:B)$(SUFOBJ) ; - Objects $(>) ; -} - -rule Hex -{ - Depends $(<) : $(>) ; - MakeLocate $(<) : $(LOCATE_TARGET) ; - Depends hex : $(<) ; - Clean clean : $(<) ; -} - -actions Hex -{ - $(OBJCOPY) -O ihex -R .eeprom $(>) $(<) -} - -rule Upload -{ - Depends $(1) : $(2) ; - Depends $(2) : $(3) ; - NotFile $(1) ; - Always $(1) ; - Always $(2) ; - UploadAction $(2) : $(3) ; -} - -actions UploadAction -{ - $(AVRDUDE) $(AVRDUDEFLAGS) -P $(<) $(AVRDUDE_WRITE_FLASH) -U flash:w:$(>):i -} - -rule Arduino -{ - LINKFLAGS on $(<) = $(LINKFLAGS) -Wl,-Map=$(LOCATE_TARGET)/$(<:B).map ; - Main $(<) : $(>) ; - LinkLibraries $(<) : libs core ; - Hex $(<:B).hex : $(<) ; - for _p in $(PORTS) - { - Upload $(_p) : $(PORT_$(_p)) : $(<:B).hex ; - } -} - -# -# Targets -# - -# Grab everything from the core directory -Library core : [ GLOB $(ARDUINO_CORE) : *.c *.cpp ] ; - -# Grab everything from libraries. To avoid this "grab everything" behaviour, you -# can specify specific modules to pick up in PROJECT_MODULES -Library libs : [ GLOB $(ARDUINO_LIB)/$(PROJECT_LIBS) $(ARDUINO_LIB)/$(PROJECT_LIBS)/utility $(SKETCH_LIB)/$(PROJECT_LIBS) : *.cpp *.c ] ; - -# Main output executable -Arduino $(PWD:B).elf : $(PROJECT_MODULES) [ GLOB $(PROJECT_DIRS) : *.c *.cpp *.pde *.ino ] ; diff --git a/examples/Usage/pingpair_maple/Jamfile b/examples/Usage/pingpair_maple/Jamfile deleted file mode 100644 index 798096cc2..000000000 --- a/examples/Usage/pingpair_maple/Jamfile +++ /dev/null @@ -1,182 +0,0 @@ -MCU = cortex-m3 ; -CHIP = STM32F103ZE ; -BOARD = maple_native ; - -#CHIP = at91sam3u4 ; -#BOARD = sam3u-ek ; - -if ! $(TOOLSET) -{ - TOOLSET = devkit ; - Echo "Assuming TOOLSET=devkit" ; -} - -if $(TOOLSET) = yagarto -{ - TOOLS_PATH = ~/Source/yagarto-4.6.2/bin ; - TOOLS_ARCH = arm-none-eabi- ; -} -if $(TOOLSET) = yagarto-install -{ - TOOLS_PATH = ~/Source/yagarto/install/bin ; - TOOLS_ARCH = arm-none-eabi- ; -} -else if $(TOOLSET) = devkit -{ - TOOLS_PATH = /opt/devkitARM/bin ; - TOOLS_ARCH = arm-eabi- ; -} -else if $(TOOLSET) = maple -{ - TOOLS_PATH = /opt/Maple/Resources/Java/hardware/tools/arm/bin ; - TOOLS_ARCH = arm-none-eabi- ; -} -else if $(TOOLSET) = ports -{ - TOOLS_PATH = /opt/local/bin ; - TOOLS_ARCH = arm-none-eabi- ; -} - -CC = $(TOOLS_PATH)/$(TOOLS_ARCH)gcc ; -C++ = $(TOOLS_PATH)/$(TOOLS_ARCH)g++ ; -AS = $(TOOLS_PATH)/$(TOOLS_ARCH)gcc -c ; -LINK = $(TOOLS_PATH)/$(TOOLS_ARCH)g++ ; -OBJCOPY = $(TOOLS_PATH)/$(TOOLS_ARCH)objcopy ; -DFU = dfu-util ; - -DEFINES += VECT_TAB_FLASH BOARD_$(BOARD) MCU_$(CHIP) ERROR_LED_PORT=GPIOC ERROR_LED_PIN=15 STM32_HIGH_DENSITY MAPLE_IDE ; -OPTIM = -Os ; -MFLAGS = cpu=$(MCU) thumb arch=armv7-m ; -CCFLAGS = -Wall -m$(MFLAGS) -g -nostdlib -ffunction-sections -fdata-sections -Wl,--gc-sections ; -C++FLAGS = $(CCFLAGS) -fno-rtti -fno-exceptions ; -LINKFLAGS += -m$(MFLAGS) -Xlinker --gc-sections ; -DFUFLAGS = -a1 -d 0x1eaf:0x0003 -R ; - -MAPLE_DIR = $(HOME)/Source/SAM3U/libmaple ; -MAPLE_LIBS = Servo LiquidCrystal Wire FreeRTOS ; -MAPLE_SUBDIRS = wirish wirish/comm wirish/boards libmaple libmaple/usb libmaple/usb/usb_lib ; - -SKETCH_DIR = $(HOME)/Source/Arduino ; -SKETCH_LIBS = RF24 ; - -MODULE_DIRS = . $(MAPLE_DIR)/$(MAPLE_SUBDIRS) $(MAPLE_DIR)/libraries/$(MAPLE_LIBS) $(SKETCH_DIR)/libraries/$(SKETCH_LIBS) ; -HDRS = $(MODULE_DIRS) ; -LOCATE_TARGET = out/$(TOOLSET) ; -LOCATE_SOURCE = $(LOCATE_TARGET) ; - -rule Pde -{ - Depends $(<) : $(>) ; - MakeLocate $(<) : $(LOCATE_SOURCE) ; - Clean clean : $(<) ; -} - -if ( $(ARDUINO_VERSION) < 100 ) -{ - ARDUINO_H = WProgram.h ; -} -else -{ - ARDUINO_H = Arduino.h ; -} - -actions Pde -{ - echo "#include <$(ARDUINO_H)>" > $(<) - echo "#line 1 \"$(>)\"" >> $(<) - cat $(>) >> $(<) -} - -rule C++Pde -{ - local _CPP = $(>:B).cpp ; - Pde $(_CPP) : $(>) ; - C++ $(<) : $(_CPP) ; -} - -rule Hex -{ - Depends $(<) : $(>) ; - MakeLocate $(<) : $(LOCATE_TARGET) ; - Depends hex : $(<) ; - Clean clean : $(<) ; -} - -actions Hex -{ - $(OBJCOPY) -O ihex $(>) $(<) -} - -rule Binary -{ - Depends $(<) : $(>) ; - MakeLocate $(<) : $(LOCATE_TARGET) ; - Depends binary : $(<) ; - Clean clean : $(<) ; -} - -actions Binary -{ - $(OBJCOPY) -O binary $(>) $(<) -} - -rule UserObject -{ - switch $(>:S) - { - case .S : As $(<) : $(>) ; - case .ino : C++Pde $(<) : $(>) ; - case .pde : C++Pde $(<) : $(>) ; - } -} - -rule Upload -{ - Depends up : $(<) ; - NotFile up ; - Always $(<) ; - Always up ; -} - -actions Upload -{ - $(DFU) $(DFUFLAGS) -D $(<) -} - -# Override base objects rule, so all output can go in the output dir -rule Objects -{ - local _i ; - - for _i in [ FGristFiles $(<) ] - { - local _b = $(_i:B)$(SUFOBJ) ; - local _o = $(_b:G=$(SOURCE_GRIST:E)) ; - Object $(_o) : $(_i) ; - Depends obj : $(_o) ; - } -} - -# Override base main rule, so all output can go in the output dir -rule Main -{ - MainFromObjects $(<) : $(>:B)$(SUFOBJ) ; - Objects $(>) ; -} - -# Modules -MODULES = [ GLOB $(MODULE_DIRS) : *.pde *.c *.cpp *.S ] ; - -# Main output executable -MAIN = $(PWD:B).elf ; - -# Linker script -LINK_DIR = $(MAPLE_DIR)/support/ld ; -LINKSCRIPT = $(LINK_DIR)/$(BOARD)/flash.ld ; - -# Bring in the map and link script -LINKFLAGS += -Wl,-Map=$(LOCATE_TARGET)/$(MAIN:B).map -T$(LINKSCRIPT) -L$(LINK_DIR) ; - -Main $(MAIN) : $(MODULES) ; -Binary $(MAIN:B).bin : $(MAIN) ; -Upload $(MAIN:B).bin ; diff --git a/examples/Usage/readme.md b/examples/Usage/readme.md deleted file mode 100644 index 69535e3bb..000000000 --- a/examples/Usage/readme.md +++ /dev/null @@ -1 +0,0 @@ -Note: These examples may have not been maintained with library updates, and are provided as-is for reference purposes. \ No newline at end of file diff --git a/examples/examples_formatter.conf b/examples/examples_formatter.conf new file mode 100644 index 000000000..57270c833 --- /dev/null +++ b/examples/examples_formatter.conf @@ -0,0 +1,31 @@ +# This configuration file contains a selection of the available options provided by the formatting tool "Artistic Style" +# http://astyle.sourceforge.net/astyle.html +# +# If you wish to change them, don't edit this file. +# Instead, copy it in the same folder of file "preferences.txt" and modify the copy. This way, you won't lose your custom formatter settings when upgrading the IDE +# If you don't know where file preferences.txt is stored, open the IDE, File -> Preferences and you'll find a link + +mode=c + +# 2 spaces indentation +indent=spaces=2 + +# also indent macros +indent-preprocessor + +# indent classes, switches (and cases), comments starting at column 1 +indent-classes +indent-switches +indent-cases +indent-col1-comments + +# put a space around operators +pad-oper + +# put a space after if/for/while +pad-header + +# if you like one-liners, keep them +keep-one-line-statements + +# remove-comment-prefix diff --git a/examples/old_backups/GettingStarted_HandlingFailures/GettingStarted_HandlingFailures.ino b/examples/old_backups/GettingStarted_HandlingFailures/GettingStarted_HandlingFailures.ino new file mode 100644 index 000000000..6e25c6f6e --- /dev/null +++ b/examples/old_backups/GettingStarted_HandlingFailures/GettingStarted_HandlingFailures.ino @@ -0,0 +1,217 @@ + +/* + Getting Started example sketch for nRF24L01+ radios + This is a very basic example of how to send data from one node to another + but modified to include failure handling. + + The nrf24l01+ radios are fairly reliable devices, but on breadboards etc, with inconsistent wiring, failures may + occur randomly after many hours to days or weeks. This sketch demonstrates how to handle the various failures and + keep the radio operational. + + The three main failure modes of the radio include: + Writing to radio: Radio unresponsive - Fixed internally by adding a timeout to the internal write functions in RF24 (failure handling) + Reading from radio: Available returns true always - Fixed by adding a timeout to available functions by the user. This is implemented internally in RF24Network. + Radio configuration settings are lost - Fixed by monitoring a value that is different from the default, and re-configuring the radio if this setting reverts to the default. + + The printDetails output should appear as follows for radio #0: + + STATUS = 0x0e RX_DR=0 TX_DS=0 MAX_RT=0 RX_P_NO=7 TX_FULL=0 + RX_ADDR_P0-1 = 0x65646f4e31 0x65646f4e32 + RX_ADDR_P2-5 = 0xc3 0xc4 0xc5 0xc6 + TX_ADDR = 0x65646f4e31 + RX_PW_P0-6 = 0x20 0x20 0x00 0x00 0x00 0x00 + EN_AA = 0x3f + EN_RXADDR = 0x02 + RF_CH = 0x4c + RF_SETUP = 0x03 + CONFIG = 0x0f + DYNPD/FEATURE = 0x00 0x00 + Data Rate = 1MBPS + Model = nRF24L01+ + CRC Length = 16 bits + PA Power = PA_LOW + + Users can use this sketch to troubleshoot radio module wiring etc. as it makes the radios hot-swapable + + Updated: 2019 by TMRh20 +*/ + +#include +#include "RF24.h" +#include "printf.h" + +/****************** User Config ***************************/ +/*** Set this radio as radio number 0 or 1 ***/ +bool radioNumber = 0; + +/* Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins 7 & 8 */ +RF24 radio(7, 8); +/**********************************************************/ + +byte addresses[][6] = {"1Node", "2Node"}; + +// Used to control whether this node is sending or receiving +bool role = 0; + + +/**********************************************************/ +//Function to configure the radio +void configureRadio() { + + radio.begin(); + + // Set the PA Level low to prevent power supply related issues since this is a + // getting_started sketch, and the likelihood of close proximity of the devices. RF24_PA_MAX is default. + radio.setPALevel(RF24_PA_LOW); + + // Open a writing and reading pipe on each radio, with opposite addresses + if (radioNumber) { + radio.openWritingPipe(addresses[1]); + radio.openReadingPipe(1, addresses[0]); + } else { + radio.openWritingPipe(addresses[0]); + radio.openReadingPipe(1, addresses[1]); + } + + // Start the radio listening for data + radio.startListening(); + radio.printDetails(); +} + + +/**********************************************************/ + +void setup() { + Serial.begin(115200); + Serial.println(F("RF24/examples/GettingStarted")); + Serial.println(F("*** PRESS 'T' to begin transmitting to the other node")); + + printf_begin(); + + configureRadio(); +} + +uint32_t configTimer = millis(); + +void loop() { + + if (radio.failureDetected) { + radio.failureDetected = false; + delay(250); + Serial.println("Radio failure detected, restarting radio"); + configureRadio(); + } + // Every 5 seconds, verify the configuration of the radio. This can be + // done using any setting that is different from the radio defaults. + if (millis() - configTimer > 5000) { + configTimer = millis(); + if (radio.getDataRate() != RF24_1MBPS) { + radio.failureDetected = true; + Serial.print("Radio configuration error detected"); + } + } + + + /****************** Ping Out Role ***************************/ + + if (role == 1) { + + radio.stopListening(); // First, stop listening so we can talk. + + Serial.println(F("Now sending")); + + unsigned long start_time = micros(); // Take the time, and send it. This will block until complete + if (!radio.write(&start_time, sizeof(unsigned long))) { + Serial.println(F("failed")); + } + + radio.startListening(); // Now, continue listening + + unsigned long started_waiting_at = micros(); // Set up a timeout period, get the current microseconds + bool timeout = false; // Set up a variable to indicate if a response was received or not + + while (!radio.available()) // While nothing is received + { + if (micros() - started_waiting_at > 200000 ) // If waited longer than 200ms, indicate timeout and exit while loop + { + timeout = true; + break; + } + } + + if (timeout) { + // Describe the results + Serial.println(F("Failed, response timed out.")); + } else { + // Grab the response, compare, and send to debugging spew + + unsigned long got_time; // Variable for the received timestamp + + // Failure Handling + uint32_t failTimer = millis(); + while (radio.available()) // If available() always returns true, there is a problem + { + if (millis() - failTimer > 250) { + radio.failureDetected = true; + Serial.println("Radio available failure detected"); + break; + } + radio.read(&got_time, sizeof(unsigned long)); + } + unsigned long end_time = micros(); + + // Spew it + Serial.print(F("Sent ")); + Serial.print(start_time); + Serial.print(F(", Got response ")); + Serial.print(got_time); + Serial.print(F(", Round-trip delay ")); + Serial.print(end_time - start_time); + Serial.println(F(" microseconds")); + } + + delay(1000); // Try again 1s later + } + + + /****************** Pong Back Role ***************************/ + + if (role == 0) { + unsigned long got_time; // Variable for the received timestamp + + if (radio.available()) { + uint32_t failTimer = millis(); + + while (radio.available()) // While there is data ready + { + if (millis() - failTimer > 500) { + Serial.println("Radio available failure detected"); + radio.failureDetected = true; + break; + } + radio.read(&got_time, sizeof(unsigned long)); // Get the payload + } + + radio.stopListening(); // First, stop listening so we can talk + radio.write(&got_time, sizeof(unsigned long)); // Send the final one back. + radio.startListening(); // Now, resume listening so we catch the next packets. + Serial.print(F("Sent response ")); + Serial.println(got_time); + } + } + + + /****************** Change Roles via Serial Commands ***************************/ + + if (Serial.available()) { + char c = toupper(Serial.read()); + if (c == 'T' && role == 0) { + Serial.println(F("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK")); + role = 1; // Become the primary transmitter (ping out) + } else if ( c == 'R' && role == 1 ) { + Serial.println(F("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK")); + role = 0; // Become the primary receiver (pong back) + radio.startListening(); + } + } +} // Loop diff --git a/examples/old_backups/TransferTimeouts/TransferTimeouts.ino b/examples/old_backups/TransferTimeouts/TransferTimeouts.ino new file mode 100644 index 000000000..cec44ed96 --- /dev/null +++ b/examples/old_backups/TransferTimeouts/TransferTimeouts.ino @@ -0,0 +1,191 @@ +/* + TMRh20 2014 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. +*/ + +/** Reliably transmitting large volumes of data with a low signal or in noisy environments + This example demonstrates data transfer functionality with the use of auto-retry + and auto-reUse functionality enabled. This sketch demonstrates how a user can extend + the auto-retry functionality to any chosen time period, preventing data loss and ensuring + the consistency of data. + + This sketh demonstrates use of the writeBlocking() functionality, and extends the standard + retry functionality of the radio. Payloads will be auto-retried until successful or the + extended timeout period is reached. +*/ + + + +#include +#include "nRF24L01.h" +#include "RF24.h" +#include "printf.h" + +/************* USER Configuration *****************************/ + +RF24 radio(7, 8); // Set up nRF24L01 radio on SPI bus plus pins 7 & 8 +unsigned long timeoutPeriod = 3000; // Set a user-defined timeout period. With auto-retransmit set to (15,15) retransmission will take up to 60ms and as little as 7.5ms with it set to (1,15). +// With a timeout period of 1000, the radio will retry each payload for up to 1 second before giving up on the transmission and starting over + +/***************************************************************/ + +const uint64_t pipes[2] = { 0xABCDABCD71LL, 0x544d52687CLL }; // Radio pipe addresses for the 2 nodes to communicate. + +byte data[32]; //Data buffer + +volatile unsigned long counter; +unsigned long rxTimer, startTime, stopTime, payloads = 0; +bool tx = 1, rx = 0, role = 0, transferInProgress = 0; + + +void setup(void) { + + Serial.begin(115200); + printf_begin(); + + radio.begin(); // Setup and configure rf radio + radio.setChannel(1); // Set the channel + radio.setPALevel(RF24_PA_LOW); // Set PA LOW for this demonstration. We want the radio to be as lossy as possible for this example. + radio.setDataRate(RF24_1MBPS); // Raise the data rate to reduce transmission distance and increase lossiness + radio.setAutoAck(1); // Ensure autoACK is enabled + radio.setRetries(2, 15); // Optionally, increase the delay between retries. Want the number of auto-retries as high as possible (15) + radio.setCRCLength(RF24_CRC_16); // Set CRC length to 16-bit to ensure quality of data + radio.openWritingPipe(pipes[0]); // Open the default reading and writing pipe + radio.openReadingPipe(1, pipes[1]); + + radio.startListening(); // Start listening + radio.printDetails(); // Dump the configuration of the rf unit for debugging + + printf("\n\rRF24/examples/Transfer Rates/\n\r"); + printf("*** PRESS 'T' to begin transmitting to the other node\n\r"); + + randomSeed(analogRead(0)); //Seed for random number generation + for (int i = 0; i < 32; i++) { + data[i] = random(255); //Load the buffer with random data + } + radio.powerUp(); //Power up the radio + + +} + + + +void loop(void) { + + + if (role == tx) { + delay(2000); // Pause for a couple seconds between transfers + printf("Initiating Extended Timeout Data Transfer\n\r"); + + unsigned long cycles = 1000; // Change this to a higher or lower number. This is the number of payloads that will be sent. + + unsigned long transferCMD[] = {'H', 'S', cycles }; // Indicate to the other radio that we are starting, and provide the number of payloads that will be sent + radio.writeFast(&transferCMD, 12); // Send the transfer command + if (radio.txStandBy(timeoutPeriod)) { // If transfer initiation was successful, do the following + + startTime = millis(); // For calculating transfer rate + boolean timedOut = 0; // Boolean for keeping track of failures + + for (unsigned long i = 0; i < cycles; i++) // Loop through a number of cycles + { + data[0] = i; // Change the first byte of the payload for identification + + if (!radio.writeBlocking(&data, 32, timeoutPeriod)) { // If retries are failing and the user defined timeout is exceeded + timedOut = 1; // Indicate failure + counter = cycles; // Set the fail count to maximum + break; // Break out of the for loop + } + } + + + stopTime = millis(); // Capture the time of completion or failure + + //This should be called to wait for completion and put the radio in standby mode after transmission, returns 0 if data still in FIFO (timed out), 1 if success + if (timedOut) { + radio.txStandBy(); //Partially blocking standby, blocks until success or max retries. FIFO flushed if auto timeout reached + } + else { + radio.txStandBy(timeoutPeriod); //Standby, block until FIFO empty (sent) or user specified timeout reached. FIFO flushed if user timeout reached. + } + + } else { + Serial.println("Communication not established"); //If unsuccessful initiating transfer, exit and retry later + } + + float rate = cycles * 32 / (stopTime - startTime); //Display results: + + Serial.print("Transfer complete at "); Serial.print(rate); printf(" KB/s \n\r"); + Serial.print(counter); + Serial.print(" of "); + Serial.print(cycles); Serial.println(" Packets Failed to Send"); + counter = 0; + + } + + + + if (role == rx) { + + if (!transferInProgress) { // If a bulk data transfer has not been started + if (radio.available()) { + radio.read(&data, 32); //Read any available payloads for analysis + + if (data[0] == 'H' && data[4] == 'S') { // If a bulk data transfer command has been received + payloads = data[8]; // Read the first two bytes of the unsigned long. Need to read the 3rd and 4th if sending more than 65535 payloads + payloads |= data[9] << 8; // This is the number of payloads that will be sent + counter = 0; // Reset the payload counter to 0 + transferInProgress = 1; // Indicate it has started + startTime = rxTimer = millis(); // Capture the start time to measure transfer rate and calculate timeouts + } + } + } else { + if (radio.available()) { // If in bulk transfer mode, and a payload is available + radio.read(&data, 32); // Read the payload + rxTimer = millis(); // Reset the timeout timer + counter++; // Keep a count of received payloads + } else if (millis() - rxTimer > timeoutPeriod) { // If no data available, check the timeout period + Serial.println("Transfer Failed"); // If per-payload timeout exceeeded, end the transfer + transferInProgress = 0; + } else if (counter >= payloads) { // If the specified number of payloads is reached, transfer is completed + startTime = millis() - startTime; // Calculate the total time spent during transfer + float numBytes = counter * 32; // Calculate the number of bytes transferred + Serial.print("Rate: "); // Print the transfer rate and number of payloads + Serial.print(numBytes / startTime); + Serial.println(" KB/s"); + Serial.print("Payload Count: "); + Serial.println(counter); + transferInProgress = 0; // End the transfer as complete + } + } + + + } + + // + // Change roles + // + + if ( Serial.available() ) + { + char c = toupper(Serial.read()); + if ( c == 'T' && role == rx ) + { + printf("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK\n\r"); + radio.openWritingPipe(pipes[1]); + radio.openReadingPipe(1, pipes[0]); + radio.stopListening(); + role = tx; // Become the primary transmitter (ping out) + } + else if ( c == 'R' && role == tx ) + { + radio.openWritingPipe(pipes[0]); + radio.openReadingPipe(1, pipes[1]); + radio.startListening(); + printf("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK\n\r"); + role = rx; // Become the primary receiver (pong back) + } + } +} diff --git a/examples/old_backups/pingpair_dyn/pingpair_dyn.ino b/examples/old_backups/pingpair_dyn/pingpair_dyn.ino new file mode 100644 index 000000000..47636f87c --- /dev/null +++ b/examples/old_backups/pingpair_dyn/pingpair_dyn.ino @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2011 J. Coliz + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +/** + * Example using Dynamic Payloads + * + * This is an example of how to use payloads of a varying (dynamic) size. + */ + +#include +#include "nRF24L01.h" +#include "RF24.h" +#include "printf.h" + +// Hardware configuration +RF24 radio(7, 8); // Set up nRF24L01 radio on SPI bus plus pins 7 & 8 + +// Radio pipe addresses for the 2 nodes to communicate. +const uint64_t addresses[2] = {0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL}; + +/************************* Role management ****************************/ +// Set up role. This sketch uses the same software for all the nodes in this +// system. Doing so greatly simplifies testing. + +// The role_pin is a digital input pin used to set the role of this radio. +// Connect the role_pin to GND to be the 'pong' receiver +// Leave the role_pin open to be the 'ping' transmitter +const short role_pin = 5; // use pin 5 +typedef enum { role_ping_out = 1, role_pong_back } role_e; // The various roles supported by this sketch +const char* role_friendly_name[] = {"invalid", "Ping out", "Pong back"}; // The debug-friendly names of those roles +role_e role; // The role of the current running sketch + + +// variables used for changing the payload size dynamically (used when role == role_ping_out) +const int min_payload_size = 4; +const int max_payload_size = 32; +const int payload_size_increment = 1; +int send_payload_size = min_payload_size; + +char receive_payload[max_payload_size + 1]; // +1 to allow room for a terminating NULL char + +void setup(void) +{ + pinMode(role_pin, INPUT); // set up the role pin + digitalWrite(role_pin, HIGH); + delay(20); // Just to get a solid reading on the role pin + + // read the role_pin, establish our role + if (digitalRead(role_pin)) { + role = role_ping_out; + } else { + role = role_pong_back; + } + + Serial.begin(115200); + printf_begin(); // needed for printDetails() + + // Print preamble + Serial.println(F("RF24/examples/pingpair_dyn/")); + Serial.print(F("ROLE: ")); + Serial.println(role_friendly_name[role]); + + // Setup and configure rf radio + radio.begin(); + radio.enableDynamicPayloads(); // Enable dynamic payloads + radio.setRetries(5, 15); // delay between retries = 5 * 250 + 250 = 1500 microseconds, number of retries = 15 + + // Open a writing and reading pipe on each radio, with opposite addresses + if (role == role_ping_out) { + radio.openWritingPipe(addresses[0]); + radio.openReadingPipe(1, addresses[1]); + } else { + radio.openWritingPipe(addresses[1]); + radio.openReadingPipe(1, addresses[0]); + } + + radio.startListening(); // Start listening + radio.printDetails(); // Dump the configuration of the rf unit for debugging +} + +void loop() { + + + /****************** Ping Out Role ***************************/ + + if (role == role_ping_out) { + // The payload will always be the same, what will change is how much of it we send. + static char send_payload[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ789012"; + + radio.stopListening(); // First, stop listening so we can talk. + + // Send the payload + Serial.print(F("Now sending length ")); + Serial.println(send_payload_size); + radio.write(send_payload, send_payload_size); // This will block until complete + + radio.startListening(); // Now, continue listening + + unsigned long started_waiting_at = millis(); // Start a timer for measuring timout + bool timeout = false; + while (!radio.available() && !timeout) // Wait until we get a response or timeout is reached + { + if (millis() - started_waiting_at > 500) // Only wait for 500 milliseconds + timeout = true; + } + + // Describe the results + if (timeout) { + Serial.println(F("Failed, response timed out.")); + } else { + // Grab the response and print it + + uint8_t len = radio.getDynamicPayloadSize(); // get payload's length + + // If an illegal payload size was detected, all RX payloads will be flushed + if (!len) + return; + + radio.read(receive_payload, len); + + // Use payload as a C-string (for easy printing) + receive_payload[len] = 0; // put a NULL terminating zero at the end + + // Spew it + Serial.print(F("Got response size=")); + Serial.print(len); + Serial.print(F(" value=")); + Serial.println(receive_payload); + } + + send_payload_size += payload_size_increment; // Update size for next time. + if (send_payload_size > max_payload_size) // if payload length is larger than the radio can handle + send_payload_size = min_payload_size; // reset the payload length + + delay(1000); // Try again 1s later + } + + + /****************** Pong Back Role ***************************/ + // Receive each packet, send it back, and dump it out + + if (role == role_pong_back) { + while (radio.available()) // if there is data ready + { + + uint8_t len = radio.getDynamicPayloadSize(); // Fetch the the payload size + + // If an illegal payload size was detected, all RX payloads will be flushed + if (!len) + continue; + + radio.read(receive_payload, len); + + // Use payload as a C-string (for easy printing) + receive_payload[len] = 0; // put a NULL terminating zero at the end + + // Spew it + Serial.print(F("Got response size=")); + Serial.print(len); + Serial.print(F(" value=")); + Serial.println(receive_payload); + + radio.stopListening(); // First, stop listening so we can talk + + // Send a reply that the packet was received + // + // You will have better luck delivering your message if + // you wait for the other node to start listening first + delay(20); + radio.write(receive_payload, len); + Serial.println(F("Sent response.")); + + radio.startListening(); // Now, resume listening so we catch the next packets. + } + } +} // loop +// vim:cin:ai:sts=2 sw=2 ft=cpp diff --git a/examples/old_backups/pingpair_irq/pingpair_irq.ino b/examples/old_backups/pingpair_irq/pingpair_irq.ino new file mode 100644 index 000000000..2a5ed9125 --- /dev/null +++ b/examples/old_backups/pingpair_irq/pingpair_irq.ino @@ -0,0 +1,172 @@ +/* + Copyright (C) 2011 J. Coliz + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. + + Update 2014 - TMRh20 +*/ + +/** + Example of using interrupts + + This is an example of how to user interrupts to interact with the radio, and a demonstration + of how to use them to sleep when receiving, and not miss any payloads. + The pingpair_sleepy example expands on sleep functionality with a timed sleep option for the transmitter. + Sleep functionality is built directly into my fork of the RF24Network library +*/ + +#include +#include "nRF24L01.h" +#include "RF24.h" +#include "printf.h" + +// Hardware configuration +RF24 radio(7, 8); // Set up nRF24L01 radio on SPI bus plus pins 7 & 8 + +// Our ACK payload will simply be 4 bytes containing the number of payloads received +static uint32_t message_count = 1; // start counting at 1 + +// Demonstrates another method of setting up the addresses +byte address[][5] = {0xCC, 0xCE, 0xCC, 0xCE, 0xCC, 0xCE, 0xCC, 0xCE, 0xCC, 0xCE}; + +/************************* Role management ****************************/ +// Set up role. This sketch uses the same software for all the nodes in this +// system. Doing so greatly simplifies testing. + +// The role_pin is a digital input pin used to set the role of this radio. +// Connect the role_pin to GND to be the 'pong' receiver +// Leave the role_pin open to be the 'ping' transmitter +const short role_pin = 5; // use pin 5 +typedef enum { role_sender = 1, role_receiver } role_e; // The various roles supported by this sketch +const char* role_friendly_name[] = {"invalid", "Sender", "Receiver"}; // The debug-friendly names of those roles +role_e role; // The role of the current running sketch + + +void setup() { + + pinMode(role_pin, INPUT); // set up the role pin + digitalWrite(role_pin, HIGH); // Change this to LOW/HIGH instead of using an external pin + delay(20); // Just to get a solid reading on the role pin + + if (digitalRead(role_pin)) // read the role_pin pin to establish our role + role = role_sender; + else + role = role_receiver; + + + Serial.begin(115200); + printf_begin(); // needed for printDetails() + + // print introduction + Serial.print(F("\n\rRF24/examples/pingpair_irq\n\rROLE: ")); + Serial.println(role_friendly_name[role]); + + + /********************** Setup and configure rf radio *********************/ + radio.begin(); + + // Examples are usually run with both radios in close proximity to each other + radio.setPALevel(RF24_PA_LOW); // defaults to RF24_PA_MAX + radio.enableAckPayload(); // We will be using the ACK Payload feature which is not enabled by default + radio.enableDynamicPayloads(); // Ack payloads are dynamic payloads + + // Open a writing and reading pipe on each radio, with opposite addresses + if (role == role_sender) { + radio.openWritingPipe(address[0]); + radio.openReadingPipe(1, address[1]); + } else { + radio.openWritingPipe(address[1]); + radio.openReadingPipe(1, address[0]); + radio.startListening(); // First we need to start listening + + // Add an ACK payload for the first time around; 1 is the pipe number to acknowledge + radio.writeAckPayload(1, &message_count, sizeof(message_count)); + ++message_count; // increment counter by 1 for next ACK payload + } + + radio.printDetails(); // Dump the configuration of the rf unit for debugging + delay(50); + + // Attach interrupt handler to interrupt #0 (using pin 2) on BOTH the sender and receiver + attachInterrupt(0, check_radio, LOW); +} // setup + + +void loop() { + + + /****************** Ping Out Role ***************************/ + + if (role == role_sender) { + // Repeatedly send the current time + + unsigned long time = millis(); // Take the time + Serial.print(F("Now sending ")); + Serial.println(time); + radio.startWrite(&time, sizeof(unsigned long), 0); // Send the time + delay(2000); // Try again soon (in 2 seconds) + } + + + /****************** Pong Back Role ***************************/ + // Receiver does nothing! All the work is in Interrupt Handler + + if (role == role_receiver) {} + +} // loop + + +/********************** Interrupt Handler *********************/ + +void check_radio(void) { + + bool tx, fail, rx; // declare variables to store IRQ flags + radio.whatHappened(tx, fail, rx); // What happened? + + if (tx) { // Have we successfully transmitted? + if (role == role_sender) + Serial.println(F("Send:OK")); + if (role == role_receiver) + Serial.println(F("Ack Payload:Sent")); + } + + if (fail) { // Have we failed to transmit? + if (role == role_sender) + Serial.println(F("Send:Failed")); + if (role == role_receiver) + Serial.println(F("Ack Payload:Failed")); + } + + if (rx || radio.available()) { // Did we receive a message? + + + + + /**************** Ping Out Role (about received ACK payload) ************************/ + // If we're the sender, we've received an ack payload + if (role == role_sender) { + // Get the payload and dump it + radio.read(&message_count, sizeof(message_count)); + Serial.print(F("Ack: ")); + Serial.println(message_count); + } + + + /****************** Pong Back Role ***************************/ + // If we're the receiver, we've received a time message + if (role == role_receiver) { + // Get the payload and dump it + + static unsigned long got_time; // variable to hold the received time + radio.read(&got_time, sizeof(got_time)); // get the payload + Serial.print(F("Got payload ")); + Serial.println(got_time); + + // Add an ACK payload for the next time around; 1 is the pipe number to acknowledge + radio.writeAckPayload(1, &message_count, sizeof(message_count)); + ++message_count; // increment packet counter + } + } +} // check_radio diff --git a/examples/pingpair_multi_dyn/pingpair_multi_dyn.ino b/examples/old_backups/pingpair_multi_dyn/pingpair_multi_dyn.ino similarity index 81% rename from examples/pingpair_multi_dyn/pingpair_multi_dyn.ino rename to examples/old_backups/pingpair_multi_dyn/pingpair_multi_dyn.ino index 03ef24c17..5f169328c 100644 --- a/examples/pingpair_multi_dyn/pingpair_multi_dyn.ino +++ b/examples/old_backups/pingpair_multi_dyn/pingpair_multi_dyn.ino @@ -1,263 +1,263 @@ -/* - Copyright (C) 2011 James Coliz, Jr. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -/** - * Example using Dynamic Payloads - * - * This is an example of how to use payloads of a varying (dynamic) size. - */ - -#include -#include "RF24.h" - -// -// Hardware configuration -// - -// Set up nRF24L01 radio on SPI bus plus pins 8 & 9 -RF24 radio(8,9); - -// Use multicast? -// sets the multicast behavior this unit in hardware. Connect to GND to use unicast -// Leave open (default) to use multicast. -const int multicast_pin = 6 ; - -// sets the role of this unit in hardware. Connect to GND to be the 'pong' receiver -// Leave open to be the 'ping' transmitter -const int role_pin = 7; -bool multicast = true ; - -// -// Topology -// - -// Radio pipe addresses for the 2 nodes to communicate. -const uint64_t pipes[2] = { 0xEEFAFDFDEELL, 0xEEFDFAF50DFLL }; - -// -// Role management -// -// Set up role. This sketch uses the same software for all the nodes -// in this system. Doing so greatly simplifies testing. The hardware itself specifies -// which node it is. -// -// This is done through the role_pin -// - -// The various roles supported by this sketch -typedef enum { role_ping_out = 1, role_pong_back } role_e; - -// The debug-friendly names of those roles -const char* role_friendly_name[] = { "invalid", "Ping out", "Pong back"}; - -// The role of the current running sketch -role_e role; - -// -// Payload -// - -const int min_payload_size = 1; -const int max_payload_size = 32; -const int payload_size_increments_by = 1; -int next_payload_size = min_payload_size; - -char receive_payload[max_payload_size+1]; // +1 to allow room for a terminating NULL char - -void setup(void) -{ - // - // Multicast - // - pinMode(multicast_pin, INPUT); - digitalWrite(multicast_pin,HIGH); - delay( 20 ) ; - - // read multicast role, LOW for unicast - if( digitalRead( multicast_pin ) ) - multicast = true ; - else - multicast = false ; - - - // - // Role - // - - // set up the role pin - pinMode(role_pin, INPUT); - digitalWrite(role_pin,HIGH); - delay( 20 ); // Just to get a solid reading on the role pin - - // read the address pin, establish our role - if ( digitalRead(role_pin) ) - role = role_ping_out; - else - role = role_pong_back; - - // - // Print preamble - // - - Serial.begin(115200); - - Serial.println(F("RF24/examples/pingpair_multi_dyn/")); - Serial.print(F("ROLE: ")); - Serial.println(role_friendly_name[role]); - - Serial.print(F("MULTICAST: ")); - Serial.println(multicast ? F("true (unreliable)") : F("false (reliable)")); - - // - // Setup and configure rf radio - // - - radio.begin(); - - // enable dynamic payloads - radio.enableDynamicPayloads(); - radio.setCRCLength( RF24_CRC_16 ) ; - - // optionally, increase the delay between retries & # of retries - radio.setRetries( 15, 5 ) ; - radio.setAutoAck( true ) ; - //radio.setPALevel( RF24_PA_LOW ) ; - - // - // Open pipes to other nodes for communication - // - - // This simple sketch opens two pipes for these two nodes to communicate - // back and forth. - // Open 'our' pipe for writing - // Open the 'other' pipe for reading, in position #1 (we can have up to 5 pipes open for reading) - - if ( role == role_ping_out ) - { - radio.openWritingPipe(pipes[0]); - radio.openReadingPipe(1,pipes[1]); - } - else - { - radio.openWritingPipe(pipes[1]); - radio.openReadingPipe(1,pipes[0]); - } - - // - // Start listening - // - radio.powerUp() ; - radio.startListening(); - - // - // Dump the configuration of the rf unit for debugging - // - - radio.printDetails(); -} - -void loop(void) -{ - // - // Ping out role. Repeatedly send the current time - // - - if (role == role_ping_out) - { - // The payload will always be the same, what will change is how much of it we send. - static char send_payload[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ789012"; - - // First, stop listening so we can talk. - radio.stopListening(); - - // Take the time, and send it. This will block until complete - Serial.print(F("Now sending length ")); - Serial.println(next_payload_size); - radio.write( send_payload, next_payload_size, multicast ); - - // Now, continue listening - radio.startListening(); - - // Wait here until we get a response, or timeout - unsigned long started_waiting_at = millis(); - bool timeout = false; - while ( ! radio.available() && ! timeout ) - if (millis() - started_waiting_at > 500 ) - timeout = true; - - // Describe the results - if ( timeout ) - { - Serial.println(F("Failed, response timed out.")); - } - else - { - // Grab the response, compare, and send to debugging spew - uint8_t len = radio.getDynamicPayloadSize(); - radio.read( receive_payload, len ); - - // Put a zero at the end for easy printing - receive_payload[len] = 0; - - // Spew it - Serial.print(F("Got response size=")); - Serial.print(len); - Serial.print(F(" value=")); - Serial.println(receive_payload); - } - - // Update size for next time. - next_payload_size += payload_size_increments_by; - if ( next_payload_size > max_payload_size ) - next_payload_size = min_payload_size; - - // Try again 1s later - delay(250); - } - - // - // Pong back role. Receive each packet, dump it out, and send it back - // - - if ( role == role_pong_back ) - { - // if there is data ready - if ( radio.available() ) - { - // Dump the payloads until we've gotten everything - uint8_t len; - bool done = false; - while (radio.available()) - { - // Fetch the payload, and see if this was the last one. - len = radio.getDynamicPayloadSize(); - radio.read( receive_payload, len ); - - // Put a zero at the end for easy printing - receive_payload[len] = 0; - - // Spew it - Serial.print(F("Got response size=")); - Serial.print(len); - Serial.print(F(" value=")); - Serial.println(receive_payload); - } - - // First, stop listening so we can talk - radio.stopListening(); - - // Send the final one back. - radio.write( receive_payload, len, multicast ); - Serial.println(F("Sent response.")); - - // Now, resume listening so we catch the next packets. - radio.startListening(); - } - } -} -// vim:cin:ai:sts=2 sw=2 ft=cpp \ No newline at end of file +/* + Copyright (C) 2011 James Coliz, Jr. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. +*/ + +/** + Example using Dynamic Payloads + + This is an example of how to use payloads of a varying (dynamic) size. +*/ + +#include +#include "RF24.h" + +// +// Hardware configuration +// + +// Set up nRF24L01 radio on SPI bus plus pins 8 & 9 +RF24 radio(7, 8); + +// Use multicast? +// sets the multicast behavior this unit in hardware. Connect to GND to use unicast +// Leave open (default) to use multicast. +const int multicast_pin = 6; + +// sets the role of this unit in hardware. Connect to GND to be the 'pong' receiver +// Leave open to be the 'ping' transmitter +const int role_pin = 5; +bool multicast = true ; + +// +// Topology +// + +// Radio pipe addresses for the 2 nodes to communicate. +const uint64_t pipes[2] = { 0xEEFAFDFDEELL, 0xEEFDFAF50DFLL }; + +// +// Role management +// +// Set up role. This sketch uses the same software for all the nodes +// in this system. Doing so greatly simplifies testing. The hardware itself specifies +// which node it is. +// +// This is done through the role_pin +// + +// The various roles supported by this sketch +typedef enum { role_ping_out = 1, role_pong_back } role_e; + +// The debug-friendly names of those roles +const char* role_friendly_name[] = { "invalid", "Ping out", "Pong back"}; + +// The role of the current running sketch +role_e role; + +// +// Payload +// + +const int min_payload_size = 1; +const int max_payload_size = 32; +const int payload_size_increments_by = 1; +int next_payload_size = min_payload_size; + +char receive_payload[max_payload_size + 1]; // +1 to allow room for a terminating NULL char + +void setup(void) +{ + // + // Multicast + // + pinMode(multicast_pin, INPUT); + digitalWrite(multicast_pin, HIGH); + delay( 20 ) ; + + // read multicast role, LOW for unicast + if ( digitalRead( multicast_pin ) ) + multicast = true ; + else + multicast = false ; + + + // + // Role + // + + // set up the role pin + pinMode(role_pin, INPUT); + digitalWrite(role_pin, HIGH); + delay( 20 ); // Just to get a solid reading on the role pin + + // read the address pin, establish our role + if ( digitalRead(role_pin) ) + role = role_ping_out; + else + role = role_pong_back; + + // + // Print preamble + // + + Serial.begin(115200); + + Serial.println(F("RF24/examples/pingpair_multi_dyn/")); + Serial.print(F("ROLE: ")); + Serial.println(role_friendly_name[role]); + + Serial.print(F("MULTICAST: ")); + Serial.println(multicast ? F("true (unreliable)") : F("false (reliable)")); + + // + // Setup and configure rf radio + // + + radio.begin(); + + // enable dynamic payloads + radio.enableDynamicPayloads(); + radio.setCRCLength( RF24_CRC_16 ) ; + + // optionally, increase the delay between retries & # of retries + radio.setRetries( 15, 5 ) ; + radio.setAutoAck( true ) ; + //radio.setPALevel( RF24_PA_LOW ) ; + + // + // Open pipes to other nodes for communication + // + + // This simple sketch opens two pipes for these two nodes to communicate + // back and forth. + // Open 'our' pipe for writing + // Open the 'other' pipe for reading, in position #1 (we can have up to 5 pipes open for reading) + + if ( role == role_ping_out ) + { + radio.openWritingPipe(pipes[0]); + radio.openReadingPipe(1, pipes[1]); + } + else + { + radio.openWritingPipe(pipes[1]); + radio.openReadingPipe(1, pipes[0]); + } + + // + // Start listening + // + radio.powerUp() ; + radio.startListening(); + + // + // Dump the configuration of the rf unit for debugging + // + + radio.printDetails(); +} + +void loop(void) +{ + // + // Ping out role. Repeatedly send the current time + // + + if (role == role_ping_out) + { + // The payload will always be the same, what will change is how much of it we send. + static char send_payload[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ789012"; + + // First, stop listening so we can talk. + radio.stopListening(); + + // Take the time, and send it. This will block until complete + Serial.print(F("Now sending length ")); + Serial.println(next_payload_size); + radio.write( send_payload, next_payload_size, multicast ); + + // Now, continue listening + radio.startListening(); + + // Wait here until we get a response, or timeout + unsigned long started_waiting_at = millis(); + bool timeout = false; + while ( ! radio.available() && ! timeout ) + if (millis() - started_waiting_at > 500 ) + timeout = true; + + // Describe the results + if ( timeout ) + { + Serial.println(F("Failed, response timed out.")); + } + else + { + // Grab the response, compare, and send to debugging spew + uint8_t len = radio.getDynamicPayloadSize(); + radio.read( receive_payload, len ); + + // Put a zero at the end for easy printing + receive_payload[len] = 0; + + // Spew it + Serial.print(F("Got response size=")); + Serial.print(len); + Serial.print(F(" value=")); + Serial.println(receive_payload); + } + + // Update size for next time. + next_payload_size += payload_size_increments_by; + if ( next_payload_size > max_payload_size ) + next_payload_size = min_payload_size; + + // Try again 1s later + delay(250); + } + + // + // Pong back role. Receive each packet, dump it out, and send it back + // + + if ( role == role_pong_back ) + { + // if there is data ready + if ( radio.available() ) + { + // Dump the payloads until we've gotten everything + uint8_t len; + bool done = false; + while (radio.available()) + { + // Fetch the payload, and see if this was the last one. + len = radio.getDynamicPayloadSize(); + radio.read( receive_payload, len ); + + // Put a zero at the end for easy printing + receive_payload[len] = 0; + + // Spew it + Serial.print(F("Got response size=")); + Serial.print(len); + Serial.print(F(" value=")); + Serial.println(receive_payload); + } + + // First, stop listening so we can talk + radio.stopListening(); + + // Send the final one back. + radio.write( receive_payload, len, multicast ); + Serial.println(F("Sent response.")); + + // Now, resume listening so we catch the next packets. + radio.startListening(); + } + } +} +// vim:cin:ai:sts=2 sw=2 ft=cpp diff --git a/examples/pingpair_sleepy/pingpair_sleepy.ino b/examples/old_backups/pingpair_sleepy/pingpair_sleepy.ino similarity index 61% rename from examples/pingpair_sleepy/pingpair_sleepy.ino rename to examples/old_backups/pingpair_sleepy/pingpair_sleepy.ino index b46480fac..7f034b3c5 100644 --- a/examples/pingpair_sleepy/pingpair_sleepy.ino +++ b/examples/old_backups/pingpair_sleepy/pingpair_sleepy.ino @@ -1,226 +1,226 @@ -/* - Copyright (C) 2011 J. Coliz - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - - TMRh20 2014 - Updates to the library allow sleeping both in TX and RX modes: - TX Mode: The radio can be powered down (.9uA current) and the Arduino slept using the watchdog timer - RX Mode: The radio can be left in standby mode (22uA current) and the Arduino slept using an interrupt pin - */ - -/** - * Example RF Radio Ping Pair which Sleeps between Sends - * - * This is an example of how to use the RF24 class to create a battery- - * efficient system. It is just like the GettingStarted_CallResponse example, but the - * ping node powers down the radio and sleeps the MCU after every - * ping/pong cycle, and the receiver sleeps between payloads. - * - * Write this sketch to two different nodes, - * connect the role_pin to ground on one. The ping node sends the current - * time to the pong node, which responds by sending the value back. The ping - * node can then see how long the whole cycle took. - */ - -#include -#include -#include -#include "nRF24L01.h" -#include "RF24.h" -#include "printf.h" - - -// Set up nRF24L01 radio on SPI bus plus pins 7 & 8 -RF24 radio(7,8); - -// sets the role of this unit in hardware. Connect to GND to be the 'pong' receiver -// Leave open to be the 'ping' transmitter -const int role_pin = 5; - -const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL }; // Radio pipe addresses for the 2 nodes to communicate. - -// Role management -// Set up role. This sketch uses the same software for all the nodes -// in this system. Doing so greatly simplifies testing. The hardware itself specifies -// which node it is. - -// The various roles supported by this sketch -typedef enum { role_ping_out = 1, role_pong_back } role_e; - -// The debug-friendly names of those roles -const char* role_friendly_name[] = { "invalid", "Ping out", "Pong back"}; - -// The role of the current running sketch -role_e role; - - -// Sleep declarations -typedef enum { wdt_16ms = 0, wdt_32ms, wdt_64ms, wdt_128ms, wdt_250ms, wdt_500ms, wdt_1s, wdt_2s, wdt_4s, wdt_8s } wdt_prescalar_e; - -void setup_watchdog(uint8_t prescalar); -void do_sleep(void); - -const short sleep_cycles_per_transmission = 4; -volatile short sleep_cycles_remaining = sleep_cycles_per_transmission; - - - -void setup(){ - - // set up the role pin - pinMode(role_pin, INPUT); - digitalWrite(role_pin,HIGH); - delay(20); // Just to get a solid reading on the role pin - - // read the address pin, establish our role - if ( digitalRead(role_pin) ) - role = role_ping_out; - else - role = role_pong_back; - - Serial.begin(115200); - printf_begin(); - Serial.print(F("\n\rRF24/examples/pingpair_sleepy/\n\rROLE: ")); - Serial.println(role_friendly_name[role]); - - // Prepare sleep parameters - // Only the ping out role uses WDT. Wake up every 4s to send a ping - //if ( role == role_ping_out ) - setup_watchdog(wdt_4s); - - // Setup and configure rf radio - - radio.begin(); - - // Open pipes to other nodes for communication - - // This simple sketch opens two pipes for these two nodes to communicate - // back and forth. - // Open 'our' pipe for writing - // Open the 'other' pipe for reading, in position #1 (we can have up to 5 pipes open for reading) - - if ( role == role_ping_out ) { - radio.openWritingPipe(pipes[0]); - radio.openReadingPipe(1,pipes[1]); - } else { - radio.openWritingPipe(pipes[1]); - radio.openReadingPipe(1,pipes[0]); - } - - // Start listening - radio.startListening(); - - // Dump the configuration of the rf unit for debugging - //radio.printDetails(); -} - -void loop(){ - - - if (role == role_ping_out) { // Ping out role. Repeatedly send the current time - radio.powerUp(); // Power up the radio after sleeping - radio.stopListening(); // First, stop listening so we can talk. - - unsigned long time = millis(); // Take the time, and send it. - Serial.print(F("Now sending... ")); - Serial.println(time); - - radio.write( &time, sizeof(unsigned long) ); - - radio.startListening(); // Now, continue listening - - unsigned long started_waiting_at = millis(); // Wait here until we get a response, or timeout (250ms) - bool timeout = false; - while ( ! radio.available() ){ - if (millis() - started_waiting_at > 250 ){ // Break out of the while loop if nothing available - timeout = true; - break; - } - } - - if ( timeout ) { // Describe the results - Serial.println(F("Failed, response timed out.")); - } else { - unsigned long got_time; // Grab the response, compare, and send to debugging spew - radio.read( &got_time, sizeof(unsigned long) ); - - printf("Got response %lu, round-trip delay: %lu\n\r",got_time,millis()-got_time); - } - - // Shut down the system - delay(500); // Experiment with some delay here to see if it has an effect - // Power down the radio. - radio.powerDown(); // NOTE: The radio MUST be powered back up again manually - - // Sleep the MCU. - do_sleep(); - - - } - - - // Pong back role. Receive each packet, dump it out, and send it back - if ( role == role_pong_back ) { - - if ( radio.available() ) { // if there is data ready - - unsigned long got_time; - while (radio.available()) { // Dump the payloads until we've gotten everything - radio.read( &got_time, sizeof(unsigned long) ); // Get the payload, and see if this was the last one. - // Spew it. Include our time, because the ping_out millis counter is unreliable - printf("Got payload %lu @ %lu...",got_time,millis()); // due to it sleeping - } - - radio.stopListening(); // First, stop listening so we can talk - radio.write( &got_time, sizeof(unsigned long) ); // Send the final one back. - Serial.println(F("Sent response.")); - radio.startListening(); // Now, resume listening so we catch the next packets. - } else { - Serial.println(F("Sleeping")); - delay(50); // Delay so the serial data can print out - do_sleep(); - - } - } -} - -void wakeUp(){ - sleep_disable(); -} - -// Sleep helpers - -//Prescaler values -// 0=16ms, 1=32ms,2=64ms,3=125ms,4=250ms,5=500ms -// 6=1 sec,7=2 sec, 8=4 sec, 9= 8sec - -void setup_watchdog(uint8_t prescalar){ - - uint8_t wdtcsr = prescalar & 7; - if ( prescalar & 8 ) - wdtcsr |= _BV(WDP3); - MCUSR &= ~_BV(WDRF); // Clear the WD System Reset Flag - WDTCSR = _BV(WDCE) | _BV(WDE); // Write the WD Change enable bit to enable changing the prescaler and enable system reset - WDTCSR = _BV(WDCE) | wdtcsr | _BV(WDIE); // Write the prescalar bits (how long to sleep, enable the interrupt to wake the MCU -} - -ISR(WDT_vect) -{ - //--sleep_cycles_remaining; - Serial.println(F("WDT")); -} - -void do_sleep(void) -{ - set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here - sleep_enable(); - attachInterrupt(0,wakeUp,LOW); - WDTCSR |= _BV(WDIE); - sleep_mode(); // System sleeps here - // The WDT_vect interrupt wakes the MCU from here - sleep_disable(); // System continues execution here when watchdog timed out - detachInterrupt(0); - WDTCSR &= ~_BV(WDIE); -} +/* + Copyright (C) 2011 J. Coliz + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. + + TMRh20 2014 - Updates to the library allow sleeping both in TX and RX modes: + TX Mode: The radio can be powered down (.9uA current) and the Arduino slept using the watchdog timer + RX Mode: The radio can be left in standby mode (22uA current) and the Arduino slept using an interrupt pin +*/ + +/** + Example RF Radio Ping Pair which Sleeps between Sends + + This is an example of how to use the RF24 class to create a battery- + efficient system. It is just like the GettingStarted_CallResponse example, but the + ping node powers down the radio and sleeps the MCU after every + ping/pong cycle, and the receiver sleeps between payloads. + + Write this sketch to two different nodes, + connect the role_pin to ground on one. The ping node sends the current + time to the pong node, which responds by sending the value back. The ping + node can then see how long the whole cycle took. +*/ + +#include +#include +#include +#include "nRF24L01.h" +#include "RF24.h" +#include "printf.h" + + +// Set up nRF24L01 radio on SPI bus plus pins 7 & 8 +RF24 radio(7, 8); + +// sets the role of this unit in hardware. Connect to GND to be the 'pong' receiver +// Leave open to be the 'ping' transmitter +const int role_pin = 5; + +const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL }; // Radio pipe addresses for the 2 nodes to communicate. + +// Role management +// Set up role. This sketch uses the same software for all the nodes +// in this system. Doing so greatly simplifies testing. The hardware itself specifies +// which node it is. + +// The various roles supported by this sketch +typedef enum { role_ping_out = 1, role_pong_back } role_e; + +// The debug-friendly names of those roles +const char* role_friendly_name[] = { "invalid", "Ping out", "Pong back"}; + +// The role of the current running sketch +role_e role; + + +// Sleep declarations +typedef enum { wdt_16ms = 0, wdt_32ms, wdt_64ms, wdt_128ms, wdt_250ms, wdt_500ms, wdt_1s, wdt_2s, wdt_4s, wdt_8s } wdt_prescalar_e; + +void setup_watchdog(uint8_t prescalar); +void do_sleep(void); + +const short sleep_cycles_per_transmission = 4; +volatile short sleep_cycles_remaining = sleep_cycles_per_transmission; + + + +void setup() { + + // set up the role pin + pinMode(role_pin, INPUT); + digitalWrite(role_pin, HIGH); + delay(20); // Just to get a solid reading on the role pin + + // read the address pin, establish our role + if ( digitalRead(role_pin) ) + role = role_ping_out; + else + role = role_pong_back; + + Serial.begin(115200); + printf_begin(); + Serial.print(F("\n\rRF24/examples/pingpair_sleepy/\n\rROLE: ")); + Serial.println(role_friendly_name[role]); + + // Prepare sleep parameters + // Only the ping out role uses WDT. Wake up every 4s to send a ping + //if ( role == role_ping_out ) + setup_watchdog(wdt_4s); + + // Setup and configure rf radio + + radio.begin(); + + // Open pipes to other nodes for communication + + // This simple sketch opens two pipes for these two nodes to communicate + // back and forth. + // Open 'our' pipe for writing + // Open the 'other' pipe for reading, in position #1 (we can have up to 5 pipes open for reading) + + if ( role == role_ping_out ) { + radio.openWritingPipe(pipes[0]); + radio.openReadingPipe(1, pipes[1]); + } else { + radio.openWritingPipe(pipes[1]); + radio.openReadingPipe(1, pipes[0]); + } + + // Start listening + radio.startListening(); + + // Dump the configuration of the rf unit for debugging + //radio.printDetails(); +} + +void loop() { + + + if (role == role_ping_out) { // Ping out role. Repeatedly send the current time + radio.powerUp(); // Power up the radio after sleeping + radio.stopListening(); // First, stop listening so we can talk. + + unsigned long time = millis(); // Take the time, and send it. + Serial.print(F("Now sending... ")); + Serial.println(time); + + radio.write( &time, sizeof(unsigned long) ); + + radio.startListening(); // Now, continue listening + + unsigned long started_waiting_at = millis(); // Wait here until we get a response, or timeout (250ms) + bool timeout = false; + while ( ! radio.available() ) { + if (millis() - started_waiting_at > 250 ) { // Break out of the while loop if nothing available + timeout = true; + break; + } + } + + if ( timeout ) { // Describe the results + Serial.println(F("Failed, response timed out.")); + } else { + unsigned long got_time; // Grab the response, compare, and send to debugging spew + radio.read( &got_time, sizeof(unsigned long) ); + + printf("Got response %lu, round-trip delay: %lu\n\r", got_time, millis() - got_time); + } + + // Shut down the system + delay(500); // Experiment with some delay here to see if it has an effect + // Power down the radio. + radio.powerDown(); // NOTE: The radio MUST be powered back up again manually + + // Sleep the MCU. + do_sleep(); + + + } + + + // Pong back role. Receive each packet, dump it out, and send it back + if ( role == role_pong_back ) { + + if ( radio.available() ) { // if there is data ready + + unsigned long got_time; + while (radio.available()) { // Dump the payloads until we've gotten everything + radio.read( &got_time, sizeof(unsigned long) ); // Get the payload, and see if this was the last one. + // Spew it. Include our time, because the ping_out millis counter is unreliable + printf("Got payload %lu @ %lu...", got_time, millis()); // due to it sleeping + } + + radio.stopListening(); // First, stop listening so we can talk + radio.write( &got_time, sizeof(unsigned long) ); // Send the final one back. + Serial.println(F("Sent response.")); + radio.startListening(); // Now, resume listening so we catch the next packets. + } else { + Serial.println(F("Sleeping")); + delay(50); // Delay so the serial data can print out + do_sleep(); + + } + } +} + +void wakeUp() { + sleep_disable(); +} + +// Sleep helpers + +//Prescaler values +// 0=16ms, 1=32ms,2=64ms,3=125ms,4=250ms,5=500ms +// 6=1 sec,7=2 sec, 8=4 sec, 9= 8sec + +void setup_watchdog(uint8_t prescalar) { + + uint8_t wdtcsr = prescalar & 7; + if ( prescalar & 8 ) + wdtcsr |= _BV(WDP3); + MCUSR &= ~_BV(WDRF); // Clear the WD System Reset Flag + WDTCSR = _BV(WDCE) | _BV(WDE); // Write the WD Change enable bit to enable changing the prescaler and enable system reset + WDTCSR = _BV(WDCE) | wdtcsr | _BV(WDIE); // Write the prescalar bits (how long to sleep, enable the interrupt to wake the MCU +} + +ISR(WDT_vect) +{ + //--sleep_cycles_remaining; + Serial.println(F("WDT")); +} + +void do_sleep(void) +{ + set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here + sleep_enable(); + attachInterrupt(0, wakeUp, LOW); + WDTCSR |= _BV(WDIE); + sleep_mode(); // System sleeps here + // The WDT_vect interrupt wakes the MCU from here + sleep_disable(); // System continues execution here when watchdog timed out + detachInterrupt(0); + WDTCSR &= ~_BV(WDIE); +} diff --git a/examples/Usage/led_remote/led_remote.pde b/examples/old_backups/recipes/led_remote/led_remote.ino similarity index 70% rename from examples/Usage/led_remote/led_remote.pde rename to examples/old_backups/recipes/led_remote/led_remote.ino index 59bdf615e..f1394f619 100644 --- a/examples/Usage/led_remote/led_remote.pde +++ b/examples/old_backups/recipes/led_remote/led_remote.ino @@ -1,254 +1,254 @@ -/* - Copyright (C) 2011 J. Coliz - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -/** - * Example LED Remote - * - * This is an example of how to use the RF24 class to control a remote - * bank of LED's using buttons on a remote control. - * - * On the 'remote', connect any number of buttons or switches from - * an arduino pin to ground. Update 'button_pins' to reflect the - * pins used. - * - * On the 'led' board, connect the same number of LED's from an - * arduino pin to a resistor to ground. Update 'led_pins' to reflect - * the pins used. Also connect a separate pin to ground and change - * the 'role_pin'. This tells the sketch it's running on the LED board. - * - * Every time the buttons change on the remote, the entire state of - * buttons is send to the led board, which displays the state. - */ - -#include -#include "nRF24L01.h" -#include "RF24.h" -#include "printf.h" - -// -// Hardware configuration -// - -// Set up nRF24L01 radio on SPI bus plus pins 9 & 10 (CE & CS) - -RF24 radio(9,10); - -// sets the role of this unit in hardware. Connect to GND to be the 'led' board receiver -// Leave open to be the 'remote' transmitter -const int role_pin = A4; - -// Pins on the remote for buttons -const uint8_t button_pins[] = { 2,3,4,5,6,7 }; -const uint8_t num_button_pins = sizeof(button_pins); - -// Pins on the LED board for LED's -const uint8_t led_pins[] = { 2,3,4,5,6,7 }; -const uint8_t num_led_pins = sizeof(led_pins); - -// -// Topology -// - -// Single radio pipe address for the 2 nodes to communicate. -const uint64_t pipe = 0xE8E8F0F0E1LL; - -// -// Role management -// -// Set up role. This sketch uses the same software for all the nodes in this -// system. Doing so greatly simplifies testing. The hardware itself specifies -// which node it is. -// -// This is done through the role_pin -// - -// The various roles supported by this sketch -typedef enum { role_remote = 1, role_led } role_e; - -// The debug-friendly names of those roles -const char* role_friendly_name[] = { "invalid", "Remote", "LED Board"}; - -// The role of the current running sketch -role_e role; - -// -// Payload -// - -uint8_t button_states[num_button_pins]; -uint8_t led_states[num_led_pins]; - -// -// Setup -// - -void setup(void) -{ - // - // Role - // - - // set up the role pin - pinMode(role_pin, INPUT); - digitalWrite(role_pin,HIGH); - delay(20); // Just to get a solid reading on the role pin - - // read the address pin, establish our role - if ( digitalRead(role_pin) ) - role = role_remote; - else - role = role_led; - - // - // Print preamble - // - - Serial.begin(115200); - printf_begin(); - printf("\n\rRF24/examples/led_remote/\n\r"); - printf("ROLE: %s\n\r",role_friendly_name[role]); - - // - // Setup and configure rf radio - // - - radio.begin(); - - // - // Open pipes to other nodes for communication - // - - // This simple sketch opens a single pipes for these two nodes to communicate - // back and forth. One listens on it, the other talks to it. - - if ( role == role_remote ) - { - radio.openWritingPipe(pipe); - } - else - { - radio.openReadingPipe(1,pipe); - } - - // - // Start listening - // - - if ( role == role_led ) - radio.startListening(); - - // - // Dump the configuration of the rf unit for debugging - // - - radio.printDetails(); - - // - // Set up buttons / LED's - // - - // Set pull-up resistors for all buttons - if ( role == role_remote ) - { - int i = num_button_pins; - while(i--) - { - pinMode(button_pins[i],INPUT); - digitalWrite(button_pins[i],HIGH); - } - } - - // Turn LED's ON until we start getting keys - if ( role == role_led ) - { - int i = num_led_pins; - while(i--) - { - pinMode(led_pins[i],OUTPUT); - led_states[i] = HIGH; - digitalWrite(led_pins[i],led_states[i]); - } - } - -} - -// -// Loop -// - -void loop(void) -{ - // - // Remote role. If the state of any button has changed, send the whole state of - // all buttons. - // - - if ( role == role_remote ) - { - // Get the current state of buttons, and - // Test if the current state is different from the last state we sent - int i = num_button_pins; - bool different = false; - while(i--) - { - uint8_t state = ! digitalRead(button_pins[i]); - if ( state != button_states[i] ) - { - different = true; - button_states[i] = state; - } - } - - // Send the state of the buttons to the LED board - if ( different ) - { - printf("Now sending..."); - bool ok = radio.write( button_states, num_button_pins ); - if (ok) - printf("ok\n\r"); - else - printf("failed\n\r"); - } - - // Try again in a short while - delay(20); - } - - // - // LED role. Receive the state of all buttons, and reflect that in the LEDs - // - - if ( role == role_led ) - { - // if there is data ready - if ( radio.available() ) - { - // Dump the payloads until we've gotten everything - while (radio.available()) - { - // Fetch the payload, and see if this was the last one. - radio.read( button_states, num_button_pins ); - - // Spew it - printf("Got buttons\n\r"); - - // For each button, if the button now on, then toggle the LED - int i = num_led_pins; - while(i--) - { - if ( button_states[i] ) - { - led_states[i] ^= HIGH; - digitalWrite(led_pins[i],led_states[i]); - } - } - } - } - } -} -// vim:ai:cin:sts=2 sw=2 ft=cpp +/* + Copyright (C) 2011 J. Coliz + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. +*/ + +/** + Example LED Remote + + This is an example of how to use the RF24 class to control a remote + bank of LED's using buttons on a remote control. + + On the 'remote', connect any number of buttons or switches from + an arduino pin to ground. Update 'button_pins' to reflect the + pins used. + + On the 'led' board, connect the same number of LED's from an + arduino pin to a resistor to ground. Update 'led_pins' to reflect + the pins used. Also connect a separate pin to ground and change + the 'role_pin'. This tells the sketch it's running on the LED board. + + Every time the buttons change on the remote, the entire state of + buttons is send to the led board, which displays the state. +*/ + +#include +#include "nRF24L01.h" +#include "RF24.h" +#include "printf.h" + +// +// Hardware configuration +// + +// Set up nRF24L01 radio on SPI bus plus pins 9 & 10 (CE & CS) + +RF24 radio(9, 10); + +// sets the role of this unit in hardware. Connect to GND to be the 'led' board receiver +// Leave open to be the 'remote' transmitter +const int role_pin = A4; + +// Pins on the remote for buttons +const uint8_t button_pins[] = { 2, 3, 4, 5, 6, 7 }; +const uint8_t num_button_pins = sizeof(button_pins); + +// Pins on the LED board for LED's +const uint8_t led_pins[] = { 2, 3, 4, 5, 6, 7 }; +const uint8_t num_led_pins = sizeof(led_pins); + +// +// Topology +// + +// Single radio pipe address for the 2 nodes to communicate. +const uint64_t pipe = 0xE8E8F0F0E1LL; + +// +// Role management +// +// Set up role. This sketch uses the same software for all the nodes in this +// system. Doing so greatly simplifies testing. The hardware itself specifies +// which node it is. +// +// This is done through the role_pin +// + +// The various roles supported by this sketch +typedef enum { role_remote = 1, role_led } role_e; + +// The debug-friendly names of those roles +const char* role_friendly_name[] = { "invalid", "Remote", "LED Board"}; + +// The role of the current running sketch +role_e role; + +// +// Payload +// + +uint8_t button_states[num_button_pins]; +uint8_t led_states[num_led_pins]; + +// +// Setup +// + +void setup(void) +{ + // + // Role + // + + // set up the role pin + pinMode(role_pin, INPUT); + digitalWrite(role_pin, HIGH); + delay(20); // Just to get a solid reading on the role pin + + // read the address pin, establish our role + if ( digitalRead(role_pin) ) + role = role_remote; + else + role = role_led; + + // + // Print preamble + // + + Serial.begin(115200); + printf_begin(); + printf("\n\rRF24/examples/led_remote/\n\r"); + printf("ROLE: %s\n\r", role_friendly_name[role]); + + // + // Setup and configure rf radio + // + + radio.begin(); + + // + // Open pipes to other nodes for communication + // + + // This simple sketch opens a single pipes for these two nodes to communicate + // back and forth. One listens on it, the other talks to it. + + if ( role == role_remote ) + { + radio.openWritingPipe(pipe); + } + else + { + radio.openReadingPipe(1, pipe); + } + + // + // Start listening + // + + if ( role == role_led ) + radio.startListening(); + + // + // Dump the configuration of the rf unit for debugging + // + + radio.printDetails(); + + // + // Set up buttons / LED's + // + + // Set pull-up resistors for all buttons + if ( role == role_remote ) + { + int i = num_button_pins; + while (i--) + { + pinMode(button_pins[i], INPUT); + digitalWrite(button_pins[i], HIGH); + } + } + + // Turn LED's ON until we start getting keys + if ( role == role_led ) + { + int i = num_led_pins; + while (i--) + { + pinMode(led_pins[i], OUTPUT); + led_states[i] = HIGH; + digitalWrite(led_pins[i], led_states[i]); + } + } + +} + +// +// Loop +// + +void loop(void) +{ + // + // Remote role. If the state of any button has changed, send the whole state of + // all buttons. + // + + if ( role == role_remote ) + { + // Get the current state of buttons, and + // Test if the current state is different from the last state we sent + int i = num_button_pins; + bool different = false; + while (i--) + { + uint8_t state = ! digitalRead(button_pins[i]); + if ( state != button_states[i] ) + { + different = true; + button_states[i] = state; + } + } + + // Send the state of the buttons to the LED board + if ( different ) + { + printf("Now sending..."); + bool ok = radio.write( button_states, num_button_pins ); + if (ok) + printf("ok\n\r"); + else + printf("failed\n\r"); + } + + // Try again in a short while + delay(20); + } + + // + // LED role. Receive the state of all buttons, and reflect that in the LEDs + // + + if ( role == role_led ) + { + // if there is data ready + if ( radio.available() ) + { + // Dump the payloads until we've gotten everything + while (radio.available()) + { + // Fetch the payload, and see if this was the last one. + radio.read( button_states, num_button_pins ); + + // Spew it + printf("Got buttons\n\r"); + + // For each button, if the button now on, then toggle the LED + int i = num_led_pins; + while (i--) + { + if ( button_states[i] ) + { + led_states[i] ^= HIGH; + digitalWrite(led_pins[i], led_states[i]); + } + } + } + } + } +} +// vim:ai:cin:sts=2 sw=2 ft=cpp diff --git a/examples/Usage/nordic_fob/nordic_fob.pde b/examples/old_backups/recipes/nordic_fob/nordic_fob.ino similarity index 50% rename from examples/Usage/nordic_fob/nordic_fob.pde rename to examples/old_backups/recipes/nordic_fob/nordic_fob.ino index 473166823..cf40cbce7 100644 --- a/examples/Usage/nordic_fob/nordic_fob.pde +++ b/examples/old_backups/recipes/nordic_fob/nordic_fob.ino @@ -1,142 +1,142 @@ -/* - Copyright (C) 2012 J. Coliz - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -/** - * Example Nordic FOB Receiver - * - * This is an example of how to use the RF24 class to receive signals from the - * Sparkfun Nordic FOB. Thanks to Kirk Mower for providing test hardware. - * - * See blog post at http://maniacbug.wordpress.com/2012/01/08/nordic-fob/ - */ - -#include -#include -#include "nRF24L01.h" -#include "printf.h" - -// -// Hardware configuration -// - -// Set up nRF24L01 radio on SPI bus plus pins 9 & 10 - -RF24 radio(9,10); - -// -// Payload -// - -struct payload_t -{ - uint8_t buttons; - uint16_t id; - uint8_t empty; -}; - -const char* button_names[] = { "Up", "Down", "Left", "Right", "Center" }; -const int num_buttons = 5; - -// -// Forward declarations -// - -uint16_t flip_endian(uint16_t in); - -// -// Setup -// - -void setup(void) -{ - // - // Print preamble - // - - Serial.begin(115200); - printf_begin(); - printf("\r\nRF24/examples/nordic_fob/\r\n"); - - // - // Setup and configure rf radio according to the built-in parameters - // of the FOB. - // - - radio.begin(); - radio.setChannel(2); - radio.setPayloadSize(4); - radio.setAutoAck(false); - radio.setCRCLength(RF24_CRC_8); - radio.openReadingPipe(1,0xE7E7E7E7E7LL); - - // - // Start listening - // - - radio.startListening(); - - // - // Dump the configuration of the rf unit for debugging - // - - radio.printDetails(); -} - -// -// Loop -// - -void loop(void) -{ - // - // Receive each packet, dump it out - // - - // if there is data ready - if ( radio.available() ) - { - // Get the packet from the radio - payload_t payload; - radio.read( &payload, sizeof(payload) ); - - // Print the ID of this message. Note that the message - // is sent 'big-endian', so we have to flip it. - printf("#%05u Buttons ",flip_endian(payload.id)); - - // Print the name of each button - int i = num_buttons; - while (i--) - { - if ( ! ( payload.buttons & _BV(i) ) ) - { - printf("%s ",button_names[i]); - } - } - - // If no buttons, print None - if ( payload.buttons == _BV(num_buttons) - 1 ) - printf("None"); - - printf("\r\n"); - } -} - -// -// Helper functions -// - -// Change a big-endian word into a little-endian -uint16_t flip_endian(uint16_t in) -{ - uint16_t low = in >> 8; - uint16_t high = in << 8; - - return high | low; -} - -// vim:cin:ai:sts=2 sw=2 ft=cpp +/* + Copyright (C) 2012 J. Coliz + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. +*/ + +/** + Example Nordic FOB Receiver + + This is an example of how to use the RF24 class to receive signals from the + Sparkfun Nordic FOB. Thanks to Kirk Mower for providing test hardware. + + See blog post at http://maniacbug.wordpress.com/2012/01/08/nordic-fob/ +*/ + +#include +#include +#include "nRF24L01.h" +#include "printf.h" + +// +// Hardware configuration +// + +// Set up nRF24L01 radio on SPI bus plus pins 9 & 10 + +RF24 radio(9, 10); + +// +// Payload +// + +struct payload_t +{ + uint8_t buttons; + uint16_t id; + uint8_t empty; +}; + +const char* button_names[] = { "Up", "Down", "Left", "Right", "Center" }; +const int num_buttons = 5; + +// +// Forward declarations +// + +uint16_t flip_endian(uint16_t in); + +// +// Setup +// + +void setup(void) +{ + // + // Print preamble + // + + Serial.begin(115200); + printf_begin(); + printf("\r\nRF24/examples/nordic_fob/\r\n"); + + // + // Setup and configure rf radio according to the built-in parameters + // of the FOB. + // + + radio.begin(); + radio.setChannel(2); + radio.setPayloadSize(4); + radio.setAutoAck(false); + radio.setCRCLength(RF24_CRC_8); + radio.openReadingPipe(1, 0xE7E7E7E7E7LL); + + // + // Start listening + // + + radio.startListening(); + + // + // Dump the configuration of the rf unit for debugging + // + + radio.printDetails(); +} + +// +// Loop +// + +void loop(void) +{ + // + // Receive each packet, dump it out + // + + // if there is data ready + if ( radio.available() ) + { + // Get the packet from the radio + payload_t payload; + radio.read( &payload, sizeof(payload) ); + + // Print the ID of this message. Note that the message + // is sent 'big-endian', so we have to flip it. + printf("#%05u Buttons ", flip_endian(payload.id)); + + // Print the name of each button + int i = num_buttons; + while (i--) + { + if ( ! ( payload.buttons & _BV(i) ) ) + { + printf("%s ", button_names[i]); + } + } + + // If no buttons, print None + if ( payload.buttons == _BV(num_buttons) - 1 ) + printf("None"); + + printf("\r\n"); + } +} + +// +// Helper functions +// + +// Change a big-endian word into a little-endian +uint16_t flip_endian(uint16_t in) +{ + uint16_t low = in >> 8; + uint16_t high = in << 8; + + return high | low; +} + +// vim:cin:ai:sts=2 sw=2 ft=cpp diff --git a/examples/Usage/pingpair_maple/main.cpp b/examples/old_backups/recipes/pingpair_maple/main.cpp similarity index 74% rename from examples/Usage/pingpair_maple/main.cpp rename to examples/old_backups/recipes/pingpair_maple/main.cpp index b4f976d3e..a6f505a4e 100644 --- a/examples/Usage/pingpair_maple/main.cpp +++ b/examples/old_backups/recipes/pingpair_maple/main.cpp @@ -1,87 +1,87 @@ -#ifdef MAPLE_IDE - -#include -#include "wirish.h" - -extern void setup(void); -extern void loop(void); - -void board_start(const char* program_name) -{ - // Set up the LED to steady on - pinMode(BOARD_LED_PIN, OUTPUT); - digitalWrite(BOARD_LED_PIN, HIGH); - - // Setup the button as input - pinMode(BOARD_BUTTON_PIN, INPUT); - digitalWrite(BOARD_BUTTON_PIN, HIGH); - - SerialUSB.begin(); - SerialUSB.println("Press BUT"); - - // Wait for button press - while ( !isButtonPressed() ) - { - } - - SerialUSB.println("Welcome!"); - SerialUSB.println(program_name); - - int i = 11; - while (i--) - { - toggleLED(); - delay(50); - } -} - -/** - * Custom version of _write, which will print to the USB. - * In order to use it you MUST ADD __attribute__((weak)) - * to _write in libmaple/syscalls.c -*/ -extern "C" int _write (int file, char * ptr, int len) -{ - if ( (file != 1) && (file != 2) ) - return 0; - else - SerialUSB.write(ptr,len); - return len; -} - -/** - * Re-entrant version of _write. Yagarto and Devkit now use - * the re-entrant newlib, so these get called instead of the - * non_r versions. - */ -extern "C" int _write_r (void*, int file, char * ptr, int len) -{ - return _write( file, ptr, len); -} - -__attribute__((constructor)) __attribute__ ((weak)) void premain() -{ - init(); -} - -__attribute__((weak)) void setup(void) -{ - board_start("No program defined"); -} - -__attribute__((weak)) void loop(void) -{ -} - -__attribute__((weak)) int main(void) -{ - setup(); - - while (true) - { - loop(); - } - return 0; -} -#endif // ifdef MAPLE_IDE -// vim:cin:ai:sts=2 sw=2 ft=cpp +#ifdef MAPLE_IDE + +#include +#include "wirish.h" + +extern void setup(void); +extern void loop(void); + +void board_start(const char* program_name) +{ + // Set up the LED to steady on + pinMode(BOARD_LED_PIN, OUTPUT); + digitalWrite(BOARD_LED_PIN, HIGH); + + // Setup the button as input + pinMode(BOARD_BUTTON_PIN, INPUT); + digitalWrite(BOARD_BUTTON_PIN, HIGH); + + SerialUSB.begin(); + SerialUSB.println("Press BUT"); + + // Wait for button press + while ( !isButtonPressed() ) + { + } + + SerialUSB.println("Welcome!"); + SerialUSB.println(program_name); + + int i = 11; + while (i--) + { + toggleLED(); + delay(50); + } +} + +/** + Custom version of _write, which will print to the USB. + In order to use it you MUST ADD __attribute__((weak)) + to _write in libmaple/syscalls.c +*/ +extern "C" int _write (int file, char * ptr, int len) +{ + if ( (file != 1) && (file != 2) ) + return 0; + else + SerialUSB.write(ptr, len); + return len; +} + +/** + Re-entrant version of _write. Yagarto and Devkit now use + the re-entrant newlib, so these get called instead of the + non_r versions. +*/ +extern "C" int _write_r (void*, int file, char * ptr, int len) +{ + return _write( file, ptr, len); +} + +__attribute__((constructor)) __attribute__ ((weak)) void premain() +{ + init(); +} + +__attribute__((weak)) void setup(void) +{ + board_start("No program defined"); +} + +__attribute__((weak)) void loop(void) +{ +} + +__attribute__((weak)) int main(void) +{ + setup(); + + while (true) + { + loop(); + } + return 0; +} +#endif // ifdef MAPLE_IDE +// vim:cin:ai:sts=2 sw=2 ft=cpp diff --git a/examples/Usage/pingpair_maple/pingpair_maple.pde b/examples/old_backups/recipes/pingpair_maple/pingpair_maple.ino similarity index 80% rename from examples/Usage/pingpair_maple/pingpair_maple.pde rename to examples/old_backups/recipes/pingpair_maple/pingpair_maple.ino index 2d3925b76..83d99c8ac 100644 --- a/examples/Usage/pingpair_maple/pingpair_maple.pde +++ b/examples/old_backups/recipes/pingpair_maple/pingpair_maple.ino @@ -1,242 +1,242 @@ -/* - Copyright (C) 2011 J. Coliz - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -/** - * Example RF Radio Ping Pair ... for Maple - * - * This is an example of how to use the RF24 class. Write this sketch to two different nodes, - * connect the role_pin to ground on one. The ping node sends the current time to the pong node, - * which responds by sending the value back. The ping node can then see how long the whole cycle - * took. - */ - -#include "WProgram.h" -#include -#include "nRF24L01.h" -#include "RF24.h" - -// -// Maple specific setup. Other than this section, the sketch is the same on Maple as on -// Arduino -// - -#ifdef MAPLE_IDE - -// External startup function -extern void board_start(const char* program_name); - -// Use SPI #2. -HardwareSPI SPI(2); - -#else -#define board_startup printf -#define toggleLED(x) (x) -#endif - -// -// Hardware configuration -// - -// Set up nRF24L01 radio on SPI bus plus pins 7 & 6 -// (This works for the Getting Started board plugged into the -// Maple Native backwards.) - -RF24 radio(7,6); - -// sets the role of this unit in hardware. Connect to GND to be the 'pong' receiver -// Leave open to be the 'ping' transmitter -const int role_pin = 10; - -// -// Topology -// - -// Radio pipe addresses for the 2 nodes to communicate. -const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL }; - -// -// Role management -// -// Set up role. This sketch uses the same software for all the nodes -// in this system. Doing so greatly simplifies testing. The hardware itself specifies -// which node it is. -// -// This is done through the role_pin -// - -// The various roles supported by this sketch -typedef enum { role_ping_out = 1, role_pong_back } role_e; - -// The debug-friendly names of those roles -const char* role_friendly_name[] = { "invalid", "Ping out", "Pong back"}; - -// The role of the current running sketch -role_e role; - -void setup(void) -{ - // - // Role - // - - // set up the role pin - pinMode(role_pin, INPUT); - digitalWrite(role_pin,HIGH); - delay(20); // Just to get a solid reading on the role pin - - // read the address pin, establish our role - if ( digitalRead(role_pin) ) - role = role_ping_out; - else - role = role_pong_back; - - // - // Print preamble - // - - board_start("\n\rRF24/examples/pingpair/\n\r"); - printf("ROLE: %s\n\r",role_friendly_name[role]); - - // - // Setup and configure rf radio - // - - radio.begin(); - - // optionally, increase the delay between retries & # of retries - radio.setRetries(15,15); - - // optionally, reduce the payload size. seems to - // improve reliability - radio.setPayloadSize(8); - - // - // Open pipes to other nodes for communication - // - - // This simple sketch opens two pipes for these two nodes to communicate - // back and forth. - // Open 'our' pipe for writing - // Open the 'other' pipe for reading, in position #1 (we can have up to 5 pipes open for reading) - - if ( role == role_ping_out ) - { - radio.openWritingPipe(pipes[0]); - radio.openReadingPipe(1,pipes[1]); - } - else - { - radio.openWritingPipe(pipes[1]); - radio.openReadingPipe(1,pipes[0]); - } - - // - // Start listening - // - - radio.startListening(); - - // - // Dump the configuration of the rf unit for debugging - // - - radio.printDetails(); -} - -void loop(void) -{ - // - // Ping out role. Repeatedly send the current time - // - - if (role == role_ping_out) - { - toggleLED(); - - // First, stop listening so we can talk. - radio.stopListening(); - - // Take the time, and send it. This will block until complete - unsigned long time = millis(); - printf("Now sending %lu...",time); - bool ok = radio.write( &time, sizeof(unsigned long) ); - - if (ok) - printf("ok...\r\n"); - else - printf("failed.\r\n"); - - // Now, continue listening - radio.startListening(); - - // Wait here until we get a response, or timeout (250ms) - unsigned long started_waiting_at = millis(); - bool timeout = false; - while ( ! radio.available() && ! timeout ) - if (millis() - started_waiting_at > 200 ) - timeout = true; - - // Describe the results - if ( timeout ) - { - printf("Failed, response timed out.\r\n"); - } - else - { - // Grab the response, compare, and send to debugging spew - unsigned long got_time; - radio.read( &got_time, sizeof(unsigned long) ); - - // Spew it - printf("Got response %lu, round-trip delay: %lu\r\n",got_time,millis()-got_time); - } - - toggleLED(); - - // Try again 1s later - delay(1000); - } - - // - // Pong back role. Receive each packet, dump it out, and send it back - // - - if ( role == role_pong_back ) - { - // if there is data ready - if ( radio.available() ) - { - // Dump the payloads until we've gotten everything - unsigned long got_time; - bool done = false; - while (!done) - { - // Fetch the payload, and see if this was the last one. - done = radio.read( &got_time, sizeof(unsigned long) ); - - // Spew it - printf("Got payload %lu...",got_time); - - // Delay just a little bit to let the other unit - // make the transition to receiver - delay(20); - } - - // First, stop listening so we can talk - radio.stopListening(); - - // Send the final one back. - radio.write( &got_time, sizeof(unsigned long) ); - printf("Sent response.\r\n"); - - // Now, resume listening so we catch the next packets. - radio.startListening(); - } - } -} -// vim:cin:ai:sts=2 sw=2 ft=cpp +/* + Copyright (C) 2011 J. Coliz + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. +*/ + +/** + Example RF Radio Ping Pair ... for Maple + + This is an example of how to use the RF24 class. Write this sketch to two different nodes, + connect the role_pin to ground on one. The ping node sends the current time to the pong node, + which responds by sending the value back. The ping node can then see how long the whole cycle + took. +*/ + +#include "WProgram.h" +#include +#include "nRF24L01.h" +#include "RF24.h" + +// +// Maple specific setup. Other than this section, the sketch is the same on Maple as on +// Arduino +// + +#ifdef MAPLE_IDE + +// External startup function +extern void board_start(const char* program_name); + +// Use SPI #2. +HardwareSPI SPI(2); + +#else +#define board_startup printf +#define toggleLED(x) (x) +#endif + +// +// Hardware configuration +// + +// Set up nRF24L01 radio on SPI bus plus pins 7 & 6 +// (This works for the Getting Started board plugged into the +// Maple Native backwards.) + +RF24 radio(7, 6); + +// sets the role of this unit in hardware. Connect to GND to be the 'pong' receiver +// Leave open to be the 'ping' transmitter +const int role_pin = 10; + +// +// Topology +// + +// Radio pipe addresses for the 2 nodes to communicate. +const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL }; + +// +// Role management +// +// Set up role. This sketch uses the same software for all the nodes +// in this system. Doing so greatly simplifies testing. The hardware itself specifies +// which node it is. +// +// This is done through the role_pin +// + +// The various roles supported by this sketch +typedef enum { role_ping_out = 1, role_pong_back } role_e; + +// The debug-friendly names of those roles +const char* role_friendly_name[] = { "invalid", "Ping out", "Pong back"}; + +// The role of the current running sketch +role_e role; + +void setup(void) +{ + // + // Role + // + + // set up the role pin + pinMode(role_pin, INPUT); + digitalWrite(role_pin, HIGH); + delay(20); // Just to get a solid reading on the role pin + + // read the address pin, establish our role + if ( digitalRead(role_pin) ) + role = role_ping_out; + else + role = role_pong_back; + + // + // Print preamble + // + + board_start("\n\rRF24/examples/pingpair/\n\r"); + printf("ROLE: %s\n\r", role_friendly_name[role]); + + // + // Setup and configure rf radio + // + + radio.begin(); + + // optionally, increase the delay between retries & # of retries + radio.setRetries(15, 15); + + // optionally, reduce the payload size. seems to + // improve reliability + radio.setPayloadSize(8); + + // + // Open pipes to other nodes for communication + // + + // This simple sketch opens two pipes for these two nodes to communicate + // back and forth. + // Open 'our' pipe for writing + // Open the 'other' pipe for reading, in position #1 (we can have up to 5 pipes open for reading) + + if ( role == role_ping_out ) + { + radio.openWritingPipe(pipes[0]); + radio.openReadingPipe(1, pipes[1]); + } + else + { + radio.openWritingPipe(pipes[1]); + radio.openReadingPipe(1, pipes[0]); + } + + // + // Start listening + // + + radio.startListening(); + + // + // Dump the configuration of the rf unit for debugging + // + + radio.printDetails(); +} + +void loop(void) +{ + // + // Ping out role. Repeatedly send the current time + // + + if (role == role_ping_out) + { + toggleLED(); + + // First, stop listening so we can talk. + radio.stopListening(); + + // Take the time, and send it. This will block until complete + unsigned long time = millis(); + printf("Now sending %lu...", time); + bool ok = radio.write( &time, sizeof(unsigned long) ); + + if (ok) + printf("ok...\r\n"); + else + printf("failed.\r\n"); + + // Now, continue listening + radio.startListening(); + + // Wait here until we get a response, or timeout (250ms) + unsigned long started_waiting_at = millis(); + bool timeout = false; + while ( ! radio.available() && ! timeout ) + if (millis() - started_waiting_at > 200 ) + timeout = true; + + // Describe the results + if ( timeout ) + { + printf("Failed, response timed out.\r\n"); + } + else + { + // Grab the response, compare, and send to debugging spew + unsigned long got_time; + radio.read( &got_time, sizeof(unsigned long) ); + + // Spew it + printf("Got response %lu, round-trip delay: %lu\r\n", got_time, millis() - got_time); + } + + toggleLED(); + + // Try again 1s later + delay(1000); + } + + // + // Pong back role. Receive each packet, dump it out, and send it back + // + + if ( role == role_pong_back ) + { + // if there is data ready + if ( radio.available() ) + { + // Dump the payloads until we've gotten everything + unsigned long got_time; + bool done = false; + while (!done) + { + // Fetch the payload, and see if this was the last one. + done = radio.read( &got_time, sizeof(unsigned long) ); + + // Spew it + printf("Got payload %lu...", got_time); + + // Delay just a little bit to let the other unit + // make the transition to receiver + delay(20); + } + + // First, stop listening so we can talk + radio.stopListening(); + + // Send the final one back. + radio.write( &got_time, sizeof(unsigned long) ); + printf("Sent response.\r\n"); + + // Now, resume listening so we catch the next packets. + radio.startListening(); + } + } +} +// vim:cin:ai:sts=2 sw=2 ft=cpp diff --git a/examples/old_backups/recipes/readme.md b/examples/old_backups/recipes/readme.md new file mode 100644 index 000000000..c22d7a24c --- /dev/null +++ b/examples/old_backups/recipes/readme.md @@ -0,0 +1,2 @@ +Note: These recipe examples may have not been maintained with library updates, and are provided as-is for reference purposes. +Warning: These are recipe examples are intended for specific hardware usage. \ No newline at end of file diff --git a/examples/scanner/scanner.ino b/examples/old_backups/scanner/scanner.ino similarity index 79% rename from examples/scanner/scanner.ino rename to examples/old_backups/scanner/scanner.ino index 722486304..c5b425a9f 100644 --- a/examples/scanner/scanner.ino +++ b/examples/old_backups/scanner/scanner.ino @@ -1,10 +1,10 @@ /* - Copyright (C) 2011 J. Coliz - Updated 2020 TMRh20 - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. + * Copyright (C) 2011 J. Coliz + * Updated 2020 TMRh20 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. */ /** @@ -13,7 +13,7 @@ * Example to detect interference on the various channels available. * This is a good diagnostic tool to check whether you're picking a * good channel for your application. - * + * * Run this sketch on two devices. On one device, start CCW output by sending a 'g' * character over Serial. The other device scanning should detect the output of the sending * device on the given channel. Adjust channel and output power of CCW below. @@ -31,7 +31,7 @@ // Set up nRF24L01 radio on SPI bus plus pins 7 & 8 -RF24 radio(7,8); +RF24 radio(7, 8); // // Channel info @@ -71,14 +71,14 @@ void setup(void) int i = 0; while ( i < num_channels ) { - Serial.print(i>>4,HEX); + Serial.print(i >> 4, HEX); ++i; } Serial.println(); i = 0; while ( i < num_channels ) { - Serial.print(i&0xf,HEX); + Serial.print(i & 0xf, HEX); ++i; } Serial.println(); @@ -97,26 +97,25 @@ void loop(void) /****************************************/ // Send g over Serial to begin CCW output // Configure the channel and power level below - if(Serial.available()){ + if (Serial.available()) { char c = Serial.read(); - if(c == 'g'){ + if (c == 'g') { constCarrierMode = 1; radio.stopListening(); delay(2); Serial.println("Starting Carrier Out"); - radio.startConstCarrier(RF24_PA_LOW,40); - }else - if(c == 'e'){ + radio.startConstCarrier(RF24_PA_LOW, 40); + } else if (c == 'e') { constCarrierMode = 0; radio.stopConstCarrier(); Serial.println("Stopping Carrier Out"); } } /****************************************/ - - if(constCarrierMode == 0){ + + if (constCarrierMode == 0) { // Clear measurement values - memset(values,0,sizeof(values)); + memset(values, 0, sizeof(values)); // Scan all channels num_reps times int rep_counter = num_reps; @@ -134,21 +133,21 @@ void loop(void) radio.stopListening(); // Did we get a carrier? - if ( radio.testCarrier() ){ + if ( radio.testCarrier() ) { ++values[i]; } } } - + // Print out channel measurements, clamped to a single hex digit int i = 0; while ( i < num_channels ) { - Serial.print(min(0xf,values[i]),HEX); + Serial.print(min(0xf, values[i]), HEX); ++i; } Serial.println(); - - }//If constCarrierMode == 0 + + }//If constCarrierMode == 0 } diff --git a/examples/pingpair_ack/pingpair_ack.ino b/examples/pingpair_ack/pingpair_ack.ino deleted file mode 100644 index b426bacb2..000000000 --- a/examples/pingpair_ack/pingpair_ack.ino +++ /dev/null @@ -1,114 +0,0 @@ -/** - Example for efficient call-response using ack-payloads - - This example continues to make use of all the normal functionality of the radios including - the auto-ack and auto-retry features, but allows ack-payloads to be written optionally as well. - This allows very fast call-response communication, with the responding radio never having to - switch out of Primary Receiver mode to send back a payload, but having the option to if wanting - to initiate communication instead of respond to a commmunication. -*/ -/* - // March 2014 - TMRh20 - Updated along with High Speed RF24 Library fork - // Parts derived from examples by J. Coliz -*/ - -#include -#include "nRF24L01.h" -#include "RF24.h" -#include "printf.h" - -// Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins 7 & 8 -RF24 radio(7, 8); - -// Topology -const uint64_t pipes[2] = { 0xABCDABCD71LL, 0x544d52687CLL }; // Radio pipe addresses for the 2 nodes to communicate. - -// Role management: Set up role. This sketch uses the same software for all the nodes -// in this system. Doing so greatly simplifies testing. - -typedef enum { role_ping_out = 1, role_pong_back } role_e; // The various roles supported by this sketch -const char* role_friendly_name[] = { "invalid", "Ping out", "Pong back"}; // The debug-friendly names of those roles -role_e role = role_pong_back; // The role of the current running sketch - -// A single byte to keep track of the data being sent back and forth -byte counter = 1; - -void setup() { - Serial.begin(115200); - printf_begin(); - Serial.print(F("\n\rRF24/examples/pingpair_ack/\n\rROLE: ")); - Serial.println(role_friendly_name[role]); - Serial.println(F("*** PRESS 'T' to begin transmitting to the other node")); - - // Setup and configure rf radio - - radio.begin(); - radio.setAutoAck(1); // Ensure autoACK is enabled - radio.enableAckPayload(); // Allow optional ack payloads - radio.setRetries(0, 15); // Smallest time between retries, max no. of retries - radio.setPayloadSize(1); // Here we are sending 1-byte payloads to test the call-response speed - radio.openWritingPipe(pipes[1]); // Both radios listen on the same pipes by default, and switch when writing - radio.openReadingPipe(1, pipes[0]); - radio.startListening(); // Start listening - radio.printDetails(); // Dump the configuration of the rf unit for debugging -} - -void loop(void) { - if (role == role_ping_out) { - radio.stopListening(); // First, stop listening so we can talk. - - printf("Now sending %d as payload. ", counter); - byte gotByte; - unsigned long time = micros(); // Take the time, and send it. This will block until complete - //Called when STANDBY-I mode is engaged (User is finished sending) - if (!radio.write(&counter, 1)) { - Serial.println(F("failed.")); - } else { - if (!radio.available()) { - Serial.println(F("Blank Payload Received.")); - } else { - while (radio.available()) { - unsigned long tim = micros(); - radio.read(&gotByte, 1); - printf("Got response %d, round-trip delay: %lu microseconds\n\r", gotByte, tim - time); - counter++; - } - } - } - // Try again later - delay(1000); - } - - // Pong back role. Receive each packet, dump it out, and send it back - - if (role == role_pong_back) { - byte pipeNo; - byte gotByte; // Dump the payloads until we've gotten everything - while (radio.available(&pipeNo)) { - radio.read(&gotByte, 1); - radio.writeAckPayload(pipeNo, &gotByte, 1); - Serial.print(F("Received message and replied at ")); - Serial.println(millis()); - } - } - - // Change roles - - if (Serial.available()) { - char c = toupper(Serial.read()); - if (c == 'T' && role == role_pong_back) { - Serial.println(F("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK")); - - role = role_ping_out; // Become the primary transmitter (ping out) - radio.openWritingPipe(pipes[0]); - radio.openReadingPipe(1, pipes[1]); - } else if (c == 'R' && role == role_ping_out) { - Serial.println(F("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK")); - - role = role_pong_back; // Become the primary receiver (pong back) - radio.openWritingPipe(pipes[1]); - radio.openReadingPipe(1, pipes[0]); - radio.startListening(); - } - } -} diff --git a/examples/pingpair_dyn/Jamfile b/examples/pingpair_dyn/Jamfile deleted file mode 100644 index 901f8da8c..000000000 --- a/examples/pingpair_dyn/Jamfile +++ /dev/null @@ -1,206 +0,0 @@ -PROJECT_NAME = $(PWD:B) ; -PROJECT_DIR = . ; -PROJECT_LIBS = SPI RF24 ; - -OUT_DIR = ojam ; -F_CPU = 16000000 ; -MCU = atmega328p ; -PORTS = /dev/tty.usbserial-A600eHIs /dev/tty.usbserial-A40081RP /dev/tty.usbserial-A9007LmI ; - -UPLOAD_RATE = 57600 ; -AVRDUDE_PROTOCOL = stk500v1 ; -COM = 33 ; - -# Host-specific overrides for locations -if $(OS) = MACOSX -{ -ARDUINO_VERSION = 22 ; -OLD_DIR = /opt/arduino-0021 ; -AVR_TOOLS_PATH = $(OLD_DIR)/hardware/tools/avr/bin ; -AVRDUDECONFIG_PATH = $(OLD_DIR)/hardware/tools/avr/etc ; -ARDUINO_DIR = /opt/Arduino ; -ARDUINO_AVR = /usr/lib/avr/include ; -} - -# Where is everything? -ARDUINO_VERSION ?= 22 ; -AVR_TOOLS_PATH ?= /usr/bin ; -ARDUINO_DIR ?= /opt/arduino-00$(ARDUINO_VERSION) ; -ARDUINO_AVR ?= $(ARDUINO_DIR)/hardware/tools/avr/avr/include/avr ; -AVRDUDECONFIG_PATH ?= $(ARDUINO_DIR)/hardware/tools ; -ARDUINO_CORE = $(ARDUINO_DIR)/hardware/arduino/cores/arduino ; -ARDUINO_LIB = $(ARDUINO_DIR)/libraries ; -SKETCH_LIB = $(HOME)/Source/Arduino/libraries ; -AVR_CC = $(AVR_TOOLS_PATH)/avr-gcc ; -AVR_CXX = $(AVR_TOOLS_PATH)/avr-g++ ; -AVR_LD = $(AVR_TOOLS_PATH)/avr-gcc ; -AVR_OBJCOPY = $(AVR_TOOLS_PATH)/avr-objcopy ; -AVRDUDE = $(AVR_TOOLS_PATH)/avrdude ; - -DEFINES = F_CPU=$(F_CPU)L ARDUINO=$(ARDUINO_VERSION) VERSION_H ; -CTUNING = -ffunction-sections -fdata-sections ; -CXXTUNING = -fno-exceptions -fno-strict-aliasing ; -CFLAGS = -Os -Wall -Wextra -mmcu=$(MCU) $(CTUNING) ; -CXXFLAGS = $(CFLAGS) $(CXXTUNING) ; -LDFLAGS = -Os -lm -Wl,--gc-sections -mmcu=atmega328p ; - -# Search everywhere for headers -HDRS = $(PROJECT_DIR) $(ARDUINO_AVR) $(ARDUINO_CORE) [ GLOB $(ARDUINO_LIB) $(SKETCH_LIB) : [^.]* ] ; - -# Grab everything from the core directory -CORE_MODULES = [ GLOB $(ARDUINO_CORE) : *.c *.cpp ] ; - -# Grab everything from libraries. To avoid this "grab everything" behaviour, you -# can specify specific modules to pick up in PROJECT_MODULES -LIB_MODULES = [ GLOB $(ARDUINO_LIB)/$(PROJECT_LIBS) $(SKETCH_LIB)/$(PROJECT_LIBS) : *.cpp ] ; - -# In addition to explicitly-specified program modules, pick up anything from the current -# dir. -PROJECT_MODULES += [ GLOB $(PROJECT_DIR) : *.c *.cpp *.pde ] ; - -# Shortcut for the out files -OUT = $(OUT_DIR)/$(PROJECT_NAME) ; - -# AvrDude setup -AVRDUDE_FLAGS = -V -F -D -C $(AVRDUDECONFIG_PATH)/avrdude.conf -p $(MCU) -c $(AVRDUDE_PROTOCOL) -b $(UPLOAD_RATE) ; - -rule GitVersion -{ - Always $(<) ; - Depends all : $(<) ; -} - -actions GitVersion -{ - echo "const char program_version[] = \"\\" > $(<) - git log -1 --pretty=format:%h >> $(<) - echo "\";" >> $(<) -} - -GitVersion version.h ; - -rule AvrCc -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - Clean clean : $(<) ; - - CCHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] ; - CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ; -} - -actions AvrCc -{ - $(AVR_CC) -c -o $(<) $(CCHDRS) $(CCDEFS) $(CFLAGS) $(>) -} - -rule AvrC++ -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - Clean clean : $(<) ; - - CCHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] ; - CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ; -} - -actions AvrC++ -{ - $(AVR_CXX) -c -o $(<) $(CCHDRS) $(CCDEFS) $(CXXFLAGS) $(>) -} - -rule Pde -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - Clean clean : $(<) ; - -} - -actions Pde -{ - echo "#include " > $(<) - echo "#line 1 \"$(>)\"" >> $(<) - cat $(>) >> $(<) -} - -rule AvrPde -{ - local _CPP = $(OUT_DIR)/$(_I:B).cpp ; - Pde $(_CPP) : $(>) ; - AvrC++ $(<) : $(_CPP) ; -} - -rule AvrObject -{ - switch $(>:S) - { - case .c : AvrCc $(<) : $(>) ; - case .cpp : AvrC++ $(<) : $(>) ; - case .pde : AvrPde $(<) : $(>) ; - } -} - -rule AvrObjects -{ - for _I in $(<) - { - AvrObject $(OUT_DIR)/$(_I:B).o : $(_I) ; - } -} - -rule AvrMainFromObjects -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - MkDir $(<:D) ; - Depends all : $(<) ; - Clean clean : $(<) ; -} - -actions AvrMainFromObjects -{ - $(AVR_LD) $(LDFLAGS) -o $(<) $(>) -} - -rule AvrMain -{ - AvrMainFromObjects $(<) : $(OUT_DIR)/$(>:B).o ; - AvrObjects $(>) ; -} - -rule AvrHex -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - Depends hex : $(<) ; - Clean clean : $(<) ; -} - -actions AvrHex -{ - $(AVR_OBJCOPY) -O ihex -R .eeprom $(>) $(<) -} - -rule AvrUpload -{ - Depends $(1) : $(2) ; - Depends $(2) : $(3) ; - NotFile $(1) ; - Always $(1) ; - Always $(2) ; - AvrUploadAction $(2) : $(3) ; -} - -actions AvrUploadAction -{ - $(AVRDUDE) $(AVRDUDE_FLAGS) -P $(<) $(AVRDUDE_WRITE_FLASH) -U flash:w:$(>):i -} - -AvrMain $(OUT).elf : $(CORE_MODULES) $(LIB_MODULES) $(PROJECT_MODULES) ; -AvrHex $(OUT).hex : $(OUT).elf ; - -AvrUpload p6 : /dev/tty.usbserial-A600eHIs : $(OUT).hex ; -AvrUpload p4 : /dev/tty.usbserial-A40081RP : $(OUT).hex ; -AvrUpload p9 : /dev/tty.usbserial-A9007LmI : $(OUT).hex ; - diff --git a/examples/pingpair_dyn/pingpair_dyn.ino b/examples/pingpair_dyn/pingpair_dyn.ino deleted file mode 100644 index 2cd239167..000000000 --- a/examples/pingpair_dyn/pingpair_dyn.ino +++ /dev/null @@ -1,243 +0,0 @@ -/* - Copyright (C) 2011 J. Coliz - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -/** - * Example using Dynamic Payloads - * - * This is an example of how to use payloads of a varying (dynamic) size. - */ - -#include -#include "nRF24L01.h" -#include "RF24.h" -#include "printf.h" - -// -// Hardware configuration -// - -// Set up nRF24L01 radio on SPI bus plus pins 7 & 8 - -RF24 radio(7, 8); - -// sets the role of this unit in hardware. Connect to GND to be the 'pong' receiver -// Leave open to be the 'ping' transmitter -const int role_pin = 5; - -// -// Topology -// - -// Radio pipe addresses for the 2 nodes to communicate. -const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL }; - -// -// Role management -// -// Set up role. This sketch uses the same software for all the nodes -// in this system. Doing so greatly simplifies testing. The hardware itself specifies -// which node it is. -// -// This is done through the role_pin -// - -// The various roles supported by this sketch -typedef enum { role_ping_out = 1, role_pong_back } role_e; - -// The debug-friendly names of those roles -const char* role_friendly_name[] = { "invalid", "Ping out", "Pong back"}; - -// The role of the current running sketch -role_e role; - -// -// Payload -// - -const int min_payload_size = 4; -const int max_payload_size = 32; -const int payload_size_increments_by = 1; -int next_payload_size = min_payload_size; - -char receive_payload[max_payload_size + 1]; // +1 to allow room for a terminating NULL char - -void setup(void) -{ - // - // Role - // - - // set up the role pin - pinMode(role_pin, INPUT); - digitalWrite(role_pin,HIGH); - delay(20); // Just to get a solid reading on the role pin - - // read the address pin, establish our role - if (digitalRead(role_pin)) { - role = role_ping_out; - } else { - role = role_pong_back; - } - - // - // Print preamble - // - Serial.begin(115200); - printf_begin(); - - Serial.println(F("RF24/examples/pingpair_dyn/")); - Serial.print(F("ROLE: ")); - Serial.println(role_friendly_name[role]); - - // - // Setup and configure rf radio - // - radio.begin(); - - // Enable dynamic payloads - radio.enableDynamicPayloads(); - - // Optionally, increase the delay between retries & # of retries - radio.setRetries(5, 15); - - // - // Open pipes to other nodes for communication - // - - // This simple sketch opens two pipes for these two nodes to communicate - // back and forth. - // Open 'our' pipe for writing - // Open the 'other' pipe for reading, in position #1 (we can have up to 5 pipes open for reading) - if (role == role_ping_out) { - radio.openWritingPipe(pipes[0]); - radio.openReadingPipe(1, pipes[1]); - } else { - radio.openWritingPipe(pipes[1]); - radio.openReadingPipe(1, pipes[0]); - } - - // - // Start listening - // - radio.startListening(); - - // - // Dump the configuration of the rf unit for debugging - // - radio.printDetails(); -} - -void loop(void) -{ - // - // Ping out role. Repeatedly send the current time - // - - if (role == role_ping_out) { - // The payload will always be the same, what will change is how much of it we send. - static char send_payload[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ789012"; - - // First, stop listening so we can talk. - radio.stopListening(); - - // Take the time, and send it. This will block until complete - Serial.print(F("Now sending length ")); - Serial.println(next_payload_size); - radio.write(send_payload, next_payload_size); - - // Now, continue listening - radio.startListening(); - - // Wait here until we get a response, or timeout - unsigned long started_waiting_at = millis(); - bool timeout = false; - while (!radio.available() && !timeout) { - if (millis() - started_waiting_at > 500 ) { - timeout = true; - } - } - - // Describe the results - if (timeout) { - Serial.println(F("Failed, response timed out.")); - } else { - // Grab the response, compare, and send to debugging spew - uint8_t len = radio.getDynamicPayloadSize(); - - // If a corrupt dynamic payload is received, it will be flushed - if (!len) { - return; - } - - radio.read(receive_payload, len); - - // Put a zero at the end for easy printing - receive_payload[len] = 0; - - // Spew it - Serial.print(F("Got response size=")); - Serial.print(len); - Serial.print(F(" value=")); - Serial.println(receive_payload); - } - - // Update size for next time. - next_payload_size += payload_size_increments_by; - if (next_payload_size > max_payload_size) { - next_payload_size = min_payload_size; - } - - // Try again 1s later - delay(100); - } - - // - // Pong back role. Receive each packet, dump it out, and send it back - // - - if (role == role_pong_back) { - // if there is data ready - while (radio.available()) { - - // Fetch the payload, and see if this was the last one. - uint8_t len = radio.getDynamicPayloadSize(); - - // If a corrupt dynamic payload is received, it will be flushed - if (!len) { - continue; - } - - radio.read(receive_payload, len); - - // Put a zero at the end for easy printing - receive_payload[len] = 0; - - // Spew it - Serial.print(F("Got response size=")); - Serial.print(len); - Serial.print(F(" value=")); - Serial.println(receive_payload); - - // First, stop listening so we can talk - radio.stopListening(); - - // Send a reply that the packet was received - // you could also use the ACK functionality - // - // You might have a bit better luck delivering your message - // if you wait for the other side to start listening first - delay(20); - radio.write(receive_payload, len); - Serial.println(F("Sent response.")); - - // Now, resume listening so we catch the next packets. - radio.startListening(); - } - } -} -// vim:cin:ai:sts=2 sw=2 ft=cpp diff --git a/examples/pingpair_irq/pingpair_irq.ino b/examples/pingpair_irq/pingpair_irq.ino deleted file mode 100644 index ae7768f92..000000000 --- a/examples/pingpair_irq/pingpair_irq.ino +++ /dev/null @@ -1,143 +0,0 @@ -/* - Copyright (C) 2011 J. Coliz - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - - Update 2014 - TMRh20 - */ - -/** - * Example of using interrupts - * - * This is an example of how to user interrupts to interact with the radio, and a demonstration - * of how to use them to sleep when receiving, and not miss any payloads. - * The pingpair_sleepy example expands on sleep functionality with a timed sleep option for the transmitter. - * Sleep functionality is built directly into my fork of the RF24Network library - */ - -#include -#include "nRF24L01.h" -#include "RF24.h" -#include "printf.h" - -// Hardware configuration -RF24 radio(7,8); // Set up nRF24L01 radio on SPI bus plus pins 7 & 8 - -const short role_pin = 5; // sets the role of this unit in hardware. Connect to GND to be the 'pong' receiver - // Leave open to be the 'ping' transmitter - -// Demonstrates another method of setting up the addresses -byte address[][5] = { 0xCC,0xCE,0xCC,0xCE,0xCC , 0xCE,0xCC,0xCE,0xCC,0xCE}; - -// Role management - -// Set up role. This sketch uses the same software for all the nodes in this -// system. Doing so greatly simplifies testing. The hardware itself specifies -// which node it is. -// This is done through the role_pin -typedef enum { role_sender = 1, role_receiver } role_e; // The various roles supported by this sketch -const char* role_friendly_name[] = { "invalid", "Sender", "Receiver"}; // The debug-friendly names of those roles -role_e role; // The role of the current running sketch - -static uint32_t message_count = 0; - - -/********************** Setup *********************/ - -void setup(){ - - pinMode(role_pin, INPUT); // set up the role pin - digitalWrite(role_pin,HIGH); // Change this to LOW/HIGH instead of using an external pin - delay(20); // Just to get a solid reading on the role pin - - if ( digitalRead(role_pin) ) // read the address pin, establish our role - role = role_sender; - else - role = role_receiver; - - - Serial.begin(115200); - printf_begin(); - Serial.print(F("\n\rRF24/examples/pingpair_irq\n\rROLE: ")); - Serial.println(role_friendly_name[role]); - - // Setup and configure rf radio - radio.begin(); - //radio.setPALevel(RF24_PA_LOW); - radio.enableAckPayload(); // We will be using the Ack Payload feature, so please enable it - radio.enableDynamicPayloads(); // Ack payloads are dynamic payloads - // Open pipes to other node for communication - if ( role == role_sender ) { // This simple sketch opens a pipe on a single address for these two nodes to - radio.openWritingPipe(address[0]); // communicate back and forth. One listens on it, the other talks to it. - radio.openReadingPipe(1,address[1]); - }else{ - radio.openWritingPipe(address[1]); - radio.openReadingPipe(1,address[0]); - radio.startListening(); - radio.writeAckPayload( 1, &message_count, sizeof(message_count) ); // Add an ack packet for the next time around. This is a simple - ++message_count; - } - radio.printDetails(); // Dump the configuration of the rf unit for debugging - delay(50); - attachInterrupt(0, check_radio, LOW); // Attach interrupt handler to interrupt #0 (using pin 2) on BOTH the sender and receiver -} - - - -/********************** Main Loop *********************/ -void loop() { - - - if (role == role_sender) { // Sender role. Repeatedly send the current time - unsigned long time = millis(); // Take the time, and send it. - Serial.print(F("Now sending ")); - Serial.println(time); - radio.startWrite( &time, sizeof(unsigned long) ,0); - delay(2000); // Try again soon - } - - - if(role == role_receiver){ // Receiver does nothing except in IRQ - } -} - - -/********************** Interrupt *********************/ - -void check_radio(void) // Receiver role: Does nothing! All the work is in IRQ -{ - - bool tx,fail,rx; - radio.whatHappened(tx,fail,rx); // What happened? - - if ( tx ) { // Have we successfully transmitted? - if ( role == role_sender ){ Serial.println(F("Send:OK")); } - if ( role == role_receiver ){ Serial.println(F("Ack Payload:Sent")); } - } - - if ( fail ) { // Have we failed to transmit? - if ( role == role_sender ){ Serial.println(F("Send:Failed")); } - if ( role == role_receiver ){ Serial.println(F("Ack Payload:Failed")); } - } - - if ( rx || radio.available()){ // Did we receive a message? - - if ( role == role_sender ) { // If we're the sender, we've received an ack payload - radio.read(&message_count,sizeof(message_count)); - Serial.print(F("Ack: ")); - Serial.println(message_count); - } - - - if ( role == role_receiver ) { // If we're the receiver, we've received a time message - static unsigned long got_time; // Get this payload and dump it - radio.read( &got_time, sizeof(got_time) ); - Serial.print(F("Got payload ")); - Serial.println(got_time); - radio.writeAckPayload( 1, &message_count, sizeof(message_count) ); // Add an ack packet for the next time around. This is a simple - ++message_count; // packet counter - } - } -} diff --git a/examples/pingpair_irq_simple/pingpair_irq_simple.ino b/examples/pingpair_irq_simple/pingpair_irq_simple.ino deleted file mode 100644 index e71e6564b..000000000 --- a/examples/pingpair_irq_simple/pingpair_irq_simple.ino +++ /dev/null @@ -1,122 +0,0 @@ -/* - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - - Created Dec 2014 - TMRh20 - */ - -/** - * Example of using interrupts - * - * This is a very simple example of using two devices to communicate using interrupts. - * With multiple devices, each device would need to have a separate reading pipe - */ - -#include -#include "RF24.h" -#include - -// Hardware configuration -// Set up nRF24L01 radio on SPI bus plus pins 7 & 8 -RF24 radio(7,8); - -// Use the same address for both devices -uint8_t address[] = { "radio" }; - -// Simple messages to represent a 'ping' and 'pong' -uint8_t ping = 111; -uint8_t pong = 222; - -volatile uint32_t round_trip_timer = 0; - - -/********************** Setup *********************/ - -void setup(){ - - Serial.begin(115200); - Serial.println(F("Simple pingpair example")); - Serial.println(F("Send a 'T' via Serial to transmit a single 'ping' ")); - //printf_begin(); You must uncomment this if you wish to use printDetails() - - // Setup and configure rf radio - radio.begin(); - - // Use dynamic payloads to improve response time - radio.enableDynamicPayloads(); - radio.openWritingPipe(address); // communicate back and forth. One listens on it, the other talks to it. - radio.openReadingPipe(1,address); - radio.startListening(); - - //radio.printDetails(); // Dump the configuration of the rf unit for debugging - - attachInterrupt(0, check_radio, LOW); // Attach interrupt handler to interrupt #0 (using pin 2) on BOTH the sender and receiver -} - - - -/********************** Main Loop *********************/ -void loop() { - - if(Serial.available()){ - switch(toupper(Serial.read())){ - case 'T': - // Only allow 1 transmission per 45ms to prevent overlapping IRQ/reads/writes - // Default retries = 5,15 = ~20ms per transmission max - while(micros() - round_trip_timer < 45000){ - //delay between writes - } - Serial.print(F("Sending Ping")); - radio.stopListening(); - round_trip_timer = micros(); - radio.startWrite( &ping, sizeof(uint8_t),0 ); - break; - } - } -} - -/********************** Interrupt *********************/ - -void check_radio(void) // Receiver role: Does nothing! All the work is in IRQ -{ - - bool tx,fail,rx; - radio.whatHappened(tx,fail,rx); // What happened? - - - // If data is available, handle it accordingly - if ( rx ){ - - if(radio.getDynamicPayloadSize() < 1){ - // Corrupt payload has been flushed - return; - } - // Read in the data - uint8_t received; - radio.read(&received,sizeof(received)); - - // If this is a ping, send back a pong - if(received == ping){ - radio.stopListening(); - // Normal delay will not work here, so cycle through some no-operations (16nops @16mhz = 1us delay) - for(uint32_t i=0; i<130;i++){ - __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); - } - radio.startWrite(&pong,sizeof(pong),0); - Serial.print("pong"); - }else - // If this is a pong, get the current micros() - if(received == pong){ - round_trip_timer = micros() - round_trip_timer; - Serial.print(F("Received Pong, Round Trip Time: ")); - Serial.println(round_trip_timer); - } - } - - // Start listening if transmission is complete - if( tx || fail ){ - radio.startListening(); - Serial.println(tx ? F(":OK") : F(":Fail")); - } -} diff --git a/examples/pingpair_multi_dyn/Jamfile b/examples/pingpair_multi_dyn/Jamfile deleted file mode 100755 index 901f8da8c..000000000 --- a/examples/pingpair_multi_dyn/Jamfile +++ /dev/null @@ -1,206 +0,0 @@ -PROJECT_NAME = $(PWD:B) ; -PROJECT_DIR = . ; -PROJECT_LIBS = SPI RF24 ; - -OUT_DIR = ojam ; -F_CPU = 16000000 ; -MCU = atmega328p ; -PORTS = /dev/tty.usbserial-A600eHIs /dev/tty.usbserial-A40081RP /dev/tty.usbserial-A9007LmI ; - -UPLOAD_RATE = 57600 ; -AVRDUDE_PROTOCOL = stk500v1 ; -COM = 33 ; - -# Host-specific overrides for locations -if $(OS) = MACOSX -{ -ARDUINO_VERSION = 22 ; -OLD_DIR = /opt/arduino-0021 ; -AVR_TOOLS_PATH = $(OLD_DIR)/hardware/tools/avr/bin ; -AVRDUDECONFIG_PATH = $(OLD_DIR)/hardware/tools/avr/etc ; -ARDUINO_DIR = /opt/Arduino ; -ARDUINO_AVR = /usr/lib/avr/include ; -} - -# Where is everything? -ARDUINO_VERSION ?= 22 ; -AVR_TOOLS_PATH ?= /usr/bin ; -ARDUINO_DIR ?= /opt/arduino-00$(ARDUINO_VERSION) ; -ARDUINO_AVR ?= $(ARDUINO_DIR)/hardware/tools/avr/avr/include/avr ; -AVRDUDECONFIG_PATH ?= $(ARDUINO_DIR)/hardware/tools ; -ARDUINO_CORE = $(ARDUINO_DIR)/hardware/arduino/cores/arduino ; -ARDUINO_LIB = $(ARDUINO_DIR)/libraries ; -SKETCH_LIB = $(HOME)/Source/Arduino/libraries ; -AVR_CC = $(AVR_TOOLS_PATH)/avr-gcc ; -AVR_CXX = $(AVR_TOOLS_PATH)/avr-g++ ; -AVR_LD = $(AVR_TOOLS_PATH)/avr-gcc ; -AVR_OBJCOPY = $(AVR_TOOLS_PATH)/avr-objcopy ; -AVRDUDE = $(AVR_TOOLS_PATH)/avrdude ; - -DEFINES = F_CPU=$(F_CPU)L ARDUINO=$(ARDUINO_VERSION) VERSION_H ; -CTUNING = -ffunction-sections -fdata-sections ; -CXXTUNING = -fno-exceptions -fno-strict-aliasing ; -CFLAGS = -Os -Wall -Wextra -mmcu=$(MCU) $(CTUNING) ; -CXXFLAGS = $(CFLAGS) $(CXXTUNING) ; -LDFLAGS = -Os -lm -Wl,--gc-sections -mmcu=atmega328p ; - -# Search everywhere for headers -HDRS = $(PROJECT_DIR) $(ARDUINO_AVR) $(ARDUINO_CORE) [ GLOB $(ARDUINO_LIB) $(SKETCH_LIB) : [^.]* ] ; - -# Grab everything from the core directory -CORE_MODULES = [ GLOB $(ARDUINO_CORE) : *.c *.cpp ] ; - -# Grab everything from libraries. To avoid this "grab everything" behaviour, you -# can specify specific modules to pick up in PROJECT_MODULES -LIB_MODULES = [ GLOB $(ARDUINO_LIB)/$(PROJECT_LIBS) $(SKETCH_LIB)/$(PROJECT_LIBS) : *.cpp ] ; - -# In addition to explicitly-specified program modules, pick up anything from the current -# dir. -PROJECT_MODULES += [ GLOB $(PROJECT_DIR) : *.c *.cpp *.pde ] ; - -# Shortcut for the out files -OUT = $(OUT_DIR)/$(PROJECT_NAME) ; - -# AvrDude setup -AVRDUDE_FLAGS = -V -F -D -C $(AVRDUDECONFIG_PATH)/avrdude.conf -p $(MCU) -c $(AVRDUDE_PROTOCOL) -b $(UPLOAD_RATE) ; - -rule GitVersion -{ - Always $(<) ; - Depends all : $(<) ; -} - -actions GitVersion -{ - echo "const char program_version[] = \"\\" > $(<) - git log -1 --pretty=format:%h >> $(<) - echo "\";" >> $(<) -} - -GitVersion version.h ; - -rule AvrCc -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - Clean clean : $(<) ; - - CCHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] ; - CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ; -} - -actions AvrCc -{ - $(AVR_CC) -c -o $(<) $(CCHDRS) $(CCDEFS) $(CFLAGS) $(>) -} - -rule AvrC++ -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - Clean clean : $(<) ; - - CCHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] ; - CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ; -} - -actions AvrC++ -{ - $(AVR_CXX) -c -o $(<) $(CCHDRS) $(CCDEFS) $(CXXFLAGS) $(>) -} - -rule Pde -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - Clean clean : $(<) ; - -} - -actions Pde -{ - echo "#include " > $(<) - echo "#line 1 \"$(>)\"" >> $(<) - cat $(>) >> $(<) -} - -rule AvrPde -{ - local _CPP = $(OUT_DIR)/$(_I:B).cpp ; - Pde $(_CPP) : $(>) ; - AvrC++ $(<) : $(_CPP) ; -} - -rule AvrObject -{ - switch $(>:S) - { - case .c : AvrCc $(<) : $(>) ; - case .cpp : AvrC++ $(<) : $(>) ; - case .pde : AvrPde $(<) : $(>) ; - } -} - -rule AvrObjects -{ - for _I in $(<) - { - AvrObject $(OUT_DIR)/$(_I:B).o : $(_I) ; - } -} - -rule AvrMainFromObjects -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - MkDir $(<:D) ; - Depends all : $(<) ; - Clean clean : $(<) ; -} - -actions AvrMainFromObjects -{ - $(AVR_LD) $(LDFLAGS) -o $(<) $(>) -} - -rule AvrMain -{ - AvrMainFromObjects $(<) : $(OUT_DIR)/$(>:B).o ; - AvrObjects $(>) ; -} - -rule AvrHex -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - Depends hex : $(<) ; - Clean clean : $(<) ; -} - -actions AvrHex -{ - $(AVR_OBJCOPY) -O ihex -R .eeprom $(>) $(<) -} - -rule AvrUpload -{ - Depends $(1) : $(2) ; - Depends $(2) : $(3) ; - NotFile $(1) ; - Always $(1) ; - Always $(2) ; - AvrUploadAction $(2) : $(3) ; -} - -actions AvrUploadAction -{ - $(AVRDUDE) $(AVRDUDE_FLAGS) -P $(<) $(AVRDUDE_WRITE_FLASH) -U flash:w:$(>):i -} - -AvrMain $(OUT).elf : $(CORE_MODULES) $(LIB_MODULES) $(PROJECT_MODULES) ; -AvrHex $(OUT).hex : $(OUT).elf ; - -AvrUpload p6 : /dev/tty.usbserial-A600eHIs : $(OUT).hex ; -AvrUpload p4 : /dev/tty.usbserial-A40081RP : $(OUT).hex ; -AvrUpload p9 : /dev/tty.usbserial-A9007LmI : $(OUT).hex ; - diff --git a/examples/rf24_ATTiny/rf24ping85/rf24ping85.ino b/examples/rf24_ATTiny/rf24ping85/rf24ping85.ino index b5fc94ec0..44a5e020e 100644 --- a/examples/rf24_ATTiny/rf24ping85/rf24ping85.ino +++ b/examples/rf24_ATTiny/rf24ping85/rf24ping85.ino @@ -1,101 +1,204 @@ -/* -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -version 2 as published by the Free Software Foundation. - - rf24ping85.ino by tong67 ( https://github.com/tong67 ) - This is an example of how to use the RF24 class to communicate with ATtiny85 and other node. - Write this sketch to an ATtiny85. It will act like the 'transmit' mode of GettingStarted.ino - Write GettingStarted.ino sketch to UNO (or other board or RPi) and put the node in 'receiver' mode. - The ATtiny85 will transmit a counting number every second starting from 1. - The ATtiny85 uses the tiny-core by CodingBadly (https://code.google.com/p/arduino-tiny/) - When direct use of 3v3 does not work (UNO boards have bad 3v3 line) use 5v with LED (1.8V ~ 2.2V drop) - For low power consumption solutions floating pins (SCK and MOSI) should be pulled high or low with eg. 10K - - ** Hardware configuration ** - ATtiny25/45/85 Pin map with CE_PIN 3 and CSN_PIN 4 - +-\/-+ - NC PB5 1|o |8 Vcc --- nRF24L01 VCC, pin2 --- LED --- 5V - nRF24L01 CE, pin3 --- PB3 2| |7 PB2 --- nRF24L01 SCK, pin5 - nRF24L01 CSN, pin4 --- PB4 3| |6 PB1 --- nRF24L01 MOSI, pin7 - nRF24L01 GND, pin1 --- GND 4| |5 PB0 --- nRF24L01 MISO, pin6 - +----+ - - ATtiny25/45/85 Pin map with CE_PIN 3 and CSN_PIN 3 => PB3 and PB4 are free to use for application - Circuit idea from http://nerdralph.blogspot.ca/2014/01/nrf24l01-control-with-3-attiny85-pins.html - Original RC combination was 1K/100nF. 22K/10nF combination worked better. - For best settletime delay value in RF24::csn() the timingSearch3pin.ino scatch can be used. - This configuration is enabled when CE_PIN and CSN_PIN are equal, e.g. both 3 - Because CE is always high the power consumption is higher than for 5 pins solution - ^^ - +-\/-+ nRF24L01 CE, pin3 ------| // - PB5 1|o |8 Vcc --- nRF24L01 VCC, pin2 ------x----------x--|<|-- 5V - NC PB3 2| |7 PB2 --- nRF24L01 SCK, pin5 --|<|---x-[22k]--| LED - NC PB4 3| |6 PB1 --- nRF24L01 MOSI, pin6 1n4148 | - nRF24L01 GND, pin1 -x- GND 4| |5 PB0 --- nRF24L01 MISO, pin7 | - | +----+ | - |-----------------------------------------------||----x-- nRF24L01 CSN, pin4 - 10nF - - ATtiny24/44/84 Pin map with CE_PIN 8 and CSN_PIN 7 - Schematic provided and successfully tested by Carmine Pastore (https://github.com/Carminepz) - +-\/-+ - nRF24L01 VCC, pin2 --- VCC 1|o |14 GND --- nRF24L01 GND, pin1 - PB0 2| |13 AREF - PB1 3| |12 PA1 - PB3 4| |11 PA2 --- nRF24L01 CE, pin3 - PB2 5| |10 PA3 --- nRF24L01 CSN, pin4 - PA7 6| |9 PA4 --- nRF24L01 SCK, pin5 - nRF24L01 MOSI, pin7 --- PA6 7| |8 PA5 --- nRF24L01 MISO, pin6 - +----+ -*/ - -// CE and CSN are configurable, specified values for ATtiny85 as connected above -#define CE_PIN 3 -#define CSN_PIN 4 -//#define CSN_PIN 3 // uncomment for ATtiny85 3 pins solution - -#include "RF24.h" - -RF24 radio(CE_PIN, CSN_PIN); - -byte addresses[][6] = { - "1Node","2Node"}; -unsigned long payload = 0; - -void setup() { - // Setup and configure rf radio - radio.begin(); // Start up the radio - radio.setAutoAck(1); // Ensure autoACK is enabled - radio.setRetries(15,15); // Max delay between retries & number of retries - radio.openWritingPipe(addresses[1]); // Write to device address '2Node' - radio.openReadingPipe(1,addresses[0]); // Read on pipe 1 for device address '1Node' - radio.startListening(); // Start listening -} - -void loop(void){ - - radio.stopListening(); // First, stop listening so we can talk. - payload++; - radio.write( &payload, sizeof(unsigned long) ); - radio.startListening(); // Now, continue listening - - unsigned long started_waiting_at = micros(); // Set up a timeout period, get the current microseconds - boolean timeout = false; // Set up a variable to indicate if a response was received or not - - while ( !radio.available() ){ // While nothing is received - if (micros() - started_waiting_at > 200000 ){ // If waited longer than 200ms, indicate timeout and exit while loop - timeout = true; - break; - } - - } - - if ( !timeout ){ // Describe the results - unsigned long got_time; // Grab the response, compare, and send to debugging spew - radio.read( &got_time, sizeof(unsigned long) ); - } - - // Try again 1s later - delay(1000); -} \ No newline at end of file +/** + * See documentation at https://nRF24.github.io/RF24 + * See License information at root directory of this library + * written in 2014 by tong67 (https://github.com/tong67) + * Updated 2020 by 2bndy5 (http://github.com/2bndy5) for the + * SpenceKonde ATTinyCore (https://github.com/SpenceKonde/ATTinyCore) + */ + +/** + * The RF24 library uses the [ATTinyCore by + * SpenceKonde](https://github.com/SpenceKonde/ATTinyCore) + * + * This sketch is a duplicate of the ManualAcknowledgements.ino example + * (without all the Serial input/output code), and it demonstrates + * a ATTiny25/45/85 or ATTiny24/44/84 driving the nRF24L01 transceiver using + * the RF24 class to communicate with another node. + * + * A simple example of sending data from 1 nRF24L01 transceiver to another + * with manually transmitted (non-automatic) Acknowledgement (ACK) payloads. + * This example still uses ACK packets, but they have no payloads. Instead the + * acknowledging response is sent with `write()`. This tactic allows for more + * updated acknowledgement payload data, where actual ACK payloads' data are + * outdated by 1 transmission because they have to loaded before receiving a + * transmission. + * + * This example was written to be used on 2 devices acting as "nodes". + */ + +/* + * ********** Hardware configuration (& schematics) ******************* + * + * When direct use of 3V does not work (UNO boards tend to have poor 3V supply), + * use 5V with LED (1.8V ~ 2.2V drop) instead. + * For low power consumption solutions floating pins (SCK and MOSI) should be + * pulled HIGH or LOW with 10K resistors. + * + * ATTiny25/45/85 Pin map with CE_PIN 3 and CSN_PIN 4 + * ^^ + * +-\/-+ // + * PB5 1|o |8 Vcc --- nRF24L01 VCC --- |<|--- 5V + * nRF24L01 CE --- PB3 2| |7 PB2 --- nRF24L01 SCK LED + * nRF24L01 CSN --- PB4 3| |6 PB1 --- nRF24L01 MOSI + * nRF24L01 GND --- GND 4| |5 PB0 --- nRF24L01 MISO + * +----+ + * + * ATTiny25/45/85 Pin map with CE_PIN 3 and CSN_PIN 3 => PB3 and PB4 are + * free to use for other purposes. This "3 pin solution" is from + * Ralph Doncaster (AKA NerdRalph) which is outlined on his blog at + * http://nerdralph.blogspot.ca/2014/01/nrf24l01-control-with-3-attiny85-pins.html + * Original RC combination was 1K/100nF. 22K/10nF combination worked better. + * + * For best settle time delay value to use for RF24::csDelay in RF24::csn(), use + * the examples/rf24_ATTiny/timingSearch3pin/timingSearch3pin.ino sketch. + * + * This configuration is enabled in the RF24 library when CE_PIN and + * CSN_PIN parameters to the constructor are equal. Notice (in the schematic + * below) that these pins aren't directly to the ATTiny85. Because the CE pin + * is always HIGH, the power consumption is higher than it would be for the + * typical 5 pins solution. + * ^^ + * +-\/-+ nRF24L01 CE --------| // + * PB5 1|o |8 Vcc --- nRF24L01 VCC -------x----------x--|<|-- 5V + * PB3 2| |7 PB2 --- nRF24L01 SCK ---|<|---x-[22k]--| LED + * PB4 3| |6 PB1 --- nRF24L01 MOSI 1n4148 | + * nRF24L01 GND -x- GND 4| |5 PB0 --- nRF24L01 MISO | + * | +----+ | + * |-----------------------------------------||----x-- nRF24L01 CSN + * 10nF + * + * ATTiny24/44/84 Pin map with CE_PIN 8 and CSN_PIN 7 & assuming 1.9V to 3V on VCC + * Schematic provided and successfully tested by + * Carmine Pastore (https://github.com/Carminepz) + * + * +-\/-+ + * nRF24L01 VCC ---- VCC 1|o |14 GND --- nRF24L01 GND + * PB0 2| |13 AREF + * PB1 3| |12 PA1 + * PB3 4| |11 PA2 --- nRF24L01 CE + * PB2 5| |10 PA3 --- nRF24L01 CSN + * PA7 6| |9 PA4 --- nRF24L01 SCK + * nRF24L01 MOSI --- PA6 7| |8 PA5 --- nRF24L01 MISO + * +----+ + */ + +#include "SPI.h" +#include "RF24.h" + +// CE and CSN are configurable, specified values for ATTiny85 as connected above +#define CE_PIN 3 +#define CSN_PIN 4 +//#define CSN_PIN 3 // uncomment for ATTiny85 3 pins solution + +// instantiate an object for the nRF24L01 transceiver +RF24 radio(CE_PIN, CSN_PIN); + +// Let these addresses be used for the pair +uint8_t address[][6] = {"1Node", "2Node"}; +// It is very helpful to think of an address as a path instead of as +// an identifying device destination + +// to use different addresses on a pair of radios, we need a variable to +// uniquely identify which address this radio will use to transmit +bool radioNumber = 1; // 0 uses address[0] to transmit, 1 uses address[1] to transmit + +// Used to control whether this node is sending or receiving +bool role = false; // true = TX node, false = RX node + +// For this example, we'll be using a payload containing +// a string & an integer number that will be incremented +// on every successful transmission. +// Make a data structure to store the entire payload of different datatypes +struct PayloadStruct { + char message[7]; // only using 6 characters for TX & RX payloads + uint8_t counter; +}; +PayloadStruct payload; + +void setup() { + + // append a NULL terminating character for printing as a c-string + payload.message[6] = 0; + + // initialize the transceiver on the SPI bus + if (!radio.begin()) { + while (1) {} // hold in infinite loop + } + + // Set the PA Level low to try preventing power supply related problems + // because these examples are likely run with nodes in close proximity to + // each other. + radio.setPALevel(RF24_PA_LOW); // RF24_PA_MAX is default. + + // save on transmission time by setting the radio to only transmit the + // number of bytes we need to transmit a float + radio.setPayloadSize(sizeof(payload)); // char[7] & uint8_t datatypes occupy 8 bytes + + // set the TX address of the RX node into the TX pipe + radio.openWritingPipe(address[radioNumber]); // always uses pipe 0 + + // set the RX address of the TX node into a RX pipe + radio.openReadingPipe(1, address[!radioNumber]); // using pipe 1 + + if (role) { + // setup the TX node + + memcpy(payload.message, "Hello ", 6); // set the outgoing message + radio.stopListening(); // put radio in TX mode + } else { + // setup the RX node + + memcpy(payload.message, "World ", 6); // set the outgoing message + radio.startListening(); // put radio in RX mode + } +} // setup() + +void loop() { + + if (role) { + // This device is a TX node + + bool report = radio.write(&payload, sizeof(payload)); // transmit & save the report + + if (report) { + // transmission successful; wait for response and print results + + radio.startListening(); // put in RX mode + unsigned long start_timeout = millis(); // timer to detect no response + while (!radio.available()) { // wait for response or timeout + if (millis() - start_timeout > 200) // only wait 200 ms + break; + } + radio.stopListening(); // put back in TX mode + + // print summary of transactions + if (radio.available()) { // is there a payload received? + + PayloadStruct received; + radio.read(&received, sizeof(received)); // get payload from RX FIFO + payload.counter = received.counter; // save incoming counter for next outgoing counter + } + } // report + + // to make this example readable in the serial monitor + delay(1000); // slow transmissions down by 1 second + + } else { + // This device is a RX node + + if (radio.available()) { // is there a payload? + + PayloadStruct received; + radio.read(&received, sizeof(received)); // get incoming payload + payload.counter = received.counter + 1; // increment incoming counter for next outgoing response + + // transmit response & save result to `report` + radio.stopListening(); // put in TX mode + + radio.writeFast(&payload, sizeof(payload)); // load response to TX FIFO + bool report = radio.txStandBy(150); // keep retrying for 150 ms + + radio.startListening(); // put back in RX mode + } + } // role +} // loop \ No newline at end of file diff --git a/examples/rf24_ATTiny/timingSearch3pin/timingSearch3pin.ino b/examples/rf24_ATTiny/timingSearch3pin/timingSearch3pin.ino index 61e42a584..ea1cd6ac3 100644 --- a/examples/rf24_ATTiny/timingSearch3pin/timingSearch3pin.ino +++ b/examples/rf24_ATTiny/timingSearch3pin/timingSearch3pin.ino @@ -1,396 +1,209 @@ -/* -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -version 2 as published by the Free Software Foundation. - - timingSearch3pin.ino by tong67 ( https://github.com/tong67 ) - This sketch can be used to determine the best settleTime values to use in RF24::csn(). - The used settleTimeValues are 100/20. Depend on used RC combiniation and voltage drop by LED. - It is setup to be completely selfcontained, copied defines and code from RF24 library. - The ATtiny85 uses the tiny-core by CodingBadly (https://code.google.com/p/arduino-tiny/) - (Intermediate) results are written to TX (PB3, pin 2). For schematic see rf24ping85.ino -*/ - -// nRF24L01.h copy - -/* Memory Map */ -#define CONFIG 0x00 -#define EN_AA 0x01 -#define EN_RXADDR 0x02 -#define SETUP_AW 0x03 -#define SETUP_RETR 0x04 -#define RF_CH 0x05 -#define RF_SETUP 0x06 -#define STATUS 0x07 -#define OBSERVE_TX 0x08 -#define CD 0x09 -#define RX_ADDR_P0 0x0A -#define RX_ADDR_P1 0x0B -#define RX_ADDR_P2 0x0C -#define RX_ADDR_P3 0x0D -#define RX_ADDR_P4 0x0E -#define RX_ADDR_P5 0x0F -#define TX_ADDR 0x10 -#define RX_PW_P0 0x11 -#define RX_PW_P1 0x12 -#define RX_PW_P2 0x13 -#define RX_PW_P3 0x14 -#define RX_PW_P4 0x15 -#define RX_PW_P5 0x16 -#define FIFO_STATUS 0x17 -#define DYNPD 0x1C -#define FEATURE 0x1D - -/* Bit Mnemonics */ -#define MASK_RX_DR 6 -#define MASK_TX_DS 5 -#define MASK_MAX_RT 4 -#define EN_CRC 3 -#define CRCO 2 -#define PWR_UP 1 -#define PRIM_RX 0 -#define ENAA_P5 5 -#define ENAA_P4 4 -#define ENAA_P3 3 -#define ENAA_P2 2 -#define ENAA_P1 1 -#define ENAA_P0 0 -#define ERX_P5 5 -#define ERX_P4 4 -#define ERX_P3 3 -#define ERX_P2 2 -#define ERX_P1 1 -#define ERX_P0 0 -#define AW 0 -#define ARD 4 -#define ARC 0 -#define PLL_LOCK 4 -#define RF_DR 3 -#define RF_PWR 6 -#define RX_DR 6 -#define TX_DS 5 -#define MAX_RT 4 -#define RX_P_NO 1 -#define TX_FULL 0 -#define PLOS_CNT 4 -#define ARC_CNT 0 -#define TX_REUSE 6 -#define FIFO_FULL 5 -#define TX_EMPTY 4 -#define RX_FULL 1 -#define RX_EMPTY 0 -#define DPL_P5 5 -#define DPL_P4 4 -#define DPL_P3 3 -#define DPL_P2 2 -#define DPL_P1 1 -#define DPL_P0 0 -#define EN_DPL 2 -#define EN_ACK_PAY 1 -#define EN_DYN_ACK 0 - -/* Instruction Mnemonics */ -#define R_REGISTER 0x00 -#define W_REGISTER 0x20 -#define REGISTER_MASK 0x1F -#define ACTIVATE 0x50 -#define R_RX_PL_WID 0x60 -#define R_RX_PAYLOAD 0x61 -#define W_TX_PAYLOAD 0xA0 -#define W_ACK_PAYLOAD 0xA8 -#define FLUSH_TX 0xE1 -#define FLUSH_RX 0xE2 -#define REUSE_TX_PL 0xE3 -#define RF24_NOP 0xFF - -/* Non-P omissions */ -#define LNA_HCURR 0 - -/* P model memory Map */ -#define RPD 0x09 -#define W_TX_PAYLOAD_NO_ACK 0xB0 - -/* P model bit Mnemonics */ -#define RF_DR_LOW 5 -#define RF_DR_HIGH 3 -#define RF_PWR_LOW 1 -#define RF_PWR_HIGH 2 -/****************************************************************************/ - -//ATTiny support code pulled in from https://github.com/jscrane/RF24 -#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) -// see http://gammon.com.au/spi -# define DI 0 // D0, pin 5 Data In -# define DO 1 // D1, pin 6 Data Out (this is *not* MOSI) -# define USCK 2 // D2, pin 7 Universal Serial Interface clock -# define SS 3 // D3, pin 2 Slave Select -#elif defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) -// these depend on the core used (check pins_arduino.h) -// this is for jeelabs' one (based on google-code core) -# define DI 4 // PA6 -# define DO 5 // PA5 -# define USCK 6 // PA4 -# define SS 3 // PA7 -#endif - -#if defined (ARDUINO) && !defined (__arm__) - #if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) - #define RF24_TINY - #else -// #include - #endif -#endif - -#if defined(RF24_TINY) -#include -#include -#include - -#define SPI_CLOCK_DIV4 0x00 -#define SPI_CLOCK_DIV16 0x01 -#define SPI_CLOCK_DIV64 0x02 -#define SPI_CLOCK_DIV128 0x03 -#define SPI_CLOCK_DIV2 0x04 -#define SPI_CLOCK_DIV8 0x05 -#define SPI_CLOCK_DIV32 0x06 -//#define SPI_CLOCK_DIV64 0x07 - -#define SPI_MODE0 0x00 -#define SPI_MODE1 0x04 -#define SPI_MODE2 0x08 -#define SPI_MODE3 0x0C - -#define SPI_MODE_MASK 0x0C // CPOL = bit 3, CPHA = bit 2 on SPCR -#define SPI_CLOCK_MASK 0x03 // SPR1 = bit 1, SPR0 = bit 0 on SPCR -#define SPI_2XCLOCK_MASK 0x01 // SPI2X = bit 0 on SPSR - -class SPIClass { -public: - static byte transfer(byte _data); - - // SPI Configuration methods - - inline static void attachInterrupt(); - inline static void detachInterrupt(); // Default - - static void begin(); // Default - static void end(); - -// static void setBitOrder(uint8_t); -// static void setDataMode(uint8_t); -// static void setClockDivider(uint8_t); -}; -extern SPIClass SPI; - -#endif /* RF24_TINY */ - - -#if defined(RF24_TINY) - -void SPIClass::begin() { - digitalWrite(SS, HIGH); - pinMode(USCK, OUTPUT); - pinMode(DO, OUTPUT); - pinMode(SS, OUTPUT); - pinMode(DI, INPUT); - USICR = _BV(USIWM0); -} - -byte SPIClass::transfer(byte b) { - USIDR = b; - USISR = _BV(USIOIF); - do - USICR = _BV(USIWM0) | _BV(USICS1) | _BV(USICLK) | _BV(USITC); - while ((USISR & _BV(USIOIF)) == 0); - return USIDR; -} - -void SPIClass::end() {} - -#endif /* RF24_TINY */ - -/****************************************************************************/ -uint8_t ce_pin; /**< "Chip Enable" pin, activates the RX or TX role */ -uint8_t csn_pin; /**< SPI Chip select */ -uint8_t csnHighSettle = 255; -uint8_t csnLowSettle = 255; -/****************************************************************************/ -void ce(bool level) { - if (ce_pin != csn_pin) digitalWrite(ce_pin,level); -} - -/****************************************************************************/ -void setCsnHighSettle(uint8_t level) { - csnHighSettle = level; -} - -/****************************************************************************/ -void setCsnLowSettle(uint8_t level) { - csnLowSettle = level; -} -/****************************************************************************/ -void csn(bool mode) { - if (ce_pin != csn_pin) { - digitalWrite(csn_pin,mode); - } else { - if (mode == HIGH) { - PORTB |= (1<CSN HIGH - delayMicroseconds(csnHighSettle); // allow csn to settle - } else { - PORTB &= ~(1<CSN LOW - delayMicroseconds(csnLowSettle); // allow csn to settle - } - } -} - -/****************************************************************************/ -uint8_t read_register(uint8_t reg) -{ - csn(LOW); - SPI.transfer( R_REGISTER | ( REGISTER_MASK & reg ) ); - uint8_t result = SPI.transfer(0xff); - csn(HIGH); - return result; -} - -/****************************************************************************/ -uint8_t write_register2(uint8_t reg, uint8_t value) -{ - uint8_t status; - - csn(LOW); - status = SPI.transfer( W_REGISTER | ( REGISTER_MASK & reg ) ); - SPI.transfer(value); - csn(HIGH); - return status; -} - -/****************************************************************************/ -#if defined(RF24_TINY) -#define CE_PIN 3 -#define CSN_PIN 3 -#else -#define CE_PIN 7 -#define CSN_PIN 8 -#endif - -#define MAX_HIGH 100 -#define MAX_LOW 100 -#define MINIMAL 8 - -void setup(void) { - uint8_t status; - - // start serial port and SPI - Serial.begin(9600); - SPI.begin(); - - // configure ce and scn as output when used - ce_pin = CE_PIN; - csn_pin = CSN_PIN; - - setCsnHighSettle(MAX_HIGH); - setCsnLowSettle(MAX_LOW); - // csn is used in SPI transfers. Set to LOW at start and HIGH after transfer. Set to HIGH to reflect no transfer active - // SPI command are accepted in Power Down state. - // ce represent PRX (LOW) or PTX (HIGH) mode apart from register settings. Start in PRX mode. - ce(LOW); - csn(HIGH); - - // nRF24L01 goes from to Power Down state 100ms after Power on Reset ( Vdd > 1.9V) or when PWR_UP is 0 in config register - // Goto Power Down state (Powerup or force) and set in transmit mode - write_register2(CONFIG, read_register(CONFIG) & ~_BV(PWR_UP) & ~_BV(PRIM_RX)); - delay(100); - - // Goto Standby-I - // Technically we require 4.5ms Tpd2stby+ 14us as a worst case. We'll just call it 5ms for good measure. - // WARNING: Delay is based on P-variant whereby non-P *may* require different timing. - write_register2(CONFIG, read_register(CONFIG) | _BV(PWR_UP)); - delay(5) ; - - // Goto Standby-II - ce(HIGH); - Serial.print("Scanning for optimal setting time for scn"); -} - - -void loop(void) { - uint8_t status; - uint8_t i; - uint8_t j; - uint8_t k; - bool success = true; - uint8_t csnHigh = MAX_HIGH; - uint8_t csnLow = MAX_LOW; - uint8_t bottom_success; - bool bottom_found; - uint8_t value[] = {5,10}; - uint8_t limit[] = {MAX_HIGH,MAX_LOW}; - uint8_t advice[] = {MAX_HIGH,MAX_LOW}; - - // check max values give correct behavior - for (k=0;k<2;k++) { - bottom_found = false; - bottom_success = 0; - while(bottom_success < 255) { - setCsnHighSettle(limit[0]); - setCsnLowSettle(limit[1]); - // check current values - i = 0; - while(i<255 & success) { - for (j=0;j<2;j++) { - write_register2(EN_AA, value[j]); - status = read_register(EN_AA); - if (value[j] != status) { - success = false; - } - } - i++; - } - // process result of current values - if (!success) { - Serial.print("Settle NOK. csnHigh="); - Serial.print(limit[0],DEC); - Serial.print(" csnLow="); - Serial.println(limit[1],DEC); - limit[k]++; - bottom_found = true; - bottom_success = 0; - success = true; - } else { - Serial.print("Settle OK. csnHigh="); - Serial.print(limit[0],DEC); - Serial.print(" csnLow="); - Serial.println(limit[1],DEC); - if (!bottom_found) { - limit[k]--; - if (limit[k] == MINIMAL) { - bottom_found = true; - bottom_success = 0; - success = true; - } - } else { - bottom_success++; - } - } - } - Serial.print("Settle value found for "); - if (k == 0) { - Serial.print("csnHigh: "); - } else { - Serial.print("csnLow: "); - } - Serial.println(limit[k],DEC); - advice[k] = limit[k] + (limit[k] / 10); - limit[k] = 100; - } - Serial.print("Adviced Settle times are: csnHigh="); - Serial.print(advice[0],DEC); - Serial.print(" csnLow="); - Serial.println(advice[1],DEC); - while (true) - { - ; - } -} - +/** + * See documentation at https://nRF24.github.io/RF24 + * See License information at root directory of this library + * written by tong67 (https://github.com/tong67) + * edited by 2bndy5 (http://github.com/2bndy5) for compatibility with SpenceKonde's ATTinyCore + */ + +/* + * This sketch can determine the best settle time values to use for + * macros, defined as RF24_CSN_SETTLE_HIGH_DELAY and RF24_CSN_SETTLE_LOW_DELAY, + * in RF24::csn(). + * The settle time values used here are 100/20. However, these values depend + * on the actual used RC combiniation and voltage drop by LED. The + * intermediate results are written to TX (PB3, pin 2 -- using Serial). + * + * For schematic details, see introductory comment block in the + * examples/rf24_ATTiny/rf24ping85/rf24ping85.ino sketch. + */ + +#include +#include +#include +#include + + +#if defined (ARDUINO) && !defined (__arm__) +#if defined(__AVR_ATtinyX5__) || defined(__AVR_ATtinyX4__) +#define RF24_TINY +#endif +#endif + +/****************************************************************************/ + +#if defined(RF24_TINY) + +// when Attiny84 or Attiny85 is detected +#define CE_PIN 3 /** "Chip Enable" pin, activates the RX or TX role */ +#define CSN_PIN 3 /** SPI Chip Select Not */ + +#else +// when not running on an ATTiny84 or ATTiny85 +#define CE_PIN 7 /** "Chip Enable" pin, activates the RX or TX role */ +#define CSN_PIN 8 /** SPI Chip Select Not */ + +#endif + +#define MAX_HIGH 100 +#define MAX_LOW 100 +#define MINIMAL 8 + +// Use these adjustable variables to test for best configuration to be used on +// the ATTiny chips. These variables are defined as macros in the library's +// RF24/utility/ATTiny/RF24_arch_config.h file. To change them, simply define +// the corresponding macro(s) before #include in your sketch. +uint8_t csnHighSettle = MAX_HIGH; // defined as RF24_CSN_SETTLE_HIGH_DELAY +uint8_t csnLowSettle = MAX_LOW; // defined as RF24_CSN_SETTLE_LOW_DELAY + +/****************************************************************************/ +void ce(bool level) { + if (CE_PIN != CSN_PIN) digitalWrite(CE_PIN, level); +} + +/****************************************************************************/ +void csn(bool mode) { + if (CE_PIN != CSN_PIN) { + digitalWrite(CSN_PIN, mode); + } else { + // digitalWrite(SCK, mode); + if (mode == HIGH) { + PORTB |= (1 << PINB2); // SCK->CSN HIGH + delayMicroseconds(csnHighSettle); // allow csn to settle + } else { + PORTB &= ~(1 << PINB2); // SCK->CSN LOW + delayMicroseconds(csnLowSettle); // allow csn to settle + } + } +} + +/****************************************************************************/ +uint8_t read_register(uint8_t reg) +{ + csn(LOW); + SPI.transfer(R_REGISTER | reg); + uint8_t result = SPI.transfer(0xff); + csn(HIGH); + return result; +} + +/****************************************************************************/ +void write_register(uint8_t reg, uint8_t value) +{ + csn(LOW); + SPI.transfer(W_REGISTER | reg); + SPI.transfer(value); + csn(HIGH); +} + +/****************************************************************************/ +void setup(void) { + +#ifndef __AVR_ATtinyX313__ + // not enough memory on ATTiny4313 or ATTint2313(a) to use Serial I/O for this sketch + + // start serial port and SPI + Serial.begin(115200); + SPI.begin(); + // configure CE and CSN as output when used + pinMode(CE_PIN, OUTPUT); + if (CSN_PIN != CE_PIN) + pinMode(CSN_PIN, OUTPUT); + + // csn is used in SPI transfers. Set to LOW at start and HIGH after transfer. Set to HIGH to reflect no transfer active + // SPI command are accepted in Power Down state. + // CE pin represent PRX (LOW) or PTX (HIGH) mode apart from register settings. Start in PRX mode. + ce(LOW); + csn(HIGH); + + // nRF24L01 goes from to Power Down state 100ms after Power on Reset ( Vdd > 1.9V) or when PWR_UP is 0 in config register + // Goto Power Down state (Powerup or force) and set in transmit mode + write_register(NRF_CONFIG, read_register(NRF_CONFIG) & ~_BV(PWR_UP) & ~_BV(PRIM_RX)); + delay(100); + + // Goto Standby-I + // Technically we require 4.5ms Tpd2stby+ 14us as a worst case. We'll just call it 5ms for good measure. + // WARNING: Delay is based on P-variant whereby non-P *may* require different timing. + write_register(NRF_CONFIG, read_register(NRF_CONFIG) | _BV(PWR_UP)); + delay(5) ; + + // Goto Standby-II + ce(HIGH); + Serial.print("Scanning for optimal setting time for csn"); + + + /************************** Main program *********************************/ + + uint8_t result; // used to compare read/write results with read/write cmds + bool success = true; + uint8_t bottom_success; + bool bottom_found; + uint8_t value[] = {5, 10}; + uint8_t limit[] = {MAX_HIGH, MAX_LOW}; + uint8_t advice[] = {MAX_HIGH, MAX_LOW}; + + // check max values give correct behavior + for (uint8_t k = 0; k < 2; k++) { + bottom_found = false; + bottom_success = 0; + while (bottom_success < 255) { + csnHighSettle = limit[0]; + csnLowSettle = limit[1]; + // check current values + uint8_t i = 0; + while (i < 255 && success) { + for (uint8_t j = 0; j < 2; j++) { + write_register(EN_AA, value[j]); + result = read_register(EN_AA); + if (value[j] != result) { + success = false; + } + } + i++; + } + // process result of current values + if (!success) { + Serial.print("Settle Not OK. csnHigh="); + Serial.print(limit[0], DEC); + Serial.print(" csnLow="); + Serial.println(limit[1], DEC); + limit[k]++; + bottom_found = true; + bottom_success = 0; + success = true; + } else { + Serial.print("Settle OK. csnHigh="); + Serial.print(limit[0], DEC); + Serial.print(" csnLow="); + Serial.println(limit[1], DEC); + if (!bottom_found) { + limit[k]--; + if (limit[k] == MINIMAL) { + bottom_found = true; + bottom_success = 0; + success = true; + } + } else { + bottom_success++; + } + } + } // while (bottom_success < 255) + Serial.print("Settle value found for "); + if (k == 0) { + Serial.print("csnHigh: "); + } else { + Serial.print("csnLow: "); + } + Serial.println(limit[k], DEC); + advice[k] = limit[k] + (limit[k] / 10); + limit[k] = 100; + } // for (uint8_t k = 0; k < 2; k++) + Serial.print("Advised Settle times are: csnHigh="); + Serial.print(advice[0], DEC); + Serial.print(" csnLow="); + Serial.println(advice[1], DEC); + +#endif // not defined __AVR_ATtinyX313__ +} + + +void loop(void) {} // this program runs only once, thus it resides in setup() diff --git a/examples/scanner/output/core.a b/examples/scanner/output/core.a deleted file mode 100644 index 6ae105d90..000000000 Binary files a/examples/scanner/output/core.a and /dev/null differ diff --git a/examples/scanner/output/scanner.cpp b/examples/scanner/output/scanner.cpp deleted file mode 100644 index 370c5754e..000000000 --- a/examples/scanner/output/scanner.cpp +++ /dev/null @@ -1,128 +0,0 @@ -#include -#line 1 "scanner.pde" - -/* - Copyright (C) 2011 James Coliz, Jr. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -/** - * Channel scanner - * - * Example to detect interference on the various channels available. - * This is a good diagnostic tool to check whether you're picking a - * good channel for your application. - * - * Inspired by cpixip. - * See http://arduino.cc/forum/index.php/topic,54795.0.html - */ - -#include -#include "nRF24L01.h" -#include "RF24.h" -#include "printf.h" - -// -// Hardware configuration -// - -// Set up nRF24L01 radio on SPI bus plus pins 8 & 9 - -RF24 radio(8,9); - -// -// Channel info -// - -const short num_channels = 128; -short values[num_channels]; - -// -// Setup -// - -void setup(void) -{ - // - // Print preamble - // - - Serial.begin(115200); - printf_begin(); - printf("\n\rRF24/examples/scanner/\n\r"); - - // - // Setup and configure rf radio - // - - radio.begin(); - radio.setAutoAck(false); - - // Get into standby mode - radio.startListening(); - radio.stopListening(); - - // Print out header, high then low digit - int i = 0; - while ( i < num_channels ) - { - printf("%x",i>>4); - ++i; - } - printf("\n\r"); - i = 0; - while ( i < num_channels ) - { - printf("%x",i&0xf); - ++i; - } - printf("\n\r"); -} - -// -// Loop -// - -const short num_reps = 100; - -void loop(void) -{ - // Clear measurement values - memset(values,0,num_channels); - - // Scan all channels num_reps times - int rep_counter = num_reps; - while (rep_counter--) - { - int i = num_channels; - while (i--) - { - // Select this channel - radio.setChannel(i); - - // Listen for a little - radio.startListening(); - delayMicroseconds(128); - radio.stopListening(); - - // Did we get a carrier? - if ( radio.testCarrier() ) - ++values[i]; - } - } - - // Print out channel measurements, clamped to a single hex digit - int i = 0; - while ( i < num_channels ) - { - printf("%x",min(0xf,values[i]&0xf)); - ++i; - } - printf("\n\r"); -} - - -// vim:ai:cin:sts=2 sw=2 ft=cpp diff --git a/examples/scanner/output/scanner.elf b/examples/scanner/output/scanner.elf deleted file mode 100755 index 5e0f4b153..000000000 Binary files a/examples/scanner/output/scanner.elf and /dev/null differ diff --git a/examples/scanner/output/scanner.hex b/examples/scanner/output/scanner.hex deleted file mode 100644 index 00a3175eb..000000000 --- a/examples/scanner/output/scanner.hex +++ /dev/null @@ -1,325 +0,0 @@ -:100000000C9463000C948B000C948B000C948B006C -:100010000C948B000C948B000C948B000C948B0034 -:100020000C948B000C948B000C948B000C948B0024 -:100030000C948B000C948B000C948B000C948B0014 -:100040000C948F050C948B000C9423060C948B005D -:100050000C948B000C948B000C948B000C948B00F4 -:100060000C948B000C948B000000000024002700EF -:100070002A0000000000250028002B0000000000DE -:1000800023002600290004040404040404040202DA -:100090000202020203030303030301020408102007 -:1000A0004080010204081020010204081020000012 -:1000B0000007000201000003040600000000000029 -:1000C000000090043B0711241FBECFEFD8E0DEBF35 -:1000D000CDBF11E0A0E0B1E0E6EFF3E102C0059092 -:1000E0000D92AA33B107D9F712E0AAE3B1E001C03B -:1000F0001D92A13FB107E1F710E0C6ECD0E004C0CB -:100100002297FE010E94F509C23CD107C9F70E945F -:100110001C060C94F9090C9400000F931F93CF93C5 -:10012000DF938C01EB01009731F46115710519F42F -:1001300020E030E038C081E090E06EE070E00E94A6 -:10014000CB02FC019C01009771F180E8838320972A -:1001500071F0D387C28781E883838091E702909111 -:10016000E802892B21F4F093E802E093E7020115FD -:100170001105C9F011870087838182608383809194 -:10018000E9029091EA02892B71F4F093EA02E0937C -:10019000E9028091EB029091EC02892B21F4F0931B -:1001A000EC02E093EB02C901DF91CF911F910F9117 -:1001B0000895A0E0B0E0EFEDF0E00C94CC09FE0172 -:1001C0003596619171918091E9029091EA02AF01B7 -:1001D0000E94EE002096E2E00C94E809ABE0B0E06B -:1001E000E4EFF0E00C94BC093C012B015A01FC0146 -:1001F00017821682838181FD03C06FEF7FEFC6C136 -:100200009AE0892E1E010894211C311CF3012381E0 -:10021000F20123FD859123FF81912F01882309F4A9 -:10022000B2C1853239F423FD859123FF81912F01DD -:10023000853229F490E0B3010E940604E7CF982F9D -:10024000FF24EE249924FFE1FF15D0F09B3269F0E2 -:100250009C3228F4903259F0933291F40EC09D32C2 -:1002600049F0903369F441E024C052E0F52A84E07B -:10027000F82A28C098E0F92A25C0E0E1FE2A22C029 -:10028000F7FC29C0892F80538A3070F4F6FE05C030 -:10029000989C902C1124980E15C0E89CE02C1124F9 -:1002A000E80EF0E2FF2A0EC09E3229F4F6FC6BC184 -:1002B00040E4F42A07C09C3619F450E8F52A02C03D -:1002C000983649F4F20123FD959123FF91912F0176 -:1002D000992309F0B8CF892F8554833018F08052C4 -:1002E000833038F444E050E0A40EB51E5FE3598338 -:1002F0000FC0933631F0933779F0933509F056C03B -:1003000020C0F5018081898342E050E0A40EB51E33 -:10031000610101E010E012C0F501C080D180F6FC5F -:1003200003C06FEF7FEF02C0692D70E042E050E044 -:10033000A40EB51EC6010E94FB038C015FE7F522E7 -:1003400014C0F501C080D180F6FC03C06FEF7FEFD1 -:1003500002C0692D70E042E050E0A40EB51EC60157 -:100360000E94E9038C0150E8F52AF3FE07C01AC089 -:1003700080E290E0B3010E940604EA948E2D90E0A2 -:1003800008171907A8F30EC0F601F7FC8591F7FED0 -:1003900081916F0190E0B3010E940604E110EA949C -:1003A000015010400115110579F7EAC0943611F09B -:1003B000993669F5F7FE08C0F50120813181428147 -:1003C000538184E090E00AC0F501808191819C0115 -:1003D000442737FD4095542F82E090E0A80EB91EC7 -:1003E0009FE6F92257FF09C0509540953095219519 -:1003F0003F4F4F4F5F4FE0E8FE2ACA01B901A1010C -:100400002AE030E00E943204D82ED21840C095373E -:1004100029F41F2D1F7E2AE030E01DC01F2D197FFB -:100420009F3661F0903720F4983509F0ACC00FC0CA -:10043000903739F0983709F0A6C004C028E030E0C2 -:100440000AC0106114FD146020E130E004C014FD06 -:10045000166020E132E017FF08C0F501608171816C -:100460008281938144E050E008C0F5018081918150 -:10047000BC0180E090E042E050E0A40EB51EA10176 -:100480000E943204D82ED2188FE7F82EF122F6FE01 -:100490000BC05EEFF522D91438F4F4FE07C0F2FC6D -:1004A00005C08FEEF82202C01D2D01C0192DF4FEEB -:1004B0000DC0FE01ED0DF11D8081803319F499EE20 -:1004C000F92208C01F5FF2FE05C003C08F2D867899 -:1004D00009F01F5F0F2DF3FC14C0F0FE0FC01E15B6 -:1004E00010F09D2C0BC09D2C9E0C911A1E2D06C049 -:1004F00080E290E0B3010E9406041F5F1E15C0F366 -:1005000004C01E1510F4E11A01C0EE2404FF0FC050 -:1005100080E390E0B3010E94060402FF1DC001FDCC -:1005200003C088E790E00EC088E590E00BC0802F04 -:10053000867891F001FF02C08BE201C080E2F7FCF7 -:100540008DE290E0B3010E94060406C080E390E0D3 -:10055000B3010E9406049A94D914C0F3DA94F1010D -:10056000ED0DF11D808190E0B3010E940604DD20B5 -:10057000A9F706C080E290E0B3010E940604EA9465 -:10058000EE20C1F743CEF30166817781CB012B9634 -:10059000E2E10C94D8090F931F93CF93DF93689FE8 -:1005A0008001699F100D789F100D1124C8010E94D1 -:1005B000E702EC01009729F060E070E0A8010E94DA -:1005C000F403CE01DF91CF911F910F910895CF9346 -:1005D000DF93BC018230910510F462E070E0A091DD -:1005E000EF02B091F002ED01E0E0F0E040E050E019 -:1005F00021C0888199818617970769F48A819B8138 -:10060000309719F09383828304C09093F002809313 -:10061000EF02FE0134C06817790738F4411551051F -:1006200019F08417950708F4AC01FE018A819B81BB -:100630009C01E9012097E9F641155105A9F1CA018C -:10064000861B970B049708F4BA01E0E0F0E02AC09B -:100650008D919C91119784179507F9F4641775078C -:1006600081F412968D919C911397309719F0938392 -:10067000828304C09093F0028093EF02FD013296D2 -:100680004CC0CA01861B970BFD01E80FF91F61934F -:10069000719302978D939C9340C0FD018281938159 -:1006A0009C01D9011097A1F68091ED029091EE0284 -:1006B000892B41F480912301909124019093EE02C3 -:1006C0008093ED024091250150912601411551057D -:1006D00041F44DB75EB78091210190912201481BF2 -:1006E000590B2091ED023091EE02CA01821B930B4F -:1006F0008617970780F0AB014E5F5F4F8417950711 -:1007000050F0420F531F5093EE024093ED02F90157 -:100710006193719302C0E0E0F0E0CF01DF91CF91EF -:100720000895CF93DF93009709F450C0EC0122970E -:100730001B821A82A091EF02B091F002109709F18A -:1007400040E050E0AC17BD0708F1BB83AA83FE016F -:1007500021913191E20FF31FAE17BF0779F48D910C -:100760009C911197280F391F2E5F3F4F39832883A3 -:1007700012968D919C9113979B838A834115510505 -:1007800071F4D093F002C093EF0220C012968D91C5 -:100790009C911397AD01009711F0DC01D3CFFA01C2 -:1007A000D383C28321913191E20FF31FCE17DF076C -:1007B00069F488819981280F391F2E5F3F4FFA0114 -:1007C000318320838A819B8193838283DF91CF91C0 -:1007D0000895FC010590615070400110D8F7809594 -:1007E00090958E0F9F1F0895DC0101C06D934150BD -:1007F0005040E0F70895FC016150704001900110F5 -:10080000D8F7809590958E0F9F1F08950F931F9393 -:10081000CF93DF938C01EB018B8181FF1BC082FFA3 -:100820000DC02E813F818C819D812817390764F48A -:10083000E881F9810193F983E88306C0E885F985A9 -:10084000802F0995892B31F48E819F8101969F839A -:100850008E8302C00FEF1FEFC801DF91CF911F9170 -:100860000F910895FA01AA27283051F1203181F122 -:10087000E8946F936E7F6E5F7F4F8F4F9F4FAF4FA8 -:10088000B1E03ED0B4E03CD0670F781F891F9A1FBB -:10089000A11D680F791F8A1F911DA11D6A0F711D6F -:1008A000811D911DA11D20D009F468943F912AE07B -:1008B000269F11243019305D3193DEF6CF01089563 -:1008C000462F4770405D4193B3E00FD0C9F7F6CF94 -:1008D000462F4F70405D4A3318F0495D31FD40525C -:1008E000419302D0A9F7EACFB4E0A69597958795F2 -:1008F00077956795BA95C9F70097610571050895D1 -:100900009B01AC010A2E069457954795379527957C -:10091000BA95C9F7620F731F841F951FA01D089514 -:100920008AE391E068E049E00E9475070895FF922C -:100930000F931F93CF93DF9380E8E7E4F1E0DF01AB -:100940001D928A95E9F704E610E021C08AE391E060 -:100950006F2D0E94F2078AE391E00E94840880E8EC -:1009600090E00E94D7058AE391E00E947C078AE329 -:1009700091E00E944608882329F088819981019698 -:10098000998388832297FA94BFEFFB16F9F60150FA -:100990001040EFEF0F3F1E0729F0C5E4D2E08FE7CC -:1009A000F82ED4CFC7E4D1E000E011E000D000D0B1 -:1009B000ADB7BEB712961C930E931197899199917A -:1009C0008F70907014969C938E9313970E94D90009 -:1009D0000F900F900F900F90B2E0C734DB0731F704 -:1009E00000D083E091E0EDB7FEB7928381830E944F -:1009F000D9000F900F90DF91CF911F910F91FF9031 -:100A0000089580E895E060E070E00E948D00089510 -:100A10000F931F93CF93DF9384ED92E040E051EE6C -:100A200060E070E00E9454060E94010500D086E05C -:100A300091E0EDB7FEB7928381830E94D9000F90B9 -:100A40000F908AE391E00E944B088AE391E060E016 -:100A50000E94E8078AE391E00E9484088AE391E01B -:100A60000E947C07C0E0D0E000E011E000D000D0A0 -:100A7000EDB7FEB712830183CE0124E095958795EB -:100A80002A95E1F7948383830E94D90021960F90E1 -:100A90000F900F900F90C038D10541F700D083E040 -:100AA00091E0EDB7FEB7928381830E94D900C0E048 -:100AB000D0E00F900F9000D000D0EDB7FEB70183CB -:100AC0001283CE018F709070948383830E94D9002B -:100AD00021960F900F900F900F90C038D10559F7C5 -:100AE00000D083E091E0EDB7FEB7928381830E944E -:100AF000D9000F900F90DF91CF911F910F91089522 -:100B00000F931F93082F84ED92E0602F0E94280717 -:100B1000112707FD1095C8011F910F9108951F928D -:100B20000F920FB60F9211242F933F938F939F93A1 -:100B3000AF93BF9380914B0290914C02A0914D02D4 -:100B4000B0914E0230914F020196A11DB11D232F8D -:100B50002D5F2D3720F02D570196A11DB11D20933B -:100B60004F0280934B0290934C02A0934D02B0939E -:100B70004E028091470290914802A0914902B091A3 -:100B80004A020196A11DB11D80934702909348022D -:100B9000A0934902B0934A02BF91AF919F918F9168 -:100BA0003F912F910F900FBE0F901F9018950197B6 -:100BB00039F0880F991F880F991F02970197F1F755 -:100BC0000895789484B5826084BD84B5816084BDC5 -:100BD00085B5826085BD85B5816085BDEEE6F0E0B6 -:100BE000808181608083E1E8F0E010828081826012 -:100BF0008083808181608083E0E8F0E08081816093 -:100C00008083E1EBF0E0808184608083E0EBF0E0C2 -:100C1000808181608083EAE7F0E080818460808366 -:100C20008081826080838081816080838081806810 -:100C300080831092C10008950E94E1050E9408057A -:100C40000E949704FDCF1F920F920FB60F921124AE -:100C50002F933F934F938F939F93EF93FF934091E5 -:100C6000C600E091D002F091D10231969F012F771A -:100C7000307031978091D2029091D30228173907B2 -:100C800039F0E05BFD4F40833093D1022093D002D6 -:100C9000FF91EF919F918F914F913F912F910F90E5 -:100CA0000FBE0F901F901895AF92BF92DF92EF92F8 -:100CB000FF920F931F93CF93DF93EC017A018B0187 -:100CC000DD24403081EE580780E0680780E0780737 -:100CD00011F0DD24D39491E0A92EB12CE885F9859B -:100CE000DD2069F0C5010A8802C0880F991F0A94A7 -:100CF000E2F7808360E079E08DE390E005C0108248 -:100D000060E874E88EE190E0A80197010E949A09DA -:100D10002150304040405040569547953795279593 -:100D200080E12030380720F0DD2011F0DD24D6CF1F -:100D3000EC81FD813083EE81FF812083EA85FB8594 -:100D4000208141E050E0CA010E8402C0880F991F43 -:100D50000A94E2F7282B2083EA85FB852081CA01CB -:100D60000F8402C0880F991F0A94E2F7282B208372 -:100D7000EA85FB858081088802C0440F551F0A94CC -:100D8000E2F7842B8083DF91CF911F910F91FF9029 -:100D9000EF90DF90BF90AF900895DC011296ED9137 -:100DA000FC911397E058FF4F2191319180819181FF -:100DB000281B390B2F773070C9010895DC0112967A -:100DC000ED91FC911397EE57FF4F20813181929165 -:100DD0008291E058F0408217930719F42FEF3FEF0C -:100DE00005C0E20FF31F8081282F30E0C90108956C -:100DF000DC011296ED91FC911397DF01AE57BF4FC6 -:100E00002D913C911197E058FF4F80819181E058DE -:100E1000F0408217930719F42FEF3FEF0BC0E20F5A -:100E2000F31F80812F5F3F4F2F7730702D933C93BE -:100E3000282F30E0C9010895DC011296ED91FC9154 -:100E40001397EE57FF4F808191819293829308957B -:100E5000FC01A085B18521898C9190E0022E02C011 -:100E6000959587950A94E2F780FFF6CF0484F5857F -:100E7000E02D608308958BE291E09093D5028093FA -:100E8000D40280E592E09093D7028093D60285EC5D -:100E900090E09093D9028093D80284EC90E09093F4 -:100EA000DB028093DA0280EC90E09093DD02809385 -:100EB000DC0281EC90E09093DF028093DE0286EC0E -:100EC00090E09093E1028093E00284E08093E2025C -:100ED00083E08093E30287E08093E40285E08093DF -:100EE000E50281E08093E6020895FC01608341837E -:100EF00080E2828313820895FC01808160E00E9479 -:100F0000CD080895FF920F931F938C01F62E80E079 -:100F10000E94650985E00E946A09F80181816F2DB0 -:100F20000E94CD081F910F91FF9008951F93CF93BA -:100F3000DF93EC0160E070E00E94820781EE8EBDDD -:100F40000DB407FEFDCF1EB5CE0161E070E00E943A -:100F50008207812FDF91CF911F9108951F93CF9327 -:100F6000DF93EC0160E070E00E94820782EE8EBDAC -:100F70000DB407FEFDCF1EB5CE0161E070E00E940A -:100F80008207812FDF91CF911F9108950F931F93B7 -:100F9000CF93DF93EC01162F042F60E070E00E94E6 -:100FA00082071F7110621EBD0DB407FEFDCF1EB576 -:100FB0000EBD0DB407FEFDCF8EB5CE0161E070E031 -:100FC0000E948207812FDF91CF911F910F91089589 -:100FD000662319F061E04FE302C061E040E00E9447 -:100FE000C6070895462F603808F04FE765E00E9475 -:100FF000C6070895EF92FF920F931F93CF93DF934D -:101000007C01162FEA01022F60E070E00E94820747 -:101010001F7110621EBD0DB407FEFDCF1EB508C0C6 -:1010200088818EBD0DB407FEFDCF21968EB501508F -:101030000023B1F7C70161E070E00E948207812FB1 -:10104000DF91CF911F910F91FF90EF9008951F9323 -:10105000CF93DF93EC01162F60E070E00E948207CF -:101060001F711EBD0DB407FEFDCF8EB58FEF8EBD77 -:101070000DB407FEFDCF1EB5CE0161E070E00E9409 -:101080008207812FDF91CF911F91089569E00E941F -:101090002708817008950F931F938C01FC018081B4 -:1010A00061E00E94A708F801818161E00E94A70821 -:1010B000F801808160E00E94CD08C80161E070E025 -:1010C0000E9482070E947B0981E00E945C0980E007 -:1010D0000E94650985E00E946A09C80164E04FEF3B -:1010E0000E94C607C80167E040E70E94C607C80122 -:1010F0000E94AE07C8010E949607C80161E00E94E5 -:10110000F2071F910F9108950F931F938C0160E0D8 -:101110004BE00E94C607C80167E040E70E94C6078F -:10112000A8014B5F5F4FC8016AE025E00E94FA0703 -:10113000C8010E94AE07F801808161E00E94CD08DD -:1011400082E890E00E94D7051F910F910895482FE3 -:1011500050E0CA0186569F4FFC0124914A575F4FC9 -:10116000FA0184918823C1F0E82FF0E0EE0FFF1F11 -:10117000E859FF4FA591B491662341F49FB7F894C5 -:101180008C91209582238C939FBF08959FB7F894EC -:101190008C91822B8C939FBF0895482F50E0CA01F9 -:1011A00082559F4FFC012491CA0186569F4FFC0136 -:1011B00034914A575F4FFA019491992309F444C03E -:1011C000222351F1233071F0243028F42130A1F092 -:1011D000223011F514C02630B1F02730C1F0243090 -:1011E000D9F404C0809180008F7703C08091800083 -:1011F0008F7D8093800010C084B58F7702C084B546 -:101200008F7D84BD09C08091B0008F7703C080912D -:10121000B0008F7D8093B000E92FF0E0EE0FFF1F4C -:10122000EE58FF4FA591B491662341F49FB7F8940F -:101230008C91309583238C939FBF08959FB7F8942A -:101240008C91832B8C939FBF08950F931F93CF9303 -:10125000DF938C01EB0109C02196D801ED91FC913F -:101260000190F081E02DC801099568816623A1F7FE -:10127000DF91CF911F910F910895EF92FF920F93FD -:101280001F93CF93DF938C017B01EA010CC0D70140 -:101290006D917D01D801ED91FC910190F081E02DDF -:1012A000C80109952197209791F7DF91CF911F9160 -:1012B0000F91FF90EF900895882319F48CB5806208 -:1012C00002C08CB58F7D8CBD08959CB5937F982B03 -:1012D0009CBD08952CB5382F33702C7F322B3CBD2C -:1012E0002DB590E0959587959595879581702E7F82 -:1012F000822B8DBD08958DE061E00E94A7088BE0F0 -:1013000061E00E94A7088AE061E00E94A7088DE0E2 -:1013100060E00E94CD088BE060E00E94CD088AE08A -:1013200061E00E94CD088CB580618CBD8CB5806475 -:101330008CBD0895A1E21A2EAA1BBB1BFD010DC096 -:10134000AA1FBB1FEE1FFF1FA217B307E407F50775 -:1013500020F0A21BB30BE40BF50B661F771F881F51 -:10136000991F1A9469F760957095809590959B01E7 -:10137000AC01BD01CF0108952F923F924F925F9231 -:101380006F927F928F929F92AF92BF92CF92DF9295 -:10139000EF92FF920F931F93CF93DF93CDB7DEB7FA -:1013A000CA1BDB0B0FB6F894DEBF0FBECDBF09948E -:1013B0002A88398848885F846E847D848C849B84E5 -:1013C000AA84B984C884DF80EE80FD800C811B81F3 -:1013D000AA81B981CE0FD11D0FB6F894DEBF0FBE22 -:1013E000CDBFED010895EE0FFF1F0590F491E02DA4 -:0613F0000994F894FFCF00 -:1013F6002578000A0D000A0D524632342F657861B1 -:101406006D706C65732F7363616E6E65722F0A0D56 -:10141600002000F102000000000000280725093D19 -:0A14260009CD06F806DE061C0700DB -:00000001FF diff --git a/examples/starping/starping.pde b/examples/starping/starping.pde deleted file mode 100644 index c1a25729e..000000000 --- a/examples/starping/starping.pde +++ /dev/null @@ -1,293 +0,0 @@ -/* - Copyright (C) 2011 J. Coliz - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -/** - * Example RF Radio Ping Star Group - * - * This sketch is a more complex example of using the RF24 library for Arduino. - * Deploy this on up to six nodes. Set one as the 'pong receiver' by tying the - * role_pin low, and the others will be 'ping transmit' units. The ping units - * unit will send out the value of millis() once a second. The pong unit will - * respond back with a copy of the value. Each ping unit can get that response - * back, and determine how long the whole cycle took. - * - * This example requires a bit more complexity to determine which unit is which. - * The pong receiver is identified by having its role_pin tied to ground. - * The ping senders are further differentiated by a byte in eeprom. - */ - -#include -#include -#include "nRF24L01.h" -#include "RF24.h" -#include "printf.h" - -// -// Hardware configuration -// - -// Set up nRF24L01 radio on SPI bus plus pins 9 & 10 - -RF24 radio(9,10); - -// sets the role of this unit in hardware. Connect to GND to be the 'pong' receiver -// Leave open to be the 'pong' receiver. -const int role_pin = 7; - -// -// Topology -// - -// Radio pipe addresses for the nodes to communicate. Only ping nodes need -// dedicated pipes in this topology. Each ping node has a talking pipe -// that it will ping into, and a listening pipe that it will listen for -// the pong. The pong node listens on all the ping node talking pipes -// and sends the pong back on the sending node's specific listening pipe. - -const uint64_t talking_pipes[5] = { 0xF0F0F0F0D2LL, 0xF0F0F0F0C3LL, 0xF0F0F0F0B4LL, 0xF0F0F0F0A5LL, 0xF0F0F0F096LL }; -const uint64_t listening_pipes[5] = { 0x3A3A3A3AD2LL, 0x3A3A3A3AC3LL, 0x3A3A3A3AB4LL, 0x3A3A3A3AA5LL, 0x3A3A3A3A96LL }; - -// -// Role management -// -// Set up role. This sketch uses the same software for all the nodes -// in this system. Doing so greatly simplifies testing. The hardware itself specifies -// which node it is. -// -// This is done through the role_pin -// - -// The various roles supported by this sketch -typedef enum { role_invalid = 0, role_ping_out, role_pong_back } role_e; - -// The debug-friendly names of those roles -const char* role_friendly_name[] = { "invalid", "Ping out", "Pong back"}; - -// The role of the current running sketch -role_e role; - -// -// Address management -// - -// Where in EEPROM is the address stored? -const uint8_t address_at_eeprom_location = 0; - -// What is our address (SRAM cache of the address from EEPROM) -// Note that zero is an INVALID address. The pong back unit takes address -// 1, and the rest are 2-6 -uint8_t node_address; - -void setup(void) -{ - // - // Role - // - - // set up the role pin - pinMode(role_pin, INPUT); - digitalWrite(role_pin,HIGH); - delay(20); // Just to get a solid reading on the role pin - - // read the address pin, establish our role - if ( digitalRead(role_pin) ) - role = role_ping_out; - else - role = role_pong_back; - - // - // Address - // - - if ( role == role_pong_back ) - node_address = 1; - else - { - // Read the address from EEPROM - uint8_t reading = EEPROM.read(address_at_eeprom_location); - - // If it is in a valid range for node addresses, it is our - // address. - if ( reading >= 2 && reading <= 6 ) - node_address = reading; - - // Otherwise, it is invalid, so set our address AND ROLE to 'invalid' - else - { - node_address = 0; - role = role_invalid; - } - } - - // - // Print preamble - // - - Serial.begin(115200); - printf_begin(); - printf("\n\rRF24/examples/starping/\n\r"); - printf("ROLE: %s\n\r",role_friendly_name[role]); - printf("ADDRESS: %i\n\r",node_address); - - // - // Setup and configure rf radio - // - - radio.begin(); - - // - // Open pipes to other nodes for communication - // - - // The pong node listens on all the ping node talking pipes - // and sends the pong back on the sending node's specific listening pipe. - if ( role == role_pong_back ) - { - radio.openReadingPipe(1,talking_pipes[0]); - radio.openReadingPipe(2,talking_pipes[1]); - radio.openReadingPipe(3,talking_pipes[2]); - radio.openReadingPipe(4,talking_pipes[3]); - radio.openReadingPipe(5,talking_pipes[4]); - } - - // Each ping node has a talking pipe that it will ping into, and a listening - // pipe that it will listen for the pong. - if ( role == role_ping_out ) - { - // Write on our talking pipe - radio.openWritingPipe(talking_pipes[node_address-2]); - // Listen on our listening pipe - radio.openReadingPipe(1,listening_pipes[node_address-2]); - } - - // - // Start listening - // - - radio.startListening(); - - // - // Dump the configuration of the rf unit for debugging - // - - radio.printDetails(); - - // - // Prompt the user to assign a node address if we don't have one - // - - if ( role == role_invalid ) - { - printf("\n\r*** NO NODE ADDRESS ASSIGNED *** Send 1 through 6 to assign an address\n\r"); - } -} - -void loop(void) -{ - // - // Ping out role. Repeatedly send the current time - // - - if (role == role_ping_out) - { - // First, stop listening so we can talk. - radio.stopListening(); - - // Take the time, and send it. This will block until complete - unsigned long time = millis(); - printf("Now sending %lu...",time); - radio.write( &time, sizeof(unsigned long) ); - - // Now, continue listening - radio.startListening(); - - // Wait here until we get a response, or timeout (250ms) - unsigned long started_waiting_at = millis(); - bool timeout = false; - while ( ! radio.available() && ! timeout ) - if (millis() - started_waiting_at > 250 ) - timeout = true; - - // Describe the results - if ( timeout ) - { - printf("Failed, response timed out.\n\r"); - } - else - { - // Grab the response, compare, and send to debugging spew - unsigned long got_time; - radio.read( &got_time, sizeof(unsigned long) ); - - // Spew it - printf("Got response %lu, round-trip delay: %lu\n\r",got_time,millis()-got_time); - } - - // Try again 1s later - delay(1000); - } - - // - // Pong back role. Receive each packet, dump it out, and send it back - // - - if ( role == role_pong_back ) - { - // if there is data ready - uint8_t pipe_num; - if ( radio.available(&pipe_num) ) - { - // Dump the payloads until we've gotten everything - unsigned long got_time; - bool done = false; - while (!done) - { - // Fetch the payload, and see if this was the last one. - done = radio.read( &got_time, sizeof(unsigned long) ); - - // Spew it - printf("Got payload %lu from node %i...",got_time,pipe_num+1); - } - - // First, stop listening so we can talk - radio.stopListening(); - - // Open the correct pipe for writing - radio.openWritingPipe(listening_pipes[pipe_num-1]); - - // Retain the low 2 bytes to identify the pipe for the spew - uint16_t pipe_id = listening_pipes[pipe_num-1] & 0xffff; - - // Send the final one back. - radio.write( &got_time, sizeof(unsigned long) ); - printf("Sent response to %04x.\n\r",pipe_id); - - // Now, resume listening so we catch the next packets. - radio.startListening(); - } - } - - // - // Listen for serial input, which is how we set the address - // - if (Serial.available()) - { - // If the character on serial input is in a valid range... - char c = Serial.read(); - if ( c >= '1' && c <= '6' ) - { - // It is our address - EEPROM.write(address_at_eeprom_location,c-'0'); - - // And we are done right now (no easy way to soft reset) - printf("\n\rManually reset address to: %c\n\rPress RESET to continue!",c); - while(1) ; - } - } -} -// vim:ai:ci sts=2 sw=2 ft=cpp diff --git a/examples_linux/Makefile b/examples_linux/Makefile index f037131b5..f035127f1 100644 --- a/examples_linux/Makefile +++ b/examples_linux/Makefile @@ -18,6 +18,6 @@ endif include ../Makefile.inc # define all programs -PROGRAMS = gettingstarted gettingstarted_call_response transfer pingpair_dyn +PROGRAMS = gettingstarted acknowledgementPayloads manualAcknowledgements streamingData multiceiverDemo interruptConfigure include Makefile.examples diff --git a/examples_linux/acknowledgementPayloads.cpp b/examples_linux/acknowledgementPayloads.cpp new file mode 100644 index 000000000..98b262888 --- /dev/null +++ b/examples_linux/acknowledgementPayloads.cpp @@ -0,0 +1,231 @@ +/* + * See documentation at https://nRF24.github.io/RF24 + * See License information at root directory of this library + * Author: Brendan Doherty (2bndy5) + */ + +/** + * A simple example of sending data from 1 nRF24L01 transceiver to another + * with Acknowledgement (ACK) payloads attached to ACK packets. + * + * This example was written to be used on 2 devices acting as "nodes". + * Use `ctrl+c` to quit at any time. + */ +#include // time() +#include // strcmp() +#include // cin, cout, endl +#include // string, getline() +#include // CLOCK_MONOTONIC_RAW, timespec, clock_gettime() +#include // RF24, RF24_PA_LOW, delay() + +using namespace std; + +/****************** Linux ***********************/ +// Radio CE Pin, CSN Pin, SPI Speed +// CE Pin uses GPIO number with BCM and SPIDEV drivers, other platforms use their own pin numbering +// CS Pin addresses the SPI bus number at /dev/spidev. +// ie: RF24 radio(, *10+); spidev1.0 is 10, spidev1.1 is 11 etc.. + +// Generic: +RF24 radio(22, 0); +/****************** Linux (BBB,x86,etc) ***********************/ +// See http://nRF24.github.io/RF24/pages.html for more information on usage +// See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA +// See https://www.kernel.org/doc/Documentation/spi/spidev for more information on SPIDEV + +// For this example, we'll be using a payload containing +// a string & an integer number that will be incremented +// on every successful transmission. +// Make a data structure to store the entire payload of different datatypes +struct PayloadStruct { + char message[7]; // only using 6 characters for TX & ACK payloads + uint8_t counter; +}; +PayloadStruct payload; + +void setRole(); // prototype to set the node's role +void master(); // prototype of the TX node's behavior +void slave(); // prototype of the RX node's behavior + +// custom defined timer for evaluating transmission time in microseconds +struct timespec startTimer, endTimer; +uint32_t getMicros(); // prototype to get ellapsed time in microseconds + + +int main(int argc, char** argv) { + // perform hardware check + if (!radio.begin()) { + cout << "radio hardware is not responding!!" << endl; + return 0; // quit now + } + + // Let these addresses be used for the pair + uint8_t address[2][6] = {"1Node", "2Node"}; + // It is very helpful to think of an address as a path instead of as + // an identifying device destination + + // to use different addresses on a pair of radios, we need a variable to + // uniquely identify which address this radio will use to transmit + bool radioNumber = 1; // 0 uses address[0] to transmit, 1 uses address[1] to transmit + + // print example's name + cout << argv[0] << endl; + + // Set the radioNumber via the terminal on startup + cout << "Which radio is this? Enter '0' or '1'. Defaults to '0' "; + string input; + getline(cin, input); + radioNumber = input.length() > 0 && (uint8_t)input[0] == 49; + + // to use ACK payloads, we need to enable dynamic payload lengths + radio.enableDynamicPayloads(); // ACK payloads are dynamically sized + + // Acknowledgement packets have no payloads by default. We need to enable + // this feature for all nodes (TX & RX) to use ACK payloads. + radio.enableAckPayload(); + + // Set the PA Level low to try preventing power supply related problems + // because these examples are likely run with nodes in close proximity to + // each other. + radio.setPALevel(RF24_PA_LOW); // RF24_PA_MAX is default. + + // set the TX address of the RX node into the TX pipe + radio.openWritingPipe(address[radioNumber]); // always uses pipe 0 + + // set the RX address of the TX node into a RX pipe + radio.openReadingPipe(1, address[!radioNumber]); // using pipe 1 + + // For debugging info + // radio.printDetails(); // (smaller) function that prints raw register values + // radio.printPrettyDetails(); // (larger) function that prints human readable data + + // ready to execute program now + setRole(); // calls master() or slave() based on user input + return 0; +} + + +/** + * set this node's role from stdin stream. + * this only considers the first char as input. + */ +void setRole() { + string input = ""; + while (!input.length()) { + cout << "*** PRESS 'T' to begin transmitting to the other node\n"; + cout << "*** PRESS 'R' to begin receiving from the other node\n"; + cout << "*** PRESS 'Q' to exit" << endl; + getline(cin, input); + if (input.length() >= 1) { + if (input[0] == 'T' || input[0] == 't') + master(); + else if (input[0] == 'R' || input[0] == 'r') + slave(); + else if (input[0] == 'Q' || input[0] == 'q') + break; + else + cout << input[0] << " is an invalid input. Please try again." << endl; + } + input = ""; // stay in the while loop + } // while +} // setRole() + + +/** + * make this node act as the transmitter + */ +void master() { + memcpy(payload.message, "Hello ", 6); // set the payload message + radio.stopListening(); // put radio in TX mode + + unsigned int failures = 0; // keep track of failures + while (failures < 6) { + clock_gettime(CLOCK_MONOTONIC_RAW, &startTimer); // start the timer + bool report = radio.write(&payload, sizeof(payload)); // transmit & save the report + uint32_t timerEllapsed = getMicros(); // end the timer + + if (report) { + // payload was delivered + cout << "Transmission successful! Time to transmit = "; + cout << timerEllapsed; // print the timer result + cout << " us. Sent: "; + cout << payload.message; // print outgoing message + cout << (unsigned int)payload.counter; // print outgoing counter counter + + uint8_t pipe; + if (radio.available(&pipe)) { + PayloadStruct received; + radio.read(&received, sizeof(received)); // get incoming ACK payload + cout << " Received "; + cout << radio.getDynamicPayloadSize(); // print incoming payload size + cout << " bytes on pipe " << (unsigned int)pipe; // print pipe that received it + cout << ": " << received.message; // print incoming message + cout << (unsigned int)received.counter << endl; // print incoming counter + payload.counter = received.counter + 1; // save incoming counter & increment for next outgoing + } // if got an ACK payload + else { + cout << " Received an empty ACK packet." << endl; // ACK had no payload + } + } // if delivered + else { + cout << "Transmission failed or timed out" << endl; // payload was not delivered + failures++; // increment failures + } + + // to make this example readable in the terminal + delay(1000); // slow transmissions down by 1 second + } // while + cout << failures << " failures detected. Leaving TX role." << endl; +} // master + + +/** + * make this node act as the receiver + */ +void slave() { + memcpy(payload.message, "World ", 6); // set the payload message + + // load the payload for the first received transmission on pipe 0 + radio.writeAckPayload(1, &payload, sizeof(payload)); + + radio.startListening(); // put radio in RX mode + time_t startTimer = time(nullptr); // start a timer + while (time(nullptr) - startTimer < 6) { // use 6 second timeout + uint8_t pipe; + if (radio.available(&pipe)) { // is there a payload? get the pipe number that recieved it + uint8_t bytes = radio.getDynamicPayloadSize(); // get the size of the payload + PayloadStruct received; + radio.read(&received, sizeof(received)); // fetch payload from RX FIFO + cout << "Received " << (unsigned int)bytes; // print the size of the payload + cout << " bytes on pipe " << (unsigned int)pipe; // print the pipe number + cout << ": " << received.message; + cout << (unsigned int)received.counter; // print received payload + cout << " Sent: "; + cout << payload.message; + cout << (unsigned int)payload.counter << endl; // print ACK payload sent + startTimer = time(nullptr); // reset timer + + // save incoming counter & increment for next outgoing + payload.counter = received.counter + 1; + // load the payload for the first received transmission on pipe 0 + radio.writeAckPayload(1, &payload, sizeof(payload)); + } // if received something + } // while + cout << "Nothing received in 6 seconds. Leaving RX role." << endl; + radio.stopListening(); // recommended idle behavior is TX mode +} // slave + + +/** + * Calculate the ellapsed time in microseconds + */ +uint32_t getMicros() { + // this function assumes that the timer was started using + // `clock_gettime(CLOCK_MONOTONIC_RAW, &startTimer);` + + clock_gettime(CLOCK_MONOTONIC_RAW, &endTimer); + uint32_t seconds = endTimer.tv_sec - startTimer.tv_sec; + uint32_t useconds = (endTimer.tv_nsec - startTimer.tv_nsec) / 1000; + + return ((seconds) * 1000 + useconds) + 0.5; +} \ No newline at end of file diff --git a/examples_linux/acknowledgement_payloads.py b/examples_linux/acknowledgement_payloads.py new file mode 100644 index 000000000..2e75b0671 --- /dev/null +++ b/examples_linux/acknowledgement_payloads.py @@ -0,0 +1,238 @@ +""" +A simple example of sending data from 1 nRF24L01 transceiver to another +with Acknowledgement (ACK) payloads attached to ACK packets. + +This example was written to be used on 2 devices acting as 'nodes'. +""" +import sys +import argparse +import time +from RF24 import RF24, RF24_PA_LOW + + +parser = argparse.ArgumentParser( + description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter +) +parser.add_argument( + "-n", + "--node", + type=int, + choices=range(2), + help="the identifying radio number (or node ID number)" +) +parser.add_argument( + "-r", + "--role", + type=int, + choices=range(2), + help="'1' specifies the TX role. '0' specifies the RX role." +) + +########### USER CONFIGURATION ########### +# See https://github.com/TMRh20/RF24/blob/master/pyRF24/readme.md +# Radio CE Pin, CSN Pin, SPI Speed +# CE Pin uses GPIO number with BCM and SPIDEV drivers, other platforms use +# their own pin numbering +# CS Pin addresses the SPI bus number at /dev/spidev. +# ie: RF24 radio(, *10+); spidev1.0 is 10, spidev1.1 is 11 etc.. + +# Generic: +radio = RF24(22, 0) +################## Linux (BBB,x86,etc) ######################### +# See http://nRF24.github.io/RF24/pages.html for more information on usage +# See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA +# See https://www.kernel.org/doc/Documentation/spi/spidev for more +# information on SPIDEV + +# using the python keyword global is bad practice. Instead we'll use a +# 1 item list to store our integer number for the payloads' counter +counter = [0] + +def master(): + """Transmits a message and an incrementing integer every second.""" + radio.stopListening() # put radio in TX mode + failures = 0 + while failures < 6: + # construct a payload to send + buffer = b"Hello \x00" + bytes(counter) + + # send the payload and prompt + start_timer = time.monotonic_ns() # start timer + result = radio.write(buffer) # save the report + end_timer = time.monotonic_ns() # stop timer + if result: + # print timer results upon transmission success + print( + "Transmission successful! Time to transmit: " + "{} us. Sent: {}{}".format( + int((end_timer - start_timer) / 1000), + buffer[:6].decode("utf-8"), + counter[0] + ), + end=" " + ) + has_payload, pipe_number = radio.available_pipe() + if has_payload: + # print the received ACK that was automatically sent + length = radio.getDynamicPayloadSize() + response = radio.read(length) + print( + "Received {} on pipe {}: {}{}".format( + length, + pipe_number, + bytes(response[:6]).decode("utf-8"), + response[7:8][0] + ) + ) + # increment counter from received payload + if response[7:8][0] < 255: + counter[0] = response[7:8][0] + 1 + else: + counter[0] = 0 + else: + print("Received an empty ACK packet") + else: + failures += 1 + print("Transmission failed or timed out") + time.sleep(1) # let the RX node prepare a new ACK payload + print(failures, "failures detected. Leaving TX role.") + + +def slave(timeout=6): + """Listen for any payloads and print the transaction + + :param int timeout: The number of seconds to wait (with no transmission) + until exiting function. + """ + radio.startListening() # put radio in RX mode + + # setup the first transmission's ACK payload + buffer = b"World \x00" + bytes(counter) + # we must set the ACK payload data and corresponding + # pipe number [0,5] + radio.writeAckPayload(1, buffer) # load ACK for first response + + start_timer = time.monotonic() # start timer + while (time.monotonic() - start_timer) < timeout: + has_payload, pipe_number = radio.available_pipe() + if has_payload: + length = radio.getDynamicPayloadSize() # grab the payload length + received = radio.read(length) # fetch 1 payload from RX FIFO + # increment counter from received payload + counter[0] = received[7:8][0] + 1 if received[7:8][0] < 255 else 0 + print( + "Received {} bytes on pipe {}: {}{} Sent: {}{}".format( + length, + pipe_number, + bytes(received[:6]).decode("utf-8"), + received[7:8][0], + buffer[:6].decode("utf-8"), + buffer[7:8][0] + ) + ) + buffer = b"World \x00" + bytes(counter) # build a new ACK payload + radio.writeAckPayload(1, buffer) # load ACK for next response + start_timer = time.monotonic() # reset timer + + print("Nothing received in 6 seconds. Leaving RX role") + # recommended behavior is to keep in TX mode while idle + radio.stopListening() # put radio in TX mode & flush unused ACK payloads + + +def set_role(): + """Set the role using stdin stream. Timeout arg for slave() can be + specified using a space delimiter (e.g. 'R 10' calls `slave(10)`) + + :return: + - True when role is complete & app should continue running. + - False when app should exit + """ + user_input = input( + "*** Enter 'R' for receiver role.\n" + "*** Enter 'T' for transmitter role.\n" + "*** Enter 'Q' to quit example.\n" + ) or "?" + user_input = user_input.split() + if user_input[0].upper().startswith("R"): + if len(user_input) > 1: + slave(int(user_input[1])) + else: + slave() + return True + elif user_input[0].upper().startswith("T"): + master() + return True + elif user_input[0].upper().startswith("Q"): + radio.powerDown() + return False + print(user_input[0], "is an unrecognized input. Please try again.") + return set_role() + + +if __name__ == "__main__": + + args = parser.parse_args() # parse any CLI args + + # initialize the nRF24L01 on the spi bus + if not radio.begin(): + raise RuntimeError("radio hardware is not responding") + + # For this example, we will use different addresses + # An address need to be a buffer protocol object (bytearray) + address = [b"1Node", b"2Node"] + # It is very helpful to think of an address as a path instead of as + # an identifying device destination + + print(sys.argv[0]) # print example name + + # to use different addresses on a pair of radios, we need a variable to + # uniquely identify which address this radio will use to transmit + # 0 uses address[0] to transmit, 1 uses address[1] to transmit + radio_number = args.node # uses default value from `parser` + if args.node is None: # if '--node' arg wasn't specified + radio_number = bool( + int( + input( + "Which radio is this? Enter '0' or '1'. Defaults to '0' " + ) or 0 + ) + ) + + # set the Power Amplifier level to -12 dBm since this test example is + # usually run with nRF24L01 transceivers in close proximity of each other + radio.setPALevel(RF24_PA_LOW) # RF24_PA_MAX is default + + # ACK payloads are dynamically sized. + radio.enableDynamicPayloads() # to use ACK payloads + + # to enable the custom ACK payload feature + radio.enableAckPayload() + + # set the Power Amplifier level to -12 dBm since this test example is + # usually run with nRF24L01 transceivers in close proximity of each other + radio.setPALevel(RF24_PA_LOW) # RF24_PA_MAX is default + + # set the TX address of the RX node into the TX pipe + radio.openWritingPipe(address[radio_number]) # always uses pipe 0 + + # set the RX address of the TX node into a RX pipe + radio.openReadingPipe(1, address[not radio_number]) # using pipe 1 + + # for debugging, we have 2 options that print a large block of details + # (smaller) function that prints raw register values + # radio.printDetails() + # (larger) function that prints human readable data + # radio.printPrettyDetails() + + try: + if args.role is None: # if not specified with CLI arg '-r' + while set_role(): + pass # continue example until 'Q' is entered + else: # if role was set using CLI args + # run role once and exit + master() if bool(args.role) else slave() + except KeyboardInterrupt: + print(" Keyboard Interrupt detected. Exiting...") + radio.powerDown() + sys.exit() diff --git a/examples_linux/getting_started.py b/examples_linux/getting_started.py new file mode 100644 index 000000000..cc5db7ccb --- /dev/null +++ b/examples_linux/getting_started.py @@ -0,0 +1,203 @@ +""" +A simple example of sending data from 1 nRF24L01 transceiver to another. +This example was written to be used on 2 devices acting as 'nodes'. +""" +import sys +import argparse +import time +import struct +from RF24 import RF24, RF24_PA_LOW + + +parser = argparse.ArgumentParser( + description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter +) +parser.add_argument( + "-n", + "--node", + type=int, + choices=range(2), + help="the identifying radio number (or node ID number)" +) +parser.add_argument( + "-r", + "--role", + type=int, + choices=range(2), + help="'1' specifies the TX role. '0' specifies the RX role." +) + + +########### USER CONFIGURATION ########### +# See https://github.com/TMRh20/RF24/blob/master/pyRF24/readme.md +# Radio CE Pin, CSN Pin, SPI Speed +# CE Pin uses GPIO number with BCM and SPIDEV drivers, other platforms use +# their own pin numbering +# CS Pin addresses the SPI bus number at /dev/spidev. +# ie: RF24 radio(, *10+); spidev1.0 is 10, spidev1.1 is 11 etc.. + +# Generic: +radio = RF24(22, 0) +################## Linux (BBB,x86,etc) ######################### +# See http://nRF24.github.io/RF24/pages.html for more information on usage +# See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA +# See https://www.kernel.org/doc/Documentation/spi/spidev for more +# information on SPIDEV + +# using the python keyword global is bad practice. Instead we'll use a 1 item +# list to store our float number for the payloads sent/received +payload = [0.0] + + +def master(): + """Transmits an incrementing float every second""" + radio.stopListening() # put radio in TX mode + failures = 0 + while failures < 6: + # use struct.pack() to packet your data into the payload + # " 1: + slave(int(user_input[1])) + else: + slave() + return True + elif user_input[0].upper().startswith("T"): + master() + return True + elif user_input[0].upper().startswith("Q"): + radio.powerDown() + return False + print(user_input[0], "is an unrecognized input. Please try again.") + return set_role() + + +if __name__ == "__main__": + + args = parser.parse_args() # parse any CLI args + + # initialize the nRF24L01 on the spi bus + if not radio.begin(): + raise RuntimeError("radio hardware is not responding") + + # For this example, we will use different addresses + # An address need to be a buffer protocol object (bytearray) + address = [b"1Node", b"2Node"] + # It is very helpful to think of an address as a path instead of as + # an identifying device destination + + print(sys.argv[0]) # print example name + + # to use different addresses on a pair of radios, we need a variable to + # uniquely identify which address this radio will use to transmit + # 0 uses address[0] to transmit, 1 uses address[1] to transmit + radio_number = args.node # uses default value from `parser` + if args.node is None: # if '--node' arg wasn't specified + radio_number = bool( + int( + input( + "Which radio is this? Enter '0' or '1'. Defaults to '0' " + ) or 0 + ) + ) + + # set the Power Amplifier level to -12 dBm since this test example is + # usually run with nRF24L01 transceivers in close proximity of each other + radio.setPALevel(RF24_PA_LOW) # RF24_PA_MAX is default + + # set the TX address of the RX node into the TX pipe + radio.openWritingPipe(address[radio_number]) # always uses pipe 0 + + # set the RX address of the TX node into a RX pipe + radio.openReadingPipe(1, address[not radio_number]) # using pipe 1 + + # To save time during transmission, we'll set the payload size to be only + # what we need. A float value occupies 4 bytes in memory using + # struct.pack(); " - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - - 03/17/2013 : Charles-Henri Hallard (http://hallard.me) - Modified to use with Arduipi board http://hallard.me/arduipi - Changed to use modified bcm2835 and RF24 library -TMRh20 2014 - Updated to work with optimized RF24 Arduino library - - */ - -/** - * Example RF Radio Ping Pair - * - * This is an example of how to use the RF24 class on RPi, communicating to an Arduino running - * the GettingStarted sketch. - */ - -#include -#include -#include -#include -#include -#include - -using namespace std; -// -// Hardware configuration -// Configure the appropriate pins for your connections - -/****************** Linux ***********************/ -// Radio CE Pin, CSN Pin, SPI Speed -// CE Pin uses GPIO number with BCM and SPIDEV drivers, other platforms use their own pin numbering -// CS Pin addresses the SPI bus number at /dev/spidev. -// ie: RF24 radio(, *10+); spidev1.0 is 10, spidev1.1 is 11 etc.. - -// Generic: -RF24 radio(22,0); - -/****************** Linux (BBB,x86,etc) ***********************/ -// See http://tmrh20.github.io/RF24/pages.html for more information on usage -// See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA -// See https://www.kernel.org/doc/Documentation/spi/spidev for more information on SPIDEV - - -/********** User Config *********/ -// Assign a unique identifier for this node, 0 or 1 -bool radioNumber = 1; - -/********************************/ - -// Radio pipe addresses for the 2 nodes to communicate. -const uint8_t pipes[][6] = {"1Node", "2Node"}; - -int main(int argc, char** argv) -{ - - bool role_ping_out = true, role_pong_back = false; - bool role = role_pong_back; - - cout << "RF24/examples/GettingStarted/\n"; - - // Setup and configure rf radio - radio.begin(); - - // optionally, increase the delay between retries & # of retries - radio.setRetries(15, 15); - // Dump the configuration of the rf unit for debugging - radio.printDetails(); - - - /********* Role chooser ***********/ - - printf("\n ************ Role Setup ***********\n"); - string input = ""; - char myChar = {0}; - cout << "Choose a role: Enter 0 for pong_back, 1 for ping_out (CTRL+C to exit) \n>"; - getline(cin, input); - - if (input.length() == 1) { - myChar = input[0]; - if (myChar == '0') { - cout << "Role: Pong Back, awaiting transmission " << endl << endl; - } else { - cout << "Role: Ping Out, starting transmission " << endl << endl; - role = role_ping_out; - } - } - /***********************************/ - // This simple sketch opens two pipes for these two nodes to communicate - // back and forth. - - if (!radioNumber) { - radio.openWritingPipe(pipes[0]); - radio.openReadingPipe(1, pipes[1]); - } else { - radio.openWritingPipe(pipes[1]); - radio.openReadingPipe(1, pipes[0]); - } - - radio.startListening(); - - // forever loop - while (1) { - if (role == role_ping_out) { - // First, stop listening so we can talk. - radio.stopListening(); - - // Take the time, and send it. This will block until complete - - printf("Now sending...\n"); - unsigned long time = millis(); - - bool ok = radio.write(&time, sizeof(unsigned long)); - - if (!ok) { - printf("failed.\n"); - } - // Now, continue listening - radio.startListening(); - - // Wait here until we get a response, or timeout (250ms) - unsigned long started_waiting_at = millis(); - bool timeout = false; - while (!radio.available() && !timeout) { - if (millis() - started_waiting_at > 200) { - timeout = true; - } - } - - - // Describe the results - if (timeout) { - printf("Failed, response timed out.\n"); - } else { - // Grab the response, compare, and send to debugging spew - unsigned long got_time; - radio.read(&got_time, sizeof(unsigned long)); - - // Spew it - printf("Got response %lu, round-trip delay: %lu\n", got_time, millis() - got_time); - } - sleep(1); - } - - // - // Pong back role. Receive each packet, dump it out, and send it back - // - - if (role == role_pong_back) { - - // if there is data ready - if (radio.available()) { - // Dump the payloads until we've gotten everything - unsigned long got_time; - - // Fetch the payload, and see if this was the last one. - while (radio.available()) { - radio.read(&got_time, sizeof(unsigned long)); - } - radio.stopListening(); - - radio.write(&got_time, sizeof(unsigned long)); - - // Now, resume listening so we catch the next packets. - radio.startListening(); - - // Spew it - printf("Got payload(%d) %lu...\n", sizeof(unsigned long), got_time); - - delay(925); //Delay after payload responded to, minimize RPi CPU time - - } - - } - - } // forever loop - - return 0; -} - +/* + * See documentation at https://nRF24.github.io/RF24 + * See License information at root directory of this library + * Author: Brendan Doherty (2bndy5) + */ + +/** + * A simple example of sending data from 1 nRF24L01 transceiver to another. + * + * This example was written to be used on 2 devices acting as "nodes". + * Use `ctrl+c` to quit at any time. + */ +#include // time() +#include // strcmp() +#include // cin, cout, endl +#include // string, getline() +#include // CLOCK_MONOTONIC_RAW, timespec, clock_gettime() +#include // RF24, RF24_PA_LOW, delay() + +using namespace std; + +/****************** Linux ***********************/ +// Radio CE Pin, CSN Pin, SPI Speed +// CE Pin uses GPIO number with BCM and SPIDEV drivers, other platforms use their own pin numbering +// CS Pin addresses the SPI bus number at /dev/spidev. +// ie: RF24 radio(, *10+); spidev1.0 is 10, spidev1.1 is 11 etc.. + +// Generic: +RF24 radio(22, 0); +/****************** Linux (BBB,x86,etc) ***********************/ +// See http://nRF24.github.io/RF24/pages.html for more information on usage +// See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA +// See https://www.kernel.org/doc/Documentation/spi/spidev for more information on SPIDEV + +// For this example, we'll be using a payload containing +// a single float number that will be incremented +// on every successful transmission +float payload = 0.0; + +void setRole(); // prototype to set the node's role +void master(); // prototype of the TX node's behavior +void slave(); // prototype of the RX node's behavior + +// custom defined timer for evaluating transmission time in microseconds +struct timespec startTimer, endTimer; +uint32_t getMicros(); // prototype to get ellapsed time in microseconds + +int main(int argc, char** argv) { + + // perform hardware check + if (!radio.begin()) { + cout << "radio hardware is not responding!!" << endl; + return 0; // quit now + } + + // to use different addresses on a pair of radios, we need a variable to + // uniquely identify which address this radio will use to transmit + bool radioNumber = 1; // 0 uses address[0] to transmit, 1 uses address[1] to transmit + + // print example's name + cout << argv[0] << endl; + + // Let these addresses be used for the pair + uint8_t address[2][6] = {"1Node", "2Node"}; + // It is very helpful to think of an address as a path instead of as + // an identifying device destination + + // Set the radioNumber via the terminal on startup + cout << "Which radio is this? Enter '0' or '1'. Defaults to '0' "; + string input; + getline(cin, input); + radioNumber = input.length() > 0 && (uint8_t)input[0] == 49; + + // save on transmission time by setting the radio to only transmit the + // number of bytes we need to transmit a float + radio.setPayloadSize(sizeof(payload)); // float datatype occupies 4 bytes + + // Set the PA Level low to try preventing power supply related problems + // because these examples are likely run with nodes in close proximity to + // each other. + radio.setPALevel(RF24_PA_LOW); // RF24_PA_MAX is default. + + // set the TX address of the RX node into the TX pipe + radio.openWritingPipe(address[radioNumber]); // always uses pipe 0 + + // set the RX address of the TX node into a RX pipe + radio.openReadingPipe(1, address[!radioNumber]); // using pipe 1 + + // For debugging info + // radio.printDetails(); // (smaller) function that prints raw register values + // radio.printPrettyDetails(); // (larger) function that prints human readable data + + // ready to execute program now + setRole(); // calls master() or slave() based on user input + return 0; +} + + +/** + * set this node's role from stdin stream. + * this only considers the first char as input. + */ +void setRole() { + string input = ""; + while (!input.length()) { + cout << "*** PRESS 'T' to begin transmitting to the other node\n"; + cout << "*** PRESS 'R' to begin receiving from the other node\n"; + cout << "*** PRESS 'Q' to exit" << endl; + getline(cin, input); + if (input.length() >= 1) { + if (input[0] == 'T' || input[0] == 't') + master(); + else if (input[0] == 'R' || input[0] == 'r') + slave(); + else if (input[0] == 'Q' || input[0] == 'q') + break; + else + cout << input[0] << " is an invalid input. Please try again." << endl; + } + input = ""; // stay in the while loop + } // while +} // setRole() + + +/** + * make this node act as the transmitter + */ +void master() { + radio.stopListening(); // put radio in TX mode + + unsigned int failure = 0; // keep track of failures + while (failure < 6) { + clock_gettime(CLOCK_MONOTONIC_RAW, &startTimer); // start the timer + bool report = radio.write(&payload, sizeof(float)); // transmit & save the report + uint32_t timerEllapsed = getMicros(); // end the timer + + if (report) { + // payload was delivered + cout << "Transmission successful! Time to transmit = "; + cout << timerEllapsed; // print the timer result + cout << " us. Sent: " << payload << endl; // print payload sent + payload += 0.01; // increment float payload + + } else { + // payload was not delivered + cout << "Transmission failed or timed out" << endl; + failure++; + } + + // to make this example readable in the terminal + delay(1000); // slow transmissions down by 1 second + } + cout << failure << " failures detected. Leaving TX role." << endl; +} + +/** + * make this node act as the receiver + */ +void slave() { + + radio.startListening(); // put radio in RX mode + + time_t startTimer = time(nullptr); // start a timer + while (time(nullptr) - startTimer < 6) { // use 6 second timeout + uint8_t pipe; + if (radio.available(&pipe)) { // is there a payload? get the pipe number that recieved it + uint8_t bytes = radio.getDynamicPayloadSize(); // get the size of the payload + radio.read(&payload, bytes); // fetch payload from FIFO + cout << "Received " << (unsigned int)bytes; // print the size of the payload + cout << " bytes on pipe " << (unsigned int)pipe; // print the pipe number + cout << ": " << payload << endl; // print the payload's value + startTimer = time(nullptr); // reset timer + } + } + cout << "Nothing received in 6 seconds. Leaving RX role." << endl; + radio.stopListening(); +} + + +/** + * Calculate the ellapsed time in microseconds + */ +uint32_t getMicros() { + // this function assumes that the timer was started using + // `clock_gettime(CLOCK_MONOTONIC_RAW, &startTimer);` + + clock_gettime(CLOCK_MONOTONIC_RAW, &endTimer); + uint32_t seconds = endTimer.tv_sec - startTimer.tv_sec; + uint32_t useconds = (endTimer.tv_nsec - startTimer.tv_nsec) / 1000; + + return ((seconds) * 1000 + useconds) + 0.5; +} + + +/** + * print a manual page of instructions on how to use this example's CLI args + */ +void printHelp(string progName) { + cout << "usage: " << progName << " [-h] [-n {0,1}] [-r {0,1}]\n\n" + << "A simple example of sending data from 1 nRF24L01 transceiver to another.\n" + << "\nThis example was written to be used on 2 devices acting as 'nodes'.\n" + << "\noptional arguments:\n -h, --help\t\tshow this help message and exit\n" + << " -n {0,1}, --node {0,1}\n\t\t\tthe identifying radio number\n" + << " -r {0,1}, --role {0,1}\n\t\t\t'1' specifies the TX role." + << " '0' specifies the RX role." << endl; +} \ No newline at end of file diff --git a/examples_linux/gettingstarted_call_response.cpp b/examples_linux/gettingstarted_call_response.cpp deleted file mode 100644 index 7f82c90fa..000000000 --- a/examples_linux/gettingstarted_call_response.cpp +++ /dev/null @@ -1,147 +0,0 @@ -/* -TMRh20 2014 - Updated to work with optimized RF24 Arduino library -*/ - - -/** - * Example for efficient call-response using ack-payloads - * - * This example continues to make use of all the normal functionality of the radios including - * the auto-ack and auto-retry features, but allows ack-payloads to be written optionlly as well. - * This allows very fast call-response communication, with the responding radio never having to - * switch out of Primary Receiver mode to send back a payload, but having the option to switch to - * primary transmitter if wanting to initiate communication instead of respond to a commmunication. - */ - -#include -#include -#include -#include -#include -#include - -using namespace std; - -// -// Hardware configuration -// Configure the appropriate pins for your connections - -/****************** Linux ***********************/ -// Radio CE Pin, CSN Pin, SPI Speed -// CE Pin uses GPIO number with BCM and SPIDEV drivers, other platforms use their own pin numbering -// CS Pin addresses the SPI bus number at /dev/spidev. -// ie: RF24 radio(, *10+); spidev1.0 is 10, spidev1.1 is 11 etc.. - -// Generic: -RF24 radio(22,0); - -/****************** Linux (BBB,x86,etc) ***********************/ -// See http://tmrh20.github.io/RF24/pages.html for more information on usage -// See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA -// See https://www.kernel.org/doc/Documentation/spi/spidev for more information on SPIDEV - -/********** User Config *********/ -// Assign a unique identifier for this node, 0 or 1. Arduino example uses radioNumber 0 by default. -bool radioNumber = 1; - -/********************************/ - - -// Radio pipe addresses for the 2 nodes to communicate. -const uint8_t addresses[][6] = {"1Node", "2Node"}; - -bool role_ping_out = 1, role_pong_back = 0, role = 0; -uint8_t counter = 1; // A single byte to keep track of the data being sent back and forth - - -int main(int argc, char** argv) -{ - - cout << "RPi/RF24/examples/gettingstarted_call_response\n"; - radio.begin(); - radio.enableAckPayload(); // Allow optional ack payloads - radio.enableDynamicPayloads(); - radio.printDetails(); // Dump the configuration of the rf unit for debugging - - - /********* Role chooser ***********/ - - printf("\n ************ Role Setup ***********\n"); - string input = ""; - char myChar = {0}; - cout << "Choose a role: Enter 0 for pong_back, 1 for ping_out (CTRL+C to exit)\n>"; - getline(cin, input); - - if (input.length() == 1) { - myChar = input[0]; - if (myChar == '0') { - cout << "Role: Pong Back, awaiting transmission " << endl << endl; - } else { - cout << "Role: Ping Out, starting transmission " << endl << endl; - role = role_ping_out; - } - } - /***********************************/ - // This opens two pipes for these two nodes to communicate - // back and forth. - if (!radioNumber) { - radio.openWritingPipe(addresses[0]); - radio.openReadingPipe(1, addresses[1]); - } else { - radio.openWritingPipe(addresses[1]); - radio.openReadingPipe(1, addresses[0]); - } - radio.startListening(); - radio.writeAckPayload(1, &counter, 1); - - // forever loop - while (1) { - - - /****************** Ping Out Role ***************************/ - - if (role == role_ping_out) { // Radio is in ping mode - - uint8_t gotByte; // Initialize a variable for the incoming response - - radio.stopListening(); // First, stop listening so we can talk. - printf("Now sending %d as payload. ", counter); // Use a simple byte counter as payload - unsigned long time = millis(); // Record the current microsecond count - - if (radio.write(&counter, 1)) { // Send the counter variable to the other radio - if (!radio.available()) { // If nothing in the buffer, we got an ack but it is blank - printf("Got blank response. round-trip delay: %lu ms\n\r", millis() - time); - } else { - while (radio.available()) { // If an ack with payload was received - radio.read(&gotByte, 1); // Read it, and display the response time - printf("Got response %d, round-trip delay: %lu ms\n\r", gotByte, millis() - time); - counter++; // Increment the counter variable - } - } - - } else { - printf("Sending failed.\n\r"); - } // If no ack response, sending failed - - sleep(1); // Try again later - } - - /****************** Pong Back Role ***************************/ - - if (role == role_pong_back) { - uint8_t pipeNo, gotByte; // Declare variables for the pipe and the byte received - if (radio.available(&pipeNo)) { // Read all available payloads - radio.read(&gotByte, 1); - // Since this is a call-response. Respond directly with an ack payload. - gotByte += 1; // Ack payloads are much more efficient than switching to transmit mode to respond to a call - radio.writeAckPayload(pipeNo, &gotByte, 1); // This can be commented out to send empty payloads. - printf("Loaded next response %d \n\r", gotByte); - delay(900); //Delay after a response to minimize CPU usage on RPi - //Expects a payload every second - } - } - - } //while 1 -} //main - - diff --git a/examples_linux/interruptConfigure.cpp b/examples_linux/interruptConfigure.cpp new file mode 100644 index 000000000..b9533406d --- /dev/null +++ b/examples_linux/interruptConfigure.cpp @@ -0,0 +1,338 @@ +/* + * See documentation at https://nRF24.github.io/RF24 + * See License information at root directory of this library + * Author: Brendan Doherty (2bndy5) + */ + +/** + * This example uses Acknowledgement (ACK) payloads attached to ACK packets to + * demonstrate how the nRF24L01's IRQ (Interrupt Request) pin can be + * configured to detect when data is received, or when data has transmitted + * successfully, or when data has failed to transmit. + * + * This example was written to be used on 2 devices acting as "nodes". + * Use `ctrl+c` to quit at any time. + */ +#include // time() +#include // strcmp() +#include // cin, cout, endl +#include // string, getline() +#include // CLOCK_MONOTONIC_RAW, timespec, clock_gettime() +#include // RF24, RF24_PA_LOW, delay(), pinMode(), INPUT, attachInterrupt(), INT_EDGE_FALLING + +using namespace std; + +// We will be using the nRF24L01's IRQ pin for this example +#define IRQ_PIN 12 // this needs to be a digital input capable pin + +// this example is a sequential program. so we need to wait for the event to be handled +volatile bool wait_for_event = false; // used to signify that the event is handled + +/****************** Linux ***********************/ +// Radio CE Pin, CSN Pin, SPI Speed +// CE Pin uses GPIO number with BCM and SPIDEV drivers, other platforms use their own pin numbering +// CS Pin addresses the SPI bus number at /dev/spidev. +// ie: RF24 radio(, *10+); spidev1.0 is 10, spidev1.1 is 11 etc.. + +// Generic: +RF24 radio(22, 0); +/****************** Linux (BBB,x86,etc) ***********************/ +// See http://nRF24.github.io/RF24/pages.html for more information on usage +// See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA +// See https://www.kernel.org/doc/Documentation/spi/spidev for more information on SPIDEV + +// For this example, we'll be using a payload containing +// a string that changes on every transmission. (successful or not) +// Make a couple arrays of payloads & an iterator to traverse them +const uint8_t tx_pl_size = 5; +const uint8_t ack_pl_size = 4; +uint8_t pl_iterator = 0; +// The " + 1" compensates for the c-string's NULL terminating 0 +char tx_payloads[4][tx_pl_size + 1] = {"Ping ", "Pong ", "Radio", "1FAIL"}; +char ack_payloads[3][ack_pl_size + 1] = {"Yak ", "Back", " ACK"}; + +void interruptHandler(); // prototype to handle the interrupt request (IRQ) pin +void setRole(); // prototype to set the node's role +void master(); // prototype of the TX node's behavior +void slave(); // prototype of the RX node's behavior +void ping_n_wait(); // prototype that sends a payload and waits for the IRQ pin to get triggered +void printRxFifo(const uint8_t); // prototype to print entire contents of RX FIFO with 1 buffer + + +int main(int argc, char** argv) { + + // perform hardware check + if (!radio.begin()) { + cout << "radio hardware is not responding!!" << endl; + return 0; // quit now + } + + // Let these addresses be used for the pair + uint8_t address[2][6] = {"1Node", "2Node"}; + // It is very helpful to think of an address as a path instead of as + // an identifying device destination + + // to use different addresses on a pair of radios, we need a variable to + // uniquely identify which address this radio will use to transmit + bool radioNumber = 1; // 0 uses address[0] to transmit, 1 uses address[1] to transmit + + // print example's name + cout << argv[0] << endl; + + // Set the radioNumber via the terminal on startup + cout << "Which radio is this? Enter '0' or '1'. Defaults to '0' "; + string input; + getline(cin, input); + radioNumber = input.length() > 0 && (uint8_t)input[0] == 49; + + // to use ACK payloads, we need to enable dynamic payload lengths + radio.enableDynamicPayloads(); // ACK payloads are dynamically sized + + // Acknowledgement packets have no payloads by default. We need to enable + // this feature for all nodes (TX & RX) to use ACK payloads. + radio.enableAckPayload(); + + // Set the PA Level low to try preventing power supply related problems + // because these examples are likely run with nodes in close proximity to + // each other. + radio.setPALevel(RF24_PA_LOW); // RF24_PA_MAX is default. + + // set the TX address of the RX node into the TX pipe + radio.openWritingPipe(address[radioNumber]); // always uses pipe 0 + + // set the RX address of the TX node into a RX pipe + radio.openReadingPipe(1, address[!radioNumber]); // using pipe 1 + + // For debugging info + // radio.printDetails(); // (smaller) function that prints raw register values + // radio.printPrettyDetails(); // (larger) function that prints human readable data + + // setup the digital input pin connected to the nRF24L01's IRQ pin + pinMode(IRQ_PIN, INPUT); + + // register the interrupt request (IRQ) to call our + // Interrupt Service Routine (ISR) callback function interruptHandler() + attachInterrupt(IRQ_PIN, INT_EDGE_FALLING, &interruptHandler); + // IMPORTANT: do not call radio.available() before calling + // radio.whatHappened() when the interruptHandler() is triggered by the + // IRQ pin FALLING event. According to the datasheet, the pipe information + // is unreliable during the IRQ pin FALLING transition. + + // ready to execute program now + setRole(); // calls master() or slave() based on user input + return 0; +} // main + + +/** + * set this node's role from stdin stream. + * this only considers the first char as input. + */ +void setRole() { + string input = ""; + while (!input.length()) { + cout << "*** PRESS 'T' to begin transmitting to the other node\n"; + cout << "*** PRESS 'R' to begin receiving from the other node\n"; + cout << "*** PRESS 'Q' to exit" << endl; + getline(cin, input); + if (input.length() >= 1) { + if (input[0] == 'T' || input[0] == 't') + master(); + else if (input[0] == 'R' || input[0] == 'r') + slave(); + else if (input[0] == 'Q' || input[0] == 'q') + break; + else + cout << input[0] << " is an invalid input. Please try again." << endl; + } + input = ""; // stay in the while loop + } // while +} // setRole + + +/** + * act as the transmitter to show 3 different IRQ events by sending 4 payloads: + * 1. Successfully receive ACK payload first + * 2. Successfully transmit on second + * 3. Send a third payload to fill RX node's RX FIFO (supposedly making RX node unresponsive) + * 4. intentionally fail transmit on the fourth + */ +void master() { + pl_iterator = 0; // reset the iterator for the following tests done in master() + + // Test the "data ready" event with the IRQ pin + cout << "\nConfiguring IRQ pin to ignore the 'data sent' event\n"; + radio.maskIRQ(true, false, false); // args = "data_sent", "data_fail", "data_ready" + cout << " Pinging RX node for 'data ready' event..."; + ping_n_wait(); // transmit a payload and detect the IRQ pin + pl_iterator++; // increment iterator for next test + + + // Test the "data sent" event with the IRQ pin + cout << "\nConfiguring IRQ pin to ignore the 'data ready' event\n"; + radio.maskIRQ(false, false, true); // args = "data_sent", "data_fail", "data_ready" + cout << " Pinging RX node for 'data sent' event..."; + radio.flush_tx(); // flush payloads from any failed prior test + ping_n_wait(); // transmit a payload and detect the IRQ pin + pl_iterator++; // increment iterator for next test + + + // Use this iteration to fill the RX node's FIFO which sets us up for the next test. + // write() uses virtual interrupt flags that work despite the masking of the IRQ pin + radio.maskIRQ(1, 1, 1); // disable IRQ masking for this step + + cout << "\nSending 1 payload to fill RX node's FIFO. IRQ pin is neglected.\n"; + // write() will call flush_tx() on 'data fail' events + if (radio.write(&tx_payloads[pl_iterator], tx_pl_size)) + cout << "RX node's FIFO is full; it is not listening any more" << endl; + else { + cout << "Transmission failed or timed out. Continuing anyway." << endl; + radio.flush_tx(); + } + pl_iterator++; // increment iterator for next test + + + // test the "data fail" event with the IRQ pin + cout << "\nConfiguring IRQ pin to reflect all events\n"; + radio.maskIRQ(0, 0, 0); // args = "data_sent", "data_fail", "data_ready" + cout << " Pinging inactive RX node for 'data fail' event..."; + ping_n_wait(); // transmit a payload and detect the IRQ pin + + // CE pin is still HIGH which consumes more power. Example is now idling so... + radio.stopListening(); // ensure CE pin is LOW + // stopListening() also calls flush_tx() when ACK payloads are enabled + + if (radio.available()) { + printRxFifo(ack_pl_size); // doing this will flush the RX FIFO + } +} // master + + +/** + * act as the receiver + */ +void slave() { + + // let IRQ pin only trigger on "data_ready" event in RX mode + radio.maskIRQ(1, 1, 0); // args = "data_sent", "data_fail", "data_ready" + + // Fill the TX FIFO with 3 ACK payloads for the first 3 received + // transmissions on pipe 0. + radio.writeAckPayload(1, &ack_payloads[0], ack_pl_size); + radio.writeAckPayload(1, &ack_payloads[1], ack_pl_size); + radio.writeAckPayload(1, &ack_payloads[2], ack_pl_size); + + radio.startListening(); // put radio in RX mode + time_t startTimer = time(nullptr); // start a timer + while (time(nullptr) - startTimer < 6 && !radio.rxFifoFull()) { + // use 6 second timeout & wait till RX FIFO is full + } + delay(100); // wait for ACK payload to finish transmitting + radio.stopListening(); // also discards unused ACK payloads + + if (radio.available()) { + printRxFifo(tx_pl_size); + } + else { + cout << "Timeout was reached. Going back to setRole()" << endl; + } +} // slave + + +/** + * pings the receiver with a non-blocking startWrite(), then waits till + * the IRQ pin is triggered + */ +void ping_n_wait() { + // use the non-blocking call to write a payload and begin transmission + // the "false" argument means we are expecting an ACK packet response + radio.startFastWrite(tx_payloads[pl_iterator], tx_pl_size, false); + + wait_for_event = true; + while (wait_for_event) { + /* + * IRQ pin is LOW when activated. Otherwise it is always HIGH + * Wait in this empty loop until IRQ pin is activated. + * + * In this example, the "data fail" event is always configured to + * trigger the IRQ pin active. Because the auto-ACK feature is on by + * default, we don't need a timeout check to prevent an infinite loop. + */ + } +} + + +/** + * when the IRQ pin goes active LOW, call this fuction print out why + */ +void interruptHandler() { + // print IRQ status and all masking flags' states + + cout << "\tIRQ pin is actively LOW" << endl; // show that this function was called + + bool tx_ds, tx_df, rx_dr; // declare variables for IRQ masks + radio.whatHappened(tx_ds, tx_df, rx_dr); // get values for IRQ masks + // whatHappened() clears the IRQ masks also. This is required for + // continued TX operations when a transmission fails. + // clearing the IRQ masks resets the IRQ pin to its inactive state (HIGH) + + cout << "\tdata_sent: " << tx_ds; // print "data sent" mask state + cout << ", data_fail: " << tx_df; // print "data fail" mask state + cout << ", data_ready: " << rx_dr << endl; // print "data ready" mask state + + if (tx_df) // if TX payload failed + radio.flush_tx(); // clear all payloads from the TX FIFO + + // print if test passed or failed. Unintentional fails mean the RX node was not listening. + if (pl_iterator == 0) + cout << " 'Data Ready' event test " << (rx_dr ? "passed" : "failed") << endl; + else if (pl_iterator == 1) + cout << " 'Data Sent' event test " << (tx_ds ? "passed" : "failed") << endl; + else if (pl_iterator == 3) + cout << " 'Data Fail' event test " << (tx_df ? "passed" : "failed") << endl; + + wait_for_event = false; // ready to continue +} // interruptHandler + + +/** + * Print the entire RX FIFO with one buffer. This will also flush the RX FIFO. + * @param pl_size used to determine received payload size. Remember that the + * payload sizes are declared as tx_pl_size and ack_pl_size. + */ +void printRxFifo(const uint8_t pl_size) { + char rx_fifo[pl_size * 3 + 1]; // assuming RX FIFO is full; declare a buffer to hold it all + if (radio.rxFifoFull()) { + rx_fifo[pl_size * 3] = 0; // add a NULL terminating char to use as a c-string + radio.read(&rx_fifo, pl_size * 3); // this clears the RX FIFO (for this example) + } + else { + uint8_t i = 0; + while (radio.available()) { + radio.read(&rx_fifo + (i * pl_size), pl_size); + i++; + } + rx_fifo[i * pl_size] = 0; // add a NULL terminating char to use as a c-string + } + + // print the entire RX FIFO with 1 buffer + cout << "Complete RX FIFO: " << rx_fifo << endl; +} + + + +/** + * print a manual page of instructions on how to use this example's CLI args + */ +void printHelp(string progName) { + cout << "usage: " << progName << " [-h] [-n {0,1}] [-r {0,1}]\n\n" + << "This example uses Acknowledgement (ACK) payloads attached to ACK packets to\n" + << "demonstrate how the nRF24L01's IRQ (Interrupt Request) pin can be\n" + << "configured to detect when data is received, or when data has transmitted\n" + << "successfully, or when data has failed to transmit.\n" + << "\nThis example was written to be used on 2 devices acting as 'nodes'.\n" + << "\noptional arguments:\n -h, --help\t\tshow this help message and exit\n" + << " -n {0,1}, --node {0,1}\n\t\t\tthe identifying radio number\n" + << " -r {0,1}, --role {0,1}\n\t\t\t'1' specifies the TX role." + << " '0' specifies the RX role." << endl; +} \ No newline at end of file diff --git a/examples_linux/interrupt_configure.py b/examples_linux/interrupt_configure.py new file mode 100644 index 000000000..8dd7f6380 --- /dev/null +++ b/examples_linux/interrupt_configure.py @@ -0,0 +1,300 @@ +""" +This example uses Acknowledgement (ACK) payloads attached to ACK packets to +demonstrate how the nRF24L01's IRQ (Interrupt Request) pin can be +configured to detect when data is received, or when data has transmitted +successfully, or when data has failed to transmit. + +This example was written to be used on 2 devices acting as "nodes". +""" +import sys +import argparse +import time +import RPi.GPIO as GPIO +from RF24 import RF24, RF24_PA_LOW + + +parser = argparse.ArgumentParser( + description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter +) +parser.add_argument( + "-n", + "--node", + type=int, + choices=range(2), + help="the identifying radio number (or node ID number)" +) +parser.add_argument( + "-r", + "--role", + type=int, + choices=range(2), + help="'1' specifies the TX role. '0' specifies the RX role." +) + +########### USER CONFIGURATION ########### +# See https://github.com/TMRh20/RF24/blob/master/pyRF24/readme.md +# Radio CE Pin, CSN Pin, SPI Speed +# CE Pin uses GPIO number with BCM and SPIDEV drivers, other platforms use +# their own pin numbering +# CS Pin addresses the SPI bus number at /dev/spidev. +# ie: RF24 radio(, *10+); spidev1.0 is 10, spidev1.1 is 11 etc.. + +# Generic: +radio = RF24(22, 0) +################## Linux (BBB,x86,etc) ######################### +# See http://nRF24.github.io/RF24/pages.html for more information on usage +# See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA +# See https://www.kernel.org/doc/Documentation/spi/spidev for more +# information on SPIDEV + +# select your digital input pin that's connected to the IRQ pin on the nRF24L01 +IRQ_PIN = 12 + +# For this example, we'll be using a payload containing +# a string that changes on every transmission. (successful or not) +# Make a couple tuples of payloads & an iterator to traverse them +pl_iterator = [0] # use a 1-item list instead of python's global keyword +tx_payloads = (b"Ping ", b"Pong ", b"Radio", b"1FAIL") +ack_payloads = (b"Yak ", b"Back", b" ACK") + + +def interrupt_handler(channel): + """This function is called when IRQ pin is detected active LOW""" + print("IRQ pin", channel, "went active LOW.") + tx_ds, tx_df, rx_dr = radio.whatHappened() # get IRQ status flags + if tx_df: + radio.flush_tx() + print("\ttx_ds: {}, tx_df: {}, rx_dr: {}".format(tx_ds, tx_df, rx_dr)) + if pl_iterator[0] == 0: + print( + " 'data ready' event test {}".format( + "passed" if rx_dr else "failed" + ) + ) + elif pl_iterator[0] == 1: + print( + " 'data sent' event test {}".format( + "passed" if tx_ds else "failed" + ) + ) + elif pl_iterator[0] == 3: + print( + " 'data fail' event test {}".format( + "passed" if tx_df else "failed" + ) + ) + + +# setup IRQ GPIO pin +GPIO.setmode(GPIO.BCM) +GPIO.setup(IRQ_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) +GPIO.add_event_detect(IRQ_PIN, GPIO.FALLING, callback=interrupt_handler) +# IMPORTANT: do not call radio.available() before calling +# radio.whatHappened() when the interruptHandler() is triggered by the +# IRQ pin FALLING event. According to the datasheet, the pipe information +# is unreliable during the IRQ pin FALLING transition. + + +def _ping_n_wait(pl_iter): + """private function to ping RX node and wait for IRQ pin to be handled + + :param int pl_iter: The index of the buffer in `tx_payloads` tuple to + send. This number is also used to determine if event test was + successful or not. + """ + # set pl_iterator[0] so interrupt_handler() can determine if test was + # successful or not + pl_iterator[0] = pl_iter + # the following False parameter means we're expecting an ACK packet + radio.startFastWrite(tx_payloads[pl_iter], False) + time.sleep(0.1) # wait 100 ms for interrupt_handler() to complete + + +def print_rx_fifo(pl_size): + """fush RX FIFO by printing all available payloads with 1 buffer + + :param int pl_size: the expected size of each payload + """ + if radio.rxFifoFull(): + # all 3 payloads received were 5 bytes each, and RX FIFO is full + # so, fetching 15 bytes from the RX FIFO also flushes RX FIFO + print( + "Complete RX FIFO:", + radio.read(pl_size * 3).decode("utf-8") + ) + else: + buffer = bytearray() + while radio.available(): + buffer += radio.read(pl_size) + if buffer: # if any payloads were read from the RX FIFO + print("Complete RX FIFO:", buffer.decode("utf-8")) + + +def master(): + """Transmits 4 times and reports results + + 1. successfully receive ACK payload first + 2. successfully transmit on second + 3. send a third payload to fill RX node's RX FIFO + (supposedly making RX node unresponsive) + 4. intentionally fail transmit on the fourth + """ + radio.stopListening() # put radio in TX mode + + # on data ready test + print("\nConfiguring IRQ pin to only ignore 'on data sent' event") + radio.maskIRQ(True, False, False) # args = tx_ds, tx_df, rx_dr + print(" Pinging slave node for an ACK payload...", end=" ") + _ping_n_wait(0) + + # on "data sent" test + print("\nConfiguring IRQ pin to only ignore 'on data ready' event") + radio.maskIRQ(False, False, True) # args = tx_ds, tx_df, rx_dr + print(" Pinging slave node again... ", end=" ") + _ping_n_wait(1) + + # trigger slave node to stopListening() by filling slave node's RX FIFO + print("\nSending one extra payload to fill RX FIFO on slave node.") + radio.maskIRQ(1, 1, 1) # disable IRQ pin for this step + if radio.write(tx_payloads[2]): + # when send_only parameter is True, send() ignores RX FIFO usage + if radio.rxFifoFull(): + print("RX node's FIFO is full; it is not listening any more") + else: + print( + "Transmission successful, but the RX node might still be " + "listening." + ) + else: + radio.flush_tx() + print("Transmission failed or timed out. Continuing anyway.") + + # on "data fail" test + print("\nConfiguring IRQ pin to go active for all events.") + radio.maskIRQ(False, False, False) # args = tx_ds, tx_df, rx_dr + print(" Sending a ping to inactive slave node...", end=" ") + _ping_n_wait(3) + + # CE pin is still HIGH which consumes more power. Example is now idling so... + radio.stopListening() # ensure CE pin is LOW + # stopListening() also calls flush_tx() when ACK payloads are enabled + + print_rx_fifo(len(ack_payloads[0])) # empty RX FIFO + + +def slave(timeout=6): # will listen for 6 seconds before timing out + """Only listen for 3 payload from the master node + + :param int timeout: The number of seconds to wait (with no transmission) + until exiting function. + """ + pl_iterator[0] = 0 # reset this to indicate event is a 'data_ready' event + # setup radio to recieve pings, fill TX FIFO with ACK payloads + radio.writeAckPayload(1, ack_payloads[0]) + radio.writeAckPayload(1, ack_payloads[1]) + radio.writeAckPayload(1, ack_payloads[2]) + radio.startListening() # start listening & clear status flags + start_timer = time.monotonic() # start timer now + while not radio.rxFifoFull() and time.monotonic() - start_timer < timeout: + # if RX FIFO is not full and timeout is not reached, then keep waiting + pass + time.sleep(0.1) # wait for last ACK payload to transmit + radio.stopListening() # put radio in TX mode & discard any ACK payloads + print_rx_fifo(len(tx_payloads[0])) + + +def set_role(): + """Set the role using stdin stream. Timeout arg for slave() can be + specified using a space delimiter (e.g. 'R 10' calls `slave(10)`) + + :return: + - True when role is complete & app should continue running. + - False when app should exit + """ + user_input = input( + "*** Enter 'R' for receiver role.\n" + "*** Enter 'T' for transmitter role.\n" + "*** Enter 'Q' to quit example.\n" + ) or "?" + user_input = user_input.split() + if user_input[0].upper().startswith("R"): + if len(user_input) > 1: + slave(int(user_input[1])) + else: + slave() + return True + elif user_input[0].upper().startswith("T"): + master() + return True + elif user_input[0].upper().startswith("Q"): + radio.powerDown() + return False + else: + print(user_input[0], "is an unrecognized input. Please try again.") + return set_role() + + +if __name__ == "__main__": + + args = parser.parse_args() # parse any CLI args + + # initialize the nRF24L01 on the spi bus + if not radio.begin(): + raise RuntimeError("radio hardware is not responding") + + # For this example, we will use different addresses + # An address need to be a buffer protocol object (bytearray) + address = [b"1Node", b"2Node"] + # It is very helpful to think of an address as a path instead of as + # an identifying device destination + + print(sys.argv[0]) # print example name + + # to use different addresses on a pair of radios, we need a variable to + # uniquely identify which address this radio will use to transmit + # 0 uses address[0] to transmit, 1 uses address[1] to transmit + radio_number = args.node # uses default value from `parser` + if args.node is None: # if '--node' arg wasn't specified + radio_number = bool( + int( + input( + "Which radio is this? Enter '0' or '1'. Defaults to '0' " + ) or 0 + ) + ) + + # set the Power Amplifier level to -12 dBm since this test example is + # usually run with nRF24L01 transceivers in close proximity of each other + radio.setPALevel(RF24_PA_LOW) # RF24_PA_MAX is default + + # ACK payloads are dynamically sized. + radio.enableDynamicPayloads() # to use ACK payloads + + # this example uses the ACK payload to trigger the IRQ pin active for + # the "on data received" event + radio.enableAckPayload() # enable ACK payloads + + # set the TX address of the RX node into the TX pipe + radio.openWritingPipe(address[radio_number]) # always uses pipe 0 + + # set the RX address of the TX node into a RX pipe + radio.openReadingPipe(1, address[not radio_number]) # using pipe 1 + + # for debugging, we have 2 options that print a large block of details + # (smaller) function that prints raw register values + # radio.printDetails() + # (larger) function that prints human readable data + # radio.printPrettyDetails() + + try: + if args.role is None: # if not specified with CLI arg '-r' + while set_role(): + pass # continue example until 'Q' is entered + else: # if role was set using CLI args + # run role once and exit + master() if bool(args.role) else slave() + except KeyboardInterrupt: + print(" Keyboard Interrupt detected. Exiting...") + radio.powerDown() + sys.exit() diff --git a/examples_linux/interrupts/gettingstarted_call_response_int.cpp b/examples_linux/interrupts/gettingstarted_call_response_int.cpp index bcd074d1f..3a9f9e27b 100644 --- a/examples_linux/interrupts/gettingstarted_call_response_int.cpp +++ b/examples_linux/interrupts/gettingstarted_call_response_int.cpp @@ -67,7 +67,7 @@ int main(int argc, char** argv) cout << "RPi/RF24/examples/gettingstarted_call_response_int\n"; radio.begin(); radio.enableAckPayload(); // Allow optional ack payloads - radio.enableDynamicPayloads(); + radio.enableDynamicPayloads(); // needed for using ACK payloads radio.printDetails(); // Dump the configuration of the rf unit for debugging @@ -88,20 +88,21 @@ int main(int argc, char** argv) role = role_ping_out; } } + /***********************************/ // This opens two pipes for these two nodes to communicate // back and forth. - if (!radioNumber) { + if (!radioNumber){ radio.openWritingPipe(addresses[0]); radio.openReadingPipe(1, addresses[1]); - } else { + }else{ radio.openWritingPipe(addresses[1]); radio.openReadingPipe(1, addresses[0]); } radio.startListening(); radio.writeAckPayload(1, &counter, 1); - radio.maskIRQ(1, 1, 0); //Mask tx_ok & tx_fail interrupts + radio.maskIRQ(1, 1, 0); //Mask tx_ok & tx_fail interrupts attachInterrupt(interruptPin, INT_EDGE_FALLING, intHandler); //Attach interrupt to bcm pin 23 // forever loop @@ -110,36 +111,35 @@ int main(int argc, char** argv) /****************** Ping Out Role ***************************/ - if (role == role_ping_out) { // Radio is in ping mode + if (role == role_ping_out){ // Radio is in ping mode uint8_t gotByte; // Initialize a variable for the incoming response radio.stopListening(); // First, stop listening so we can talk. - printf("Now sending %d as payload. ", counter); // Use a simple byte counter as payload + printf("Now sending %d as payload. ", counter); // Use a simple byte counter as payload unsigned long time = millis(); // Record the current microsecond count - if (radio.write(&counter, 1)) { // Send the counter variable to the other radio - if (!radio.available()) { // If nothing in the buffer, we got an ack but it is blank + if (radio.write(&counter, 1)) // Send the counter variable to the other radio + { + if (!radio.available()){ // If nothing in the buffer, we got an ack but it is blank printf("Got blank response. round-trip delay: %lu ms\n\r", millis() - time); - } else { - - while (radio.available()) { // If an ack with payload was received - radio.read(&gotByte, 1); // Read it, and display the response time + }else{ + while (radio.available()) // If an ack with payload was received + { + radio.read(&gotByte, 1); // Read it, and display the response time printf("Got response %d, round-trip delay: %lu ms\n\r", gotByte, millis() - time); counter++; // Increment the counter variable } } - - } else { - printf("Sending failed.\n\r"); - } // If no ack response, sending failed - - sleep(1); // Try again later + }else{ + printf("Sending failed.\n\r"); // If no ack response, sending failed + } + sleep(1); // Try again later } - /****************** Pong Back Role ***************************/ - + /****************** Pong Back Role ***************************/ + // This is done using ACK payloads & IRQ } //while 1 } //main diff --git a/examples_linux/interrupts/gettingstarted_call_response_int2.cpp b/examples_linux/interrupts/gettingstarted_call_response_int2.cpp index fec3b50a9..ae01e608c 100644 --- a/examples_linux/interrupts/gettingstarted_call_response_int2.cpp +++ b/examples_linux/interrupts/gettingstarted_call_response_int2.cpp @@ -41,11 +41,10 @@ int interruptPin = 23; const uint8_t addresses[][6] = {"1Node", "2Node"}; bool role_ping_out = 1, role_pong_back = 0, role = 0; -uint8_t counter = 1; // A single byte to keep track of the data being sent back and forth +uint8_t counter = 1; // A single byte to keep track of the data being sent back and forth uint32_t timer = 0; -void intHandler() -{ +void intHandler(){ bool tx_ok, tx_fail, rx; radio.whatHappened(tx_ok, tx_fail, rx); @@ -54,14 +53,14 @@ void intHandler() printf("Sending failed.\n\r"); } - if (role == role_ping_out && tx_ok) { - if (!radio.available()) { + if (role == role_ping_out && tx_ok){ + if (!radio.available()){ printf("Got blank response. round-trip delay: %u ms\n\r", millis() - timer); } } - if (role == role_ping_out) { - while (radio.available()) { + if (role == role_ping_out){ + while (radio.available()){ uint8_t gotByte; radio.read(&gotByte, 1); printf("Got response %d, round-trip delay: %u ms\n\r", gotByte, millis() - timer); @@ -80,19 +79,16 @@ void intHandler() gotByte += 1; radio.writeAckPayload(pipeNo, &gotByte, 1); printf("Loaded next response %d \n\r", gotByte); - } } - } -int main(int argc, char** argv) -{ +int main(int argc, char** argv){ cout << "RPi/RF24/examples/gettingstarted_call_response\n"; radio.begin(); radio.enableAckPayload(); // Allow optional ack payloads - radio.enableDynamicPayloads(); + radio.enableDynamicPayloads(); // needed for using ACK payloads radio.printDetails(); // Dump the configuration of the rf unit for debugging @@ -104,22 +100,24 @@ int main(int argc, char** argv) cout << "Choose a role: Enter 0 for pong_back, 1 for ping_out (CTRL+C to exit)\n>"; getline(cin, input); - if (input.length() == 1) { + if (input.length() == 1){ myChar = input[0]; - if (myChar == '0') { + if (myChar == '0'){ cout << "Role: Pong Back, awaiting transmission " << endl << endl; - } else { + }else{ cout << "Role: Ping Out, starting transmission " << endl << endl; role = role_ping_out; } } + + /***********************************/ // This opens two pipes for these two nodes to communicate // back and forth. - if (!radioNumber) { + if (!radioNumber){ radio.openWritingPipe(addresses[0]); radio.openReadingPipe(1, addresses[1]); - } else { + }else{ radio.openWritingPipe(addresses[1]); radio.openReadingPipe(1, addresses[0]); } @@ -129,28 +127,26 @@ int main(int argc, char** argv) attachInterrupt(interruptPin, INT_EDGE_FALLING, intHandler); //Attach interrupt to bcm pin 23 // forever loop - while (1) { + while (1){ /****************** Ping Out Role ***************************/ - if (role == role_ping_out) { // Radio is in ping mode - + if (role == role_ping_out) // Radio is in ping mode + { //uint8_t gotByte; // Initialize a variable for the incoming response radio.stopListening(); // First, stop listening so we can talk. - printf("Now sending %d as payload. ", counter); // Use a simple byte counter as payload + printf("Now sending %d as payload. ", counter); // Use a simple byte counter as payload timer = millis(); // Record the current microsecond count - radio.startWrite(&counter, 1, false); // Send the counter variable to the other radio - sleep(1); // Try again later + radio.startWrite(&counter, 1, false); // Send the counter variable to the other radio + sleep(1); // Try again later } - /****************** Pong Back Role ***************************/ - + /****************** Pong Back Role ***************************/ + // This is done by using ACK payloads & IRQ } //while 1 } //main - - diff --git a/examples_linux/manualAcknowledgements.cpp b/examples_linux/manualAcknowledgements.cpp new file mode 100644 index 000000000..92eaf3456 --- /dev/null +++ b/examples_linux/manualAcknowledgements.cpp @@ -0,0 +1,260 @@ +/* + * See documentation at https://nRF24.github.io/RF24 + * See License information at root directory of this library + * Author: Brendan Doherty (2bndy5) + */ + +/** + * A simple example of sending data from 1 nRF24L01 transceiver to another + * with manually transmitted (non-automatic) Acknowledgement (ACK) payloads. + * This example still uses ACK packets, but they have no payloads. Instead the + * acknowledging response is sent with `write()`. This tactic allows for more + * updated acknowledgement payload data, where actual ACK payloads' data are + * outdated by 1 transmission because they have to loaded before receiving a + * transmission. + * + * This example was written to be used on 2 devices acting as "nodes". + * Use `ctrl+c` to quit at any time. + */ +#include // time() +#include // strcmp() +#include // cin, cout, endl +#include // string, getline() +#include // CLOCK_MONOTONIC_RAW, timespec, clock_gettime() +#include // RF24, RF24_PA_LOW, delay() + +using namespace std; + +/****************** Linux ***********************/ +// Radio CE Pin, CSN Pin, SPI Speed +// CE Pin uses GPIO number with BCM and SPIDEV drivers, other platforms use their own pin numbering +// CS Pin addresses the SPI bus number at /dev/spidev. +// ie: RF24 radio(, *10+); spidev1.0 is 10, spidev1.1 is 11 etc.. + +// Generic: +RF24 radio(22, 0); +/****************** Linux (BBB,x86,etc) ***********************/ +// See http://nRF24.github.io/RF24/pages.html for more information on usage +// See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA +// See https://www.kernel.org/doc/Documentation/spi/spidev for more information on SPIDEV + +// For this example, we'll be using a payload containing +// a string & an integer number that will be incremented +// on every successful transmission. +// Make a data structure to store the entire payload of different datatypes +struct PayloadStruct { + char message[7]; // only using 6 characters for TX & RX payloads + uint8_t counter; +}; +PayloadStruct payload; + +void setRole(); // prototype to set the node's role +void master(); // prototype of the TX node's behavior +void slave(); // prototype of the RX node's behavior + +// custom defined timer for evaluating transmission time in microseconds +struct timespec startTimer, endTimer; +uint32_t getMicros(); // prototype to get ellapsed time in microseconds + + +int main(int argc, char** argv) { + + // perform hardware check + if (!radio.begin()) { + cout << "radio hardware is not responding!!" << endl; + return 0; // quit now + } + + // append a NULL terminating 0 for printing as a c-string + payload.message[6] = 0; + + // Let these addresses be used for the pair of nodes used in this example + uint8_t address[2][6] = {"1Node", "2Node"}; + // the TX address^ , ^the RX address + // It is very helpful to think of an address as a path instead of as + // an identifying device destination + + // to use different addresses on a pair of radios, we need a variable to + // uniquely identify which address this radio will use to transmit + bool radioNumber = 1; // 0 uses address[0] to transmit, 1 uses address[1] to transmit + + // print example's name + cout << argv[0] << endl; + + // Set the radioNumber via the terminal on startup + cout << "Which radio is this? Enter '0' or '1'. Defaults to '0' "; + string input; + getline(cin, input); + radioNumber = input.length() > 0 && (uint8_t)input[0] == 49; + + // Set the PA Level low to try preventing power supply related problems + // because these examples are likely run with nodes in close proximity to + // each other. + radio.setPALevel(RF24_PA_LOW); // RF24_PA_MAX is default. + + // save on transmission time by setting the radio to only transmit the + // number of bytes we need to transmit a float + radio.setPayloadSize(sizeof(payload)); // char[7] & uint8_t datatypes occupy 8 bytes + + // set the TX address of the RX node into the TX pipe + radio.openWritingPipe(address[radioNumber]); // always uses pipe 0 + + // set the RX address of the TX node into a RX pipe + radio.openReadingPipe(1, address[!radioNumber]); // using pipe 1 + + // For debugging info + // radio.printDetails(); // (smaller) function that prints raw register values + // radio.printPrettyDetails(); // (larger) function that prints human readable data + + // ready to execute program now + setRole(); // calls master() or slave() based on user input + return 0; +} // main + + +/** + * set this node's role from stdin stream. + * this only considers the first char as input. + */ +void setRole() { + string input = ""; + while (!input.length()) { + cout << "*** PRESS 'T' to begin transmitting to the other node\n"; + cout << "*** PRESS 'R' to begin receiving from the other node\n"; + cout << "*** PRESS 'Q' to exit" << endl; + getline(cin, input); + if (input.length() >= 1) { + if (input[0] == 'T' || input[0] == 't') + master(); + else if (input[0] == 'R' || input[0] == 'r') + slave(); + else if (input[0] == 'Q' || input[0] == 'q') + break; + else + cout << input[0] << " is an invalid input. Please try again." << endl; + } + input = ""; // stay in the while loop + } // while +} // setRole() + + +/** + * make this node act as the transmitter + */ +void master() { + + memcpy(payload.message, "Hello ", 6); // set the outgoing message + radio.stopListening(); // put in TX mode + + unsigned int failures = 0; // keep track of failures + while (failures < 6) { + clock_gettime(CLOCK_MONOTONIC_RAW, &startTimer); // start the timer + bool report = radio.write(&payload, sizeof(payload)); // transmit & save the report + + if (report) { + // transmission successful; wait for response and print results + + radio.startListening(); // put in RX mode + unsigned long start_timeout = millis(); // timer to detect no response + while (!radio.available()) { // wait for response + if (millis() - start_timeout > 200) // only wait 200 ms + break; + } + unsigned long ellapsedTime = getMicros(); // end the timer + radio.stopListening(); // put back in TX mode + + // print summary of transactions + uint8_t pipe; + cout << "Transmission successful! "; + if (radio.available(&pipe)) { // is there a payload received? grab the pipe number that received it + uint8_t bytes = radio.getPayloadSize(); // grab the incoming payload size + cout << "Round trip delay = "; + cout << ellapsedTime; // print the timer result + cout << " us. Sent: " << payload.message; // print outgoing message + cout << (unsigned int)payload.counter; // print outgoing counter + PayloadStruct received; + radio.read(&received, sizeof(received)); // get incoming payload + cout << " Recieved " << (unsigned int)bytes; // print incoming payload size + cout << " on pipe " << (unsigned int)pipe; // print RX pipe number + cout << ": " << received.message; // print the incoming message + cout << (unsigned int)received.counter; // print the incoming counter + cout << endl; + payload.counter = received.counter; // save incoming counter for next outgoing counter + } + else { + cout << "Recieved no response." << endl; // no response received + } + } + else { + cout << "Transmission failed or timed out"; // payload was not delivered + cout << endl; + failures++; // increment failure counter + } // report + + // to make this example readable in the terminal + delay(1000); // slow transmissions down by 1 second + } // while + + cout << failures << " failures detected. Leaving TX role." << endl; +} // master + + +/** + * make this node act as the receiver + */ +void slave() { + memcpy(payload.message, "World ", 6); // set the response message + radio.startListening(); // put in RX mode + + time_t startTimer = time(nullptr); // start a timer + while (time(nullptr) - startTimer < 6) { // use 6 second timeout + uint8_t pipe; + if (radio.available(&pipe)) { // is there a payload? get the pipe number that recieved it + uint8_t bytes = radio.getPayloadSize(); // get size of incoming payload + PayloadStruct received; + radio.read(&received, sizeof(received)); // get incoming payload + payload.counter = received.counter + 1; // increment payload for response + + // transmit response & save result to `report` + radio.stopListening(); // put in TX mode + radio.writeFast(&payload, sizeof(payload)); // load response into TX FIFO + bool report = radio.txStandBy(150); // keep retrying for 150 ms + radio.startListening(); // put back in RX mode + + // print summary of transactions + cout << "Received " << (unsigned int)bytes; // print the size of the payload + cout << " bytes on pipe "; + cout << (unsigned int)pipe; // print the pipe number + cout << ": " << received.message; // print incoming message + cout << (unsigned int)received.counter; // print incoming counter + + if (report) { + cout << " Sent: " << payload.message; // print outgoing message + cout << (unsigned int)payload.counter; // print outgoing counter + cout << endl; + } + else { + cout << " Response failed to send." << endl; // failed to send response + } + startTimer = time(nullptr); // reset timer + } // available + } // while + + cout << "Nothing received in 6 seconds. Leaving RX role." << endl; + radio.stopListening(); // recommended idle mode is TX mode +} // slave + + +/** + * Calculate the ellapsed time in microseconds + */ +uint32_t getMicros() { + // this function assumes that the timer was started using + // `clock_gettime(CLOCK_MONOTONIC_RAW, &startTimer);` + + clock_gettime(CLOCK_MONOTONIC_RAW, &endTimer); + uint32_t seconds = endTimer.tv_sec - startTimer.tv_sec; + uint32_t useconds = (endTimer.tv_nsec - startTimer.tv_nsec) / 1000; + + return ((seconds) * 1000 + useconds) + 0.5; +} diff --git a/examples_linux/manual_acknowledgements.py b/examples_linux/manual_acknowledgements.py new file mode 100644 index 000000000..bb9f02e43 --- /dev/null +++ b/examples_linux/manual_acknowledgements.py @@ -0,0 +1,254 @@ +""" +A simple example of sending data from 1 nRF24L01 transceiver to another +with manually transmitted (non-automatic) Acknowledgement (ACK) payloads. +This example still uses ACK packets, but they have no payloads. Instead the +acknowledging response is sent with `write()`. This tactic allows for more +updated acknowledgement payload data, where actual ACK payloads' data are +outdated by 1 transmission because they have to loaded before receiving a +transmission. + +This example was written to be used on 2 devices acting as 'nodes'. +""" +import sys +import argparse +import time +import struct +from RF24 import RF24, RF24_PA_LOW + + +parser = argparse.ArgumentParser( + description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter +) +parser.add_argument( + "-n", + "--node", + type=int, + choices=range(2), + help="the identifying radio number (or node ID number)" +) +parser.add_argument( + "-r", + "--role", + type=int, + choices=range(2), + help="'1' specifies the TX role. '0' specifies the RX role." +) + +########### USER CONFIGURATION ########### +# See https://github.com/TMRh20/RF24/blob/master/pyRF24/readme.md +# Radio CE Pin, CSN Pin, SPI Speed +# CE Pin uses GPIO number with BCM and SPIDEV drivers, other platforms use +# their own pin numbering +# CS Pin addresses the SPI bus number at /dev/spidev. +# ie: RF24 radio(, *10+); spidev1.0 is 10, spidev1.1 is 11 etc.. + +# Generic: +radio = RF24(22, 0) +################## Linux (BBB,x86,etc) ######################### +# See http://nRF24.github.io/RF24/pages.html for more information on usage +# See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA +# See https://www.kernel.org/doc/Documentation/spi/spidev for more +# information on SPIDEV + +# using the python keyword global is bad practice. Instead we'll use a 1 item +# list to store our integer number for the payloads' counter +counter = [0] + + +def master(): + """Transmits a message and an incrementing integer every second, then + wait for a response for up to 200 ms. + """ + radio.stopListening() # put radio in TX mode + failures = 0 + while failures < 6: + # use bytes() to pack our counter data into the payload + # NOTE b"\x00" byte is a c-string's NULL terminating 0 + buffer = b"Hello \x00" + bytes(counter) + start_timer = time.monotonic_ns() # start timer + result = radio.write(buffer) + if not result: + failures += 1 + print("Transmission failed or timed out") + else: + radio.startListening() # put radio in RX mode + timout = time.monotonic() * 1000 + 200 # use 200 ms timeout + # declare a variable to save the incoming response + while not radio.available() and time.monotonic() * 1000 < timout: + pass # wait for incoming payload or timeout + radio.stopListening() # put radio in TX mode + end_timer = time.monotonic_ns() # end timer + print( + "Transmission successful. Sent: {}{}.".format( + buffer[:6].decode("utf-8"), + counter[0] + ), + end=" " + ) + has_payload, pipe_number = radio.available_pipe() + if has_payload: + # grab the incoming payload + received = radio.read(radio.payloadSize) + # NOTE received[7:8] discards NULL terminating 0 + counter[0] = received[7:8][0] # save the counter + print( + "Received {} bytes on pipe {}: {}{}. " + "Round-trip delay: {} us.".format( + radio.payloadSize, + pipe_number, + bytes(received[:6]).decode("utf-8"), + counter[0], + (end_timer - start_timer) / 1000 + ) + ) + else: + print("No response received.") + time.sleep(1) # make example readable by slowing down transmissions + print(failures, "failures detected. Leaving TX role.") + + +def slave(timeout=6): + """Listen for any payloads and print the transaction + + :param int timeout: The number of seconds to wait (with no transmission) + until exiting function. + """ + radio.startListening() # put radio in RX mode + + start_timer = time.monotonic() # start a timer to detect timeout + while (time.monotonic() - start_timer) < timeout: + # receive `count` payloads or wait 6 seconds till timing out + has_payload, pipe_number = radio.available_pipe() + if has_payload: + received = radio.read(radio.payloadSize) # fetch the payload + # NOTE received[7:8] discards NULL terminating 0 + # increment the counter from received payload + counter[0] = received[7:8][0] + 1 if received[7:8][0] < 255 else 0 + # use bytes() to pack our counter data into the payload + # NOTE b"\x00" byte is a c-string's NULL terminating 0 + buffer = b"World \x00" + bytes(counter) + radio.stopListening() # put radio in TX mode + radio.writeFast(buffer) # load response into TX FIFO + # keep retrying to send response for 150 milliseconds + result = radio.txStandBy(150) # save response's result + # NOTE txStandBy() flushes TX FIFO on transmission failure + radio.startListening() # put radio back in RX mode + # print the payload received payload + print( + "Received {} bytes on pipe {}: {}{}.".format( + radio.payloadSize, + pipe_number, + bytes(received[:6]).decode("utf-8"), + received[7:8][0] + ), + end=" " + ) + if result: # did response succeed? + # print response's payload + print( + "Sent: {}{}".format( + buffer[:6].decode("utf-8"), + counter[0] + ) + ) + else: + print("Response failed or timed out") + start_timer = time.monotonic() # reset the timeout timer + + print("Nothing received in 6 seconds. Leaving RX role") + # recommended behavior is to keep in TX mode while idle + radio.stopListening() # put the radio in TX mode + + +def set_role(): + """Set the role using stdin stream. Timeout arg for slave() can be + specified using a space delimiter (e.g. 'R 10' calls `slave(10)`) + + :return: + - True when role is complete & app should continue running. + - False when app should exit + """ + user_input = input( + "*** Enter 'R' for receiver role.\n" + "*** Enter 'T' for transmitter role.\n" + "*** Enter 'Q' to quit example.\n" + ) or "?" + user_input = user_input.split() + if user_input[0].upper().startswith("R"): + if len(user_input) > 1: + slave(int(user_input[1])) + else: + slave() + return True + elif user_input[0].upper().startswith("T"): + master() + return True + elif user_input[0].upper().startswith("Q"): + radio.powerDown() + return False + print(user_input[0], "is an unrecognized input. Please try again.") + return set_role() + + +if __name__ == "__main__": + + args = parser.parse_args() # parse any CLI args + + # initialize the nRF24L01 on the spi bus + if not radio.begin(): + raise RuntimeError("radio hardware is not responding") + + # For this example, we will use different addresses + # An address need to be a buffer protocol object (bytearray) + address = [b"1Node", b"2Node"] + # It is very helpful to think of an address as a path instead of as + # an identifying device destination + + print(sys.argv[0]) # print example name + + # to use different addresses on a pair of radios, we need a variable to + # uniquely identify which address this radio will use to transmit + # 0 uses address[0] to transmit, 1 uses address[1] to transmit + radio_number = args.node # uses default value from `parser` + if args.node is None: # if '--node' arg wasn't specified + radio_number = bool( + int( + input( + "Which radio is this? Enter '0' or '1'. Defaults to '0' " + ) or 0 + ) + ) + + # set the Power Amplifier level to -12 dBm since this test example is + # usually run with nRF24L01 transceivers in close proximity of each other + radio.setPALevel(RF24_PA_LOW) # RF24_PA_MAX is default + + # set the TX address of the RX node into the TX pipe + radio.openWritingPipe(address[radio_number]) # always uses pipe 0 + + # set the RX address of the TX node into a RX pipe + radio.openReadingPipe(1, address[not radio_number]) # using pipe 1 + + # To save time during transmission, we'll set the payload size to be only + # what we need. For this example, we'll be using a byte for the + # payload counter and 7 bytes for the payload message + radio.payloadSize = 8 + + # for debugging, we have 2 options that print a large block of details + # (smaller) function that prints raw register values + # radio.printDetails() + # (larger) function that prints human readable data + # radio.printPrettyDetails() + + try: + if args.role is None: # if not specified with CLI arg '-r' + while set_role(): + pass # continue example until 'Q' is entered + else: # if role was set using CLI args + # run role once and exit + master() if bool(args.role) else slave() + except KeyboardInterrupt: + print(" Keyboard Interrupt detected. Exiting...") + radio.powerDown() + sys.exit() diff --git a/examples_linux/multiceiverDemo.cpp b/examples_linux/multiceiverDemo.cpp new file mode 100644 index 000000000..0e78f683a --- /dev/null +++ b/examples_linux/multiceiverDemo.cpp @@ -0,0 +1,273 @@ +/* + * See documentation at https://nRF24.github.io/RF24 + * See License information at root directory of this library + * Author: Brendan Doherty (2bndy5) + */ + +/** + * A simple example of sending data from as many as 6 nRF24L01 transceivers to + * 1 receiving transceiver. This technique is trademarked by + * Nordic Semiconductors as "MultiCeiver". + * + * This example was written to be used on up to 6 devices acting as TX nodes & + * only 1 device acting as the RX node (that's a maximum of 7 devices). + * Use `ctrl+c` to quit at any time. + */ +#include // time() +#include // strcmp() +#include // cin, cout, endl +#include // string, getline() +#include // CLOCK_MONOTONIC_RAW, timespec, clock_gettime() +#include // RF24, RF24_PA_LOW, delay() + +using namespace std; + +/****************** Linux ***********************/ +// Radio CE Pin, CSN Pin, SPI Speed +// CE Pin uses GPIO number with BCM and SPIDEV drivers, other platforms use their own pin numbering +// CS Pin addresses the SPI bus number at /dev/spidev. +// ie: RF24 radio(, *10+); spidev1.0 is 10, spidev1.1 is 11 etc.. + +// Generic: +RF24 radio(22, 0); +/****************** Linux (BBB,x86,etc) ***********************/ +// See http://nRF24.github.io/RF24/pages.html for more information on usage +// See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA +// See https://www.kernel.org/doc/Documentation/spi/spidev for more information on SPIDEV + + +// For this example, we'll be using 6 addresses; 1 for each TX node +// It is very helpful to think of an address as a path instead of as +// an identifying device destination +// Notice that the last byte is the only byte that changes in the last 5 +// addresses. This is a limitation of the nRF24L01 transceiver for pipes 2-5 +// because they use the same first 4 bytes from pipe 1. +uint64_t address[6] = {0x7878787878LL, + 0xB3B4B5B6F1LL, + 0xB3B4B5B6CDLL, + 0xB3B4B5B6A3LL, + 0xB3B4B5B60FLL, + 0xB3B4B5B605LL}; + + +// For this example, we'll be using a payload containing +// a node ID number and a single integer number that will be incremented +// on every successful transmission. +// Make a data structure to use as a payload. +struct PayloadStruct +{ + unsigned int nodeID; + unsigned int payloadID; +}; +PayloadStruct payload; + +void setRole(); // prototype to set the node's role +void master(unsigned int); // prototype of a TX node's behavior +void slave(); // prototype of the RX node's behavior +void printHelp(string); // prototype to function that explain CLI arg usage + +// custom defined timer for evaluating transmission time in microseconds +struct timespec startTimer, endTimer; +uint32_t getMicros(); // prototype to get ellapsed time in microseconds + + +int main(int argc, char** argv) { + + // perform hardware check + if (!radio.begin()) { + cout << "radio hardware is not responding!!" << endl; + return 0; // quit now + } + + // to use different addresses on a pair of radios, we need a variable to + // uniquely identify which address this radio will use to transmit + unsigned int nodeNumber = 'R'; // 0 uses address[0] to transmit, 1 uses address[1] to transmit + + bool foundArgNode = false; + if (argc > 1) { + if ((argc - 1) != 2) { + // CLI arg "-n"/"--node" needs an option specified for it + // only 1 arg is expected, so only traverse the first "--arg option" pair + printHelp(string(argv[0])); + return 0; + } + else if (strcmp(argv[1], "-n") == 0 || strcmp(argv[1], "--node") == 0) { + // "-n" or "--node" has been specified + foundArgNode = true; + if ((argv[2][0] - 48) < 6) { + nodeNumber = argv[2][0] - 48; + } + else if (argv[2][0] == 'R' || argv[2][0] == 'r') { + nodeNumber = 'R'; + } + else { + printHelp(string(argv[0])); + return 0; + } + } + else { + // "-n"/"--node" arg was not specified + printHelp(string(argv[0])); + return 0; + } + } + + // print example's name + cout << argv[0] << endl; + + // Set the PA Level low to try preventing power supply related problems + // because these examples are likely run with nodes in close proximity to + // each other. + radio.setPALevel(RF24_PA_LOW); // RF24_PA_MAX is default. + + // save on transmission time by setting the radio to only transmit the + // number of bytes we need to transmit a float + radio.setPayloadSize(sizeof(payload)); // 2x int datatype occupy 8 bytes + + // For debugging info + // radio.printDetails(); // (smaller) function that prints raw register values + // radio.printPrettyDetails(); // (larger) function that prints human readable data + + // ready to execute program now + if (!foundArgNode) { + setRole(); // calls master() or slave() based on user input + } + else { + nodeNumber < 6 ? master(nodeNumber) : slave(); + } + return 0; +} + + +/** + * set this node's role from stdin stream. + * this only considers the first char as input. + */ +void setRole() { + + string input = ""; + while (!input.length()) { + cout << "*** Enter a number between 0 and 5 (inclusive) to act as\n"; + cout << " a unique node number that transmits to the RX node.\n"; + cout << "*** PRESS 'R' to begin receiving from the other nodes\n"; + cout << "*** PRESS 'Q' to exit" << endl; + getline(cin, input); + if (input.length() >= 1) { + unsigned int toNumber = (unsigned int)(input[0]) - 48; + if (toNumber < 6 && toNumber >= 0) + master(toNumber); + else if (input[0] == 'R' || input[0] == 'r') + slave(); + else if (input[0] == 'Q' || input[0] == 'q') + break; + else + cout << input[0] << " is an invalid input. Please try again." << endl; + } + input = ""; // stay in the while loop + } // while +} // setRole + + +/** + * act as unique TX node identified by the `role` number + */ +void master(unsigned int role) { + // set the payload's nodeID & reset the payload's identifying number + payload.nodeID = role; + payload.payloadID = 0; + + // Set the address on pipe 0 to the RX node. + radio.stopListening(); // put radio in TX mode + radio.openWritingPipe(address[role]); + + // According to the datasheet, the auto-retry features's delay value should + // be "skewed" to allow the RX node to receive 1 transmission at a time. + // So, use varying delay between retry attempts and 15 (at most) retry attempts + radio.setRetries(((role * 3) % 12) + 3, 15); // maximum value is 15 for both args + + unsigned int failures = 0; + while (failures < 6) { + clock_gettime(CLOCK_MONOTONIC_RAW, &startTimer); // start the timer + bool report = radio.write(&payload, sizeof(payload)); // transmit & save the report + uint32_t timerEllapsed = getMicros(); // end the timer + + if (report) { + // payload was delivered + cout << "Transmission of PayloadID "; + cout << payload.payloadID; // print payload number + cout << " as node " << payload.nodeID; // print node number + cout << " successful! Time to transmit = "; + cout << timerEllapsed << " us" << endl; // print the timer result + } + else { + // payload was not delivered + failures++; + cout << "Transmission failed or timed out" << endl; + } + payload.payloadID++; // increment payload number + + // to make this example readable in the terminal + delay(500); // slow transmissions down by 0.5 second + } // while + cout << failures << " failures detected. Leaving TX role." << endl; +} // master + + +/** + * act as the RX node that receives from up to 6 other TX nodes + */ +void slave() { + + // Set the addresses for all pipes to TX nodes + for (uint8_t i = 0; i < 6; ++i) + radio.openReadingPipe(i, address[i]); + + radio.startListening(); // put radio in RX mode + + time_t startTimer = time(nullptr); // start a timer + while (time(nullptr) - startTimer < 6) { // use 6 second timeout + uint8_t pipe; + if (radio.available(&pipe)) { // is there a payload? get the pipe number that recieved it + uint8_t bytes = radio.getPayloadSize(); // get the size of the payload + radio.read(&payload, bytes); // fetch payload from FIFO + cout << "Received " << (unsigned int)bytes; // print the size of the payload + cout << " bytes on pipe " << (unsigned int)pipe; // print the pipe number + cout << " from node " << payload.nodeID; // print the payload's origin + cout << ". PayloadID: " << payload.payloadID << endl; // print the payload's number + startTimer = time(nullptr); // reset timer + } + } + cout << "Nothing received in 6 seconds. Leaving RX role." << endl; +} // slave + + +/** + * Calculate the ellapsed time in microseconds + */ +uint32_t getMicros() { + // this function assumes that the timer was started using + // `clock_gettime(CLOCK_MONOTONIC_RAW, &startTimer);` + + clock_gettime(CLOCK_MONOTONIC_RAW, &endTimer); + uint32_t seconds = endTimer.tv_sec - startTimer.tv_sec; + uint32_t useconds = (endTimer.tv_nsec - startTimer.tv_nsec) / 1000; + + return ((seconds) * 1000 + useconds) + 0.5; +} + + +/** + * print a manual page of instructions on how to use this example's CLI args + */ +void printHelp(string progName) { + cout << "usage: " << progName << " [-h] [-n {0,1,2,3,4,5,r,R}]\n\n" + << "A simple example of sending data from as many as 6 nRF24L01 transceivers to\n" + << "1 receiving transceiver. This technique is trademarked by\n" + << "Nordic Semiconductors as 'MultiCeiver'.\n" + << "\nThis example was written to be used on up to 6 devices acting as TX nodes with\n" + << "another device acting as a RX node (that's a total of 7 devices).\n" + << "\noptional arguments:\n -h, --help\t\tshow this help message and exit\n" + << " -n {0,1,2,3,4,5,r,R}, --node {0,1,2,3,4,5,r,R}" + << "\n\t\t\t0-5 specifies the identifying node ID number for the TX role." + << "\n\t\t\t'r' or 'R' specifies the RX role." << endl; +} \ No newline at end of file diff --git a/examples_linux/multiceiver_demo.py b/examples_linux/multiceiver_demo.py new file mode 100644 index 000000000..242ae50dd --- /dev/null +++ b/examples_linux/multiceiver_demo.py @@ -0,0 +1,199 @@ +""" +A simple example of sending data from as many as 6 nRF24L01 transceivers to +1 receiving transceiver. This technique is trademarked by +Nordic Semiconductors as "MultiCeiver". + +This example was written to be used on up to 6 devices acting as TX nodes & +only 1 device acting as the RX node (that's a maximum of 7 devices). +""" +import sys +import argparse +import time +import struct +from RF24 import RF24, RF24_PA_LOW + + +parser = argparse.ArgumentParser( + description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter +) +parser.add_argument( + "-n", + "--node", + choices=("0", "1", "2", "3", "4", "5", "R", "r"), + help="the identifying node ID number for the TX role. " + "Use 'R' or 'r' to specify the RX role" +) + +########### USER CONFIGURATION ########### +# See https://github.com/TMRh20/RF24/blob/master/pyRF24/readme.md +# Radio CE Pin, CSN Pin, SPI Speed +# CE Pin uses GPIO number with BCM and SPIDEV drivers, other platforms use +# their own pin numbering +# CS Pin addresses the SPI bus number at /dev/spidev. +# ie: RF24 radio(, *10+); spidev1.0 is 10, spidev1.1 is 11 etc.. + +# Generic: +radio = RF24(22, 0) +################## Linux (BBB,x86,etc) ######################### +# See http://nRF24.github.io/RF24/pages.html for more information on usage +# See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA +# See https://www.kernel.org/doc/Documentation/spi/spidev for more +# information on SPIDEV + +# setup the addresses for all transmitting radio nodes +addresses = [ + b"\x78" * 5, + b"\xF1\xB6\xB5\xB4\xB3", + b"\xCD\xB6\xB5\xB4\xB3", + b"\xA3\xB6\xB5\xB4\xB3", + b"\x0F\xB6\xB5\xB4\xB3", + b"\x05\xB6\xB5\xB4\xB3" +] +# It is very helpful to think of an address as a path instead of as +# an identifying device destination + + +def master(node_number): + """start transmitting to the base station. + + :param int node_number: the node's identifying index (from the + the `addresses` list). This is a required parameter + """ + radio.stopListening() # put radio in TX mode + # set the TX address to the address of the base station. + radio.openWritingPipe(addresses[node_number]) + counter = 0 + failures = 0 + while failures < 6: + counter += 1 + # payloads will include the node_number and a payload ID character + payload = struct.pack(" 1: + slave(int(user_input[1])) + else: + slave() + return True + elif user_input[0].isdigit() and 0 <= int(user_input[0]) <= 5: + master(int(user_input[0])) + return True + elif user_input[0].upper().startswith("Q"): + radio.powerDown() + return False + print(user_input[0], "is an unrecognized input. Please try again.") + return set_role() + + +if __name__ == "__main__": + + args = parser.parse_args() # parse any CLI args + + # initialize the nRF24L01 on the spi bus + if not radio.begin(): + raise RuntimeError("radio hardware is not responding") + + print(sys.argv[0]) # print example name + + # set the Power Amplifier level to -12 dBm since this test example is + # usually run with nRF24L01 transceivers in close proximity of each other + radio.setPALevel(RF24_PA_LOW) # RF24_PA_MAX is default + + # To save time during transmission, we'll set the payload size to be only what + # we need. + # 2 int occupy 8 bytes in memory using len(struct.pack()) + # " -#include -#include -#include -#include "./RF24.h" - -using namespace std; -// -// Hardware configuration -// Configure the appropriate pins for your connections - -/****************** Linux ***********************/ -// Radio CE Pin, CSN Pin, SPI Speed -// CE Pin uses GPIO number with BCM and SPIDEV drivers, other platforms use their own pin numbering -// CS Pin addresses the SPI bus number at /dev/spidev. -// ie: RF24 radio(, *10+); spidev1.0 is 10, spidev1.1 is 11 etc.. - -// Generic: -RF24 radio(22,0); - -/****************** Linux (BBB,x86,etc) ***********************/ -// See http://tmrh20.github.io/RF24/pages.html for more information on usage -// See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA -// See https://www.kernel.org/doc/Documentation/spi/spidev for more information on SPIDEV - -/**************************************************************/ - -// Radio pipe addresses for the 2 nodes to communicate. -const uint64_t pipes[2] = {0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL}; - -const int min_payload_size = 4; -const int max_payload_size = 32; -const int payload_size_increments_by = 1; -int next_payload_size = min_payload_size; - -char receive_payload[max_payload_size + 1]; // +1 to allow room for a terminating NULL char - -int main(int argc, char** argv) -{ - - bool role_ping_out = 1, role_pong_back = 0; - bool role = 0; - - // Print preamble: - cout << "RF24/examples/pingpair_dyn/\n"; - - // Setup and configure rf radio - radio.begin(); - radio.enableDynamicPayloads(); - radio.setRetries(5, 15); - radio.printDetails(); - - - /********* Role chooser ***********/ - - printf("\n ************ Role Setup ***********\n"); - string input = ""; - char myChar = {0}; - cout << "Choose a role: Enter 0 for receiver, 1 for transmitter (CTRL+C to exit) \n>"; - getline(cin, input); - - if (input.length() == 1) { - myChar = input[0]; - if (myChar == '0') { - cout << "Role: Pong Back, awaiting transmission " << endl << endl; - } else { - cout << "Role: Ping Out, starting transmission " << endl << endl; - role = role_ping_out; - } - } - /***********************************/ - - if (role == role_ping_out) { - radio.openWritingPipe(pipes[0]); - radio.openReadingPipe(1, pipes[1]); - } else { - radio.openWritingPipe(pipes[1]); - radio.openReadingPipe(1, pipes[0]); - radio.startListening(); - } - - // forever loop - while (1) { - - if (role == role_ping_out) { - // The payload will always be the same, what will change is how much of it we send. - static char send_payload[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ789012"; - - // First, stop listening so we can talk. - radio.stopListening(); - - // Take the time, and send it. This will block until complete - printf("Now sending length %i...", next_payload_size); - radio.write(send_payload, next_payload_size); - - // Now, continue listening - radio.startListening(); - - // Wait here until we get a response, or timeout - unsigned long started_waiting_at = millis(); - bool timeout = false; - while (!radio.available() && !timeout) { - if (millis() - started_waiting_at > 500) { - timeout = true; - } - } - - // Describe the results - if (timeout) { - printf("Failed, response timed out.\n\r"); - } else { - // Grab the response, compare, and send to debugging spew - uint8_t len = radio.getDynamicPayloadSize(); - radio.read(receive_payload, len); - - // Put a zero at the end for easy printing - receive_payload[len] = 0; - - // Spew it - printf("Got response size=%i value=%s\n\r", len, receive_payload); - } - - // Update size for next time. - next_payload_size += payload_size_increments_by; - if (next_payload_size > max_payload_size) { - next_payload_size = min_payload_size; - } - - // Try again 1s later - delay(100); - } - - // - // Pong back role. Receive each packet, dump it out, and send it back - // - - if (role == role_pong_back) { - // if there is data ready - if (radio.available()) { - // Dump the payloads until we've gotten everything - uint8_t len = 0; - - while (radio.available()) { - // Fetch the payload, and see if this was the last one. - len = radio.getDynamicPayloadSize(); - radio.read(receive_payload, len); - - // Put a zero at the end for easy printing - receive_payload[len] = 0; - - // Spew it - printf("Got payload size=%i value=%s\n\r", len, receive_payload); - } - - // First, stop listening so we can talk - radio.stopListening(); - - // Send the final one back. - radio.write(receive_payload, len); - printf("Sent response.\n\r"); - - // Now, resume listening so we catch the next packets. - radio.startListening(); - } - } - } -} - - diff --git a/examples_linux/pingpair_dyn.py b/examples_linux/pingpair_dyn.py deleted file mode 100755 index 08a470fc2..000000000 --- a/examples_linux/pingpair_dyn.py +++ /dev/null @@ -1,134 +0,0 @@ -#!/usr/bin/env python - -# -# Example using Dynamic Payloads -# -# This is an example of how to use payloads of a varying (dynamic) size. -# - -from __future__ import print_function -import time -from RF24 import * -import RPi.GPIO as GPIO - -irq_gpio_pin = None - -########### USER CONFIGURATION ########### -# See https://github.com/TMRh20/RF24/blob/master/pyRF24/readme.md -# Radio CE Pin, CSN Pin, SPI Speed -# CE Pin uses GPIO number with BCM and SPIDEV drivers, other platforms use their own pin numbering -# CS Pin addresses the SPI bus number at /dev/spidev. -# ie: RF24 radio(, *10+); spidev1.0 is 10, spidev1.1 is 11 etc.. - -# Generic: -radio = RF24(22,0); - -# RPi Alternate, with SPIDEV - Note: Edit RF24/arch/BBB/spi.cpp and set 'this->device = "/dev/spidev0.0";;' or as listed in /dev -#radio = RF24(22, 0); - - -# Setup for connected IRQ pin, GPIO 24 on RPi B+; uncomment to activate -# irq_gpio_pin = 24 - -########################################## -def try_read_data(channel=0): - if radio.available(): - while radio.available(): - len = radio.getDynamicPayloadSize() - receive_payload = radio.read(len) - print('Got payload size={} value="{}"'.format(len, receive_payload.decode('utf-8'))) - # First, stop listening so we can talk - radio.stopListening() - - # Send the final one back. - radio.write(receive_payload) - print('Sent response.') - - # Now, resume listening so we catch the next packets. - radio.startListening() - - -pipes = [0xF0F0F0F0E1, 0xF0F0F0F0D2] -min_payload_size = 4 -max_payload_size = 32 -payload_size_increments_by = 1 -next_payload_size = min_payload_size -inp_role = 'none' -send_payload = b'ABCDEFGHIJKLMNOPQRSTUVWXYZ789012' -millis = lambda: int(round(time.time() * 1000)) - -print('pyRF24/examples/pingpair_dyn/') -radio.begin() -radio.enableDynamicPayloads() -radio.setRetries(5, 15) -radio.printDetails() - -print(' ************ Role Setup *********** ') -while (inp_role != '0') and (inp_role != '1'): - inp_role = str(input('Choose a role: Enter 0 for receiver, 1 for transmitter (CTRL+C to exit) ')) - -if inp_role == '0': - print('Role: Pong Back, awaiting transmission') - if irq_gpio_pin is not None: - # set up callback for irq pin - GPIO.setmode(GPIO.BCM) - GPIO.setup(irq_gpio_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP) - GPIO.add_event_detect(irq_gpio_pin, GPIO.FALLING, callback=try_read_data) - - radio.openWritingPipe(pipes[1]) - radio.openReadingPipe(1, pipes[0]) - radio.startListening() -else: - print('Role: Ping Out, starting transmission') - radio.openWritingPipe(pipes[0]) - radio.openReadingPipe(1, pipes[1]) - -# forever loop -while 1: - if inp_role == '1': # ping out - # The payload will always be the same, what will change is how much of it we send. - - # First, stop listening so we can talk. - radio.stopListening() - - # Take the time, and send it. This will block until complete - print('Now sending length {} ... '.format(next_payload_size), end="") - radio.write(send_payload[:next_payload_size]) - - # Now, continue listening - radio.startListening() - - # Wait here until we get a response, or timeout - started_waiting_at = millis() - timeout = False - while (not radio.available()) and (not timeout): - if (millis() - started_waiting_at) > 500: - timeout = True - - # Describe the results - if timeout: - print('failed, response timed out.') - else: - # Grab the response, compare, and send to debugging spew - len = radio.getDynamicPayloadSize() - receive_payload = radio.read(len) - - # Spew it - print('got response size={} value="{}"'.format(len, receive_payload.decode('utf-8'))) - - # Update size for next time. - next_payload_size += payload_size_increments_by - if next_payload_size > max_payload_size: - next_payload_size = min_payload_size - time.sleep(0.1) - else: - # Pong back role. Receive each packet, dump it out, and send it back - - # if there is data ready - if irq_gpio_pin is None: - # no irq pin is set up -> poll it - try_read_data() - else: - # callback routine set for irq pin takes care for reading - - # do nothing, just sleeps in order not to burn cpu by looping - time.sleep(1000) diff --git a/examples_linux/streamingData.cpp b/examples_linux/streamingData.cpp new file mode 100644 index 000000000..bb27baf48 --- /dev/null +++ b/examples_linux/streamingData.cpp @@ -0,0 +1,291 @@ +/* + * See documentation at https://nRF24.github.io/RF24 + * See License information at root directory of this library + * Author: Brendan Doherty (2bndy5) + */ + +/** + * A simple example of streaming data from 1 nRF24L01 transceiver to another. + * + * This example was written to be used on 2 devices acting as "nodes". + * Use `ctrl+c` to quit at any time. + */ +#include // abs() +#include // time() +#include // strcmp() +#include // cin, cout, endl +#include // string, getline() +#include // CLOCK_MONOTONIC_RAW, timespec, clock_gettime() +#include // RF24, RF24_PA_LOW, delay() + +using namespace std; + +/****************** Linux ***********************/ +// Radio CE Pin, CSN Pin, SPI Speed +// CE Pin uses GPIO number with BCM and SPIDEV drivers, other platforms use their own pin numbering +// CS Pin addresses the SPI bus number at /dev/spidev. +// ie: RF24 radio(, *10+); spidev1.0 is 10, spidev1.1 is 11 etc.. + +// Generic: +RF24 radio(22, 0); +/****************** Linux (BBB,x86,etc) ***********************/ +// See http://nRF24.github.io/RF24/pages.html for more information on usage +// See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA +// See https://www.kernel.org/doc/Documentation/spi/spidev for more information on SPIDEV + +// For this example, we'll be sending 32 payloads each containing +// 32 bytes of data that looks like ASCII art when printed to the serial +// monitor. The TX node and RX node needs only a single 32 byte buffer. +#define SIZE 32 // this is the maximum for this example. (minimum is 1) +char buffer[SIZE + 1]; // for the RX node +unsigned int counter = 0; // for counting the number of received payloads +void makePayload(uint8_t); // prototype to construct a payload dynamically +void setRole(); // prototype to set the node's role +void master(); // prototype of the TX node's behavior +void slave(); // prototype of the RX node's behavior +void printHelp(string); // prototype to function that explain CLI arg usage + +// custom defined timer for evaluating transmission time in microseconds +struct timespec startTimer, endTimer; +uint32_t getMicros(); // prototype to get ellapsed time in microseconds + + +int main(int argc, char** argv) { + + // perform hardware check + if (!radio.begin()) { + cout << "radio hardware is not responding!!" << endl; + return 0; // quit now + } + + // add a NULL terminating 0 for printing as a c-string + buffer[SIZE] = 0; + + // Let these addresses be used for the pair of nodes used in this example + uint8_t address[2][6] = {"1Node", "2Node"}; + // the TX address^ , ^the RX address + // It is very helpful to think of an address as a path instead of as + // an identifying device destination + + // to use different addresses on a pair of radios, we need a variable to + // uniquely identify which address this radio will use to transmit + bool radioNumber = 1; // 0 uses address[0] to transmit, 1 uses address[1] to transmit + + bool foundArgNode = false; + bool foundArgRole = false; + bool role = false; + if (argc > 1) { + // CLI args are specified + if ((argc - 1) % 2 != 0) { + // some CLI arg doesn't have an option specified for it + printHelp(string(argv[0])); // all args need an option in this example + return 0; + } + else { + // iterate through args starting after program name + int a = 1; + while (a < argc) { + bool invalidOption = false; + if (strcmp(argv[a], "-n") == 0 || strcmp(argv[a], "--node") == 0) { + // "-n" or "--node" has been specified + foundArgNode = true; + if (argv[a + 1][0] - 48 <= 1) { + radioNumber = (argv[a + 1][0] - 48) == 1; + } + else { + // option is invalid + invalidOption = true; + } + } + else if (strcmp(argv[a], "-r") == 0 || strcmp(argv[a], "--role") == 0) { + // "-r" or "--role" has been specified + foundArgRole = true; + if (argv[a + 1][0] - 48 <= 1) { + role = (argv[a + 1][0] - 48) == 1; + } + else { + // option is invalid + invalidOption = true; + } + } + if (invalidOption) { + printHelp(string(argv[0])); + return 0; + } + a += 2; + } // while + if (!foundArgNode && !foundArgRole) { + // no valid args were specified + printHelp(string(argv[0])); + return 0; + } + } // else + } // if + + // print example's name + cout << argv[0] << endl; + + if (!foundArgNode) { + // Set the radioNumber via the terminal on startup + cout << "Which radio is this? Enter '0' or '1'. Defaults to '0' "; + string input; + getline(cin, input); + radioNumber = input.length() > 0 && (uint8_t)input[0] == 49; + } + + // save on transmission time by setting the radio to only transmit the + // number of bytes we need to transmit a float + radio.setPayloadSize(SIZE); // default value is the maximum 32 bytes + + // Set the PA Level low to try preventing power supply related problems + // because these examples are likely run with nodes in close proximity to + // each other. + radio.setPALevel(RF24_PA_LOW); // RF24_PA_MAX is default. + + // set the TX address of the RX node into the TX pipe + radio.openWritingPipe(address[radioNumber]); // always uses pipe 0 + + // set the RX address of the TX node into a RX pipe + radio.openReadingPipe(1, address[!radioNumber]); // using pipe 1 + + // For debugging info + // radio.printDetails(); // (smaller) function that prints raw register values + // radio.printPrettyDetails(); // (larger) function that prints human readable data + + // ready to execute program now + if (!foundArgRole) { // if CLI arg "-r"/"--role" was not specified + setRole(); // calls master() or slave() based on user input + } + else { // if CLI arg "-r"/"--role" was specified + role ? master() : slave(); // based on CLI arg option + } + return 0; +} + + +/** + * set this node's role from stdin stream. + * this only considers the first char as input. + */ +void setRole() { + string input = ""; + while (!input.length()) { + cout << "*** PRESS 'T' to begin transmitting to the other node\n"; + cout << "*** PRESS 'R' to begin receiving from the other node\n"; + cout << "*** PRESS 'Q' to exit" << endl; + getline(cin, input); + if (input.length() >= 1) { + if (input[0] == 'T' || input[0] == 't') + master(); + else if (input[0] == 'R' || input[0] == 'r') + slave(); + else if (input[0] == 'Q' || input[0] == 'q') + break; + else + cout << input[0] << " is an invalid input. Please try again." << endl; + } + input = ""; // stay in the while loop + } // while +} // setRole() + + +/** + * make this node act as the transmitter + */ +void master() { + radio.stopListening(); // put radio in TX mode + + unsigned int failures = 0; // keep track of failures + uint8_t i = 0; + clock_gettime(CLOCK_MONOTONIC_RAW, &startTimer); // start the timer + while (i < SIZE) { + makePayload(i); + if (!radio.writeFast(&buffer, SIZE)) { + failures++; + radio.reUseTX(); + } else { + i++; + } + + if (failures >= 100) { + // most likely no device is listening for the data stream + cout << "Too many failures detected. "; + cout << "Aborting at payload " << buffer[0]; + break; + } + } // while + uint32_t ellapsedTime = getMicros(); // end the timer + cout << "Time to transmit data = "; + cout << ellapsedTime; // print the timer result + cout << " us. " << failures; // print number of retries + cout << " failures detected. Leaving TX role." << endl; +} // master + + +/** + * make this node act as the receiver + */ +void slave() { + + counter = 0; + radio.startListening(); // put radio in RX mode + time_t startTimer = time(nullptr); // start a timer + while (time(nullptr) - startTimer < 6) { // use 6 second timeout + if (radio.available()) { // is there a payload + radio.read(&buffer, SIZE); // fetch payload from FIFO + cout << "Received: " << buffer; // print the payload's value + cout << " - " << counter << endl; // print the counter + counter++; // increment counter + startTimer = time(nullptr); // reset timer + } + } + radio.stopListening(); // use TX mode for idle behavior + + cout << "Nothing received in 6 seconds. Leaving RX role." << endl; +} + + +/** + * Make a single payload based on position in stream. + * This example employs this function to save on memory allocated. + */ +void makePayload(uint8_t i) { + + // let the first character be an identifying alphanumeric prefix + // this lets us see which payload didn't get received + buffer[0] = i + (i < 26 ? 65 : 71); + for (uint8_t j = 0; j < SIZE - 1; ++j) { + char chr = j >= (SIZE - 1) / 2 + abs((SIZE - 1) / 2 - i); + chr |= j < (SIZE - 1) / 2 - abs((SIZE - 1) / 2 - i); + buffer[j + 1] = chr + 48; + } +} + + +/** + * Calculate the ellapsed time in microseconds + */ +uint32_t getMicros() { + // this function assumes that the timer was started using + // `clock_gettime(CLOCK_MONOTONIC_RAW, &startTimer);` + + clock_gettime(CLOCK_MONOTONIC_RAW, &endTimer); + uint32_t seconds = endTimer.tv_sec - startTimer.tv_sec; + uint32_t useconds = (endTimer.tv_nsec - startTimer.tv_nsec) / 1000; + + return ((seconds) * 1000 + useconds) + 0.5; +} + + +/** + * print a manual page of instructions on how to use this example's CLI args + */ +void printHelp(string progName) { + cout << "usage: " << progName << " [-h] [-n {0,1}] [-r {0,1}]\n\n" + << "A simple example of streaming data from 1 nRF24L01 transceiver to another.\n" + << "\nThis example was written to be used on 2 devices acting as 'nodes'.\n" + << "\noptional arguments:\n -h, --help\t\tshow this help message and exit\n" + << " -n {0,1}, --node {0,1}\n\t\t\tthe identifying radio number\n" + << " -r {0,1}, --role {0,1}\n\t\t\t'1' specifies the TX role." + << " '0' specifies the RX role." << endl; +} \ No newline at end of file diff --git a/examples_linux/streaming_data.py b/examples_linux/streaming_data.py new file mode 100644 index 000000000..09c3a8e29 --- /dev/null +++ b/examples_linux/streaming_data.py @@ -0,0 +1,219 @@ +""" +A simple example of streaming data from 1 nRF24L01 transceiver to another. + +This example was written to be used on 2 devices acting as 'nodes'. +""" +import sys +import argparse +import time +from RF24 import RF24, RF24_PA_LOW + + +parser = argparse.ArgumentParser( + description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter +) +parser.add_argument( + "-n", + "--node", + type=int, + choices=range(2), + help="the identifying radio number (or node ID number)" +) +parser.add_argument( + "-r", + "--role", + type=int, + choices=range(2), + help="'1' specifies the TX role. '0' specifies the RX role." +) + +########### USER CONFIGURATION ########### +# See https://github.com/TMRh20/RF24/blob/master/pyRF24/readme.md +# Radio CE Pin, CSN Pin, SPI Speed +# CE Pin uses GPIO number with BCM and SPIDEV drivers, other platforms use +# their own pin numbering +# CS Pin addresses the SPI bus number at /dev/spidev. +# ie: RF24 radio(, *10+); spidev1.0 is 10, spidev1.1 is 11 etc.. + +# Generic: +radio = RF24(22, 0) +################## Linux (BBB,x86,etc) ######################### +# See http://nRF24.github.io/RF24/pages.html for more information on usage +# See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA +# See https://www.kernel.org/doc/Documentation/spi/spidev for more +# information on SPIDEV + +# Specify the number of bytes in the payload. This is also used to +# specify the number of payloads in 1 stream of data +SIZE = 32 # this is the default maximum payload size + + +def make_buffer(buf_iter): + """Returns a dynamically created payloads + + :param int buf_iter: The position of the payload in the data stream + """ + # we'll use `SIZE` for the number of payloads in the list and the + # payloads' length + # prefix payload with a sequential letter to indicate which + # payloads were lost (if any) + buff = bytes([buf_iter + (65 if 0 <= buf_iter < 26 else 71)]) + for j in range(SIZE - 1): + char = bool(j >= (SIZE - 1) / 2 + abs((SIZE - 1) / 2 - buf_iter)) + char |= bool(j < (SIZE - 1) / 2 - abs((SIZE - 1) / 2 - buf_iter)) + buff += bytes([char + 48]) + return buff + + +def master(count=1): + """Uses all 3 levels of the TX FIFO to send a stream of data + + :param int count: how many times to transmit the stream of data. + """ + radio.stopListening() # put radio in TX mode + radio.flush_tx() # clear the TX FIFO so we can use all 3 levels + failures = 0 # keep track of manual retries + start_timer = time.monotonic_ns() # start timer + for multiplier in range(count): # repeat transmit the same data stream + buf_iter = 0 # iterator of payloads for the while loop + while buf_iter < SIZE: # cycle through all the payloads + buffer = make_buffer(buf_iter) # make a payload + + if not radio.writeFast(buffer): # transmission failed + failures += 1 # increment manual retry count + if failures > 99 and buf_iter < 7 and multiplier < 2: + # we need to prevent an infinite loop + print( + "Too many failures detected. Aborting at payload ", + buffer[0] + ) + multiplier = count # be sure to exit the for loop + break # exit the while loop + radio.reUseTX() # resend payload in top level of TX FIFO + else: # transmission succeeded + buf_iter += 1 + end_timer = time.monotonic_ns() # end timer + print( + "Time to transmit data = {} us. Detected {} failures.".format( + (end_timer - start_timer) / 1000, + failures + ) + ) + + +def slave(timeout=6): + """Listen for any payloads and print them out (suffixed with received + counter) + + :param int timeout: The number of seconds to wait (with no transmission) + until exiting function. + """ + radio.startListening() # put radio in RX mode + count = 0 # keep track of the number of received payloads + start_timer = time.monotonic() # start timer + while (time.monotonic() - start_timer) < timeout: + if radio.available(): + count += 1 + # retreive the received packet's payload + receive_payload = radio.read(radio.payloadSize) + print("Received: {} - {}".format(receive_payload, count)) + start_timer = time.monotonic() # reset timer on every RX payload + + # recommended behavior is to keep in TX mode while idle + radio.stopListening() # put the radio in TX mode + + +def set_role(): + """Set the role using stdin stream. Role args can be specified using space + delimiters (e.g. 'R 10' calls `slave(10)` & 'T 3' calls `master(3)`) + + :return: + - True when role is complete & app should continue running. + - False when app should exit + """ + user_input = input( + "*** Enter 'R' for receiver role.\n" + "*** Enter 'T' for transmitter role.\n" + "*** Enter 'Q' to quit example.\n" + ) or "?" + user_input = user_input.split() + if user_input[0].upper().startswith("R"): + if len(user_input) > 1: + slave(int(user_input[1])) + else: + slave() + return True + elif user_input[0].upper().startswith("T"): + if len(user_input) > 1: + master(int(user_input[1])) + else: + master() + return True + elif user_input[0].upper().startswith("Q"): + radio.powerDown() + return False + print(user_input[0], "is an unrecognized input. Please try again.") + return set_role() + + +if __name__ == "__main__": + + args = parser.parse_args() # parse any CLI args + + # initialize the nRF24L01 on the spi bus + if not radio.begin(): + raise RuntimeError("radio hardware is not responding") + + # For this example, we will use different addresses + # An address need to be a buffer protocol object (bytearray) + address = [b"1Node", b"2Node"] + # It is very helpful to think of an address as a path instead of as + # an identifying device destination + + print(sys.argv[0]) # print example name + + # to use different addresses on a pair of radios, we need a variable to + # uniquely identify which address this radio will use to transmit + # 0 uses address[0] to transmit, 1 uses address[1] to transmit + radio_number = args.node # uses default value from `parser` + if args.node is None: # if '--node' arg wasn't specified + radio_number = bool( + int( + input( + "Which radio is this? Enter '0' or '1'. Defaults to '0' " + ) or 0 + ) + ) + + # set the Power Amplifier level to -12 dBm since this test example is + # usually run with nRF24L01 transceivers in close proximity of each other + radio.setPALevel(RF24_PA_LOW) # RF24_PA_MAX is default + + # set the TX address of the RX node into the TX pipe + radio.openWritingPipe(address[radio_number]) # always uses pipe 0 + + # set the RX address of the TX node into a RX pipe + radio.openReadingPipe(1, address[not radio_number]) # using pipe 1 + + # To save time during transmission, we'll set the payload size to be only + # what we need. For this example, we'll be using the default maximum 32 + radio.payloadSize = SIZE + + # for debugging, we have 2 options that print a large block of details + # (smaller) function that prints raw register values + # radio.printDetails() + # (larger) function that prints human readable data + # radio.printPrettyDetails() + + try: + if args.role is None: # if not specified with CLI arg '-r' + while set_role(): + pass # continue example until 'Q' is entered + else: # if role was set using CLI args + # run role once and exit + master() if bool(args.role) else slave() + except KeyboardInterrupt: + print(" Keyboard Interrupt detected. Exiting...") + radio.powerDown() + sys.exit() diff --git a/examples_linux/transfer.cpp b/examples_linux/transfer.cpp deleted file mode 100644 index b285b7036..000000000 --- a/examples_linux/transfer.cpp +++ /dev/null @@ -1,163 +0,0 @@ -/* -TMRh20 2014 - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -/** General Data Transfer Rate Test - * This example demonstrates basic data transfer functionality with the - updated library. This example will display the transfer rates acheived using - the slower form of high-speed transfer using blocking-writes. - */ - -#include -#include -#include -#include -#include -#include - -using namespace std; -// -// Hardware configuration -// - -/****************** Linux ***********************/ -// Radio CE Pin, CSN Pin, SPI Speed -// CE Pin uses GPIO number with BCM and SPIDEV drivers, other platforms use their own pin numbering -// CS Pin addresses the SPI bus number at /dev/spidev. -// ie: RF24 radio(, *10+); spidev1.0 is 10, spidev1.1 is 11 etc.. - -// Generic: -RF24 radio(22,0); - -/****************** Linux (BBB,x86,etc) ***********************/ -// See http://tmrh20.github.io/RF24/pages.html for more information on usage -// See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA -// See https://www.kernel.org/doc/Documentation/spi/spidev for more information on SPIDEV - -/**************************************************************/ - -// Radio pipe addresses for the 2 nodes to communicate. -const uint64_t addresses[2] = {0xABCDABCD71LL, 0x544d52687CLL}; - -uint8_t data[32]; -unsigned long startTime, stopTime, counter, rxTimer = 0; - -int main(int argc, char** argv) -{ - - bool role_ping_out = 1, role_pong_back = 0; - bool role = 0; - - // Print preamble: - - cout << "RF24/examples/Transfer/\n"; - - radio.begin(); // Setup and configure rf radio - radio.setChannel(1); - radio.setPALevel(RF24_PA_MAX); - radio.setDataRate(RF24_1MBPS); - radio.setAutoAck(1); // Ensure autoACK is enabled - radio.setRetries(2, 15); // Optionally, increase the delay between retries & # of retries - radio.setCRCLength(RF24_CRC_8); // Use 8-bit CRC for performance - radio.printDetails(); - /********* Role chooser ***********/ - - printf("\n ************ Role Setup ***********\n"); - string input = ""; - char myChar = {0}; - cout << "Choose a role: Enter 0 for receiver, 1 for transmitter (CTRL+C to exit)\n>"; - getline(cin, input); - - if (input.length() == 1) { - myChar = input[0]; - if (myChar == '0') { - cout << "Role: Pong Back, awaiting transmission " << endl << endl; - } else { - cout << "Role: Ping Out, starting transmission " << endl << endl; - role = role_ping_out; - } - } - /***********************************/ - - if (role == role_ping_out) { - radio.openWritingPipe(addresses[1]); - radio.openReadingPipe(1, addresses[0]); - radio.stopListening(); - } else { - radio.openWritingPipe(addresses[0]); - radio.openReadingPipe(1, addresses[1]); - radio.startListening(); - } - - for (int i = 0; i < 32; i++) { - data[i] = rand() % 255; //Load the buffer with random data - } - - // forever loop - while (1) { - - if (role == role_ping_out) { - sleep(2); - printf("Initiating Basic Data Transfer\n\r"); - - long int cycles = 10000; //Change this to a higher or lower number. - - // unsigned long pauseTime = millis(); //Uncomment if autoAck == 1 ( NOACK ) - startTime = millis(); - - for (int i = 0; i < cycles; i++) { //Loop through a number of cycles - data[0] = i; //Change the first byte of the payload for identification - if (!radio.writeFast(&data, 32)) { //Write to the FIFO buffers - counter++; //Keep count of failed payloads - } - - - //This is only required when NO ACK ( enableAutoAck(0) ) payloads are used - /* if(millis() - pauseTime > 3){ // Need to drop out of TX mode every 4ms if sending a steady stream of multicast data - pauseTime = millis(); - radio.txStandBy(); // This gives the PLL time to sync back up - } - */ - } - stopTime = millis(); - - if (!radio.txStandBy()) { - counter += 3; - } - - float numBytes = cycles * 32; - float rate = numBytes / (stopTime - startTime); - - printf("Transfer complete at %.2f KB/s \n\r", rate); - printf("%lu of %lu Packets Failed to Send\n\r", counter, cycles); - counter = 0; - - } - - if (role == role_pong_back) { - while (radio.available()) { - radio.read(&data, 32); - counter++; - } - if (millis() - rxTimer > 1000) { - rxTimer = millis(); - printf("Rate: "); - float numBytes = counter * 32; - printf("%.2f KB/s \n\r", numBytes / 1000); - printf("Payload Count: %lu \n\r", counter); - counter = 0; - } - } - - } // loop -} // main - - - - - - diff --git a/keywords.txt b/keywords.txt index ebb66ffb5..5e39f1e88 100644 --- a/keywords.txt +++ b/keywords.txt @@ -1,22 +1,59 @@ - RF24 KEYWORD1 - begin KEYWORD2 - setChannel KEYWORD2 - setPayloadSize KEYWORD2 - getPayloadSize KEYWORD2 - startListening KEYWORD2 - stopListening KEYWORD2 - write KEYWORD2 - writeFast KEYWORD2 - writeBlocking KEYWORD2 - txStandBy KEYWORD2 - available KEYWORD2 - read KEYWORD2 - openWritingPipe KEYWORD2 - openReadingPipe KEYWORD2 - setPALevel KEYWORD2 - setAutoAck KEYWORD2 - setRetries KEYWORD2 - setCRCLength KEYWORD2 - printDetails KEYWORD2 - powerUp KEYWORD2 - printf_begin KEYWORD2 +RF24 KEYWORD1 +begin KEYWORD2 +isChipConnected KEYWORD2 +startListening KEYWORD2 +stopListening KEYWORD2 +available KEYWORD2 +read KEYWORD2 +write KEYWORD2 +openWritingPipe KEYWORD2 +openReadingPipe KEYWORD2 +printDetails KEYWORD2 +printPrettyDetails KEYWORD2 +rxFifoFull KEYWORD2 +powerDown KEYWORD2 +powerUp KEYWORD2 +writeFast KEYWORD2 +writeBlocking KEYWORD2 +txStandBy KEYWORD2 +writeAckPayload KEYWORD2 +whatHappened KEYWORD2 +startFastWrite KEYWORD2 +startWrite KEYWORD2 +reUseTX KEYWORD2 +flush_tx KEYWORD2 +flush_rx KEYWORD2 +testCarrier KEYWORD2 +testRPD KEYWORD2 +isValid KEYWORD2 +closeReadingPipe KEYWORD2 +failureDetected KEYWORD2 +setAddressWidth KEYWORD2 +setRetries KEYWORD2 +setChannel KEYWORD2 +getChannel KEYWORD2 +setPayloadSize KEYWORD2 +getPayloadSize KEYWORD2 +getDynamicPayloadSize KEYWORD2 +enableAckPayload KEYWORD2 +disableAckPayload KEYWORD2 +enableDynamicPayloads KEYWORD2 +disableDynamicPayloads KEYWORD2 +isPVariant KEYWORD2 +setAutoAck KEYWORD2 +setPALevel KEYWORD2 +getPALevel KEYWORD2 +getARC KEYWORD2 +setDataRate KEYWORD2 +getDataRate KEYWORD2 +setCRCLength KEYWORD2 +getCRCLength KEYWORD2 +disableCRC KEYWORD2 +maskIRQ KEYWORD2 +txDelay KEYWORD2 +csDelay KEYWORD2 +startConstCarrier KEYWORD2 +stopConstCarrier KEYWORD2 +enableDynamicAck KEYWORD2 +isAckPayloadAvailable KEYWORD2 +printf_begin KEYWORD2 \ No newline at end of file diff --git a/library.properties b/library.properties index f277acfca..48e478078 100644 --- a/library.properties +++ b/library.properties @@ -5,5 +5,5 @@ maintainer=TMRh20,Avamander sentence=Radio driver, OSI layer 2 library for nrf24L01(+) modules. paragraph=Core library for nRF24L01(+) communication. Simple to use for beginners, but offers advanced configuration options. Many examples are included to demonstrate various modes of communication. category=Communication -url=https://tmrh20.github.io/RF24/ +url=https://nRF24.github.io/RF24/ architectures=* diff --git a/pyRF24/crossunixccompiler.py b/pyRF24/crossunixccompiler.py index 0532c15e9..881d907d3 100644 --- a/pyRF24/crossunixccompiler.py +++ b/pyRF24/crossunixccompiler.py @@ -4,10 +4,12 @@ def register(): - sys.modules['distutils.crossunixccompiler'] = sys.modules[__name__] - ccompiler.compiler_class['crossunix'] = (__name__, - 'CrossUnixCCompiler', - 'UNIX-style compiler for cross compilation') + sys.modules["distutils.crossunixccompiler"] = sys.modules[__name__] + ccompiler.compiler_class["crossunix"] = ( + __name__, + "CrossUnixCCompiler", + "UNIX-style compiler for cross compilation", + ) def try_remove_all(lst, starts): @@ -16,23 +18,53 @@ def try_remove_all(lst, starts): class CrossUnixCCompiler(unixccompiler.UnixCCompiler): def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts): - try_remove_all(self.compiler_so, ('-m64', '-fstack-protector-strong', '-mtune=generic')) - try_remove_all(cc_args, '-I/usr') - try_remove_all(pp_opts, '-I/usr') - return unixccompiler.UnixCCompiler._compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts) - - def link(self, target_desc, objects, - output_filename, output_dir=None, libraries=None, - library_dirs=None, runtime_library_dirs=None, - export_symbols=None, debug=0, extra_preargs=None, - extra_postargs=None, build_temp=None, target_lang=None): - try_remove_all(self.library_dirs, ('/usr')) - return unixccompiler.UnixCCompiler.link(self, target_desc, objects, output_filename, output_dir, libraries, - library_dirs, runtime_library_dirs, export_symbols, debug, - extra_preargs, extra_postargs, build_temp, target_lang) + try_remove_all( + self.compiler_so, ("-m64", "-fstack-protector-strong", "-mtune=generic") + ) + try_remove_all(cc_args, "-I/usr") + try_remove_all(pp_opts, "-I/usr") + return unixccompiler.UnixCCompiler._compile( + self, obj, src, ext, cc_args, extra_postargs, pp_opts + ) + + def link( + self, + target_desc, + objects, + output_filename, + output_dir=None, + libraries=None, + library_dirs=None, + runtime_library_dirs=None, + export_symbols=None, + debug=0, + extra_preargs=None, + extra_postargs=None, + build_temp=None, + target_lang=None, + ): + try_remove_all(self.library_dirs, ("/usr")) + return unixccompiler.UnixCCompiler.link( + self, + target_desc, + objects, + output_filename, + output_dir, + libraries, + library_dirs, + runtime_library_dirs, + export_symbols, + debug, + extra_preargs, + extra_postargs, + build_temp, + target_lang, + ) def _fix_lib_args(self, libraries, library_dirs, runtime_library_dirs): self.__class__ = unixccompiler.UnixCCompiler - ret = unixccompiler.UnixCCompiler._fix_lib_args(self, libraries, library_dirs, runtime_library_dirs) + ret = unixccompiler.UnixCCompiler._fix_lib_args( + self, libraries, library_dirs, runtime_library_dirs + ) self.__class__ = CrossUnixCCompiler return ret diff --git a/pyRF24/pyRF24.cpp b/pyRF24/pyRF24.cpp index 86d9b0ea6..9cf760473 100644 --- a/pyRF24/pyRF24.cpp +++ b/pyRF24/pyRF24.cpp @@ -5,7 +5,7 @@ namespace bp = boost::python; // ******************** explicit wrappers ************************** // for methods which need it - mostly for buffer operations -// +// void throw_ba_exception(void) { @@ -126,13 +126,17 @@ bp::tuple available_wrap(RF24& ref) return bp::make_tuple(result, pipe); } +void setPALevel_wrap(RF24& ref, rf24_pa_dbm_e level) { + ref.setPALevel(level, 1); +} + BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(txStandBy_wrap1, RF24::txStandBy, 0, 2) //BOOST_PYTHON_FUNCTION_OVERLOADS(txStandBy_wrap2, RF24::txStandBy, 1, 2) // ******************** enums ************************** // from both RF24 and bcm2835 -// +// BOOST_PYTHON_MODULE(RF24){ @@ -239,13 +243,13 @@ bp::enum_< bcm2835SPIChipSelect>("bcm2835SPIChipSelect") "RF24_CRC_16", RF24_CRC_16).export_values() ; - bp::enum_< rf24_datarate_e>("rf24_datarate_e") + bp::enum_("rf24_datarate_e") .value("RF24_1MBPS", RF24_1MBPS) .value("RF24_2MBPS", RF24_2MBPS) .value("RF24_250KBPS", RF24_250KBPS) .export_values(); - bp::enum_< rf24_pa_dbm_e>("rf24_pa_dbm_e") + bp::enum_("rf24_pa_dbm_e") .value("RF24_PA_MIN", RF24_PA_MIN) .value("RF24_PA_LOW", RF24_PA_LOW) .value("RF24_PA_HIGH", RF24_PA_HIGH) @@ -255,19 +259,21 @@ bp::enum_< bcm2835SPIChipSelect>("bcm2835SPIChipSelect") // ******************** RF24 class ************************** // - bp::class_< RF24 >( "RF24", bp::init< uint8_t, uint8_t >(( bp::arg("_cepin"), bp::arg("_cspin")))) + bp::class_< RF24 >("RF24", bp::init< uint8_t, uint8_t >((bp::arg("_cepin"), bp::arg("_cspin")))) #if defined (RF24_LINUX) && !defined (MRAA) - .def( bp::init< uint8_t, uint8_t, uint32_t >(( bp::arg("_cepin"), bp::arg("_cspin"), bp::arg("spispeed") )) ) + .def(bp::init< uint8_t, uint8_t, uint32_t >((bp::arg("_cepin"), bp::arg("_cspin"), bp::arg("spispeed")))) #endif - .def("available", (bool (::RF24::* )( ))( &::RF24::available )) - .def("available_pipe", &available_wrap ) // needed to rename this method as python does not allow such overloading + .def("available", (bool (::RF24::*)())(&::RF24::available)) + .def("available_pipe", &available_wrap) // needed to rename this method as python does not allow such overloading .def("begin", &RF24::begin) .def("closeReadingPipe", &RF24::closeReadingPipe) .def("disableCRC", &RF24::disableCRC) .def("enableAckPayload", &RF24::enableAckPayload) .def("enableDynamicAck", &RF24::enableDynamicAck) .def("enableDynamicPayloads", &RF24::enableDynamicPayloads) + .def("disableDynamicPayloads", &RF24::disableDynamicPayloads) .def("flush_tx", &RF24::flush_tx) + .def("flush_rx", &RF24::flush_rx) .def("getCRCLength", &RF24::getCRCLength) .def("getDataRate", &RF24::getDataRate) .def("getDynamicPayloadSize", &RF24::getDynamicPayloadSize) @@ -275,41 +281,43 @@ bp::enum_< bcm2835SPIChipSelect>("bcm2835SPIChipSelect") .def("isAckPayloadAvailable", &RF24::isAckPayloadAvailable) .def("isPVariant", &RF24::isPVariant) .def("isValid", &RF24::isValid) - .def("maskIRQ", &RF24::maskIRQ, ( bp::arg("tx_ok"), bp::arg("tx_fail"), bp::arg("rx_ready"))) + .def("maskIRQ", &RF24::maskIRQ, (bp::arg("tx_ok"), bp::arg("tx_fail"), bp::arg("rx_ready"))) .def("openReadingPipe", &openReadingPipe_wrap, (bp::arg("number"), bp::arg("address"))) - .def("openReadingPipe", (void (::RF24::* )(::uint8_t,::uint64_t ))( &::RF24::openReadingPipe), (bp::arg("number"), bp::arg("address"))) + .def("openReadingPipe", (void (::RF24::*)(::uint8_t,::uint64_t))(&::RF24::openReadingPipe), (bp::arg("number"), bp::arg("address"))) .def("openWritingPipe", &openWritingPipe_wrap, (bp::arg("address"))) - .def("openWritingPipe", (void (::RF24::* )(::uint64_t ))( &::RF24::openWritingPipe), ( bp::arg("address"))) + .def("openWritingPipe", (void (::RF24::*)(::uint64_t))(&::RF24::openWritingPipe), (bp::arg("address"))) .def("powerDown", &RF24::powerDown) .def("powerUp", &RF24::powerUp) .def("printDetails", &RF24::printDetails) + .def("printPrettyDetails", &RF24::printPrettyDetails) .def("reUseTX", &RF24::reUseTX) .def("read", &read_wrap, (bp::arg("maxlen"))) .def("rxFifoFull", &RF24::rxFifoFull) .def("setAddressWidth", &RF24::setAddressWidth) - .def("setAutoAck", (void (::RF24::* )( bool ))( &::RF24::setAutoAck ), ( bp::arg("enable"))) - .def("setAutoAck", (void (::RF24::* )(::uint8_t, bool ))( &::RF24::setAutoAck ), ( bp::arg("pipe"), bp::arg("enable"))) - .def("setCRCLength", &RF24::setCRCLength, ( bp::arg("length"))) - .def("setChannel", &RF24::setChannel, ( bp::arg("channel"))) - .def("setDataRate", &RF24::setDataRate, ( bp::arg("speed"))) - .def("setPALevel", &RF24::setPALevel, ( bp::arg("level"), bp::arg("lnaEnable")=1)) + .def("setAutoAck", (void (::RF24::*)(bool))(&::RF24::setAutoAck), (bp::arg("enable"))) + .def("setAutoAck", (void (::RF24::*)(::uint8_t, bool))(&::RF24::setAutoAck), (bp::arg("pipe"), bp::arg("enable"))) + .def("setCRCLength", &RF24::setCRCLength, (bp::arg("length"))) + .def("setDataRate", &RF24::setDataRate, (bp::arg("speed"))) + .def("setPALevel", &RF24::setPALevel, (bp::arg("level"), bp::arg("lnaEnable")=1)) + .def("setPALevel", &setPALevel_wrap, (bp::arg("level"))) .def("setRetries", &RF24::setRetries, (bp::arg("delay"), bp::arg("count"))) - .def("startFastWrite", &startFastWrite_wrap1, ( bp::arg("buf"), bp::arg("len"), bp::arg("multicast"))) - .def("startFastWrite", &startFastWrite_wrap2, ( bp::arg("buf"), bp::arg("len"), bp::arg("multicast"), bp::arg("startTx"))) + .def("startFastWrite", &startFastWrite_wrap1, (bp::arg("buf"), bp::arg("len"), bp::arg("multicast"))) + .def("startFastWrite", &startFastWrite_wrap2, (bp::arg("buf"), bp::arg("len"), bp::arg("multicast"), bp::arg("startTx"))) .def("startListening", &RF24::startListening) - .def("startWrite", &startWrite_wrap, ( bp::arg("buf"), bp::arg("len"), bp::arg("multicast"))) + .def("startWrite", &startWrite_wrap, (bp::arg("buf"), bp::arg("len"), bp::arg("multicast"))) .def("stopListening", &RF24::stopListening) .def("testCarrier", &RF24::testCarrier) .def("testRPD", &RF24::testRPD) - .def("txStandBy", (bool (::RF24::* )(::uint32_t, bool))(&RF24::txStandBy), txStandBy_wrap1( bp::args("timeout", "startTx"))) + .def("txStandBy", (bool (::RF24::*)(::uint32_t, bool))(&RF24::txStandBy), txStandBy_wrap1(bp::args("timeout", "startTx"))) .def("whatHappened", &whatHappened_wrap) - .def("startConstCarrier",&RF24::startConstCarrier, ( bp::arg("level"), bp::arg("channel"))) + .def("startConstCarrier", &RF24::startConstCarrier, (bp::arg("level"), bp::arg("channel"))) .def("stopConstCarrier",&RF24::stopConstCarrier) - .def("write", &write_wrap1, ( bp::arg("buf"))) - .def("write", &write_wrap2, ( bp::arg("buf"), bp::arg("multicast"))) - .def("writeAckPayload", writeAckPayload_wrap, ( bp::arg("pipe"), bp::arg("buf"))) - .def("writeBlocking", &writeBlocking_wrap, ( bp::arg("buf"), bp::arg("timeout"))) - .def("writeFast", &writeFast_wrap1, ( bp::arg("buf"))) - .def("writeFast", &writeFast_wrap2, ( bp::arg("buf"), bp::arg("multicast"))) + .def("write", &write_wrap1, (bp::arg("buf"))) + .def("write", &write_wrap2, (bp::arg("buf"), bp::arg("multicast"))) + .def("writeAckPayload", writeAckPayload_wrap, (bp::arg("pipe"), bp::arg("buf"))) + .def("writeBlocking", &writeBlocking_wrap, (bp::arg("buf"), bp::arg("timeout"))) + .def("writeFast", &writeFast_wrap1, (bp::arg("buf"))) + .def("writeFast", &writeFast_wrap2, (bp::arg("buf"), bp::arg("multicast"))) + .add_property("channel", &RF24::getChannel, &RF24::setChannel) .add_property("payloadSize", &RF24::getPayloadSize, &RF24::setPayloadSize) - .def_readwrite( "failureDetected", &RF24::failureDetected );} + .def_readwrite("failureDetected", &RF24::failureDetected);} diff --git a/pyRF24/pyRF24Mesh/setup.py b/pyRF24/pyRF24Mesh/setup.py index 64ae359db..f7d5679b8 100644 --- a/pyRF24/pyRF24Mesh/setup.py +++ b/pyRF24/pyRF24Mesh/setup.py @@ -4,14 +4,14 @@ import sys if sys.version_info >= (3,): - BOOST_LIB = 'boost_python3' + BOOST_LIB = "boost_python3" else: - BOOST_LIB = 'boost_python' + BOOST_LIB = "boost_python" -module_RF24Mesh = Extension('RF24Mesh', - libraries=['rf24mesh', 'rf24network', BOOST_LIB], - sources=['pyRF24Mesh.cpp']) +module_RF24Mesh = Extension( + "RF24Mesh", + libraries=["rf24mesh", "rf24network", BOOST_LIB], + sources=["pyRF24Mesh.cpp"], +) -setup(name='RF24Mesh', - version='1.0', - ext_modules=[module_RF24Mesh]) +setup(name="RF24Mesh", version="1.0", ext_modules=[module_RF24Mesh]) diff --git a/pyRF24/pyRF24Network/setup.py b/pyRF24/pyRF24Network/setup.py index b56fa264b..a215c2bab 100644 --- a/pyRF24/pyRF24Network/setup.py +++ b/pyRF24/pyRF24Network/setup.py @@ -4,15 +4,12 @@ import sys if sys.version_info >= (3,): - BOOST_LIB = 'boost_python3' + BOOST_LIB = "boost_python3" else: - BOOST_LIB = 'boost_python' + BOOST_LIB = "boost_python" -module_RF24Network = Extension('RF24Network', - libraries=['rf24network', BOOST_LIB], - sources=['pyRF24Network.cpp']) +module_RF24Network = Extension( + "RF24Network", libraries=["rf24network", BOOST_LIB], sources=["pyRF24Network.cpp"] +) -setup(name='RF24Network', - version='1.0', - ext_modules=[module_RF24Network] - ) +setup(name="RF24Network", version="1.0", ext_modules=[module_RF24Network]) diff --git a/pyRF24/readme.md b/pyRF24/readme.md index b58563de7..3aa14f78b 100644 --- a/pyRF24/readme.md +++ b/pyRF24/readme.md @@ -1,2 +1,2 @@ Python Wrapper for RF24 -See http://tmrh20.github.io/RF24 for more information +See http://nRF24.github.io/RF24 for more information diff --git a/pyRF24/setup.py b/pyRF24/setup.py index f8ace892a..e2acbee12 100644 --- a/pyRF24/setup.py +++ b/pyRF24/setup.py @@ -5,13 +5,21 @@ import setuptools import crossunixccompiler -version = '' +version = "" def process_configparams(): - global version - - with open('../Makefile.inc') as f: + version = "" # using python keyword `global` is bad practice + + # NOTE current repo directory structure requires the use of + # `python3 setup.py build` and `python3 setup.py install` + # where `pip3 install ./pyRF24` copies pyRF24 directory to + # `tmp` folder that doesn't have the needed `../Makefile.inc` + # NOTE can't access "../Makefile.inc" from working dir because + # it's relative. Brute force absolute path dynamically. + script_dir = os.path.split(os.path.abspath(os.getcwd()))[0] + abs_file_path = os.path.join(script_dir, "Makefile.inc") + with open(abs_file_path) as f: config_lines = f.read().splitlines() cflags = os.getenv("CFLAGS", "") @@ -29,20 +37,20 @@ def process_configparams(): os.environ[identifier] = value os.environ["CFLAGS"] = cflags - + return version if sys.version_info >= (3,): - BOOST_LIB = 'boost_python3' + BOOST_LIB = "boost_python3" else: - BOOST_LIB = 'boost_python' + BOOST_LIB = "boost_python" -process_configparams() +version = process_configparams() crossunixccompiler.register() -module_RF24 = setuptools.Extension('RF24', - libraries=['rf24', BOOST_LIB], - sources=['pyRF24.cpp']) +module_RF24 = setuptools.Extension("RF24", + libraries=["rf24", BOOST_LIB], + sources=["pyRF24.cpp"]) -setuptools.setup(name='RF24', +setuptools.setup(name="RF24", version=version, ext_modules=[module_RF24]) diff --git a/tests/native/pingpair_irq.pde b/tests/native/pingpair_irq.pde index cced6d19b..8bce21be7 100644 --- a/tests/native/pingpair_irq.pde +++ b/tests/native/pingpair_irq.pde @@ -48,7 +48,7 @@ const uint64_t pipe = 0xE8E8F0F0E1LL; // // The various roles supported by this sketch -typedef enum { +typedef enum{ role_sender = 1, role_receiver } role_e; @@ -62,8 +62,7 @@ role_e role; // Interrupt handler, check the radio because we got an IRQ void check_radio(void); -void setup(void) -{ +void setup(void){ // // Role // @@ -74,7 +73,7 @@ void setup(void) delay(20); // Just to get a solid reading on the role pin // read the address pin, establish our role - if (digitalRead(role_pin)) { + if (digitalRead(role_pin)){ role = role_sender; } else { role = role_receiver; @@ -97,6 +96,7 @@ void setup(void) // We will be using the Ack Payload feature, so please enable it radio.enableAckPayload(); + radio.enableDynamicPayloads(); // needed for using ACK payloads // // Open pipes to other nodes for communication @@ -115,9 +115,8 @@ void setup(void) // Start listening // - if (role == role_receiver) { + if (role == role_receiver) radio.startListening(); - } // // Dump the configuration of the rf unit for debugging @@ -148,7 +147,7 @@ void loop(void) // Sender role. Repeatedly send the current time // - if (role == role_sender) { + if (role == role_sender){ // Take the time, and send it. unsigned long time = millis(); printf("Now sending %lu\n\r", time); @@ -171,43 +170,43 @@ void check_radio(void) radio.whatHappened(tx, fail, rx); // Have we successfully transmitted? - if (tx) { - if (role == role_sender) { + if (tx){ + if (role == role_sender){ printf("Send:OK\n\r"); } - if (role == role_receiver) { + if (role == role_receiver){ printf("Ack Payload:Sent\n\r"); } } // Have we failed to transmit? - if (fail) { - if (role == role_sender) { + if (fail){ + if (role == role_sender){ printf("Send:Failed\n\r"); } - if (role == role_receiver) { + if (role == role_receiver){ printf("Ack Payload:Failed\n\r"); } } // Transmitter can power down for now, because // the transmission is done. - if ((tx || fail) && (role == role_sender)) { + if ((tx || fail) && (role == role_sender)){ radio.powerDown(); } // Did we receive a message? - if (rx) { + if (rx){ // If we're the sender, we've received an ack payload - if (role == role_sender) { + if (role == role_sender){ radio.read(&message_count, sizeof(message_count)); printf("Ack:%lu\n\r", (unsigned long) message_count); } // If we're the receiver, we've received a time message - if (role == role_receiver) { + if (role == role_receiver){ // Get this payload and dump it static unsigned long got_time; radio.read(&got_time, sizeof(got_time)); diff --git a/tests/pingpair_test/pingpair_test.pde b/tests/pingpair_test/pingpair_test.pde index 39007905c..189298fed 100644 --- a/tests/pingpair_test/pingpair_test.pde +++ b/tests/pingpair_test/pingpair_test.pde @@ -113,7 +113,7 @@ void one_failed(void) } // -// Setup +// Setup // void setup(void) @@ -173,13 +173,14 @@ void setup(void) // We will be using the Ack Payload feature, so please enable it radio.enableAckPayload(); + radio.enableDynamicPayloads(); // needed for using ACK payloads // Config 2 is special radio config - if (configuration == '2') { + if (configuration == '2'){ radio.setCRCLength(RF24_CRC_8); radio.setDataRate(RF24_250KBPS); radio.setChannel(10); - } else { + }else{ //Otherwise, default radio config // Optional: Increase CRC length for improved reliability @@ -193,23 +194,23 @@ void setup(void) } // Config 3 is static payloads only - if (configuration == '3') { + if (configuration == '3'){ next_payload_size = 16; payload_size_increments_by = 0; radio.setPayloadSize(next_payload_size); - } else { + }else{ // enable dynamic payloads radio.enableDynamicPayloads(); } // Config 4 tests out a higher pipe ## - if (configuration == '4' && role == role_sender) { + if (configuration == '4' && role == role_sender){ // Set top 4 bytes of the address in pipe 1 radio.openReadingPipe(1, pipe & 0xFFFFFFFF00ULL); // indicate the pipe to use pipe_number = 5; - } else if (role == role_sender) { + }else if (role == role_sender){ radio.openReadingPipe(5, 0); } @@ -220,9 +221,9 @@ void setup(void) // This simple sketch opens a single pipe for these two nodes to communicate // back and forth. One listens on it, the other talks to it. - if (role == role_sender) { + if (role == role_sender){ radio.openWritingPipe(pipe); - } else { + }else{ radio.openReadingPipe(pipe_number, pipe); } @@ -230,7 +231,7 @@ void setup(void) // Start listening // - if (role == role_receiver) { + if (role == role_receiver){ radio.startListening(); } @@ -247,7 +248,7 @@ void setup(void) attachInterrupt(0, check_radio, FALLING); delay(50); - if (role == role_receiver) { + if (role == role_receiver){ printf("\n\r+OK "); } } @@ -265,19 +266,18 @@ char* prbuf_in = prbuf; char* prbuf_out = prbuf; // -// Loop +// Loop // static uint32_t message_count = 0; static uint32_t last_message_count = 0; -void loop(void) -{ +void loop(void){ // // Sender role. Repeatedly send the current time // - if (role == role_sender && !done) { + if (role == role_sender && !done){ // The payload will always be the same, what will change is how much of it we send. static char send_payload[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ789012"; @@ -290,7 +290,7 @@ void loop(void) // Update size for next time. next_payload_size += payload_size_increments_by; - if (next_payload_size > max_payload_size) { + if (next_payload_size > max_payload_size){ next_payload_size = min_payload_size; } @@ -298,7 +298,7 @@ void loop(void) delay(interval); // Timeout if we have not received anything back ever - if (!last_message_count && millis() > interval * 100) { + if (!last_message_count && millis() > interval * 100){ printf("No responses received. Are interrupts connected??\n\r"); done = true; } @@ -313,7 +313,7 @@ void loop(void) // size_t write_length = prbuf_in - prbuf_out; - if (write_length) { + if (write_length){ Serial.write(reinterpret_cast(prbuf_out), write_length); prbuf_out += write_length; } @@ -321,17 +321,16 @@ void loop(void) // // Stop the test if we're done and report results // - if (done && !notified) { + if (done && !notified){ notified = true; printf("\n\r+OK "); - if (passed) { + if (passed){ printf("PASS\n\r\n\r"); - } else { + }else{ printf("FAIL\n\r\n\r"); } } - } void check_radio(void) @@ -341,48 +340,47 @@ void check_radio(void) radio.whatHappened(tx, fail, rx); // Have we successfully transmitted? - if (tx) { - if (role == role_sender) { + if (tx){ + if (role == role_sender){ prbuf_in += sprintf(prbuf_in, "Send:OK "); } - if (role == role_receiver) { + if (role == role_receiver){ prbuf_in += sprintf(prbuf_in, "Ack Payload:Sent\n\r"); } } // Have we failed to transmit? - if (fail) { - if (role == role_sender) { + if (fail){ + if (role == role_sender){ prbuf_in += sprintf(prbuf_in, "Send:Failed "); // log status of this line one_failed(); } - if (role == role_receiver) { + if (role == role_receiver){ prbuf_in += sprintf(prbuf_in, "Ack Payload:Failed\n\r"); } } // Not powering down since radio is in standby mode - //if ( ( tx || fail ) && ( role == role_sender ) ) - //radio.powerDown(); + //if (( tx || fail ) && ( role == role_sender )){ radio.powerDown(); } // Did we receive a message? - if (rx) { + if (rx){ // If we're the sender, we've received an ack payload - if (role == role_sender) { + if (role == role_sender){ radio.read(&message_count, sizeof(message_count)); prbuf_in += sprintf(prbuf_in, "Ack:%lu ", message_count); // is this ack what we were expecting? to account // for failures, we simply want to make sure we get a // DIFFERENT ack every time. - if ((message_count != last_message_count) || (configuration == '3' && message_count == 16)) { + if ((message_count != last_message_count) || (configuration == '3' && message_count == 16)){ prbuf_in += sprintf(prbuf_in, "OK "); one_ok(); - } else { + }else{ prbuf_in += sprintf(prbuf_in, "FAILED "); one_failed(); } @@ -390,14 +388,14 @@ void check_radio(void) } // If we're the receiver, we've received a time message - if (role == role_receiver) { + if (role == role_receiver){ // Get this payload and dump it size_t len = max_payload_size; memset(receive_payload, 0, max_payload_size); - if (configuration == '3') { + if (configuration == '3'){ len = next_payload_size; - } else { + }else{ len = radio.getDynamicPayloadSize(); } @@ -415,6 +413,5 @@ void check_radio(void) ++message_count; } - } } diff --git a/utility/ATTiny/RF24_arch_config.h b/utility/ATTiny/RF24_arch_config.h index 585d066e5..4b527a899 100644 --- a/utility/ATTiny/RF24_arch_config.h +++ b/utility/ATTiny/RF24_arch_config.h @@ -21,12 +21,21 @@ #include #endif -#include +#include #include #define _SPI SPI +#if !defined(RF24_CSN_SETTLE_LOW_DELAY) +#define RF24_CSN_SETTLE_LOW_DELAY 11 +#endif + +#if !defined(RF24_CSN_SETTLE_HIGH_DELAY) +#define RF24_CSN_SETTLE_HIGH_DELAY 100 +#endif + + #ifdef SERIAL_DEBUG #define IF_SERIAL_DEBUG(x) ({x;}) #else diff --git a/utility/ATXMegaD3/README.md b/utility/ATXMegaD3/README.md index 06cf94547..6b704fa71 100644 --- a/utility/ATXMegaD3/README.md +++ b/utility/ATXMegaD3/README.md @@ -1,4 +1,4 @@ -This is a fork from **http://tmrh20.github.io/RF24** which can be build as a static library for Atmel Studio 7. +This is a fork from **http://nRF24.github.io/RF24** which can be build as a static library for Atmel Studio 7. Not all files are needed. @@ -28,7 +28,7 @@ Only ATXMega256D3 is supported right now! ## Notes The millisecond functionality is based on the TCE0 so don't use these pins as IO. -The operating frequency of the uC is 32MHz. If else change the TCE0 registers appropriatly in function **__start_timer()** in **compatibility.c** file for your frequency. +The operating frequency of the uC is 32MHz. If else change the TCE0 registers appropriatly in function **__start_timer()** in **compatibility.c** file for your frequency. ## Usage @@ -45,10 +45,10 @@ Declare the rf24 radio with **RF24 radio(XMEGA_PORTC_PIN3, XMEGA_SPI_PORT_C);** First parameter is the CE pin which can be any available pin on the uC. -Second parameter is the CS which can be on port C (**XMEGA_SPI_PORT_C**) or on port D (**XMEGA_SPI_PORT_D**). +Second parameter is the CS which can be on port C (**XMEGA_SPI_PORT_C**) or on port D (**XMEGA_SPI_PORT_D**). Call the **__start_timer()** to start the millisecond timer. -** For further information please see http://tmrh20.github.io/RF24 for all documentation** +** For further information please see http://nRF24.github.io/RF24 for all documentation** diff --git a/utility/ATXMegaD3/RF24_arch_config.h b/utility/ATXMegaD3/RF24_arch_config.h index 9e1ba3fb9..5b10d1936 100644 --- a/utility/ATXMegaD3/RF24_arch_config.h +++ b/utility/ATXMegaD3/RF24_arch_config.h @@ -62,7 +62,7 @@ typedef uint16_t prog_uint16_t; //#define printf_P printf //#define strlen_P strlen //#define PROGMEM -//#define pgm_read_word(p) (*(p)) +//#define pgm_read_word(p) (*(p)) #define PRIPSTR "%s" //#define pgm_read_byte(p) (*(p)) @@ -80,4 +80,4 @@ typedef uint16_t prog_uint16_t; #endif // __RF24_ARCH_CONFIG_H__ -/*@}*/ +/*@}*/ diff --git a/utility/ATXMegaD3/compatibility.h b/utility/ATXMegaD3/compatibility.h index e6fc03c78..31e8c4c23 100644 --- a/utility/ATXMegaD3/compatibility.h +++ b/utility/ATXMegaD3/compatibility.h @@ -1,4 +1,4 @@ -/* +/* * File: compatiblity.h * Author: purinda * @@ -46,4 +46,4 @@ void update_milisec(); #endif /* COMPATIBLITY_H */ -/*@}*/ \ No newline at end of file +/*@}*/ \ No newline at end of file diff --git a/utility/ATXMegaD3/gpio.cpp b/utility/ATXMegaD3/gpio.cpp index 897847a07..23a644179 100644 --- a/utility/ATXMegaD3/gpio.cpp +++ b/utility/ATXMegaD3/gpio.cpp @@ -25,7 +25,7 @@ void GPIO::close(int port) // Nothing to do with close; } -int read(int port) +int GPIO::read(int port) { uint8_t pin; PORT_t* p = GPIO_getPort(port, &pin); diff --git a/utility/ATXMegaD3/gpio.h b/utility/ATXMegaD3/gpio.h index 50acc91cc..01c0b1896 100644 --- a/utility/ATXMegaD3/gpio.h +++ b/utility/ATXMegaD3/gpio.h @@ -14,7 +14,7 @@ * @{ */ #ifndef GPIO_H -#define GPIO_H +#define GPIO_H #include #include "gpio_helper.h" @@ -46,7 +46,6 @@ class GPIO { /** * Similar to Arduino digitalRead(pin); * @param port - * @param value */ static int read(int port); @@ -62,4 +61,4 @@ class GPIO { }; #endif /* GPIO_H */ -/*@}*/ \ No newline at end of file +/*@}*/ \ No newline at end of file diff --git a/utility/MRAA/RF24_arch_config.h b/utility/MRAA/RF24_arch_config.h index 391e21b80..0699ca9d0 100644 --- a/utility/MRAA/RF24_arch_config.h +++ b/utility/MRAA/RF24_arch_config.h @@ -19,8 +19,8 @@ //#include // Precompiled arduino x86 based utiltime for timing functions // GCC a Arduino Missing -#define HIGH 1 -#define LOW 0 +#define HIGH 1 +#define LOW 0 #define _BV(x) (1<<(x)) #define pgm_read_word(p) (*(p)) #define pgm_read_byte(p) (*(p)) diff --git a/utility/MRAA/compatibility.h b/utility/MRAA/compatibility.h index b1f804a5d..f881d358e 100644 --- a/utility/MRAA/compatibility.h +++ b/utility/MRAA/compatibility.h @@ -1,4 +1,4 @@ -/* +/* * File: compatiblity.h * Author: purinda * diff --git a/utility/MRAA/gpio.h b/utility/MRAA/gpio.h index 312aec906..e30935a6a 100644 --- a/utility/MRAA/gpio.h +++ b/utility/MRAA/gpio.h @@ -1,13 +1,13 @@ -/* +/* * TMRh20 2015 - * + * */ #ifndef RF24_ARCH_GPIO_H -#define RF24_ARCH_GPIO_H +#define RF24_ARCH_GPIO_H /** * @file spi.h -* \cond HIDDEN_SYMBOLS +* @cond HIDDEN_SYMBOLS * Class declaration for GPIO helper files */ #include @@ -46,7 +46,6 @@ class GPIO { /** * * @param port - * @param value */ int read(int port); @@ -64,7 +63,7 @@ class GPIO { //mraa::Gpio* gpio_1; /** gpio object for cs_pin **/ }; /** - * \endcond + * @endcond */ -#endif /* RF24_ARCH_GPIO_H */ +#endif /* RF24_ARCH_GPIO_H */ diff --git a/utility/RPi/RF24_arch_config.h b/utility/RPi/RF24_arch_config.h index 59e8c9cfe..eda562c94 100644 --- a/utility/RPi/RF24_arch_config.h +++ b/utility/RPi/RF24_arch_config.h @@ -39,7 +39,7 @@ #endif #define digitalWrite(pin, value) bcm2835_gpio_write(pin, value) -#define pinMode(pin, value) bcm2835_gpio_fsel(pin,value); +#define pinMode(pin, value) bcm2835_gpio_fsel(pin,value) #define OUTPUT BCM2835_GPIO_FSEL_OUTP - +#define INPUT BCM2835_GPIO_FSEL_INPT #endif \ No newline at end of file diff --git a/utility/RPi/compatibility.c b/utility/RPi/compatibility.c index 9b8846044..b62edaca6 100644 --- a/utility/RPi/compatibility.c +++ b/utility/RPi/compatibility.c @@ -9,5 +9,5 @@ uint32_t millis(void) ms = ((now.tv_sec * 1000000) + now.tv_usec) / 1000; return (ms); - -} \ No newline at end of file + +} diff --git a/utility/RPi/interrupt.c b/utility/RPi/interrupt.c index 05e41fac4..b942f63f0 100644 --- a/utility/RPi/interrupt.c +++ b/utility/RPi/interrupt.c @@ -59,7 +59,7 @@ int waitForInterrupt(int pin, int mS) // A one character read appars to be enough. // Followed by a seek to reset it. - (void) read(fd, &c, 1); + (void) (read(fd, &c, 1) + 1); lseek(fd, 0, SEEK_SET); return x; @@ -153,7 +153,7 @@ int attachInterrupt(int pin, int mode, void (* function)(void)) ioctl(sysFds[bcmGpioPin], FIONREAD, &count); for (i = 0; i < count; ++i) { - read(sysFds[bcmGpioPin], &c, 1); + (void) (read(sysFds[bcmGpioPin], &c, 1) + 1); } isrFunctions[pin] = function; diff --git a/utility/SPIDEV/compatibility.c b/utility/SPIDEV/compatibility.c index fe0a0c88e..e7595fb37 100644 --- a/utility/SPIDEV/compatibility.c +++ b/utility/SPIDEV/compatibility.c @@ -48,3 +48,4 @@ uint32_t __millis() mtime = ((seconds) * 1000 + useconds / 1000.0) + 0.5; return mtime; } + diff --git a/utility/SPIDEV/compatibility.h b/utility/SPIDEV/compatibility.h index 817573c1d..2a2167c85 100644 --- a/utility/SPIDEV/compatibility.h +++ b/utility/SPIDEV/compatibility.h @@ -1,4 +1,4 @@ -/* +/* * File: compatiblity.h * Author: purinda * @@ -13,7 +13,7 @@ extern "C" { #endif -#include // for uintXX_t types +#include // for uintXX_t types #include #include #include diff --git a/utility/SPIDEV/gpio.h b/utility/SPIDEV/gpio.h index 0b986d819..2209dc555 100644 --- a/utility/SPIDEV/gpio.h +++ b/utility/SPIDEV/gpio.h @@ -27,7 +27,7 @@ class GPIOException : public std::runtime_error { /** * @file gpio.h - * \cond HIDDEN_SYMBOLS + * @cond HIDDEN_SYMBOLS * Class declaration for GPIO helper files */ @@ -71,7 +71,6 @@ class GPIO { /** * Similar to Arduino digitalRead(pin); * @param port - * @param value */ static int read(int port); @@ -89,7 +88,7 @@ class GPIO { static std::map cache; }; /** - * \endcond + * @endcond */ -/*@}*/ +/**@}*/ #endif /* H */ diff --git a/utility/SPIDEV/interrupt.c b/utility/SPIDEV/interrupt.c index eda2ccd46..4411bbe9a 100644 --- a/utility/SPIDEV/interrupt.c +++ b/utility/SPIDEV/interrupt.c @@ -59,7 +59,7 @@ int waitForInterrupt(int pin, int mS) // A one character read appars to be enough. // Followed by a seek to reset it. - (void) read(fd, &c, 1); + (void) (read(fd, &c, 1) + 1); lseek(fd, 0, SEEK_SET); return x; @@ -153,7 +153,7 @@ int attachInterrupt(int pin, int mode, void (* function)(void)) ioctl(sysFds[bcmGpioPin], FIONREAD, &count); for (i = 0; i < count; ++i) { - read(sysFds[bcmGpioPin], &c, 1); + (void) (read(sysFds[bcmGpioPin], &c, 1) + 1); } isrFunctions[pin] = function; diff --git a/utility/Template/RF24_arch_config.h b/utility/Template/RF24_arch_config.h index 222fafec3..50e1b4d25 100644 --- a/utility/Template/RF24_arch_config.h +++ b/utility/Template/RF24_arch_config.h @@ -1,25 +1,24 @@ /* - Copyright (C) 2011 J. Coliz - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - + * Copyright (C) 2011 J. Coliz + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * */ /** -* @file RF24_arch_config.h -* General defines and includes for RF24/Linux -*/ + * @file RF24_arch_config.h + * General defines and includes for RF24/Linux + */ /** -* Example of RF24_arch_config.h for RF24 portability -* -* @defgroup Porting_General Porting: General -* -* -* @{ -*/ + * Example of RF24_arch_config.h for RF24 portability + * + * @defgroup Porting_General Porting: General + * + * @{ + */ #ifndef __ARCH_CONFIG_H__ @@ -80,4 +79,4 @@ typedef uint16_t prog_uint16_t; #endif // __ARCH_CONFIG_H__ -/**@}*/ +/**@}*/ diff --git a/utility/Template/compatibility.h b/utility/Template/compatibility.h index a350f6feb..6c53a7c88 100644 --- a/utility/Template/compatibility.h +++ b/utility/Template/compatibility.h @@ -1,4 +1,4 @@ -/* +/* * File: compatiblity.h * Author: purinda * @@ -6,18 +6,17 @@ */ /** -* @file compatibility.h -* Class declaration for SPI helper files -*/ + * @file compatibility.h + * Class declaration for SPI helper files + */ /** -* Example of compatibility.h class declaration for timing functions portability -* -* @defgroup Porting_Timing Porting: Timing -* -* -* @{ -*/ + * Example of compatibility.h class declaration for timing functions portability + * + * @defgroup Porting_Timing Porting: Timing + * + * @{ + */ #ifndef COMPATIBLITY_H #define COMPATIBLITY_H @@ -44,4 +43,4 @@ long __millis(); #endif /* COMPATIBLITY_H */ -/**@}*/ \ No newline at end of file +/**@}*/ \ No newline at end of file diff --git a/utility/Template/gpio.h b/utility/Template/gpio.h index d806a0115..47a954c07 100644 --- a/utility/Template/gpio.h +++ b/utility/Template/gpio.h @@ -6,57 +6,53 @@ */ /** -* Example of gpio.h class declaration for GPIO portability -* -* @defgroup Porting_GPIO Porting: GPIO -* -* -* @{ -*/ -#ifndef H -#define H - -#include - -//class GPIO { -public: -/* Constants */ -static const int DIRECTION_OUT = 1; -static const int DIRECTION_IN = 0; - -static const int OUTPUT_HIGH = 1; -static const int OUTPUT_LOW = 0; - -GPIO(); - -/** - * Similar to Arduino pinMode(pin,mode); - * @param port - * @param DDR - */ -static void open(int port, int DDR); - -/** + * Example of gpio.h class declaration for GPIO portability * - * @param port - */ -static void close(int port); - -/** - * Similar to Arduino digitalRead(pin); - * @param port + * @defgroup Porting_GPIO Porting: GPIO + * + * @{ */ -static int read(int port); -/** -* Similar to Arduino digitalWrite(pin,state); -* @param port -* @param value -*/ -static void write(int port, int value); - -virtual ~ GPIO(); +#include +// class GPIO { +public: + /* Constants */ + static const int DIRECTION_OUT = 1; + static const int DIRECTION_IN = 0; + + static const int OUTPUT_HIGH = 1; + static const int OUTPUT_LOW = 0; + + GPIO(); + + /** + * Similar to Arduino pinMode(pin,mode); + * @param port + * @param DDR + */ + static void open(int port, int DDR); + + /** + * + * @param port + */ + static void close(int port); + + /** + * Similar to Arduino digitalRead(pin); + * @param port + */ + static int read(int port); + + /** + * Similar to Arduino digitalWrite(pin,state); + * @param port + * @param value + */ + static void write(int port, int value); + + virtual ~ GPIO(); }; -/**@}*/ \ No newline at end of file +/**@}*/ \ No newline at end of file diff --git a/utility/Template/includes.h b/utility/Template/includes.h index 24730a4f3..04c67a7a8 100644 --- a/utility/Template/includes.h +++ b/utility/Template/includes.h @@ -1,16 +1,15 @@ /** -* @file includes.h -* Configuration defines for RF24/Linux -*/ + * @file includes.h + * Configuration defines for RF24/Linux + */ /** -* Example of includes.h for RF24 Linux portability -* -* @defgroup Porting_Includes Porting: Includes -* -* -* @{ -*/ + * Example of includes.h for RF24 Linux portability + * + * @defgroup Porting_Includes Porting: Includes + * + * @{ + */ #ifndef __RF24_INCLUDES_H__ #define __RF24_INCLUDES_H__ @@ -22,9 +21,9 @@ /** * Load the correct configuration for this platform -*/ + */ #include "BBB/RF24_arch_config.h" #endif -/**@}*/ \ No newline at end of file +/**@}*/ \ No newline at end of file diff --git a/utility/Template/spi.h b/utility/Template/spi.h index fa91e4158..8b1ce7eaf 100644 --- a/utility/Template/spi.h +++ b/utility/Template/spi.h @@ -4,13 +4,12 @@ */ /** -* Example of spi.h class declaration for SPI portability -* -* @defgroup Porting_SPI Porting: SPI -* -* -* @{ -*/ + * Example of spi.h class declaration for SPI portability + * + * @defgroup Porting_SPI Porting: SPI + * + * @{ + */ #include #include #include @@ -24,58 +23,58 @@ #include using namespace std; -//class SPI { + +// class SPI { public: -/** - * SPI constructor - */ -SPI(); + /** + * SPI constructor + */ + SPI(); -/** -* Start SPI -*/ -void begin(int busNo); + /** + * Start SPI + */ + void begin(int busNo); -/** -* Transfer a single byte -* @param tx_ Byte to send -* @return Data returned via spi -*/ -uint8_t transfer(uint8_t tx_); + /** + * Transfer a single byte + * @param tx_ Byte to send + * @return Data returned via spi + */ + uint8_t transfer(uint8_t tx_); -/** -* Transfer a buffer of data -* @param tbuf Transmit buffer -* @param rbuf Receive buffer -* @param len Length of the data -*/ -void transfernb(char* tbuf, char* rbuf, uint32_t len); + /** + * Transfer a buffer of data + * @param tbuf Transmit buffer + * @param rbuf Receive buffer + * @param len Length of the data + */ + void transfernb(char* tbuf, char* rbuf, uint32_t len); -/** -* Transfer a buffer of data without an rx buffer -* @param buf Pointer to a buffer of data -* @param len Length of the data -*/ -void transfern(char* buf, uint32_t len); + /** + * Transfer a buffer of data without an rx buffer + * @param buf Pointer to a buffer of data + * @param len Length of the data + */ + void transfern(char* buf, uint32_t len); -virtual ~ SPI(); + virtual ~ SPI(); private: -/** Default SPI device */ -string device; -/** SPI Mode set */ -uint8_t mode; -/** word size*/ -uint8_t bits; -/** Set SPI speed*/ -uint32_t speed; -int fd; + /** Default SPI device */ + string device; + /** SPI Mode set */ + uint8_t mode; + /** word size*/ + uint8_t bits; + /** Set SPI speed*/ + uint32_t speed; + int fd; -void init(); + void init(); }; - /**@}*/ \ No newline at end of file