Fix: Ext. timeout hang, examples, board support

- Initial support for Due and ATTiny boards
- Fix for 0 timeout period causing hang
- Remove unnecessary delays from startWrite
- Cleaned up/Updated example files
- Optimization is nearing completion
This commit is contained in:
TMRh20
2014-04-01 23:47:19 -06:00
parent 6263bccd02
commit 2f7e4489ba
31 changed files with 1437 additions and 2638 deletions
+27 -26
View File
@@ -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.
+70 -17
View File
@@ -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)<<ARD | (count&0xf)<<ARC);
}
// vim:ai:cin:sts=2 sw=2 ft=cpp
#if defined (ATTINY)
#include "pins_arduino.h"
#if defined( __AVR_ATtiny85__ )
const static uint8_t _CS = PB4;
const static uint8_t _MOSI = PB1;
const static uint8_t _MISO = PB0;
const static uint8_t _SCK = PB2;
#endif
#if defined( __AVR_ATtiny84__ )
const static uint8_t _CS = 3;
const static uint8_t _MOSI = 5;
const static uint8_t _MISO = 4;
const static uint8_t _SCK = 6;
#endif
SPIClass SPI;
void SPIClass::begin() {
pinMode(_SCK, OUTPUT);
pinMode(_MOSI, OUTPUT);
pinMode(_MISO,INPUT);
digitalWrite(_MISO,HIGH);
digitalWrite(_SCK, LOW);
digitalWrite(_MOSI, LOW);
}
void SPIClass::end() {
pinMode(_SCK, INPUT);
pinMode(_MOSI, INPUT);
pinMode(_MISO,INPUT);
}
void SPIClass::setDataMode(byte mode){}
void SPIClass::setClockDivider(byte rate){}
#endif
+517 -491
View File
File diff suppressed because it is too large Load Diff
+114 -46
View File
@@ -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 <WProgram.h>
#else
#include <Arduino.h>
#endif
#if ARDUINO < 100
#include <WProgram.h>
#else
#include <Arduino.h>
#endif
#include <stddef.h>
#include <stddef.h>
// Stuff that is normally provided by Arduino
#ifdef ARDUINO
#include <SPI.h>
#else
#include <stdint.h>
#include <stdio.h>
#include <string.h>
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 <avr/pgmspace.h>
#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 <avr/pgmspace.h>
#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 <stdint.h>
#include <stdio.h>
#include <string.h>
extern HardwareSPI SPI;
#else
#if !defined( __AVR_ATtiny85__ ) || defined( __AVR_ATtiny84__)
#include <SPI.h>
#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
+63 -104
View File
@@ -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 <SPI.h>
#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]);
}
}
}
}
-210
View File
@@ -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 ;
}
@@ -0,0 +1,124 @@
/*
// March 2014 - TMRh20 - Updated along with High Speed RF24 Library fork
// Parts derived from examples by J. Coliz <maniacbug@ymail.com>
/**
* 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 <SPI.h>
#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
}
}
}
+26 -24
View File
@@ -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<cycles; i++){ //Loop through a number of cycles
data[0] = i; //Change the first byte of the payload for identification
if(!radio.writeFast(&data,32)){ //Write to the FIFO buffers
if(!radio.writeFast(&data,32)){ //Write to the FIFO buffers
counter++; //Keep count of failed payloads
}
}
stopTime = millis();
while(!radio.txStandBy()){ } //This should be called to wait for completion and put the radio in standby mode after transmission
stopTime = millis();
//This should be called to wait for completion and put the radio in standby mode after transmission, returns 0 if data still in FIFO (timed out), 1 if success
if(!radio.txStandBy()){ counter+=3; } //Standby, block only until FIFO empty or auto-retry timeout. Flush TX FIFO if failed
//radio.txStandBy(1000); //Standby, using extended timeout period of 1 second
float numBytes = cycles * 32;
float rate = numBytes / (stopTime - startTime) / cycles;
float numBytes = cycles*32;
float rate = numBytes / (stopTime - startTime);
printf("Transfer complete at "); Serial.print(rate); printf(" KB/s \n\r");
printf("%d of ",counter); Serial.print(cycles); printf(" Packets Failed to Send\n\r");
@@ -104,16 +101,17 @@ void loop(void){
if(role == RX){
if(role == RX){
while(radio.available()){
radio.read(&data,32);
counter++;
}
if(millis() - rxTimer > 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
// vim:cin:ai:sts=2 sw=2 ft=cpp
-219
View File
@@ -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 ] ;
-186
View File
@@ -1,186 +0,0 @@
/*
Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
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 <SPI.h>
#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
+123
View File
@@ -0,0 +1,123 @@
/*
// March 2014 - TMRh20 - Updated along with High Speed RF24 Library fork
// Parts derived from examples by J. Coliz <maniacbug@ymail.com>
/**
* 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 <SPI.h>
#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();
}
}
}
-219
View File
@@ -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 ] ;
+144
View File
@@ -0,0 +1,144 @@
/*
Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
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 <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"
#include "printf.h"
#include <avr/sleep.h>
#include <avr/power.h>
// 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
}
}
}
-216
View File
@@ -1,216 +0,0 @@
/*
Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
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 <SPI.h>
#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
-206
View File
@@ -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 <WProgram.h>" > $(<)
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 ;
-180
View File
@@ -1,180 +0,0 @@
/*
Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
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 <SPI.h>
#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
-206
View File
@@ -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 <WProgram.h>" > $(<)
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 ;
@@ -0,0 +1,226 @@
/*
Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
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 <SPI.h>
#include <avr/sleep.h>
#include <avr/power.h>
#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);
}
@@ -1,288 +0,0 @@
/*
Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
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 <SPI.h>
#include <avr/sleep.h>
#include <avr/power.h>
#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
+3
View File
@@ -7,6 +7,9 @@
startListening KEYWORD2
stopListening KEYWORD2
write KEYWORD2
writeFast KEYWORD2
writeBlocking KEYWORD2
txStandBy KEYWORD2
available KEYWORD2
read KEYWORD2
openWritingPipe KEYWORD2