diff --git a/README.md b/README.md index 24f69e1..a71fb6b 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,29 @@ # Optimized High Speed Arduino driver for nRF24L01 2.4GHz Wireless Transceiver - -Note: March 2014, this fork was just published and is still undergoing fine tuning. - -Class documenation is now available at http://tmrh20.github.io/RF24/class_r_f24.html - -See http://TMRh20.blogspot.com for an overview of the new functionality. - -Design Goals: This library is designed to be... - -* More compliat with the manufacturer specified operation of the chip -* Utilize the capabilities of the radio to their full potential via Arduino -* More reliable and feature rich -* Easy for beginners to use -* Consumed with a public interface that's similiar to other Arduino standard libraries -* Built against the standard SPI library. - -Please refer to: - -* [Documentation Main Page](http://tmrh20.github.io/) -* [Class Reference]( http://tmrh20.github.io/RF24/class_r_f24.html) -* [Source Code](https://github.com/tmrh20/RF24) -* [Downloads](https://github.com/tmrh20/RF24/archives/master) -* [Chip Datasheet](http://www.nordicsemi.com/files/Product/data_sheet/nRF24L01_Product_Specification_v2_0.pdf) - -This chip uses the SPI bus, plus two chip control pins. Remember that pin 10 must still remain an output, or -the SPI hardware will go into 'slave' mode. + +Design Goals: This library is designed to be... + +* More complianct with the manufacturer specified operation of the chip +* More reliable and feature rich +* Easy for beginners to use +* Consumed with a public interface that's similiar to other Arduino standard libraries +* Built against the standard SPI library. + +March 2014: Optimization begun +April 2014: Optimization nearing completion +* The library has been tweaked to allow full use of the FIFO buffers for maximum transfer speeds +* Changes to read() functionality have increased reliability and response +* Extended timeout periods have been added to aid in noisy or otherwise unreliable environments +* Delays have been removed where possible to ensure maximum efficiency +* More! See the links below and class documentation for more info. + +Please refer to: + +* [Documentation Main Page](http://tmrh20.github.io/) +* [Class Reference]( http://tmrh20.github.io/RF24/classRF24.html) +* [Source Code](https://github.com/tmrh20/RF24) +* [Downloads](https://github.com/TMRh20/RF24/archive/master.zip) +* [Chip Datasheet](http://www.nordicsemi.com/files/Product/data_sheet/nRF24L01_Product_Specification_v2_0.pdf) + +This chip uses the SPI bus, plus two chip control pins. Remember that pin 10 must still remain an output, or +the SPI hardware will go into 'slave' mode. diff --git a/RF24.cpp b/RF24.cpp index e0713ac..f534b7d 100644 --- a/RF24.cpp +++ b/RF24.cpp @@ -19,9 +19,15 @@ void RF24::csn(int mode) // divider of 4 is the minimum we want. // CLK:BUS 8Mhz:2Mhz, 16Mhz:4Mhz, or 20Mhz:5Mhz #ifdef ARDUINO + #if !defined( __AVR_ATtiny85__ ) && !defined( __AVR_ATtiny84__) SPI.setBitOrder(MSBFIRST); SPI.setDataMode(SPI_MODE0); - SPI.setClockDivider(SPI_CLOCK_DIV4); + #ifdef __arm__ // Shouldn't need to set the clock divider on DUE + SPI.setClockDivider(21); + #else + SPI.setClockDivider(SPI_CLOCK_DIV4); + #endif +#endif #endif digitalWrite(csn_pin,mode); } @@ -273,6 +279,8 @@ uint8_t RF24::getPayloadSize(void) /****************************************************************************/ +#if !defined (MINIMAL) + static const char rf24_datarate_e_str_0[] PROGMEM = "1MBPS"; static const char rf24_datarate_e_str_1[] PROGMEM = "2MBPS"; static const char rf24_datarate_e_str_2[] PROGMEM = "250KBPS"; @@ -328,6 +336,7 @@ void RF24::printDetails(void) printf_P(PSTR("PA Power\t = %S\r\n"),pgm_read_word(&rf24_pa_dbm_e_str_P[getPALevel()])); } +#endif /****************************************************************************/ void RF24::begin(void) @@ -440,6 +449,7 @@ void RF24::powerDown(void) void RF24::powerUp(void) { write_register(CONFIG,read_register(CONFIG) | _BV(PWR_UP)); + delay(2); } /******************************************************************/ @@ -484,8 +494,9 @@ bool RF24::writeBlocking( const void* buf, uint8_t len, unsigned long 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(millis() - timer > timeout){ return 0; } //If this payload has exceeded the user-defined timeout, exit and return 0 } - if(millis() - timer > timeout){ return 0; } //If this payload has exceeded the user-defined timeout, exit and return 0 + } //Start Writing @@ -548,32 +559,29 @@ void RF24::startFastWrite( const void* buf, uint8_t len ){ //TMRh20 //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 ) -{ - // Transmitter power-up - write_register(CONFIG, ( read_register(CONFIG) | _BV(PWR_UP) ) & ~_BV(PRIM_RX) ); - delayMicroseconds(150); +void RF24::startWrite( const void* buf, uint8_t len ){ // Send the payload - write_payload( buf, len ); - // Allons! + write_payload( buf, len ); ce(HIGH); - delayMicroseconds(15); ce(LOW); + + } bool RF24::txStandBy(){ + while( ! (read_register(FIFO_STATUS) & _BV(TX_EMPTY)) ){ if( get_status() & _BV(MAX_RT)){ write_register(STATUS,_BV(MAX_RT) ); + ce(LOW); flush_tx(); //Non blocking, flush the data - ce(LOW); //Set STANDBY-I mode return 0; } } - ce(LOW); //Set STANDBY-I mode + ce(LOW); //Set STANDBY-I mode return 1; } @@ -584,12 +592,11 @@ bool RF24::txStandBy(unsigned long timeout){ while( ! (read_register(FIFO_STATUS) & _BV(TX_EMPTY)) ){ if( get_status() & _BV(MAX_RT)){ write_register(STATUS,_BV(MAX_RT) ); - if(timeout > 0){ ce(LOW); //Set re-transmit ce(HIGH); - if(millis() - start > timeout){ ce(LOW); flush_tx(); return 0; } - - } + if(millis() - start >= timeout){ + ce(LOW); flush_tx(); return 0; + } } } ce(LOW); //Set STANDBY-I mode @@ -1051,5 +1058,51 @@ void RF24::setRetries(uint8_t delay, uint8_t count) write_register(SETUP_RETR,(delay&0xf)< -64dBm, false if not + */ + bool testRPD(void) ; + + /** + * Test whether this is a real radio, or a mock shim for + * debugging. Setting either pin to 0xff is the way to + * indicate that this is not a real radio. + * + * @return true if this is a legitimate radio + */ + bool isValid() { return ce_pin != 0xff && csn_pin != 0xff; } + + /** + * + */ + void maskIRQ(bool tx_ok,bool tx_fail,bool rx_ready); + + /**@}*/ + /**@}*/ /** * @name Optional Configurators @@ -495,6 +516,7 @@ public: * defaults. */ /**@{*/ + /** * Set the number and delay of retries upon failed submit * @@ -656,258 +678,211 @@ public: */ void disableCRC( void ) ; - /**@}*/ +private: + /** - * @name Advanced Operation + * @name Low-level internal interface. * - * Methods you can use to drive the chip in more advanced ways + * Protected methods that address the chip directly. Regular users cannot + * ever call these. They are documented for completeness and for developers who + * may want to extend this class. */ /**@{*/ /** - * Print a giant block of debugging information to stdout + * Set chip select pin * - * @warning Does nothing if stdout is not defined. See fdevopen in stdio.h + * Running SPI bus at PI_CLOCK_DIV2 so we don't waste time transferring data + * and best of all, we make use of the radio's FIFO buffers. A lower speed + * means we're less likely to effectively leverage our FIFOs and pay a higher + * AVR runtime cost as toll. + * + * @param mode HIGH to take this unit off the SPI bus, LOW to put it on */ - void printDetails(void); + void csn(int mode); /** - * Enter low-power mode + * Set chip enable * - * To return to normal power mode, either write() some data or - * startListening, or powerUp(). - * - * @note Optimization: The radio will never enter power down unless instructed - * by the MCU via this command. + * @param level HIGH to actively begin transmission or LOW to put in standby. Please see data sheet + * for a much more detailed description of this pin. */ - void powerDown(void); + void ce(int level); /** - * Leave low-power mode - making radio more responsive + * Read a chunk of data in from a register * - * To return to low power mode, call powerDown(). + * @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 */ - void powerUp(void) ; + uint8_t read_register(uint8_t reg, uint8_t* buf, uint8_t len); /** - * Non-blocking write to the open writing pipe + * Read single byte from a register * - * Just like write(), but it returns immediately. To find out what happened - * to the send, catch the IRQ and then call whatHappened(). + * @param reg Which register. Use constants from nRF24L01.h + * @return Current value of register @p reg + */ + uint8_t read_register(uint8_t reg); + + /** + * Write a chunk of data to a register * - * @note Optimization: This function again behaves as it did previously for backwards-compatibility. - * with user code. The library uses startFastWrite() internally. - * This is mainly used for single-payload transactions. + * @param reg Which register. Use constants from nRF24L01.h + * @param buf Where to get the data + * @param len How many bytes of data to transfer + * @return Current value of status register + */ + uint8_t write_register(uint8_t reg, const uint8_t* buf, uint8_t len); + + /** + * Write a single byte to a register * - * @see write() - * @see writeFast() - * @see startFastWrite() - * @see whatHappened() + * @param reg Which register. Use constants from nRF24L01.h + * @param value The new value to write + * @return Current value of status register + */ + uint8_t write_register(uint8_t reg, uint8_t value); + + /** + * Write the transmit payload * - * @param buf Pointer to the data to be sent + * The size of data written is the fixed payload size, see getPayloadSize() + * + * @param buf Where to get the data * @param len Number of bytes to be sent - * + * @return Current value of status register */ - void startWrite( const void* buf, uint8_t len ); + uint8_t write_payload(const void* buf, uint8_t len); /** - * Optimization: New Command + * Read the receive payload * - * 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 size of data read is the fixed payload size, see getPayloadSize() * - * 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. - * - * @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. + * @param buf Where to put the data + * @param len Maximum number of bytes to read + * @return Current value of status register */ - void reUseTX(); + uint8_t read_payload(void* buf, uint8_t len); /** - * Write an ack payload for the specified pipe - * - * The next time a message is received on @p pipe, the data in @p buf will - * be sent back in the acknowledgement. - * - * @warning According to the data sheet, only three of these can be pending - * at any time as there are only 3 FIFO buffers. - * - * @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(). - * - * Call read() to retrieve the ack payload. - * - * @note Optimization: Calling this function NO LONGER clears the interrupt - * flag. The new functionality checks the RX FIFO buffer for an ACK payload - * instead of relying on interrupt flags.Reading the payload will clear the flags. - * - * @return True if an ack payload is available. - */ - bool isAckPayloadAvailable(void); - - /** - * Test whether there are bytes available to be read in the - * FIFO buffers. This optimized version does not rely on interrupt - * flags, but checks the actual FIFO buffers. - * - * @note Optimization: Interrupt flags are no longer cleared when available is called, - * but will be reset only when the data is read from the FIFO buffers. - * - * @param[out] pipe_num Which pipe has the payload available - * @return True if there is a payload available, false if none is - */ - bool available(uint8_t* pipe_num); - - /** - * Call this when you get an interrupt to find out why - * - * Tells you what caused the interrupt, and clears the state of - * interrupts. - * - * @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) - */ - void whatHappened(bool& tx_ok,bool& tx_fail,bool& rx_ready); - - /** - * Empty the transmit buffer + * Empty the receive buffer * * @return Current value of status register */ - uint8_t flush_tx(void); + uint8_t flush_rx(void); /** - * Test whether there was a carrier on the line for the - * previous listening period. + * Retrieve the current status of the chip * - * Useful to check for interference on the current channel. - * - * @return true if was carrier, false if not + * @return Current value of status register */ - bool testCarrier(void); + uint8_t get_status(void); /** - * Test whether a signal (carrier or otherwise) greater than - * or equal to -64dBm is present on the channel. Valid only - * on nRF24L01P (+) hardware. On nRF24L01, use testCarrier(). + * Decode and print the given status to stdout * - * Useful to check for interference on the current channel and - * channel hopping strategies. + * @param status Status value to print * - * @return true if signal => -64dBm, false if not + * @warning Does nothing if stdout is not defined. See fdevopen in stdio.h */ - bool testRPD(void) ; + void print_status(uint8_t status); /** - * Test whether this is a real radio, or a mock shim for - * debugging. Setting either pin to 0xff is the way to - * indicate that this is not a real radio. + * Decode and print the given 'observe_tx' value to stdout * - * @return true if this is a legitimate radio + * @param value The observe_tx value to print + * + * @warning Does nothing if stdout is not defined. See fdevopen in stdio.h */ - bool isValid() { return ce_pin != 0xff && csn_pin != 0xff; } + void print_observe_tx(uint8_t value); /** - * @see txStandBy() + * Print the name and value of an 8-bit register to stdout + * + * Optionally it can print some quantity of successive + * registers on the same line. This is useful for printing a group + * of related registers on one line. + * + * @param name Name of the register + * @param reg Which register. Use constants from nRF24L01.h + * @param qty How many successive registers to print */ - bool txStandBy(bool block); + void print_byte_register(const char* name, uint8_t reg, uint8_t qty = 1); + /** + * Print the name and value of a 40-bit address register to stdout + * + * Optionally it can print some quantity of successive + * registers on the same line. This is useful for printing a group + * of related registers on one line. + * + * @param name Name of the register + * @param reg Which register. Use constants from nRF24L01.h + * @param qty How many successive registers to print + */ + void print_address_register(const char* name, uint8_t reg, uint8_t qty = 1); + + /** + * Turn on or off the special features of the chip + * + * The chip has certain 'features' which are only available when the 'features' + * are enabled. See the datasheet for details. + */ + void toggle_features(void); /**@}*/ + }; /** * @example GettingStarted.ino - * Updated: TMRh20 - * This is an example which corresponds to my "Getting Started" blog post: - * Getting Started with nRF24L01+ on Arduino. + * Updated: TMRh20 2014
* - * 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 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. + * This is an example of how to use the RF24 class to communicate on a basic level. 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 GettingStarted_CallResponse.ino + * 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 Transfer.ino - * Updated: TMRh20 - * This example demonstrates half-rate transfer using the FIFO buffers + * New: TMRh20
+ * 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 + * 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) + * with the receiver displaying the payload count. (32Byte Payloads)
*/ /** * @example TransferTimeouts.ino - * Updated: TMRh20 + * New: 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 + * mode by connecting with the serial monitor and sending a 'T'. The data
* transfer will begin, with the receiver displaying the payload count and the * data transfer rate. */ -/** - * @example nordic_fob.pde - * - * This is an example of how to use the RF24 class to receive signals from the - * Sparkfun Nordic FOB. See http://www.sparkfun.com/products/8602 . - * Thanks to Kirk Mower for providing test hardware. - */ - -/** - * @example led_remote.pde - * - * 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. - * - * Every time the buttons change on the remote, the entire state of - * buttons is send to the led board, which displays the state. - */ - -/** - * @example pingpair.ino - * - * 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. - */ - -/** - * @example pingpair_maple.pde - * - * This is an example of how to use the RF24 class on the Maple. For a more - * detailed explanation, see my blog post: - * nRF24L01+ Running on Maple - * - * It will communicate well to an Arduino-based unit as well, so it's not for only Maple-to-Maple communication. - * - * 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. - */ - /** * @example starping.pde * @@ -924,28 +899,70 @@ public: */ /** - * @example pingpair_pl.pde - * - * This is an example of how to do two-way communication without changing - * transmit/receive modes. Here, a payload is set to the transmitter within - * the Ack packet of each transmission. Note that the payload is set BEFORE - * the sender's message arrives. + * @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.pde - * - * This is an example of how to user interrupts to interact with the radio. - * It builds on the pingpair_pl example, and uses ack payloads. + * @example pingpair_irq.ino + * Update: 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. + * Sleep functionality is built directly into my fork of the RF24Network library
*/ /** - * @example pingpair_sleepy.pde - * + * @example pingpair_sleepy.ino + * Update: TMRh20
* This is an example of how to use the RF24 class to create a battery- - * efficient system. It is just like the pingpair.pde example, but the + * 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. + * ping/pong cycle, and the receiver sleeps between payloads.
+ */ + +/** + * @example pingpair_dyn.pde + * + * This is an example of how to use payloads of a varying (dynamic) size. + */ + +/** + * @example pingpair_maple.pde + * + * This is an example of how to use the RF24 class on the Maple. For a more + * detailed explanation, see my blog post: + * nRF24L01+ Running on Maple + * + * It will communicate well to an Arduino-based unit as well, so it's not for only Maple-to-Maple communication. + * + * 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. + */ + +/** + * @example nordic_fob.pde + * + * This is an example of how to use the RF24 class to receive signals from the + * Sparkfun Nordic FOB. See http://www.sparkfun.com/products/8602 . + * Thanks to Kirk Mower for providing test hardware. + */ + +/** + * @example led_remote.pde + * + * 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. + * + * Every time the buttons change on the remote, the entire state of + * buttons is send to the led board, which displays the state. */ /** @@ -973,14 +990,21 @@ public: * * @section News News * - * March 2014: Fork currently being optimized for high speed and more responsive data transfers + * March 2014: Optimization begun
+ * April 2014: Optimization nearing completion

+ * - The library has been tweaked to allow full use of the FIFO buffers for maximum transfer speeds + * - Changes to read() functionality have increased reliability and response + * - Extended timeout periods have been added to aid in noisy or otherwise unreliable environments + * - Delays have been removed where possible to ensure maximum efficiency + * - More! See the links below and class documentation for more info. + * * If issues are discovered with the documentation, please report them here: here * @section Useful Useful References * * Please refer to: * * @li Documentation Main Page - * @li RF24 Class Documentation + * @li RF24 Class Documentation * @li Source Code * @li Downloads Page * @li Chip Datasheet @@ -995,6 +1019,8 @@ public: * * @li Project blog: * @li TMRh20.blogspot.com + * @li RF24 Wireless Audio Library (Coming Soon) + * @li Optimized RF24 Network Layer * @li ManiacBug on GitHub (Original Library Author) */ diff --git a/RF24_config.h b/RF24_config.h index fc7397f..5d62655 100644 --- a/RF24_config.h +++ b/RF24_config.h @@ -5,61 +5,129 @@ 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. + + Added Arduino Due support from https://github.com/mcrosson/ */ #ifndef __RF24_CONFIG_H__ #define __RF24_CONFIG_H__ -#if ARDUINO < 100 -#include -#else -#include -#endif + #if ARDUINO < 100 + #include + #else + #include + #endif -#include + #include -// Stuff that is normally provided by Arduino -#ifdef ARDUINO -#include -#else -#include -#include -#include -extern HardwareSPI SPI; -#define _BV(x) (1<<(x)) -#endif + //TMRh20: + //#define MINIMAL -#undef SERIAL_DEBUG -#ifdef SERIAL_DEBUG -#define IF_SERIAL_DEBUG(x) ({x;}) -#else -#define IF_SERIAL_DEBUG(x) -#endif + // Define _BV for non-Arduino platforms and for Arduino DUE + #if ! defined(ARDUINO) || (defined(ARDUINO) && defined(__arm__)) + #define _BV(x) (1<<(x)) + #endif -// Avoid spurious warnings -#if 1 -#if ! defined( NATIVE ) && defined( ARDUINO ) -#undef PROGMEM -#define PROGMEM __attribute__(( section(".progmem.data") )) -#undef PSTR -#define PSTR(s) (__extension__({static const char __c[] PROGMEM = (s); &__c[0];})) -#endif -#endif + #undef SERIAL_DEBUG + #ifdef SERIAL_DEBUG + #define IF_SERIAL_DEBUG(x) ({x;}) + #else + #define IF_SERIAL_DEBUG(x) + #endif -// Progmem is Arduino-specific -#ifdef ARDUINO -#include -#define PRIPSTR "%S" -#else -typedef char const char; -typedef uint16_t prog_uint16_t; -#define PSTR(x) (x) -#define printf_P printf -#define strlen_P strlen -#define PROGMEM -#define pgm_read_word(p) (*(p)) -#define PRIPSTR "%s" -#endif + // Avoid spurious warnings + #if 1 + #if ! defined( NATIVE ) && defined( ARDUINO ) && ! defined(__arm__) + #undef PROGMEM + #define PROGMEM __attribute__(( section(".progmem.data") )) + #undef PSTR + #define PSTR(s) (__extension__({static const char __c[] PROGMEM = (s); &__c[0];})) + #endif + #endif + + // Progmem is Arduino-specific + #if defined(ARDUINO) && ! defined(__arm__) + #include + #define PRIPSTR "%S" + #else + + #if ! defined(ARDUINO) + typedef char const char; + else // Fill in pgm_read_byte that is used, but missing from DUE + #define pgm_read_byte(addr) (*(const unsigned char *)(addr)) + #endif + typedef uint16_t prog_uint16_t; + #define PSTR(x) (x) + #define printf_P printf + #define strlen_P strlen + #define PROGMEM + #define pgm_read_word(p) (*(p)) + #define PRIPSTR "%s" + #endif + + + + // Stuff that is normally provided by Arduino + #if !defined ARDUINO + + #include + #include + #include + extern HardwareSPI SPI; + #else + + #if !defined( __AVR_ATtiny85__ ) || defined( __AVR_ATtiny84__) + #include + #else + #define ATTINY + + #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: + inline static byte transfer(byte _data); + + static void begin(); // Default + static void end(); + + static void setDataMode(byte); + static void setClockDivider(byte); + static void setBitOrder(byte); + }; + + extern SPIClass SPI; + + byte SPIClass::transfer(byte _data){ + + USIDR = _data; + USISR = _BV(USIOIF); + + while((USISR & _BV(USIOIF)) == 0){ + USICR = _BV(USIWM0) | _BV(USICS1) | _BV(USICLK) | _BV(USITC); + } + return USIDR; + } + #endif //ATTINY + + #endif //Defined Arduino #endif // __RF24_CONFIG_H__ -// vim:ai:cin:sts=2 sw=2 ft=cpp + diff --git a/examples/GettingStarted/GettingStarted.ino b/examples/GettingStarted/GettingStarted.ino index 1dfd8ab..8b0353c 100644 --- a/examples/GettingStarted/GettingStarted.ino +++ b/examples/GettingStarted/GettingStarted.ino @@ -4,156 +4,115 @@ 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. +//2014 - TMRh20 - Updated along with Optimized RF24 Library fork */ /** * Example for Getting Started with nRF24L01+ radios. * - * This 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 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. + * This is an example of how to use the RF24 class to communicate on a basic level. 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 */ -//March 2014 - TMRh20 - Updated to utilize High Speed RF24 Library fork -//This - #include #include "nRF24L01.h" #include "RF24.h" #include "printf.h" -// Hardware configuration -// Set up nRF24L01 radio on SPI bus plus pins 9 & 10 +// Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins 9 & 10 +RF24 radio(7,8); -RF24 radio(48,49); +const uint64_t addresses[2] = { 0xABCDABCD71LL, 0x544d52687CLL }; // Radio pipe addresses for the 2 nodes to communicate. -// Topology -// Radio pipe addresses for the 2 nodes to communicate. -const uint64_t pipes[2] = { 0xABCDABCD71LL, 0x544d52687CLL }; +// Set up roles to simplify testing +boolean role; // The main role variable, holds the current role identifier +boolean role_ping_out = 1, role_pong_back = 0; // The two different roles. -// -// Role management -// Set up role. This sketch uses the same software for all the nodes -// in this system. Doing so greatly simplifies testing. +void setup() { -// 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 = role_pong_back; - -void setup(void) -{ - // - // Print preamble - // Serial.begin(57600); printf_begin(); printf("\n\rRF24/examples/GettingStarted/\n\r"); - printf("ROLE: %s\n\r",role_friendly_name[role]); printf("*** PRESS 'T' to begin transmitting to the other node\n\r"); - // // Setup and configure rf radio - - radio.begin(); + radio.begin(); // Start up the radio radio.setAutoAck(1); // Ensure autoACK is enabled - - radio.setRetries(15,15); // Optionally, increase the delay between retries & # of retries - - radio.openWritingPipe(pipes[1]); - radio.openReadingPipe(1,pipes[0]); + radio.setRetries(15,15); // Max delay between retries & number of retries + + radio.openWritingPipe(addresses[1]); // Open a writing pipe on pipe 0, with address 1 + radio.openReadingPipe(1,addresses[0]); // Open a reading pipe on pipe 1, with address 0 radio.startListening(); // Start listening - radio.printDetails(); // Dump the configuration of the rf unit for debugging } -void loop(void) -{ - // - // Ping out role. Repeatedly send the current time - // +void loop(void){ + - if (role == role_ping_out) - { +/****************** Ping Out Role ***************************/ + if (role == role_ping_out) { - radio.stopListening(); // First, stop listening so we can talk. + radio.stopListening(); // First, stop listening so we can talk. - unsigned long time = millis(); // Take the time, and send it. This will block until complete - printf("Now sending %lu...",time); - radio.writeFast( &time, sizeof(unsigned long) ); //New function for proper use of FIFO buffers - bool ok = radio.txStandBy(); //Called when STANDBY-I mode is engaged (User is finished sending) - if (!ok) - printf("failed.\n\r"); - - - 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() && ! timeout ) - if (millis() - started_waiting_at > 200 ) - timeout = true; + unsigned long time; + printf("Now sending ",time); + + time = micros(); // Take the time, and send it. This will block until complete + boolean ok = radio.write( &time, sizeof(unsigned long) ); // Send the current time + if (!ok){ printf("failed.\n\r"); } - if ( timeout ) // Describe the results - { - printf("Failed, response timed out.\n\r"); + 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; + } } - else - { - unsigned long got_time; // Grab the response, compare, and send to debugging spew - radio.read( &got_time, sizeof(unsigned long) ); - unsigned long tim = millis(); - // Spew it - printf("Got response %lu, round-trip delay: %lu\n\r",got_time,tim-got_time); + + if ( timeout ){ // Describe the results + printf("Failed, response timed out.\n\r"); + }else{ + unsigned long got_time; // Grab the response, compare, and send to debugging spew + radio.read( &got_time, sizeof(unsigned long) ); + + // Spew it + printf("Sent %lu, Got response %lu, round-trip delay: %lu microseconds\n\r",time,got_time,micros()-got_time); } // Try again 1s later delay(1000); } - // - // Pong back role. Receive each packet, dump it out, and send it back - // +/****************** Pong Back Role ***************************/ if ( role == role_pong_back ) { if( radio.available()){ - unsigned long got_time; // Dump the payloads until we've gotten everything - bool done = false; + unsigned long got_time; // Variable for the received timestamp while (radio.available()) { // While there is data ready - // Fetch the payload, and see if this was the last one. - radio.read( &got_time, sizeof(unsigned long) ); + radio.read( &got_time, sizeof(unsigned long) ); // Get the payload } - // Spew it - //printf("Got payload %lu...",got_time); - - // Delay just a little bit to let the other unit - // make the transition to receiver - //delay(2); - radio.stopListening(); // First, stop listening so we can talk - - radio.writeFast( &got_time, sizeof(unsigned long) ); // Send the final one back. - radio.txStandBy(); - radio.startListening(); // Now, resume listening so we catch the next packets. - - //printf("Sent response.\n\r"); - + 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. + printf("Sent response %lu \n\r", got_time); } } - // - // Change roles - // + +/****************** Change Roles via Serial Commands ***************************/ if ( Serial.available() ) { @@ -163,16 +122,16 @@ void loop(void) printf("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK\n\r"); role = role_ping_out; // Become the primary transmitter (ping out) - radio.openWritingPipe(pipes[0]); - radio.openReadingPipe(1,pipes[1]); + radio.openWritingPipe(addresses[0]); + radio.openReadingPipe(1,addresses[1]); } else if ( c == 'R' && role == role_ping_out ) { printf("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK\n\r"); role = role_pong_back; // Become the primary receiver (pong back) - radio.openWritingPipe(pipes[1]); - radio.openReadingPipe(1,pipes[0]); + radio.openWritingPipe(addresses[1]); + radio.openReadingPipe(1,addresses[0]); } } -} +} \ No newline at end of file diff --git a/examples/GettingStarted/Jamfile b/examples/GettingStarted/Jamfile deleted file mode 100644 index 9a5f2c4..0000000 --- a/examples/GettingStarted/Jamfile +++ /dev/null @@ -1,210 +0,0 @@ -# (1) Project Information - -PROJECT_LIBS = SPI RF24 ; - -# (2) Board Information - -UPLOAD_PROTOCOL ?= arduino ; -UPLOAD_SPEED ?= 57600 ; -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 ; -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 -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 = $(PWD) $(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 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 -} - -# -# Targets -# - -# 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) $(ARDUINO_LIB)/$(PROJECT_LIBS)/utility $(SKETCH_LIB)/$(PROJECT_LIBS) : *.cpp *.c ] ; - -# Grab everything from the current dir -PROJECT_MODULES += [ GLOB $(PWD) : *.c *.cpp *.pde *.ino ] ; - -# Main output executable -MAIN = $(PWD:B).elf ; - -Main $(MAIN) : $(CORE_MODULES) $(LIB_MODULES) $(PROJECT_MODULES) ; -Hex $(MAIN:B).hex : $(MAIN) ; - -# Upload targets -for _p in $(PORTS) -{ - Upload $(_p) : $(PORT_$(_p)) : $(MAIN:B).hex ; -} diff --git a/examples/GettingStarted_CallResponse/GettingStarted_CallResponse.ino b/examples/GettingStarted_CallResponse/GettingStarted_CallResponse.ino new file mode 100644 index 0000000..d491a83 --- /dev/null +++ b/examples/GettingStarted_CallResponse/GettingStarted_CallResponse.ino @@ -0,0 +1,124 @@ +/* + // March 2014 - TMRh20 - Updated along with High Speed RF24 Library fork + // Parts 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 "nRF24L01.h" +#include "RF24.h" +#include "printf.h" + +// Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins 9 & 10 +RF24 radio(7,8); + // Topology +const uint64_t addresses[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 + +byte counter = 1; // A single byte to keep track of the data being sent back and forth + + +void setup(){ + + Serial.begin(57600); + printf_begin(); + printf("\n\rRF24/examples/GettingStarted/\n\r"); + printf("ROLE: %s\n\r",role_friendly_name[role]); + printf("*** PRESS 'T' to begin transmitting to the other node\n\r"); + + // Setup and configure 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(addresses[1]); // Both radios listen on the same pipes by default, and switch when writing + radio.openReadingPipe(1,addresses[0]); // Open a reading pipe on address 0, pipe 1 + radio.startListening(); // Start listening + radio.powerUp(); + radio.printDetails(); // Dump the configuration of the rf unit for debugging +} + +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 + unsigned long time = micros(); // Record the current microsecond count + + radio.stopListening(); // First, stop listening so we can talk. + printf("Now sending %d as payload. ",counter); // Use a simple byte counter as payload + + 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 microseconds\n\r",micros()-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 microseconds\n\r",gotByte,micros()-time); + counter++; // Increment the counter variable + } + } + + }else{ printf("Sending failed.\n\r"); } // 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. + // 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("Sent response %d \n\r", gotByte); + } + } + + + +/****************** Change Roles via Serial Commands ***************************/ + + if ( Serial.available() ) + { + char c = toupper(Serial.read()); + if ( c == 'T' && role == role_pong_back ) + { + printf("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK\n\r"); + + role = role_ping_out; // Change roles (ping out) + radio.openWritingPipe(addresses[0]); // Open different pipes when writing. Write on pipe 0, address 0 + radio.openReadingPipe(1,addresses[1]); // Read on pipe 1, as address 1 + } + else if ( c == 'R' && role == role_ping_out ) + { + printf("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK\n\r"); + + role = role_pong_back; // Become the primary receiver (pong back) + radio.openWritingPipe(addresses[1]); // Since only two radios involved, both listen on the same addresses and pipe numbers in RX mode + radio.openReadingPipe(1,addresses[0]); // then switch pipes & addresses to transmit. + radio.startListening(); // Need to start listening after opening new reading pipes + } + } +} diff --git a/examples/led_remote/printf.h b/examples/GettingStarted_CallResponse/printf.h similarity index 100% rename from examples/led_remote/printf.h rename to examples/GettingStarted_CallResponse/printf.h diff --git a/examples/Transfer/Transfer.ino b/examples/Transfer/Transfer.ino index 080c208..b9b1362 100644 --- a/examples/Transfer/Transfer.ino +++ b/examples/Transfer/Transfer.ino @@ -21,7 +21,7 @@ TMRh20 2014 /************* USER Configuration *****************************/ // Hardware configuration -RF24 radio(48,49); // Set up nRF24L01 radio on SPI bus plus pins 9 & 10 +RF24 radio(48,49); // Set up nRF24L01 radio on SPI bus plus pins 7 & 8 boolean RADIO_NO = 0; //SET THIS TO 0 or 1 for 1st or 2nd radio /***************************************************************/ @@ -31,7 +31,7 @@ const uint64_t pipes[2] = { 0xABCDABCD71LL, 0x544d52687CLL }; // Radio pipe ad byte data[32]; //Data buffer for testing data transfer speeds unsigned long counter, rxTimer; //Counter and timer for keeping track transfer info -float startTime, stopTime; +unsigned long startTime, stopTime; bool TX=1,RX=0,role=0; void setup(void) { @@ -42,17 +42,13 @@ void setup(void) { 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(1,1); // Optionally, increase the delay between retries & # of retries + radio.setRetries(2,15); // Optionally, increase the delay between retries & # of retries radio.setCRCLength(RF24_CRC_8); - - if(RADIO_NO){ //Lets the two radios choose the correct pipes depending on user selection - radio.openWritingPipe(pipes[0]); - radio.openReadingPipe(1,pipes[1]); - }else{ - radio.openWritingPipe(pipes[1]); - radio.openReadingPipe(1,pipes[0]); - } + //radio.disableCRC(); + radio.openWritingPipe(pipes[0]); + radio.openReadingPipe(1,pipes[1]); radio.startListening(); // Start listening radio.printDetails(); // Dump the configuration of the rf unit for debugging @@ -73,28 +69,29 @@ void loop(void){ if(role == TX){ - delay(1500); + delay(2000); printf("Initiating Basic Data Transfer\n\r"); - float cycles = 1000; //Change this to a higher or lower number. + unsigned long cycles = 10000; //Change this to a higher or lower number. startTime = millis(); for(int i=0; i 1000){ rxTimer = millis(); -// printf("Rx Rate: "); -// Serial.print(counter*32/1000); -// printf(" KB/s\n\r"); + printf("Rate: "); + float numBytes = counter*32; + Serial.print(numBytes/1000); + printf(" KB/s\n\r"); printf("Payload Count: %d \n\r", counter); counter = 0; } @@ -128,15 +126,19 @@ void loop(void){ 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) } } } -// vim:cin:ai:sts=2 sw=2 ft=cpp \ No newline at end of file +// vim:cin:ai:sts=2 sw=2 ft=cpp diff --git a/examples/led_remote/Jamfile b/examples/Usage/led_remote/Jamfile similarity index 100% rename from examples/led_remote/Jamfile rename to examples/Usage/led_remote/Jamfile diff --git a/examples/led_remote/led_remote.pde b/examples/Usage/led_remote/led_remote.pde similarity index 100% rename from examples/led_remote/led_remote.pde rename to examples/Usage/led_remote/led_remote.pde diff --git a/examples/nordic_fob/printf.h b/examples/Usage/led_remote/printf.h similarity index 100% rename from examples/nordic_fob/printf.h rename to examples/Usage/led_remote/printf.h diff --git a/examples/nordic_fob/Jamfile b/examples/Usage/nordic_fob/Jamfile similarity index 100% rename from examples/nordic_fob/Jamfile rename to examples/Usage/nordic_fob/Jamfile diff --git a/examples/nordic_fob/nordic_fob.pde b/examples/Usage/nordic_fob/nordic_fob.pde similarity index 100% rename from examples/nordic_fob/nordic_fob.pde rename to examples/Usage/nordic_fob/nordic_fob.pde diff --git a/examples/pingpair/printf.h b/examples/Usage/nordic_fob/printf.h similarity index 100% rename from examples/pingpair/printf.h rename to examples/Usage/nordic_fob/printf.h diff --git a/examples/pingpair_maple/Jamfile b/examples/Usage/pingpair_maple/Jamfile similarity index 100% rename from examples/pingpair_maple/Jamfile rename to examples/Usage/pingpair_maple/Jamfile diff --git a/examples/pingpair_maple/main.cpp b/examples/Usage/pingpair_maple/main.cpp similarity index 100% rename from examples/pingpair_maple/main.cpp rename to examples/Usage/pingpair_maple/main.cpp diff --git a/examples/pingpair_maple/pingpair_maple.pde b/examples/Usage/pingpair_maple/pingpair_maple.pde similarity index 100% rename from examples/pingpair_maple/pingpair_maple.pde rename to examples/Usage/pingpair_maple/pingpair_maple.pde diff --git a/examples/pingpair/Jamfile b/examples/pingpair/Jamfile deleted file mode 100644 index 18244ec..0000000 --- a/examples/pingpair/Jamfile +++ /dev/null @@ -1,219 +0,0 @@ -# (1) Project Information - -PROJECT_LIBS = SPI RF24 ; -PROJECT_DIRS = $(PWD) ; - -# (2) Board Information - -UPLOAD_PROTOCOL ?= arduino ; -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 $(<) : core libs ; - 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/pingpair/pingpair.ino b/examples/pingpair/pingpair.ino deleted file mode 100644 index 80baba5..0000000 --- a/examples/pingpair/pingpair.ino +++ /dev/null @@ -1,186 +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 Pair - * - * 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. - */ - -//March 2014 TMRh20 - Updated to utilize High Speed RF24 Library fork - -#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 '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; - -void setup(void) -{ - // - // Role - // - pinMode(role_pin, INPUT); // set up the role pin - digitalWrite(role_pin,HIGH); //Change this to HIGH/LOW to pre-choose a role - 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_ping_out; - else - role = role_pong_back; - - // - // Print preamble - // - - Serial.begin(57600); - printf_begin(); - printf("\n\rRF24/examples/pingpair/\n\r"); - printf("ROLE: %s\n\r",role_friendly_name[role]); - - // - // Setup and configure rf radio - // - - radio.begin(); - - radio.setRetries(15,15); // optionally, increase the delay between retries & # of retries - - radio.setPayloadSize(8); // optionally, reduce the payload size. seems to improve reliability - - // - // 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]); - } - - radio.startListening(); // Start listening - - radio.printDetails(); // Dump the configuration of the rf unit for debugging -} - -void loop(void) -{ - // - // Ping out role. Repeatedly send the current time - // - - if (role == role_ping_out) - { - radio.stopListening(); // First, stop listening so we can talk. - - unsigned long time = millis(); // Take the time, and send it. This will block until complete - printf("Now sending %lu...",time); - bool ok = radio.writeFast( &time, sizeof(unsigned long) ); // NEW command to buffer data more efficiently - - if (!ok) - printf("failed.\n\r"); - - while(!radio.txStandBy()){} //NEW command needs to be called after done sending. Allows FIFO buffers to be filled - - 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() && ! timeout ) - if (millis() - started_waiting_at > 200 ) - timeout = true; - - if ( timeout ) // Describe the results - { - printf("Failed, response timed out.\n\r"); - } - 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); // Spew it - } - - delay(1000); // Try again 1s later - } - - // - // 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; // Dump the payloads until we've gotten everything - bool done = false; - while (radio.available()) - { - radio.read( &got_time, sizeof(unsigned long) ); // Fetch the payload, and see if this was the last one. - } - printf("Got payload %lu...",got_time); // Spew it - - // Delay just a little bit to let the other unit - // make the transition to receiver - //delay(20); - - radio.stopListening(); // First, stop listening so we can talk - - radio.write( &got_time, sizeof(unsigned long) );// Send the final one back. - printf("Sent response.\n\r"); - - radio.startListening(); // Now, resume listening so we catch the next packets. - } - } -} -// vim:cin:ai:sts=2 sw=2 ft=cpp \ No newline at end of file diff --git a/examples/pingpair_ack/pingpair_ack.ino b/examples/pingpair_ack/pingpair_ack.ino new file mode 100644 index 0000000..2d3ecf7 --- /dev/null +++ b/examples/pingpair_ack/pingpair_ack.ino @@ -0,0 +1,123 @@ +/* + // March 2014 - TMRh20 - Updated along with High Speed RF24 Library fork + // Parts 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 if wanting + * to initiate communication instead of respond to a commmunication. + */ + + + +#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(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(57600); + printf_begin(); + printf("\n\rRF24/examples/GettingStarted/\n\r"); + printf("ROLE: %s\n\r",role_friendly_name[role]); + printf("*** PRESS 'T' to begin transmitting to the other node\n\r"); + + // 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 )){ + printf("failed.\n\r"); + }else{ + + if(!radio.available()){ + printf("Blank Payload Received\n\r"); + }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 ); + } + } + + // Change roles + + if ( Serial.available() ) + { + char c = toupper(Serial.read()); + if ( c == 'T' && role == role_pong_back ) + { + printf("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK\n\r"); + + 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 ) + { + printf("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK\n\r"); + + 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_pl/printf.h b/examples/pingpair_ack/printf.h similarity index 100% rename from examples/pingpair_pl/printf.h rename to examples/pingpair_ack/printf.h diff --git a/examples/pingpair_irq/Jamfile b/examples/pingpair_irq/Jamfile deleted file mode 100644 index 97237bc..0000000 --- a/examples/pingpair_irq/Jamfile +++ /dev/null @@ -1,219 +0,0 @@ -# (1) Project Information - -PROJECT_LIBS = SPI RF24 ; -PROJECT_DIRS = $(PWD) ; - -# (2) Board Information - -UPLOAD_PROTOCOL ?= arduino ; -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 $(<) : core libs ; - 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/pingpair_irq/pingpair_irq.ino b/examples/pingpair_irq/pingpair_irq.ino new file mode 100644 index 0000000..de00b62 --- /dev/null +++ b/examples/pingpair_irq/pingpair_irq.ino @@ -0,0 +1,144 @@ +/* + 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" +#include +#include + +// Hardware configuration +RF24 radio(7,8); // Set up nRF24L01 radio on SPI bus plus pins 9 & 10 + +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 + + const uint64_t address[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. 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 + +boolean gotMsg = 0; // So we know when to go to sleep + +/********************** 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(); + printf("\n\rRF24/examples/pingpair_irq/\n\r"); + printf("ROLE: %s\n\r",role_friendly_name[role]); + + // Setup and configure rf radio + radio.begin(); + radio.enableAckPayload(); // We will be using the Ack Payload feature, so please enable it + // 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. + }else{ + radio.openReadingPipe(1,address[0]); + radio.startListening(); + } + radio.printDetails(); // Dump the configuration of the rf unit for debugging + radio.powerUp(); // Power up the radio + attachInterrupt(0, check_radio, FALLING); // Attach interrupt handler to interrupt #0 (using pin 2) on BOTH the sender and receiver +} + +static uint32_t message_count = 0; + + +/********************** 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. + printf("Now sending %lu\n\r",time); + radio.startWrite( &time, sizeof(unsigned long) ); + delay(2000); // Try again soon + } + + + if(role == role_receiver){ // Receiver does nothing but sleep between payloads + if(!radio.available() && gotMsg == 1 ){ // Display the uptime in millis(). (Counter does not increment during sleep) + gotMsg = 0; + set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Put the Arduino to sleep between payloads + sleep_enable(); + sleep_mode(); // Arduino goes to sleep here + //ZZZ... sleeping + sleep_disable(); // This happens when the interrupt wakes Arduino up + } + } +} + + +/********************** 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 ){ printf("Send:OK\n\r"); } + if ( role == role_receiver ){ printf("Ack Payload:Sent\n\r"); } + } + + if ( fail ) { // Have we failed to transmit? + if ( role == role_sender ){ printf("Send:Failed\n\r"); } + if ( role == role_receiver ){ printf("Ack Payload:Failed\n\r"); } + } + + 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)); + printf("Ack:%lu\n\r",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) ); + printf("Got payload %lu\n\r",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/pingpair_irq.pde b/examples/pingpair_irq/pingpair_irq.pde deleted file mode 100644 index 47084a1..0000000 --- a/examples/pingpair_irq/pingpair_irq.pde +++ /dev/null @@ -1,216 +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 of using interrupts - * - * This is an example of how to user interrupts to interact with the radio. - * It builds on the pingpair_pl example, and uses ack payloads. - */ - -#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(8,9); - -// sets the role of this unit in hardware. Connect to GND to be the 'pong' receiver -// Leave open to be the 'ping' transmitter -const short role_pin = 7; - -// -// 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_sender = 1, role_receiver } role_e; - -// The debug-friendly names of those roles -const char* role_friendly_name[] = { "invalid", "Sender", "Receiver"}; - -// The role of the current running sketch -role_e role; - -// Interrupt handler, check the radio because we got an IRQ -void check_radio(void); - -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_sender; - else - role = role_receiver; - - // - // Print preamble - // - - Serial.begin(57600); - printf_begin(); - printf("\n\rRF24/examples/pingpair_irq/\n\r"); - printf("ROLE: %s\n\r",role_friendly_name[role]); - - // - // Setup and configure rf radio - // - - radio.begin(); - - // We will be using the Ack Payload feature, so please enable it - radio.enableAckPayload(); - - // - // Open pipes to other nodes for communication - // - - // 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 ) - { - radio.openWritingPipe(pipe); - } - else - { - radio.openReadingPipe(1,pipe); - } - - // - // Start listening - // - - if ( role == role_receiver ) - radio.startListening(); - - // - // Dump the configuration of the rf unit for debugging - // - - radio.printDetails(); - - // - // Attach interrupt handler to interrupt #0 (using pin 2) - // on BOTH the sender and receiver - // - - attachInterrupt(0, check_radio, FALLING); -} - -static uint32_t message_count = 0; - -void loop(void) -{ - // - // Sender role. Repeatedly send the current time - // - - if (role == role_sender) - { - // Take the time, and send it. - unsigned long time = millis(); - printf("Now sending %lu\n\r",time); - radio.startWrite( &time, sizeof(unsigned long) ); - - // Try again soon - delay(2000); - } - - // - // Receiver role: Does nothing! All the work is in IRQ - // - -} - -void check_radio(void) -{ - // What happened? - bool tx,fail,rx; - radio.whatHappened(tx,fail,rx); - - // Have we successfully transmitted? - if ( tx ) - { - if ( role == role_sender ) - printf("Send:OK\n\r"); - - if ( role == role_receiver ) - printf("Ack Payload:Sent\n\r"); - } - - // Have we failed to transmit? - if ( fail ) - { - if ( role == role_sender ) - printf("Send:Failed\n\r"); - - 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 ) ) - radio.powerDown(); - - // Did we receive a message? - if ( rx ) - { - // If we're the sender, we've received an ack payload - if ( role == role_sender ) - { - radio.read(&message_count,sizeof(message_count)); - printf("Ack:%lu\n\r",message_count); - } - - // If we're the receiver, we've received a time message - if ( role == role_receiver ) - { - // Get this payload and dump it - static unsigned long got_time; - radio.read( &got_time, sizeof(got_time) ); - printf("Got payload %lu\n\r",got_time); - - // Add an ack packet for the next time around. This is a simple - // packet counter - radio.writeAckPayload( 1, &message_count, sizeof(message_count) ); - ++message_count; - } - } -} - -// vim:ai:cin:sts=2 sw=2 ft=cpp diff --git a/examples/pingpair_pl/Jamfile b/examples/pingpair_pl/Jamfile deleted file mode 100644 index 901f8da..0000000 --- a/examples/pingpair_pl/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_pl/pingpair_pl.pde b/examples/pingpair_pl/pingpair_pl.pde deleted file mode 100644 index 70aed6e..0000000 --- a/examples/pingpair_pl/pingpair_pl.pde +++ /dev/null @@ -1,180 +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 of using Ack Payloads - * - * This is an example of how to do two-way communication without changing - * transmit/receive modes. Here, a payload is set to the transmitter within - * the Ack packet of each transmission. Note that the payload is set BEFORE - * the sender's message arrives. - */ - -#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 'ping' transmitter -const short role_pin = 7; - -// -// 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_sender = 1, role_receiver } role_e; - -// The debug-friendly names of those roles -const char* role_friendly_name[] = { "invalid", "Sender", "Receiver"}; - -// 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_sender; - else - role = role_receiver; - - // - // Print preamble - // - - Serial.begin(57600); - printf_begin(); - printf("\n\rRF24/examples/pingpair_pl/\n\r"); - printf("ROLE: %s\n\r",role_friendly_name[role]); - - // - // Setup and configure rf radio - // - - radio.begin(); - - // We will be using the Ack Payload feature, so please enable it - radio.enableAckPayload(); - - // - // 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_sender ) - { - radio.openWritingPipe(pipe); - } - else - { - radio.openReadingPipe(1,pipe); - } - - // - // Start listening - // - - if ( role == role_receiver ) - radio.startListening(); - - // - // Dump the configuration of the rf unit for debugging - // - - radio.printDetails(); -} - -void loop(void) -{ - static uint32_t message_count = 0; - - // - // Sender role. Repeatedly send the current time - // - - if (role == role_sender) - { - // 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) ); - - if ( radio.isAckPayloadAvailable() ) - { - radio.read(&message_count,sizeof(message_count)); - printf("Ack: [%lu] ",message_count); - } - printf("OK\n\r"); - - // Try again soon - delay(2000); - } - - // - // Receiver role. Receive each packet, dump it out, add ack payload for next time - // - - if ( role == role_receiver ) - { - // if there is data ready - if ( radio.available() ) - { - // Dump the payloads until we've gotten everything - static 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\n",got_time); - } - - // Add an ack packet for the next time around. This is a simple - // packet counter - radio.writeAckPayload( 1, &message_count, sizeof(message_count) ); - ++message_count; - } - } -} -// vim:ai:cin:sts=2 sw=2 ft=cpp diff --git a/examples/pingpair_sleepy/Jamfile b/examples/pingpair_sleepy/Jamfile deleted file mode 100644 index 901f8da..0000000 --- a/examples/pingpair_sleepy/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_sleepy/pingpair_sleepy.ino b/examples/pingpair_sleepy/pingpair_sleepy.ino new file mode 100644 index 0000000..ebc024e --- /dev/null +++ b/examples/pingpair_sleepy/pingpair_sleepy.ino @@ -0,0 +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 9 & 10 +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,LOW); + 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(57600); + printf_begin(); + printf("\n\rRF24/examples/pingpair_sleepy/\n\r"); + printf("ROLE: %s\n\r",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. + + printf("Now sending... "); + unsigned long time = millis(); // Take the time, and send it. + 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 + printf("Failed, response timed out.\n\r"); + }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. + printf("Sent response.\n\r"); + radio.startListening(); // Now, resume listening so we catch the next packets. + }else{ + Serial.println("Sleeping"); + delay(200); // 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); + Serial.println(wdtcsr); + 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("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/pingpair_sleepy/pingpair_sleepy.pde b/examples/pingpair_sleepy/pingpair_sleepy.pde deleted file mode 100644 index 49daa69..0000000 --- a/examples/pingpair_sleepy/pingpair_sleepy.pde +++ /dev/null @@ -1,288 +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 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 pingpair.pde example, but the - * ping node powers down the radio and sleeps the MCU after every - * ping/pong cycle. - * - * As with the pingpair.pde example, 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" - -// -// 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 'ping' transmitter -const int role_pin = 7; - -// -// 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; - -// -// 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; - -// -// Normal operation -// - -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(57600); - printf_begin(); - printf("\n\rRF24/examples/pingpair_sleepy/\n\r"); - printf("ROLE: %s\n\r",role_friendly_name[role]); - - // - // Prepare sleep parameters - // - - // Only the ping out role sleeps. Wake up every 4s to send a ping - if ( role == role_ping_out ) - setup_watchdog(wdt_1s); - - // - // 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(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); - } - - // - // Shut down the system - // - - // Experiment with some delay here to see if it has an effect - delay(500); - - // Power down the radio. Note that the radio will get powered back up - // on the next write() call. - radio.powerDown(); - - // Sleep the MCU. The watchdog timer will awaken in a short while, and - // continue execution here. - while( sleep_cycles_remaining ) - do_sleep(); - - sleep_cycles_remaining = sleep_cycles_per_transmission; - } - - // - // Pong back role. Receive each packet, dump it out, and send it back - // - // This is untouched from the pingpair example. - // - - 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. Include our time, because the ping_out millis counter is unreliable - // due to it sleeping - printf("Got payload %lu @ %lu...",got_time,millis()); - } - - // First, stop listening so we can talk - radio.stopListening(); - - // Send the final one back. - radio.write( &got_time, sizeof(unsigned long) ); - printf("Sent response.\n\r"); - - // Now, resume listening so we catch the next packets. - radio.startListening(); - } - } -} - -// -// Sleep helpers -// - -// 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) -{ - prescalar = min(9,prescalar); - uint8_t wdtcsr = prescalar & 7; - if ( prescalar & 8 ) - wdtcsr |= _BV(WDP3); - - MCUSR &= ~_BV(WDRF); - WDTCSR = _BV(WDCE) | _BV(WDE); - WDTCSR = _BV(WDCE) | wdtcsr | _BV(WDIE); -} - -ISR(WDT_vect) -{ - --sleep_cycles_remaining; -} - -void do_sleep(void) -{ - set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here - sleep_enable(); - - sleep_mode(); // System sleeps here - - sleep_disable(); // System continues execution here when watchdog timed out -} - -// vim:ai:cin:sts=2 sw=2 ft=cpp diff --git a/keywords.txt b/keywords.txt index d0bd557..d829ee9 100644 --- a/keywords.txt +++ b/keywords.txt @@ -7,6 +7,9 @@ startListening KEYWORD2 stopListening KEYWORD2 write KEYWORD2 + writeFast KEYWORD2 + writeBlocking KEYWORD2 + txStandBy KEYWORD2 available KEYWORD2 read KEYWORD2 openWritingPipe KEYWORD2