From 997140e0d46b6ec98da293a6a280bfd413bdb050 Mon Sep 17 00:00:00 2001 From: maniacbug Date: Thu, 28 Apr 2011 16:14:07 -0700 Subject: [PATCH 01/10] Added new sample, based on pingpair --- examples/ackpacket/.gitignore | 1 + examples/ackpacket/ackpacket.pde | 204 ++++++++++++++++++++++ examples/ackpacket/makefile | 290 +++++++++++++++++++++++++++++++ examples/ackpacket/printf.h | 33 ++++ 4 files changed, 528 insertions(+) create mode 100644 examples/ackpacket/.gitignore create mode 100644 examples/ackpacket/ackpacket.pde create mode 100644 examples/ackpacket/makefile create mode 100644 examples/ackpacket/printf.h diff --git a/examples/ackpacket/.gitignore b/examples/ackpacket/.gitignore new file mode 100644 index 0000000..ea1472e --- /dev/null +++ b/examples/ackpacket/.gitignore @@ -0,0 +1 @@ +output/ diff --git a/examples/ackpacket/ackpacket.pde b/examples/ackpacket/ackpacket.pde new file mode 100644 index 0000000..b0b3f0e --- /dev/null +++ b/examples/ackpacket/ackpacket.pde @@ -0,0 +1,204 @@ +/* + Copyright (C) 2011 James Coliz, Jr. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. + */ + +/** + * Example 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. + */ + +#include +#include "nRF24L01.h" +#include "RF24.h" +#include "printf.h" + +// +// Hardware configuration +// + +// Set up nRF24L01 radio on SPI bus plus pins 8 & 9 + +RF24 radio(8,9); + +// 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; + +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(9600); + 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(); + + // + // 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); + } + + // Try again 1s later + delay(1000); + } + + // + // Pong back role. Receive each packet, dump it out, and send it back + // + + if ( role == role_pong_back ) + { + // if there is data ready + if ( radio.available() ) + { + // Dump the payloads until we've gotten everything + unsigned long got_time; + boolean done = false; + while (!done) + { + // Fetch the payload, and see if this was the last one. + done = radio.read( &got_time, sizeof(unsigned long) ); + + // Spew it + printf("Got payload %lu...",got_time); + } + + // 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(); + } + } +} +// vim:ci sts=2 sw=2 ft=cpp diff --git a/examples/ackpacket/makefile b/examples/ackpacket/makefile new file mode 100644 index 0000000..a1c6d4c --- /dev/null +++ b/examples/ackpacket/makefile @@ -0,0 +1,290 @@ +# Arduino Makefile +# Arduino adaptation by mellis, eighthave, oli.keller +# Modified by Kerry Wong to support NetBeans +# Modified by Rob Gray (Graynomad) for use with Windows and no IDE +# This works in my environment and I use it to program two different +# 328-based boards and a Mega2560. It's not necessarily robust and +# I may have broken something in the original file that I don't use. +# +# This makefile allows you to build sketches from the command line +# without the Arduino environment. +# +# Instructions for using the makefile: +# +# 1. Copy this file into the folder with your sketch. The project code file +# should have a .c extension however the file gets copied to a .cpp before +# compilation so you still write in C++. +# +# 2. Modify the lines between the double ### rows to set the paths +# comm ports etc for your system. EG. c:/progra~1/arduino/arduino-00 +# for the Arduino IDE, Note the use of short folder name, don't use +# "Program files" because spaces will break the build. +# +# Set the line containing "MCU" to match your board's processor. +# Typically ATmega328 or ATmega2560. If you're using a LilyPad Arduino, +# change F_CPU to 8000000. +# +# 3. At the command line, change to the directory containing your +# program's file and the makefile. +# +# 4. Type "make" and press enter to compile/verify your program. +# The default make target will also perform the uplode using avrdude. +# +# The first time this is done all required libraries will be built +# and a core.a file will be created in the output folder. +# +# NOTES: +# All output goes into a folder called "output" underneath the working folder. +# The default all: target creates symbol (.sym) and expanded assembly +# (.lss) files and uploads the program. +# +# +########################################################## +########################################################## +# Select processor here +MCU = atmega328p +#MCU = atmega2560 + +ifeq ($(MCU),atmega2560) +UPLOAD_RATE = 115200 +AVRDUDE_PROTOCOL = stk500v2 +COM = 39 +endif + +ifeq ($(MCU),atmega328p) +UPLOAD_RATE = 57600 +AVRDUDE_PROTOCOL = stk500v1 +COM = 33 +endif + +UNAME := $(shell uname) + +ifeq ($(UNAME),Darwin) +ARDUINO_VERSION = 21 +ARDUINO_DIR = /opt/arduino-00$(ARDUINO_VERSION) +AVR_TOOLS_PATH = $(ARDUINO_DIR)/hardware/tools/avr/bin +AVRDUDECONFIG_PATH = $(ARDUINO_DIR)/hardware/tools/avr/etc +PORT = /dev/tty.usbserial-A600eHIs +PORT2 = /dev/tty.usbserial-A9007LmI +else +ARDUINO_VERSION = 22 +ARDUINO_DIR = /opt/arduino-00$(ARDUINO_VERSION) +AVR_TOOLS_PATH = /usr/bin +AVRDUDECONFIG_PATH = $(ARDUINO_DIR)/hardware/tools +PORT = /dev/ttyUSB0 +PORT2 = /dev/ttyUSB1 +endif + +PROJECT_NAME = $(notdir $(PWD)) +PROJECT_DIR = . +ARDUINO_CORE = $(ARDUINO_DIR)/hardware/arduino/cores/arduino +ARDUINO_AVR = $(ARDUINO_DIR)/hardware/tools/avr/avr/include/avr +ARDUINO_LIB = $(ARDUINO_DIR)/libraries +F_CPU = 16000000 + +########################################################## +########################################################## + +# Note that if your program has dependencies other than those +# already listed below, you will need to add them accordingly. +C_MODULES = \ +$(ARDUINO_CORE)/wiring_pulse.c \ +$(ARDUINO_CORE)/wiring_analog.c \ +$(ARDUINO_CORE)/pins_arduino.c \ +$(ARDUINO_CORE)/wiring.c \ +$(ARDUINO_CORE)/wiring_digital.c \ +$(ARDUINO_CORE)/WInterrupts.c \ +$(ARDUINO_CORE)/wiring_shift.c \ + +CXX_MODULES = \ +$(ARDUINO_CORE)/Tone.cpp \ +$(ARDUINO_CORE)/main.cpp \ +$(ARDUINO_CORE)/WMath.cpp \ +$(ARDUINO_CORE)/Print.cpp \ +$(ARDUINO_CORE)/HardwareSerial.cpp \ +$(ARDUINO_LIB)/SPI/SPI.cpp \ +../../RF24.cpp + +CXX_APP = output/$(PROJECT_NAME).cpp +MODULES = $(C_MODULES) $(CXX_MODULES) +SRC = $(C_MODULES) +CXXSRC = $(CXX_MODULES) $(CXX_APP) +FORMAT = ihex + +# Name of this Makefile (used for "make depend"). +MAKEFILE = Makefile + +# Debugging format. +# Native formats for AVR-GCC's -g are stabs [default], or dwarf-2. +# AVR (extended) COFF requires stabs, plus an avr-objcopy run. +#DEBUG = stabs +DEBUG = + +OPT = s + +# Place -D or -U options here +CDEFS = -DF_CPU=$(F_CPU)L -DARDUINO=$(ARDUINO_VERSION) +CXXDEFS = -DF_CPU=$(F_CPU)L -DARDUINO=$(ARDUINO_VERSION) + +# Place -I options here +CINCS = -I$(ARDUINO_CORE) -I$(ARDUINO_LIB) -I$(PROJECT_DIR) -I$(ARDUINO_AVR) -I$(ARDUINO_LIB)/SPI -I../.. + +CXXINCS = -I$(ARDUINO_CORE) -I$(ARDUINO_LIB) + +# Compiler flag to set the C Standard level. +# c89 - "ANSI" C +# gnu89 - c89 plus GCC extensions +# c99 - ISO C99 standard (not yet fully implemented) +# gnu99 - c99 plus GCC extensions +#CSTANDARD = -std=gnu99 +CDEBUG = -g$(DEBUG) +#CWARN = -Wall -Wstrict-prototypes +CWARN = -Wall # show all warnings +#CWARN = -w # suppress all warnings +CMAP = -Wl,-Map,output.map +####CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums +CTUNING = -ffunction-sections -fdata-sections +CXXTUNING = -fno-exceptions -ffunction-sections -fdata-sections +#CEXTRA = -Wa,-adhlns=$(<:.c=.lst) +MMCU = -mmcu=$(MCU) + +CFLAGS = $(CDEBUG) -O$(OPT) $(CMAP) $(CWARN) $(CTUNING) $(MMCU) $(CDEFS) $(CINCS) $(CSTANDARD) $(CEXTRA) +CXXFLAGS = $(CDEBUG) -O$(OPT) $(CWARN) $(CXXTUNING) $(CDEFS) $(CINCS) +#ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs +LDFLAGS = -O$(OPT) -lm -Wl,--gc-sections +#LDFLAGS = -O$(OPT) -lm -Wl,-Map,output/$(PROJECT_NAME).map + +# Programming support using avrdude. Settings and variables. +AVRDUDE_PORT = $(PORT) +AVRDUDE_WRITE_FLASH = -U flash:w:output/$(PROJECT_NAME).hex:i + +AVRDUDE_FLAGS = -V -F -D -C $(AVRDUDECONFIG_PATH)/avrdude.conf \ +-p $(MCU) -c $(AVRDUDE_PROTOCOL) -b $(UPLOAD_RATE) + +# Program settings +CC = $(AVR_TOOLS_PATH)/avr-gcc +CXX = $(AVR_TOOLS_PATH)/avr-g++ +LD = $(AVR_TOOLS_PATH)/avr-gcc +OBJCOPY = $(AVR_TOOLS_PATH)/avr-objcopy +OBJDUMP = $(AVR_TOOLS_PATH)/avr-objdump +AR = $(AVR_TOOLS_PATH)/avr-ar +SIZE = $(AVR_TOOLS_PATH)/avr-size +NM = $(AVR_TOOLS_PATH)/avr-nm +AVRDUDE = $(AVR_TOOLS_PATH)/avrdude +REMOVE = rm -f +MV = mv -f + +# Define all object files. +OBJ = $(SRC:.c=.o) $(CXXSRC:.cpp=.o) $(ASRC:.S=.o) +OBJ_MODULES = $(C_MODULES:.c=.o) $(CXX_MODULES:.cpp=.o) + +# Define all listing files. +LST = $(ASRC:.S=.lst) $(CXXSRC:.cpp=.lst) $(SRC:.c=.lst) + +# Combine all necessary flags and optional flags. +# Add target processor to flags. +ALL_CFLAGS = $(CFLAGS) -mmcu=$(MCU) +ALL_CXXFLAGS = $(CXXFLAGS) -mmcu=$(MCU) +ALL_ASFLAGS = -x assembler-with-cpp $(ASFLAGS) -mmcu=$(MCU) +ALL_LDFLAGS = $(LDFLAGS) -mmcu=$(MCU) + +# Default target. +# This is th etarget that gets executed with a make command +# that has no parameters, ie "make". +all: applet_files build sym lss size upload + +build: elf hex + +output/$(PROJECT_NAME).cpp: $(PROJECT_NAME).pde + test -d output || mkdir output + echo "#include " > $@ + echo "#line 1 \"$<\"" >> $@ + cat $< >> $@ + +elf: output/$(PROJECT_NAME).elf +hex: output/$(PROJECT_NAME).hex +eep: output/$(PROJECT_NAME).eep +lss: output/$(PROJECT_NAME).lss +#sym: output/$(PROJECT_NAME).sym + +# Upload HEX file to Arduino +upload: output/$(PROJECT_NAME).hex + $(AVRDUDE) $(AVRDUDE_FLAGS) -P $(PORT) $(AVRDUDE_WRITE_FLASH) + $(AVRDUDE) $(AVRDUDE_FLAGS) -P $(PORT2) $(AVRDUDE_WRITE_FLASH) + +sym: + $(NM) -n -C --format=posix output/$(PROJECT_NAME).elf > output/$(PROJECT_NAME).sym + +# Display size of file. +size: + $(SIZE) output/$(PROJECT_NAME).elf + +# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB. +COFFCONVERT=$(OBJCOPY) --debugging \ +--change-section-address .data-0x800000 \ +--change-section-address .bss-0x800000 \ +--change-section-address .noinit-0x800000 \ +--change-section-address .eeprom-0x810000 + +coff: output/$(PROJECT_NAME).elf + $(COFFCONVERT) -O coff-avr output/$(PROJECT_NAME).elf $(PROJECT_NAME).cof + + extcoff: $(PROJECT_NAME).elf + $(COFFCONVERT) -O coff-ext-avr output/$(PROJECT_NAME).elf $(PROJECT_NAME).cof + +.SUFFIXES: .elf .hex .eep .lss .sym + +.elf.hex: + $(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@ + +.elf.eep: + $(OBJCOPY) -O $(FORMAT) -j .eeprom --set-section-flags=.eeprom="alloc,load" \ + --no-change-warnings \ + --change-section-lma .eeprom=0 $< $@ + +# Create extended listing file from ELF output file. +.elf.lss: + $(OBJDUMP) -h -S $< > $@ + +# Link: create ELF output file from library. +#output/$(PROJECT_NAME).elf: $(PROJECT_NAME).c output/core.a +output/$(PROJECT_NAME).elf: output/$(PROJECT_NAME).o output/core.a + $(LD) $(ALL_LDFLAGS) -o $@ output/$(PROJECT_NAME).o output/core.a + +output/core.a: $(OBJ_MODULES) + @for i in $(OBJ_MODULES); do echo $(AR) rcs output/core.a $$i; $(AR) rcs output/core.a $$i; done + +# Compile: create object files from C++ source files. +.cpp.o: + $(CXX) -c $(ALL_CXXFLAGS) $< -o $@ + +# Compile: create object files from C source files. +.c.o: + $(CC) -c $(ALL_CFLAGS) $< -o $@ + +# Compile: create assembler files from C source files. +.c.s: + $(CC) -S $(ALL_CFLAGS) $< -o $@ + +# Assemble: create object files from assembler source files. +.S.o: + $(CC) -c $(ALL_ASFLAGS) $< -o $@ + +# Automatic dependencies +%.d: %.c + $(CC) -M $(ALL_CFLAGS) $< | sed "s;$(notdir $*).o:;$*.o $*.d:;" > $@ + +%.d: %.cpp + $(CXX) -M $(ALL_CXXFLAGS) $< | sed "s;$(notdir $*).o:;$*.o $*.d:;" > $@ + +# Target: clean project. +clean: + $(REMOVE) output/$(PROJECT_NAME).hex output/$(PROJECT_NAME).eep output/$(PROJECT_NAME).cof output/$(PROJECT_NAME).elf \ + output/$(PROJECT_NAME).map output/$(PROJECT_NAME).sym output/$(PROJECT_NAME).lss output/core.a \ + $(OBJ) $(LST) $(SRC:.c=.s) $(SRC:.c=.d) $(CXXSRC:.cpp=.s) $(CXXSRC:.cpp=.d) + +#.PHONY: all build elf hex eep lss sym program coff extcoff clean applet_files sizebefore sizeafter +.PHONY: all build elf hex eep lss sym program coff extcoff applet_files sizebefore sizeafter + +#include $(SRC:.c=.d) +#include $(CXXSRC:.cpp=.d) diff --git a/examples/ackpacket/printf.h b/examples/ackpacket/printf.h new file mode 100644 index 0000000..63501e4 --- /dev/null +++ b/examples/ackpacket/printf.h @@ -0,0 +1,33 @@ +/* + Copyright (C) 2011 James Coliz, Jr. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. + */ + +/** + * @file printf.h + * + * Setup necessary to direct stdout to the Arduino Serial library, which + * enables 'printf' + */ + +#ifndef __PRINTF_H__ +#define __PRINTF_H__ + +#include "WProgram.h" + +int serial_putc( char c, FILE *t ) +{ + Serial.write( c ); + + return c; +} + +void printf_begin(void) +{ + fdevopen( &serial_putc, 0 ); +} + +#endif // __PRINTF_H__ From 79628e7849cc3b9f92bc7203ed3d8fbe49d8e537 Mon Sep 17 00:00:00 2001 From: maniacbug Date: Sat, 30 Apr 2011 15:31:04 -0700 Subject: [PATCH 02/10] Added ack payload. Added a sample using pingpair as a base with minimal changes. --- RF24.cpp | 111 +++++++++- RF24.h | 13 +- examples/pingpair_pl/.gitignore | 1 + examples/pingpair_pl/makefile | 290 +++++++++++++++++++++++++++ examples/pingpair_pl/pingpair_pl.pde | 249 +++++++++++++++++++++++ examples/pingpair_pl/printf.h | 33 +++ nRF24L01.h | 14 ++ 7 files changed, 703 insertions(+), 8 deletions(-) create mode 100644 examples/pingpair_pl/.gitignore create mode 100644 examples/pingpair_pl/makefile create mode 100644 examples/pingpair_pl/pingpair_pl.pde create mode 100644 examples/pingpair_pl/printf.h diff --git a/RF24.cpp b/RF24.cpp index b9606cd..6b8a073 100644 --- a/RF24.cpp +++ b/RF24.cpp @@ -11,7 +11,7 @@ #include "RF24.h" #include "nRF24L01.h" -#undef SERIAL_DEBUG +#define SERIAL_DEBUG #ifdef SERIAL_DEBUG #define IF_SERIAL_DEBUG(x) (x) #else @@ -51,6 +51,18 @@ uint8_t RF24::read_register(uint8_t reg, uint8_t* buf, uint8_t len) /******************************************************************/ +uint8_t RF24::read_register(uint8_t reg) +{ + csn(LOW); + SPI.transfer( R_REGISTER | ( REGISTER_MASK & reg ) ); + uint8_t result = SPI.transfer(0xff); + + csn(HIGH); + return result; +} + +/******************************************************************/ + uint8_t RF24::write_register(uint8_t reg, const uint8_t* buf, uint8_t len) { uint8_t status; @@ -190,7 +202,7 @@ void RF24::print_observe_tx(uint8_t value) /******************************************************************/ RF24::RF24(uint8_t _cepin, uint8_t _cspin): - ce_pin(_cepin), csn_pin(_cspin), payload_size(32) + ce_pin(_cepin), csn_pin(_cspin), payload_size(32), ack_packet_available(false) { } @@ -327,6 +339,7 @@ boolean RF24::write( const void* buf, uint8_t len ) // Transmitter power-up write_register(CONFIG, _BV(EN_CRC) | _BV(PWR_UP)); + delay(2); // Send the payload write_payload( buf, len ); @@ -339,18 +352,37 @@ boolean RF24::write( const void* buf, uint8_t len ) // Monitor the send uint8_t observe_tx; uint8_t status; + uint8_t retries = 255; do { status = read_register(OBSERVE_TX,&observe_tx,1); IF_SERIAL_DEBUG(Serial.print(status,HEX)); IF_SERIAL_DEBUG(Serial.print(observe_tx,HEX)); + if ( ! retries-- ) + { + IF_SERIAL_DEBUG(printf("ABORTED: too many retries\n\r")); + break; + } } while( ! ( status & ( _BV(TX_DS) | _BV(MAX_RT) ) ) ); if ( status & _BV(TX_DS) ) result = true; - - IF_SERIAL_DEBUG(Serial.println(result?"...OK.":"...Failed")); + + IF_SERIAL_DEBUG(Serial.print(result?"...OK.":"...Failed")); + + ack_packet_available = ( status & _BV(RX_DR) ); + uint8_t pl_len = 0; + if ( ack_packet_available ) + { + write_register(STATUS,_BV(RX_DR) ); + csn(LOW); + SPI.transfer( R_RX_PL_WID ); + pl_len = SPI.transfer(0xff); + csn(HIGH); + IF_SERIAL_DEBUG(Serial.print("[AckPacket]/")); + IF_SERIAL_DEBUG(Serial.println(pl_len,DEC)); + } // Yay, we are done. ce(LOW); @@ -378,12 +410,11 @@ boolean RF24::available(void) boolean RF24::available(uint8_t* pipe_num) { uint8_t status = get_status(); + IF_SERIAL_DEBUG(print_status(status)); boolean result = ( status & _BV(RX_DR) ); if (result) { - IF_SERIAL_DEBUG(print_status(status)); - // If the caller wants the pipe number, include that if ( pipe_num ) *pipe_num = ( status >> RX_P_NO ) & B111; @@ -394,6 +425,12 @@ boolean RF24::available(uint8_t* pipe_num) // actually READ the payload? write_register(STATUS,_BV(RX_DR) ); + + // Handle ack payload receipt + if ( status & _BV(TX_DS) ) + { + write_register(STATUS,_BV(TX_DS)); + } } return result; @@ -458,5 +495,67 @@ void RF24::openReadingPipe(uint8_t child, uint64_t value) write_register(EN_RXADDR,en_rx); } } + +/******************************************************************/ + +void RF24::toggle_features(void) +{ + csn(LOW); + SPI.transfer( ACTIVATE ); + SPI.transfer( 0x73 ); + csn(HIGH); +} + +/******************************************************************/ + +void RF24::enableAckPayload(void) +{ + // + // enable ack payload and dynamic payload features + // + + write_register(FEATURE,read_register(FEATURE) | _BV(EN_ACK_PAY) | _BV(EN_DPL) ); + + // If it didn't work, the features are not enabled + if ( ! read_register(FEATURE) ) + { + // So enable them and try again + toggle_features(); + write_register(FEATURE,read_register(FEATURE) | _BV(EN_ACK_PAY) | _BV(EN_DPL) ); + } + + IF_SERIAL_DEBUG(printf("FEATURE=%i\n\r",read_register(FEATURE))); + + // + // Enable dynamic payload on pipe 0 + // + + write_register(DYNPD,read_register(DYNPD) | _BV(DPL_P1) | _BV(DPL_P0)); +} + +/******************************************************************/ + +void RF24::writeAckPayload(uint8_t pipe, const void* buf, uint8_t len) +{ + const uint8_t* current = (const uint8_t*)buf; + + csn(LOW); + SPI.transfer( W_ACK_PAYLOAD | ( pipe & B111 ) ); + uint8_t data_len = min(len,32); + while ( data_len-- ) + SPI.transfer(*current++); + + csn(HIGH); +} + +/******************************************************************/ + +boolean RF24::isAckPayloadAvailable(void) +{ + boolean result = ack_packet_available; + ack_packet_available = false; + return result; +} + // vim:ai:cin:sts=2 sw=2 ft=cpp diff --git a/RF24.h b/RF24.h index 2b2d6b0..d68deac 100644 --- a/RF24.h +++ b/RF24.h @@ -21,6 +21,7 @@ private: uint8_t ce_pin; /**< "Chip Enable" pin, activates the RX or TX role */ uint8_t csn_pin; /**< SPI Chip select */ uint8_t payload_size; /**< Fixed size of payloads */ + boolean ack_packet_available; /**< Whether there is an ack packet waiting */ protected: /** @@ -54,6 +55,8 @@ protected: * @return Current value of status register */ uint8_t read_register(uint8_t reg, uint8_t* buf, uint8_t len) ; + + uint8_t read_register(uint8_t reg) ; /** * Write a chunk of data to a register @@ -95,7 +98,7 @@ protected: * @return Current value of status register */ uint8_t read_payload(void* buf, uint8_t len) ; - +public: /** * Empty the receive buffer * @@ -109,7 +112,7 @@ protected: * @return Current value of status register */ uint8_t flush_tx(void); - +protected: /** * Retrieve the current status of the chip * @@ -135,6 +138,7 @@ protected: */ void print_observe_tx(uint8_t value) ; + void toggle_features(void); /**@}*/ public: @@ -299,6 +303,11 @@ public: */ void openReadingPipe(uint8_t number, uint64_t address); + void enableAckPayload(void); + + void writeAckPayload(uint8_t pipe, const void* buf, uint8_t len); + + boolean isAckPayloadAvailable(void); }; /** diff --git a/examples/pingpair_pl/.gitignore b/examples/pingpair_pl/.gitignore new file mode 100644 index 0000000..ea1472e --- /dev/null +++ b/examples/pingpair_pl/.gitignore @@ -0,0 +1 @@ +output/ diff --git a/examples/pingpair_pl/makefile b/examples/pingpair_pl/makefile new file mode 100644 index 0000000..a1c6d4c --- /dev/null +++ b/examples/pingpair_pl/makefile @@ -0,0 +1,290 @@ +# Arduino Makefile +# Arduino adaptation by mellis, eighthave, oli.keller +# Modified by Kerry Wong to support NetBeans +# Modified by Rob Gray (Graynomad) for use with Windows and no IDE +# This works in my environment and I use it to program two different +# 328-based boards and a Mega2560. It's not necessarily robust and +# I may have broken something in the original file that I don't use. +# +# This makefile allows you to build sketches from the command line +# without the Arduino environment. +# +# Instructions for using the makefile: +# +# 1. Copy this file into the folder with your sketch. The project code file +# should have a .c extension however the file gets copied to a .cpp before +# compilation so you still write in C++. +# +# 2. Modify the lines between the double ### rows to set the paths +# comm ports etc for your system. EG. c:/progra~1/arduino/arduino-00 +# for the Arduino IDE, Note the use of short folder name, don't use +# "Program files" because spaces will break the build. +# +# Set the line containing "MCU" to match your board's processor. +# Typically ATmega328 or ATmega2560. If you're using a LilyPad Arduino, +# change F_CPU to 8000000. +# +# 3. At the command line, change to the directory containing your +# program's file and the makefile. +# +# 4. Type "make" and press enter to compile/verify your program. +# The default make target will also perform the uplode using avrdude. +# +# The first time this is done all required libraries will be built +# and a core.a file will be created in the output folder. +# +# NOTES: +# All output goes into a folder called "output" underneath the working folder. +# The default all: target creates symbol (.sym) and expanded assembly +# (.lss) files and uploads the program. +# +# +########################################################## +########################################################## +# Select processor here +MCU = atmega328p +#MCU = atmega2560 + +ifeq ($(MCU),atmega2560) +UPLOAD_RATE = 115200 +AVRDUDE_PROTOCOL = stk500v2 +COM = 39 +endif + +ifeq ($(MCU),atmega328p) +UPLOAD_RATE = 57600 +AVRDUDE_PROTOCOL = stk500v1 +COM = 33 +endif + +UNAME := $(shell uname) + +ifeq ($(UNAME),Darwin) +ARDUINO_VERSION = 21 +ARDUINO_DIR = /opt/arduino-00$(ARDUINO_VERSION) +AVR_TOOLS_PATH = $(ARDUINO_DIR)/hardware/tools/avr/bin +AVRDUDECONFIG_PATH = $(ARDUINO_DIR)/hardware/tools/avr/etc +PORT = /dev/tty.usbserial-A600eHIs +PORT2 = /dev/tty.usbserial-A9007LmI +else +ARDUINO_VERSION = 22 +ARDUINO_DIR = /opt/arduino-00$(ARDUINO_VERSION) +AVR_TOOLS_PATH = /usr/bin +AVRDUDECONFIG_PATH = $(ARDUINO_DIR)/hardware/tools +PORT = /dev/ttyUSB0 +PORT2 = /dev/ttyUSB1 +endif + +PROJECT_NAME = $(notdir $(PWD)) +PROJECT_DIR = . +ARDUINO_CORE = $(ARDUINO_DIR)/hardware/arduino/cores/arduino +ARDUINO_AVR = $(ARDUINO_DIR)/hardware/tools/avr/avr/include/avr +ARDUINO_LIB = $(ARDUINO_DIR)/libraries +F_CPU = 16000000 + +########################################################## +########################################################## + +# Note that if your program has dependencies other than those +# already listed below, you will need to add them accordingly. +C_MODULES = \ +$(ARDUINO_CORE)/wiring_pulse.c \ +$(ARDUINO_CORE)/wiring_analog.c \ +$(ARDUINO_CORE)/pins_arduino.c \ +$(ARDUINO_CORE)/wiring.c \ +$(ARDUINO_CORE)/wiring_digital.c \ +$(ARDUINO_CORE)/WInterrupts.c \ +$(ARDUINO_CORE)/wiring_shift.c \ + +CXX_MODULES = \ +$(ARDUINO_CORE)/Tone.cpp \ +$(ARDUINO_CORE)/main.cpp \ +$(ARDUINO_CORE)/WMath.cpp \ +$(ARDUINO_CORE)/Print.cpp \ +$(ARDUINO_CORE)/HardwareSerial.cpp \ +$(ARDUINO_LIB)/SPI/SPI.cpp \ +../../RF24.cpp + +CXX_APP = output/$(PROJECT_NAME).cpp +MODULES = $(C_MODULES) $(CXX_MODULES) +SRC = $(C_MODULES) +CXXSRC = $(CXX_MODULES) $(CXX_APP) +FORMAT = ihex + +# Name of this Makefile (used for "make depend"). +MAKEFILE = Makefile + +# Debugging format. +# Native formats for AVR-GCC's -g are stabs [default], or dwarf-2. +# AVR (extended) COFF requires stabs, plus an avr-objcopy run. +#DEBUG = stabs +DEBUG = + +OPT = s + +# Place -D or -U options here +CDEFS = -DF_CPU=$(F_CPU)L -DARDUINO=$(ARDUINO_VERSION) +CXXDEFS = -DF_CPU=$(F_CPU)L -DARDUINO=$(ARDUINO_VERSION) + +# Place -I options here +CINCS = -I$(ARDUINO_CORE) -I$(ARDUINO_LIB) -I$(PROJECT_DIR) -I$(ARDUINO_AVR) -I$(ARDUINO_LIB)/SPI -I../.. + +CXXINCS = -I$(ARDUINO_CORE) -I$(ARDUINO_LIB) + +# Compiler flag to set the C Standard level. +# c89 - "ANSI" C +# gnu89 - c89 plus GCC extensions +# c99 - ISO C99 standard (not yet fully implemented) +# gnu99 - c99 plus GCC extensions +#CSTANDARD = -std=gnu99 +CDEBUG = -g$(DEBUG) +#CWARN = -Wall -Wstrict-prototypes +CWARN = -Wall # show all warnings +#CWARN = -w # suppress all warnings +CMAP = -Wl,-Map,output.map +####CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums +CTUNING = -ffunction-sections -fdata-sections +CXXTUNING = -fno-exceptions -ffunction-sections -fdata-sections +#CEXTRA = -Wa,-adhlns=$(<:.c=.lst) +MMCU = -mmcu=$(MCU) + +CFLAGS = $(CDEBUG) -O$(OPT) $(CMAP) $(CWARN) $(CTUNING) $(MMCU) $(CDEFS) $(CINCS) $(CSTANDARD) $(CEXTRA) +CXXFLAGS = $(CDEBUG) -O$(OPT) $(CWARN) $(CXXTUNING) $(CDEFS) $(CINCS) +#ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs +LDFLAGS = -O$(OPT) -lm -Wl,--gc-sections +#LDFLAGS = -O$(OPT) -lm -Wl,-Map,output/$(PROJECT_NAME).map + +# Programming support using avrdude. Settings and variables. +AVRDUDE_PORT = $(PORT) +AVRDUDE_WRITE_FLASH = -U flash:w:output/$(PROJECT_NAME).hex:i + +AVRDUDE_FLAGS = -V -F -D -C $(AVRDUDECONFIG_PATH)/avrdude.conf \ +-p $(MCU) -c $(AVRDUDE_PROTOCOL) -b $(UPLOAD_RATE) + +# Program settings +CC = $(AVR_TOOLS_PATH)/avr-gcc +CXX = $(AVR_TOOLS_PATH)/avr-g++ +LD = $(AVR_TOOLS_PATH)/avr-gcc +OBJCOPY = $(AVR_TOOLS_PATH)/avr-objcopy +OBJDUMP = $(AVR_TOOLS_PATH)/avr-objdump +AR = $(AVR_TOOLS_PATH)/avr-ar +SIZE = $(AVR_TOOLS_PATH)/avr-size +NM = $(AVR_TOOLS_PATH)/avr-nm +AVRDUDE = $(AVR_TOOLS_PATH)/avrdude +REMOVE = rm -f +MV = mv -f + +# Define all object files. +OBJ = $(SRC:.c=.o) $(CXXSRC:.cpp=.o) $(ASRC:.S=.o) +OBJ_MODULES = $(C_MODULES:.c=.o) $(CXX_MODULES:.cpp=.o) + +# Define all listing files. +LST = $(ASRC:.S=.lst) $(CXXSRC:.cpp=.lst) $(SRC:.c=.lst) + +# Combine all necessary flags and optional flags. +# Add target processor to flags. +ALL_CFLAGS = $(CFLAGS) -mmcu=$(MCU) +ALL_CXXFLAGS = $(CXXFLAGS) -mmcu=$(MCU) +ALL_ASFLAGS = -x assembler-with-cpp $(ASFLAGS) -mmcu=$(MCU) +ALL_LDFLAGS = $(LDFLAGS) -mmcu=$(MCU) + +# Default target. +# This is th etarget that gets executed with a make command +# that has no parameters, ie "make". +all: applet_files build sym lss size upload + +build: elf hex + +output/$(PROJECT_NAME).cpp: $(PROJECT_NAME).pde + test -d output || mkdir output + echo "#include " > $@ + echo "#line 1 \"$<\"" >> $@ + cat $< >> $@ + +elf: output/$(PROJECT_NAME).elf +hex: output/$(PROJECT_NAME).hex +eep: output/$(PROJECT_NAME).eep +lss: output/$(PROJECT_NAME).lss +#sym: output/$(PROJECT_NAME).sym + +# Upload HEX file to Arduino +upload: output/$(PROJECT_NAME).hex + $(AVRDUDE) $(AVRDUDE_FLAGS) -P $(PORT) $(AVRDUDE_WRITE_FLASH) + $(AVRDUDE) $(AVRDUDE_FLAGS) -P $(PORT2) $(AVRDUDE_WRITE_FLASH) + +sym: + $(NM) -n -C --format=posix output/$(PROJECT_NAME).elf > output/$(PROJECT_NAME).sym + +# Display size of file. +size: + $(SIZE) output/$(PROJECT_NAME).elf + +# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB. +COFFCONVERT=$(OBJCOPY) --debugging \ +--change-section-address .data-0x800000 \ +--change-section-address .bss-0x800000 \ +--change-section-address .noinit-0x800000 \ +--change-section-address .eeprom-0x810000 + +coff: output/$(PROJECT_NAME).elf + $(COFFCONVERT) -O coff-avr output/$(PROJECT_NAME).elf $(PROJECT_NAME).cof + + extcoff: $(PROJECT_NAME).elf + $(COFFCONVERT) -O coff-ext-avr output/$(PROJECT_NAME).elf $(PROJECT_NAME).cof + +.SUFFIXES: .elf .hex .eep .lss .sym + +.elf.hex: + $(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@ + +.elf.eep: + $(OBJCOPY) -O $(FORMAT) -j .eeprom --set-section-flags=.eeprom="alloc,load" \ + --no-change-warnings \ + --change-section-lma .eeprom=0 $< $@ + +# Create extended listing file from ELF output file. +.elf.lss: + $(OBJDUMP) -h -S $< > $@ + +# Link: create ELF output file from library. +#output/$(PROJECT_NAME).elf: $(PROJECT_NAME).c output/core.a +output/$(PROJECT_NAME).elf: output/$(PROJECT_NAME).o output/core.a + $(LD) $(ALL_LDFLAGS) -o $@ output/$(PROJECT_NAME).o output/core.a + +output/core.a: $(OBJ_MODULES) + @for i in $(OBJ_MODULES); do echo $(AR) rcs output/core.a $$i; $(AR) rcs output/core.a $$i; done + +# Compile: create object files from C++ source files. +.cpp.o: + $(CXX) -c $(ALL_CXXFLAGS) $< -o $@ + +# Compile: create object files from C source files. +.c.o: + $(CC) -c $(ALL_CFLAGS) $< -o $@ + +# Compile: create assembler files from C source files. +.c.s: + $(CC) -S $(ALL_CFLAGS) $< -o $@ + +# Assemble: create object files from assembler source files. +.S.o: + $(CC) -c $(ALL_ASFLAGS) $< -o $@ + +# Automatic dependencies +%.d: %.c + $(CC) -M $(ALL_CFLAGS) $< | sed "s;$(notdir $*).o:;$*.o $*.d:;" > $@ + +%.d: %.cpp + $(CXX) -M $(ALL_CXXFLAGS) $< | sed "s;$(notdir $*).o:;$*.o $*.d:;" > $@ + +# Target: clean project. +clean: + $(REMOVE) output/$(PROJECT_NAME).hex output/$(PROJECT_NAME).eep output/$(PROJECT_NAME).cof output/$(PROJECT_NAME).elf \ + output/$(PROJECT_NAME).map output/$(PROJECT_NAME).sym output/$(PROJECT_NAME).lss output/core.a \ + $(OBJ) $(LST) $(SRC:.c=.s) $(SRC:.c=.d) $(CXXSRC:.cpp=.s) $(CXXSRC:.cpp=.d) + +#.PHONY: all build elf hex eep lss sym program coff extcoff clean applet_files sizebefore sizeafter +.PHONY: all build elf hex eep lss sym program coff extcoff applet_files sizebefore sizeafter + +#include $(SRC:.c=.d) +#include $(CXXSRC:.cpp=.d) diff --git a/examples/pingpair_pl/pingpair_pl.pde b/examples/pingpair_pl/pingpair_pl.pde new file mode 100644 index 0000000..96896e3 --- /dev/null +++ b/examples/pingpair_pl/pingpair_pl.pde @@ -0,0 +1,249 @@ +/* + Copyright (C) 2011 James Coliz, Jr. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. + */ + +/** + * Example 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. + */ + +#include +#include "nRF24L01.h" +#include "RF24.h" +#include "printf.h" + +// +// Hardware configuration +// + +// Set up nRF24L01 radio on SPI bus plus pins 8 & 9 + +RF24 radio(8,9); + +// 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; + +const short led_pin = 13; // flash the led when a packet has been sent + +// +// Topology +// + +// Radio pipe addresses for the 2 nodes to communicate. +const uint64_t pipes[2] = { 0xE8E8F0F0E1LL, 0xE8E8F0F0D2LL }; + +// +// Role management +// +// Set up role. This sketch uses the same software for all the nodes +// in this system. Doing so greatly simplifies testing. The hardware itself specifies +// which node it is. +// +// This is done through the role_pin +// + +// The various roles supported by this sketch +typedef enum { role_ping_out = 1, role_pong_back } role_e; + +// The debug-friendly names of those roles +const char* role_friendly_name[] = { "invalid", "Ping out", "Pong back"}; + +// The role of the current running sketch +role_e role; + +void setup(void) +{ + // + // Role + // + + // set up the role pin + pinMode(role_pin, INPUT); + digitalWrite(role_pin,HIGH); + delay(20); // Just to get a solid reading on the role pin + + // read the address pin, establish our role + if ( digitalRead(role_pin) ) + role = role_ping_out; + else + role = role_pong_back; + + // + // Print preamble + // + + Serial.begin(9600); + 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 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) ); + + if ( radio.isAckPayloadAvailable() ) + { + static char response[32]; + radio.read(response,32); + printf("Ack: [%s]",response); + + // try flushing the rx buffer to get the ack packet out of the system ... + radio.flush_rx(); + } + + // 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 > 500 ) + timeout = true; + + // Describe the results + if ( timeout ) + { + printf("Failed, response timed out.\n\r"); + } + else + { + // Stop listening while we are clocking out the data + radio.stopListening(); + + // Dump the payloads until we've gotten everything + unsigned long got_time; + boolean 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 response %lu, round-trip delay: %lu\n\r",got_time,millis()-got_time); + } + // Begin listening again + radio.startListening(); + } + + // Try again later + digitalWrite(led_pin,HIGH); + delay(3000); + digitalWrite(led_pin,LOW); + } + + // + // Pong back role. Receive each packet, dump it out, and send it back + // + + if ( role == role_pong_back ) + { + // if there is data ready + if ( radio.available() ) + { + // Dump the payloads until we've gotten everything + unsigned long got_time; + boolean done = false; + while (!done) + { + // Fetch the payload, and see if this was the last one. + done = radio.read( &got_time, sizeof(unsigned long) ); + + // Spew it + printf("Got payload %lu...",got_time); + } + + // First, stop listening so we can talk + radio.stopListening(); + + //delay(250); + + // necessary to flush the ack packet out + // but kills the entire tx queue, which I might not + // want in the future!! + radio.flush_tx(); + + // 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(); + + //delay(250); + + // Add an ack packet for the next time around + static unsigned id = 0; + static char pl_buffer[10]; + memset(pl_buffer,' ',10); + pl_buffer[9] = 0; + snprintf(pl_buffer,10,"id %04x",id++); + radio.writeAckPayload( 1, pl_buffer, 10 ); + + } + } +} +// vim:ai:cin:sts=2 sw=2 ft=cpp diff --git a/examples/pingpair_pl/printf.h b/examples/pingpair_pl/printf.h new file mode 100644 index 0000000..63501e4 --- /dev/null +++ b/examples/pingpair_pl/printf.h @@ -0,0 +1,33 @@ +/* + Copyright (C) 2011 James Coliz, Jr. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. + */ + +/** + * @file printf.h + * + * Setup necessary to direct stdout to the Arduino Serial library, which + * enables 'printf' + */ + +#ifndef __PRINTF_H__ +#define __PRINTF_H__ + +#include "WProgram.h" + +int serial_putc( char c, FILE *t ) +{ + Serial.write( c ); + + return c; +} + +void printf_begin(void) +{ + fdevopen( &serial_putc, 0 ); +} + +#endif // __PRINTF_H__ diff --git a/nRF24L01.h b/nRF24L01.h index 10aedb3..5f4d1b8 100644 --- a/nRF24L01.h +++ b/nRF24L01.h @@ -47,6 +47,8 @@ #define RX_PW_P4 0x15 #define RX_PW_P5 0x16 #define FIFO_STATUS 0x17 +#define DYNPD 0x1C +#define FEATURE 0x1D /* Bit Mnemonics */ #define MASK_RX_DR 6 @@ -87,13 +89,25 @@ #define TX_EMPTY 4 #define RX_FULL 1 #define RX_EMPTY 0 +#define DPL_P5 5 +#define DPL_P4 4 +#define DPL_P3 3 +#define DPL_P2 2 +#define DPL_P1 1 +#define DPL_P0 0 +#define EN_DPL 2 +#define EN_ACK_PAY 1 +#define EN_DYN_ACK 0 /* Instruction Mnemonics */ #define R_REGISTER 0x00 #define W_REGISTER 0x20 #define REGISTER_MASK 0x1F +#define ACTIVATE 0x50 +#define R_RX_PL_WID 0x60 #define R_RX_PAYLOAD 0x61 #define W_TX_PAYLOAD 0xA0 +#define W_ACK_PAYLOAD 0xA8 #define FLUSH_TX 0xE1 #define FLUSH_RX 0xE2 #define REUSE_TX_PL 0xE3 From 38392fa5f46e945afbfe7e7962a7d94702e9a727 Mon Sep 17 00:00:00 2001 From: maniacbug Date: Sat, 30 Apr 2011 19:52:13 -0700 Subject: [PATCH 03/10] Removed ping/pong. Now tx just sends and rx just sends ack payload --- examples/pingpair_pl/pingpair_pl.pde | 68 ++-------------------------- 1 file changed, 4 insertions(+), 64 deletions(-) diff --git a/examples/pingpair_pl/pingpair_pl.pde b/examples/pingpair_pl/pingpair_pl.pde index 96896e3..7f7dcec 100644 --- a/examples/pingpair_pl/pingpair_pl.pde +++ b/examples/pingpair_pl/pingpair_pl.pde @@ -136,9 +136,6 @@ void loop(void) 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); @@ -149,45 +146,8 @@ void loop(void) static char response[32]; radio.read(response,32); printf("Ack: [%s]",response); - - // try flushing the rx buffer to get the ack packet out of the system ... - radio.flush_rx(); - } - - // 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 > 500 ) - timeout = true; - - // Describe the results - if ( timeout ) - { - printf("Failed, response timed out.\n\r"); - } - else - { - // Stop listening while we are clocking out the data - radio.stopListening(); - - // Dump the payloads until we've gotten everything - unsigned long got_time; - boolean 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 response %lu, round-trip delay: %lu\n\r",got_time,millis()-got_time); - } - // Begin listening again - radio.startListening(); - } + } + printf(" OK\n\r"); // Try again later digitalWrite(led_pin,HIGH); @@ -196,7 +156,7 @@ void loop(void) } // - // Pong back role. Receive each packet, dump it out, and send it back + // Pong back role. Receive each packet, dump it out, add ack payload for next time // if ( role == role_pong_back ) @@ -213,28 +173,9 @@ void loop(void) done = radio.read( &got_time, sizeof(unsigned long) ); // Spew it - printf("Got payload %lu...",got_time); + printf("Got payload %lu\n",got_time); } - // First, stop listening so we can talk - radio.stopListening(); - - //delay(250); - - // necessary to flush the ack packet out - // but kills the entire tx queue, which I might not - // want in the future!! - radio.flush_tx(); - - // 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(); - - //delay(250); - // Add an ack packet for the next time around static unsigned id = 0; static char pl_buffer[10]; @@ -242,7 +183,6 @@ void loop(void) pl_buffer[9] = 0; snprintf(pl_buffer,10,"id %04x",id++); radio.writeAckPayload( 1, pl_buffer, 10 ); - } } } From 39b15c8b55f8e86ac0295cf430123818eb9db349 Mon Sep 17 00:00:00 2001 From: maniacbug Date: Sat, 30 Apr 2011 21:10:33 -0700 Subject: [PATCH 04/10] Stripped down extraneous pipe opens, and other un-needed things. --- examples/pingpair_pl/pingpair_pl.pde | 49 ++++++++++++---------------- 1 file changed, 20 insertions(+), 29 deletions(-) diff --git a/examples/pingpair_pl/pingpair_pl.pde b/examples/pingpair_pl/pingpair_pl.pde index 7f7dcec..6bcb495 100644 --- a/examples/pingpair_pl/pingpair_pl.pde +++ b/examples/pingpair_pl/pingpair_pl.pde @@ -32,14 +32,12 @@ RF24 radio(8,9); // Leave open to be the 'ping' transmitter const short role_pin = 7; -const short led_pin = 13; // flash the led when a packet has been sent - // // Topology // -// Radio pipe addresses for the 2 nodes to communicate. -const uint64_t pipes[2] = { 0xE8E8F0F0E1LL, 0xE8E8F0F0D2LL }; +// Radio pipe address for the 2 nodes to communicate. +const uint64_t pipe = 0xE8E8F0F0E1LL; // // Role management @@ -99,27 +97,24 @@ void setup(void) // 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) + // 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_ping_out ) { - radio.openWritingPipe(pipes[0]); - radio.openReadingPipe(1,pipes[1]); + radio.openWritingPipe(pipe); } else { - radio.openWritingPipe(pipes[1]); - radio.openReadingPipe(1,pipes[0]); + radio.openReadingPipe(1,pipe); } // // Start listening // - radio.startListening(); + if ( role == role_pong_back ) + radio.startListening(); // // Dump the configuration of the rf unit for debugging @@ -130,6 +125,8 @@ void setup(void) void loop(void) { + static uint32_t id = 0; + // // Ping out role. Repeatedly send the current time // @@ -143,16 +140,13 @@ void loop(void) if ( radio.isAckPayloadAvailable() ) { - static char response[32]; - radio.read(response,32); - printf("Ack: [%s]",response); + radio.read(&id,sizeof(id)); + printf("Ack: [%lu] ",id); } - printf(" OK\n\r"); + printf("OK\n\r"); - // Try again later - digitalWrite(led_pin,HIGH); - delay(3000); - digitalWrite(led_pin,LOW); + // Try again soon + delay(2000); } // @@ -165,7 +159,7 @@ void loop(void) if ( radio.available() ) { // Dump the payloads until we've gotten everything - unsigned long got_time; + static unsigned long got_time; boolean done = false; while (!done) { @@ -176,13 +170,10 @@ void loop(void) printf("Got payload %lu\n",got_time); } - // Add an ack packet for the next time around - static unsigned id = 0; - static char pl_buffer[10]; - memset(pl_buffer,' ',10); - pl_buffer[9] = 0; - snprintf(pl_buffer,10,"id %04x",id++); - radio.writeAckPayload( 1, pl_buffer, 10 ); + // Add an ack packet for the next time around. This is a simple + // packet counter + radio.writeAckPayload( 1, &id, sizeof(id) ); + ++id; } } } From ffc7d099ed05e48724b6471b4d75ce98d8a05075 Mon Sep 17 00:00:00 2001 From: maniacbug Date: Tue, 10 May 2011 14:39:01 -0700 Subject: [PATCH 05/10] Got ack payloads working. Renamed from 'ackpacket' --- RF24.cpp | 33 ++++++++++++++++++++++----------- RF24.h | 17 ++++++++++++++--- 2 files changed, 36 insertions(+), 14 deletions(-) diff --git a/RF24.cpp b/RF24.cpp index 6b8a073..215ade7 100644 --- a/RF24.cpp +++ b/RF24.cpp @@ -202,7 +202,7 @@ void RF24::print_observe_tx(uint8_t value) /******************************************************************/ RF24::RF24(uint8_t _cepin, uint8_t _cspin): - ce_pin(_cepin), csn_pin(_cspin), payload_size(32), ack_packet_available(false) + ce_pin(_cepin), csn_pin(_cspin), payload_size(32), ack_payload_available(false) { } @@ -371,17 +371,13 @@ boolean RF24::write( const void* buf, uint8_t len ) IF_SERIAL_DEBUG(Serial.print(result?"...OK.":"...Failed")); - ack_packet_available = ( status & _BV(RX_DR) ); - uint8_t pl_len = 0; - if ( ack_packet_available ) + ack_payload_available = ( status & _BV(RX_DR) ); + if ( ack_payload_available ) { write_register(STATUS,_BV(RX_DR) ); - csn(LOW); - SPI.transfer( R_RX_PL_WID ); - pl_len = SPI.transfer(0xff); - csn(HIGH); + ack_payload_length = read_payload_length(); IF_SERIAL_DEBUG(Serial.print("[AckPacket]/")); - IF_SERIAL_DEBUG(Serial.println(pl_len,DEC)); + IF_SERIAL_DEBUG(Serial.println(ack_payload_length,DEC)); } // Yay, we are done. @@ -398,6 +394,21 @@ boolean RF24::write( const void* buf, uint8_t len ) return result; } + +/******************************************************************/ + +uint8_t RF24::read_payload_length(void) +{ + uint8_t result = 0; + + csn(LOW); + SPI.transfer( R_RX_PL_WID ); + result = SPI.transfer(0xff); + csn(HIGH); + + return result; +} + /******************************************************************/ boolean RF24::available(void) @@ -552,8 +563,8 @@ void RF24::writeAckPayload(uint8_t pipe, const void* buf, uint8_t len) boolean RF24::isAckPayloadAvailable(void) { - boolean result = ack_packet_available; - ack_packet_available = false; + boolean result = ack_payload_available; + ack_payload_available = false; return result; } diff --git a/RF24.h b/RF24.h index d68deac..e920b3f 100644 --- a/RF24.h +++ b/RF24.h @@ -21,7 +21,8 @@ private: uint8_t ce_pin; /**< "Chip Enable" pin, activates the RX or TX role */ uint8_t csn_pin; /**< SPI Chip select */ uint8_t payload_size; /**< Fixed size of payloads */ - boolean ack_packet_available; /**< Whether there is an ack packet waiting */ + boolean ack_payload_available; /**< Whether there is an ack payload waiting */ + uint8_t ack_payload_length; /**< Dynamic size of pending ack payload. Note: not used. */ protected: /** @@ -98,7 +99,17 @@ protected: * @return Current value of status register */ uint8_t read_payload(void* buf, uint8_t len) ; -public: + + /** + * Read the payload length + * + * For dynamic payloads, this pulls the size of the payload off + * the chip + * + * @return Payload length of last-received dynamic payload + */ + uint8_t read_payload_length(void); + /** * Empty the receive buffer * @@ -112,7 +123,7 @@ public: * @return Current value of status register */ uint8_t flush_tx(void); -protected: + /** * Retrieve the current status of the chip * From f3356f31a281dc5895b16c7842440a32979738bf Mon Sep 17 00:00:00 2001 From: maniacbug Date: Tue, 10 May 2011 14:40:42 -0700 Subject: [PATCH 06/10] Cleaned up comments, variables names, enums --- examples/pingpair_pl/pingpair_pl.pde | 46 ++++++++++++++-------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/examples/pingpair_pl/pingpair_pl.pde b/examples/pingpair_pl/pingpair_pl.pde index 6bcb495..952648b 100644 --- a/examples/pingpair_pl/pingpair_pl.pde +++ b/examples/pingpair_pl/pingpair_pl.pde @@ -7,12 +7,12 @@ */ /** - * Example RF Radio Ping Pair + * Example of using Ack Payloads * - * 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. + * 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 @@ -36,24 +36,24 @@ const short role_pin = 7; // Topology // -// Radio pipe address for the 2 nodes to communicate. +// 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 +// 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; +typedef enum { role_sender = 1, role_receiver } role_e; // The debug-friendly names of those roles -const char* role_friendly_name[] = { "invalid", "Ping out", "Pong back"}; +const char* role_friendly_name[] = { "invalid", "Sender", "Receiver"}; // The role of the current running sketch role_e role; @@ -71,9 +71,9 @@ void setup(void) // read the address pin, establish our role if ( digitalRead(role_pin) ) - role = role_ping_out; + role = role_sender; else - role = role_pong_back; + role = role_receiver; // // Print preamble @@ -100,7 +100,7 @@ void setup(void) // 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_ping_out ) + if ( role == role_sender ) { radio.openWritingPipe(pipe); } @@ -113,7 +113,7 @@ void setup(void) // Start listening // - if ( role == role_pong_back ) + if ( role == role_receiver ) radio.startListening(); // @@ -125,13 +125,13 @@ void setup(void) void loop(void) { - static uint32_t id = 0; + static uint32_t message_count = 0; // - // Ping out role. Repeatedly send the current time + // Sender role. Repeatedly send the current time // - if (role == role_ping_out) + if (role == role_sender) { // Take the time, and send it. This will block until complete unsigned long time = millis(); @@ -140,8 +140,8 @@ void loop(void) if ( radio.isAckPayloadAvailable() ) { - radio.read(&id,sizeof(id)); - printf("Ack: [%lu] ",id); + radio.read(&message_count,sizeof(message_count)); + printf("Ack: [%lu] ",message_count); } printf("OK\n\r"); @@ -150,10 +150,10 @@ void loop(void) } // - // Pong back role. Receive each packet, dump it out, add ack payload for next time + // Receiver role. Receive each packet, dump it out, add ack payload for next time // - if ( role == role_pong_back ) + if ( role == role_receiver ) { // if there is data ready if ( radio.available() ) @@ -172,8 +172,8 @@ void loop(void) // Add an ack packet for the next time around. This is a simple // packet counter - radio.writeAckPayload( 1, &id, sizeof(id) ); - ++id; + radio.writeAckPayload( 1, &message_count, sizeof(message_count) ); + ++message_count; } } } From f9b664cd34834885eb383fd166921239e39f065e Mon Sep 17 00:00:00 2001 From: maniacbug Date: Tue, 10 May 2011 14:42:29 -0700 Subject: [PATCH 07/10] Removed 'ackpacket' example. It was never working --- examples/ackpacket/.gitignore | 1 - examples/ackpacket/ackpacket.pde | 204 ---------------------- examples/ackpacket/makefile | 290 ------------------------------- examples/ackpacket/printf.h | 33 ---- 4 files changed, 528 deletions(-) delete mode 100644 examples/ackpacket/.gitignore delete mode 100644 examples/ackpacket/ackpacket.pde delete mode 100644 examples/ackpacket/makefile delete mode 100644 examples/ackpacket/printf.h diff --git a/examples/ackpacket/.gitignore b/examples/ackpacket/.gitignore deleted file mode 100644 index ea1472e..0000000 --- a/examples/ackpacket/.gitignore +++ /dev/null @@ -1 +0,0 @@ -output/ diff --git a/examples/ackpacket/ackpacket.pde b/examples/ackpacket/ackpacket.pde deleted file mode 100644 index b0b3f0e..0000000 --- a/examples/ackpacket/ackpacket.pde +++ /dev/null @@ -1,204 +0,0 @@ -/* - Copyright (C) 2011 James Coliz, Jr. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -/** - * Example 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. - */ - -#include -#include "nRF24L01.h" -#include "RF24.h" -#include "printf.h" - -// -// Hardware configuration -// - -// Set up nRF24L01 radio on SPI bus plus pins 8 & 9 - -RF24 radio(8,9); - -// 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; - -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(9600); - 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(); - - // - // 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); - } - - // Try again 1s later - delay(1000); - } - - // - // Pong back role. Receive each packet, dump it out, and send it back - // - - if ( role == role_pong_back ) - { - // if there is data ready - if ( radio.available() ) - { - // Dump the payloads until we've gotten everything - unsigned long got_time; - boolean done = false; - while (!done) - { - // Fetch the payload, and see if this was the last one. - done = radio.read( &got_time, sizeof(unsigned long) ); - - // Spew it - printf("Got payload %lu...",got_time); - } - - // 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(); - } - } -} -// vim:ci sts=2 sw=2 ft=cpp diff --git a/examples/ackpacket/makefile b/examples/ackpacket/makefile deleted file mode 100644 index a1c6d4c..0000000 --- a/examples/ackpacket/makefile +++ /dev/null @@ -1,290 +0,0 @@ -# Arduino Makefile -# Arduino adaptation by mellis, eighthave, oli.keller -# Modified by Kerry Wong to support NetBeans -# Modified by Rob Gray (Graynomad) for use with Windows and no IDE -# This works in my environment and I use it to program two different -# 328-based boards and a Mega2560. It's not necessarily robust and -# I may have broken something in the original file that I don't use. -# -# This makefile allows you to build sketches from the command line -# without the Arduino environment. -# -# Instructions for using the makefile: -# -# 1. Copy this file into the folder with your sketch. The project code file -# should have a .c extension however the file gets copied to a .cpp before -# compilation so you still write in C++. -# -# 2. Modify the lines between the double ### rows to set the paths -# comm ports etc for your system. EG. c:/progra~1/arduino/arduino-00 -# for the Arduino IDE, Note the use of short folder name, don't use -# "Program files" because spaces will break the build. -# -# Set the line containing "MCU" to match your board's processor. -# Typically ATmega328 or ATmega2560. If you're using a LilyPad Arduino, -# change F_CPU to 8000000. -# -# 3. At the command line, change to the directory containing your -# program's file and the makefile. -# -# 4. Type "make" and press enter to compile/verify your program. -# The default make target will also perform the uplode using avrdude. -# -# The first time this is done all required libraries will be built -# and a core.a file will be created in the output folder. -# -# NOTES: -# All output goes into a folder called "output" underneath the working folder. -# The default all: target creates symbol (.sym) and expanded assembly -# (.lss) files and uploads the program. -# -# -########################################################## -########################################################## -# Select processor here -MCU = atmega328p -#MCU = atmega2560 - -ifeq ($(MCU),atmega2560) -UPLOAD_RATE = 115200 -AVRDUDE_PROTOCOL = stk500v2 -COM = 39 -endif - -ifeq ($(MCU),atmega328p) -UPLOAD_RATE = 57600 -AVRDUDE_PROTOCOL = stk500v1 -COM = 33 -endif - -UNAME := $(shell uname) - -ifeq ($(UNAME),Darwin) -ARDUINO_VERSION = 21 -ARDUINO_DIR = /opt/arduino-00$(ARDUINO_VERSION) -AVR_TOOLS_PATH = $(ARDUINO_DIR)/hardware/tools/avr/bin -AVRDUDECONFIG_PATH = $(ARDUINO_DIR)/hardware/tools/avr/etc -PORT = /dev/tty.usbserial-A600eHIs -PORT2 = /dev/tty.usbserial-A9007LmI -else -ARDUINO_VERSION = 22 -ARDUINO_DIR = /opt/arduino-00$(ARDUINO_VERSION) -AVR_TOOLS_PATH = /usr/bin -AVRDUDECONFIG_PATH = $(ARDUINO_DIR)/hardware/tools -PORT = /dev/ttyUSB0 -PORT2 = /dev/ttyUSB1 -endif - -PROJECT_NAME = $(notdir $(PWD)) -PROJECT_DIR = . -ARDUINO_CORE = $(ARDUINO_DIR)/hardware/arduino/cores/arduino -ARDUINO_AVR = $(ARDUINO_DIR)/hardware/tools/avr/avr/include/avr -ARDUINO_LIB = $(ARDUINO_DIR)/libraries -F_CPU = 16000000 - -########################################################## -########################################################## - -# Note that if your program has dependencies other than those -# already listed below, you will need to add them accordingly. -C_MODULES = \ -$(ARDUINO_CORE)/wiring_pulse.c \ -$(ARDUINO_CORE)/wiring_analog.c \ -$(ARDUINO_CORE)/pins_arduino.c \ -$(ARDUINO_CORE)/wiring.c \ -$(ARDUINO_CORE)/wiring_digital.c \ -$(ARDUINO_CORE)/WInterrupts.c \ -$(ARDUINO_CORE)/wiring_shift.c \ - -CXX_MODULES = \ -$(ARDUINO_CORE)/Tone.cpp \ -$(ARDUINO_CORE)/main.cpp \ -$(ARDUINO_CORE)/WMath.cpp \ -$(ARDUINO_CORE)/Print.cpp \ -$(ARDUINO_CORE)/HardwareSerial.cpp \ -$(ARDUINO_LIB)/SPI/SPI.cpp \ -../../RF24.cpp - -CXX_APP = output/$(PROJECT_NAME).cpp -MODULES = $(C_MODULES) $(CXX_MODULES) -SRC = $(C_MODULES) -CXXSRC = $(CXX_MODULES) $(CXX_APP) -FORMAT = ihex - -# Name of this Makefile (used for "make depend"). -MAKEFILE = Makefile - -# Debugging format. -# Native formats for AVR-GCC's -g are stabs [default], or dwarf-2. -# AVR (extended) COFF requires stabs, plus an avr-objcopy run. -#DEBUG = stabs -DEBUG = - -OPT = s - -# Place -D or -U options here -CDEFS = -DF_CPU=$(F_CPU)L -DARDUINO=$(ARDUINO_VERSION) -CXXDEFS = -DF_CPU=$(F_CPU)L -DARDUINO=$(ARDUINO_VERSION) - -# Place -I options here -CINCS = -I$(ARDUINO_CORE) -I$(ARDUINO_LIB) -I$(PROJECT_DIR) -I$(ARDUINO_AVR) -I$(ARDUINO_LIB)/SPI -I../.. - -CXXINCS = -I$(ARDUINO_CORE) -I$(ARDUINO_LIB) - -# Compiler flag to set the C Standard level. -# c89 - "ANSI" C -# gnu89 - c89 plus GCC extensions -# c99 - ISO C99 standard (not yet fully implemented) -# gnu99 - c99 plus GCC extensions -#CSTANDARD = -std=gnu99 -CDEBUG = -g$(DEBUG) -#CWARN = -Wall -Wstrict-prototypes -CWARN = -Wall # show all warnings -#CWARN = -w # suppress all warnings -CMAP = -Wl,-Map,output.map -####CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -CTUNING = -ffunction-sections -fdata-sections -CXXTUNING = -fno-exceptions -ffunction-sections -fdata-sections -#CEXTRA = -Wa,-adhlns=$(<:.c=.lst) -MMCU = -mmcu=$(MCU) - -CFLAGS = $(CDEBUG) -O$(OPT) $(CMAP) $(CWARN) $(CTUNING) $(MMCU) $(CDEFS) $(CINCS) $(CSTANDARD) $(CEXTRA) -CXXFLAGS = $(CDEBUG) -O$(OPT) $(CWARN) $(CXXTUNING) $(CDEFS) $(CINCS) -#ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs -LDFLAGS = -O$(OPT) -lm -Wl,--gc-sections -#LDFLAGS = -O$(OPT) -lm -Wl,-Map,output/$(PROJECT_NAME).map - -# Programming support using avrdude. Settings and variables. -AVRDUDE_PORT = $(PORT) -AVRDUDE_WRITE_FLASH = -U flash:w:output/$(PROJECT_NAME).hex:i - -AVRDUDE_FLAGS = -V -F -D -C $(AVRDUDECONFIG_PATH)/avrdude.conf \ --p $(MCU) -c $(AVRDUDE_PROTOCOL) -b $(UPLOAD_RATE) - -# Program settings -CC = $(AVR_TOOLS_PATH)/avr-gcc -CXX = $(AVR_TOOLS_PATH)/avr-g++ -LD = $(AVR_TOOLS_PATH)/avr-gcc -OBJCOPY = $(AVR_TOOLS_PATH)/avr-objcopy -OBJDUMP = $(AVR_TOOLS_PATH)/avr-objdump -AR = $(AVR_TOOLS_PATH)/avr-ar -SIZE = $(AVR_TOOLS_PATH)/avr-size -NM = $(AVR_TOOLS_PATH)/avr-nm -AVRDUDE = $(AVR_TOOLS_PATH)/avrdude -REMOVE = rm -f -MV = mv -f - -# Define all object files. -OBJ = $(SRC:.c=.o) $(CXXSRC:.cpp=.o) $(ASRC:.S=.o) -OBJ_MODULES = $(C_MODULES:.c=.o) $(CXX_MODULES:.cpp=.o) - -# Define all listing files. -LST = $(ASRC:.S=.lst) $(CXXSRC:.cpp=.lst) $(SRC:.c=.lst) - -# Combine all necessary flags and optional flags. -# Add target processor to flags. -ALL_CFLAGS = $(CFLAGS) -mmcu=$(MCU) -ALL_CXXFLAGS = $(CXXFLAGS) -mmcu=$(MCU) -ALL_ASFLAGS = -x assembler-with-cpp $(ASFLAGS) -mmcu=$(MCU) -ALL_LDFLAGS = $(LDFLAGS) -mmcu=$(MCU) - -# Default target. -# This is th etarget that gets executed with a make command -# that has no parameters, ie "make". -all: applet_files build sym lss size upload - -build: elf hex - -output/$(PROJECT_NAME).cpp: $(PROJECT_NAME).pde - test -d output || mkdir output - echo "#include " > $@ - echo "#line 1 \"$<\"" >> $@ - cat $< >> $@ - -elf: output/$(PROJECT_NAME).elf -hex: output/$(PROJECT_NAME).hex -eep: output/$(PROJECT_NAME).eep -lss: output/$(PROJECT_NAME).lss -#sym: output/$(PROJECT_NAME).sym - -# Upload HEX file to Arduino -upload: output/$(PROJECT_NAME).hex - $(AVRDUDE) $(AVRDUDE_FLAGS) -P $(PORT) $(AVRDUDE_WRITE_FLASH) - $(AVRDUDE) $(AVRDUDE_FLAGS) -P $(PORT2) $(AVRDUDE_WRITE_FLASH) - -sym: - $(NM) -n -C --format=posix output/$(PROJECT_NAME).elf > output/$(PROJECT_NAME).sym - -# Display size of file. -size: - $(SIZE) output/$(PROJECT_NAME).elf - -# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB. -COFFCONVERT=$(OBJCOPY) --debugging \ ---change-section-address .data-0x800000 \ ---change-section-address .bss-0x800000 \ ---change-section-address .noinit-0x800000 \ ---change-section-address .eeprom-0x810000 - -coff: output/$(PROJECT_NAME).elf - $(COFFCONVERT) -O coff-avr output/$(PROJECT_NAME).elf $(PROJECT_NAME).cof - - extcoff: $(PROJECT_NAME).elf - $(COFFCONVERT) -O coff-ext-avr output/$(PROJECT_NAME).elf $(PROJECT_NAME).cof - -.SUFFIXES: .elf .hex .eep .lss .sym - -.elf.hex: - $(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@ - -.elf.eep: - $(OBJCOPY) -O $(FORMAT) -j .eeprom --set-section-flags=.eeprom="alloc,load" \ - --no-change-warnings \ - --change-section-lma .eeprom=0 $< $@ - -# Create extended listing file from ELF output file. -.elf.lss: - $(OBJDUMP) -h -S $< > $@ - -# Link: create ELF output file from library. -#output/$(PROJECT_NAME).elf: $(PROJECT_NAME).c output/core.a -output/$(PROJECT_NAME).elf: output/$(PROJECT_NAME).o output/core.a - $(LD) $(ALL_LDFLAGS) -o $@ output/$(PROJECT_NAME).o output/core.a - -output/core.a: $(OBJ_MODULES) - @for i in $(OBJ_MODULES); do echo $(AR) rcs output/core.a $$i; $(AR) rcs output/core.a $$i; done - -# Compile: create object files from C++ source files. -.cpp.o: - $(CXX) -c $(ALL_CXXFLAGS) $< -o $@ - -# Compile: create object files from C source files. -.c.o: - $(CC) -c $(ALL_CFLAGS) $< -o $@ - -# Compile: create assembler files from C source files. -.c.s: - $(CC) -S $(ALL_CFLAGS) $< -o $@ - -# Assemble: create object files from assembler source files. -.S.o: - $(CC) -c $(ALL_ASFLAGS) $< -o $@ - -# Automatic dependencies -%.d: %.c - $(CC) -M $(ALL_CFLAGS) $< | sed "s;$(notdir $*).o:;$*.o $*.d:;" > $@ - -%.d: %.cpp - $(CXX) -M $(ALL_CXXFLAGS) $< | sed "s;$(notdir $*).o:;$*.o $*.d:;" > $@ - -# Target: clean project. -clean: - $(REMOVE) output/$(PROJECT_NAME).hex output/$(PROJECT_NAME).eep output/$(PROJECT_NAME).cof output/$(PROJECT_NAME).elf \ - output/$(PROJECT_NAME).map output/$(PROJECT_NAME).sym output/$(PROJECT_NAME).lss output/core.a \ - $(OBJ) $(LST) $(SRC:.c=.s) $(SRC:.c=.d) $(CXXSRC:.cpp=.s) $(CXXSRC:.cpp=.d) - -#.PHONY: all build elf hex eep lss sym program coff extcoff clean applet_files sizebefore sizeafter -.PHONY: all build elf hex eep lss sym program coff extcoff applet_files sizebefore sizeafter - -#include $(SRC:.c=.d) -#include $(CXXSRC:.cpp=.d) diff --git a/examples/ackpacket/printf.h b/examples/ackpacket/printf.h deleted file mode 100644 index 63501e4..0000000 --- a/examples/ackpacket/printf.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - Copyright (C) 2011 James Coliz, Jr. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -/** - * @file printf.h - * - * Setup necessary to direct stdout to the Arduino Serial library, which - * enables 'printf' - */ - -#ifndef __PRINTF_H__ -#define __PRINTF_H__ - -#include "WProgram.h" - -int serial_putc( char c, FILE *t ) -{ - Serial.write( c ); - - return c; -} - -void printf_begin(void) -{ - fdevopen( &serial_putc, 0 ); -} - -#endif // __PRINTF_H__ From 72dc77467e0d42a0e0ccc2c5d20e2506074330e0 Mon Sep 17 00:00:00 2001 From: maniacbug Date: Tue, 10 May 2011 14:51:51 -0700 Subject: [PATCH 08/10] Created a new example to show sleeping in between sends. This isn't done yet. It's just a copy of pingpair for now. --- examples/pingpair_sleepy/.gitignore | 1 + examples/pingpair_sleepy/makefile | 290 +++++++++++++++++++ examples/pingpair_sleepy/pingpair_sleepy.pde | 205 +++++++++++++ examples/pingpair_sleepy/printf.h | 33 +++ 4 files changed, 529 insertions(+) create mode 100644 examples/pingpair_sleepy/.gitignore create mode 100644 examples/pingpair_sleepy/makefile create mode 100644 examples/pingpair_sleepy/pingpair_sleepy.pde create mode 100644 examples/pingpair_sleepy/printf.h diff --git a/examples/pingpair_sleepy/.gitignore b/examples/pingpair_sleepy/.gitignore new file mode 100644 index 0000000..ea1472e --- /dev/null +++ b/examples/pingpair_sleepy/.gitignore @@ -0,0 +1 @@ +output/ diff --git a/examples/pingpair_sleepy/makefile b/examples/pingpair_sleepy/makefile new file mode 100644 index 0000000..a1c6d4c --- /dev/null +++ b/examples/pingpair_sleepy/makefile @@ -0,0 +1,290 @@ +# Arduino Makefile +# Arduino adaptation by mellis, eighthave, oli.keller +# Modified by Kerry Wong to support NetBeans +# Modified by Rob Gray (Graynomad) for use with Windows and no IDE +# This works in my environment and I use it to program two different +# 328-based boards and a Mega2560. It's not necessarily robust and +# I may have broken something in the original file that I don't use. +# +# This makefile allows you to build sketches from the command line +# without the Arduino environment. +# +# Instructions for using the makefile: +# +# 1. Copy this file into the folder with your sketch. The project code file +# should have a .c extension however the file gets copied to a .cpp before +# compilation so you still write in C++. +# +# 2. Modify the lines between the double ### rows to set the paths +# comm ports etc for your system. EG. c:/progra~1/arduino/arduino-00 +# for the Arduino IDE, Note the use of short folder name, don't use +# "Program files" because spaces will break the build. +# +# Set the line containing "MCU" to match your board's processor. +# Typically ATmega328 or ATmega2560. If you're using a LilyPad Arduino, +# change F_CPU to 8000000. +# +# 3. At the command line, change to the directory containing your +# program's file and the makefile. +# +# 4. Type "make" and press enter to compile/verify your program. +# The default make target will also perform the uplode using avrdude. +# +# The first time this is done all required libraries will be built +# and a core.a file will be created in the output folder. +# +# NOTES: +# All output goes into a folder called "output" underneath the working folder. +# The default all: target creates symbol (.sym) and expanded assembly +# (.lss) files and uploads the program. +# +# +########################################################## +########################################################## +# Select processor here +MCU = atmega328p +#MCU = atmega2560 + +ifeq ($(MCU),atmega2560) +UPLOAD_RATE = 115200 +AVRDUDE_PROTOCOL = stk500v2 +COM = 39 +endif + +ifeq ($(MCU),atmega328p) +UPLOAD_RATE = 57600 +AVRDUDE_PROTOCOL = stk500v1 +COM = 33 +endif + +UNAME := $(shell uname) + +ifeq ($(UNAME),Darwin) +ARDUINO_VERSION = 21 +ARDUINO_DIR = /opt/arduino-00$(ARDUINO_VERSION) +AVR_TOOLS_PATH = $(ARDUINO_DIR)/hardware/tools/avr/bin +AVRDUDECONFIG_PATH = $(ARDUINO_DIR)/hardware/tools/avr/etc +PORT = /dev/tty.usbserial-A600eHIs +PORT2 = /dev/tty.usbserial-A9007LmI +else +ARDUINO_VERSION = 22 +ARDUINO_DIR = /opt/arduino-00$(ARDUINO_VERSION) +AVR_TOOLS_PATH = /usr/bin +AVRDUDECONFIG_PATH = $(ARDUINO_DIR)/hardware/tools +PORT = /dev/ttyUSB0 +PORT2 = /dev/ttyUSB1 +endif + +PROJECT_NAME = $(notdir $(PWD)) +PROJECT_DIR = . +ARDUINO_CORE = $(ARDUINO_DIR)/hardware/arduino/cores/arduino +ARDUINO_AVR = $(ARDUINO_DIR)/hardware/tools/avr/avr/include/avr +ARDUINO_LIB = $(ARDUINO_DIR)/libraries +F_CPU = 16000000 + +########################################################## +########################################################## + +# Note that if your program has dependencies other than those +# already listed below, you will need to add them accordingly. +C_MODULES = \ +$(ARDUINO_CORE)/wiring_pulse.c \ +$(ARDUINO_CORE)/wiring_analog.c \ +$(ARDUINO_CORE)/pins_arduino.c \ +$(ARDUINO_CORE)/wiring.c \ +$(ARDUINO_CORE)/wiring_digital.c \ +$(ARDUINO_CORE)/WInterrupts.c \ +$(ARDUINO_CORE)/wiring_shift.c \ + +CXX_MODULES = \ +$(ARDUINO_CORE)/Tone.cpp \ +$(ARDUINO_CORE)/main.cpp \ +$(ARDUINO_CORE)/WMath.cpp \ +$(ARDUINO_CORE)/Print.cpp \ +$(ARDUINO_CORE)/HardwareSerial.cpp \ +$(ARDUINO_LIB)/SPI/SPI.cpp \ +../../RF24.cpp + +CXX_APP = output/$(PROJECT_NAME).cpp +MODULES = $(C_MODULES) $(CXX_MODULES) +SRC = $(C_MODULES) +CXXSRC = $(CXX_MODULES) $(CXX_APP) +FORMAT = ihex + +# Name of this Makefile (used for "make depend"). +MAKEFILE = Makefile + +# Debugging format. +# Native formats for AVR-GCC's -g are stabs [default], or dwarf-2. +# AVR (extended) COFF requires stabs, plus an avr-objcopy run. +#DEBUG = stabs +DEBUG = + +OPT = s + +# Place -D or -U options here +CDEFS = -DF_CPU=$(F_CPU)L -DARDUINO=$(ARDUINO_VERSION) +CXXDEFS = -DF_CPU=$(F_CPU)L -DARDUINO=$(ARDUINO_VERSION) + +# Place -I options here +CINCS = -I$(ARDUINO_CORE) -I$(ARDUINO_LIB) -I$(PROJECT_DIR) -I$(ARDUINO_AVR) -I$(ARDUINO_LIB)/SPI -I../.. + +CXXINCS = -I$(ARDUINO_CORE) -I$(ARDUINO_LIB) + +# Compiler flag to set the C Standard level. +# c89 - "ANSI" C +# gnu89 - c89 plus GCC extensions +# c99 - ISO C99 standard (not yet fully implemented) +# gnu99 - c99 plus GCC extensions +#CSTANDARD = -std=gnu99 +CDEBUG = -g$(DEBUG) +#CWARN = -Wall -Wstrict-prototypes +CWARN = -Wall # show all warnings +#CWARN = -w # suppress all warnings +CMAP = -Wl,-Map,output.map +####CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums +CTUNING = -ffunction-sections -fdata-sections +CXXTUNING = -fno-exceptions -ffunction-sections -fdata-sections +#CEXTRA = -Wa,-adhlns=$(<:.c=.lst) +MMCU = -mmcu=$(MCU) + +CFLAGS = $(CDEBUG) -O$(OPT) $(CMAP) $(CWARN) $(CTUNING) $(MMCU) $(CDEFS) $(CINCS) $(CSTANDARD) $(CEXTRA) +CXXFLAGS = $(CDEBUG) -O$(OPT) $(CWARN) $(CXXTUNING) $(CDEFS) $(CINCS) +#ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs +LDFLAGS = -O$(OPT) -lm -Wl,--gc-sections +#LDFLAGS = -O$(OPT) -lm -Wl,-Map,output/$(PROJECT_NAME).map + +# Programming support using avrdude. Settings and variables. +AVRDUDE_PORT = $(PORT) +AVRDUDE_WRITE_FLASH = -U flash:w:output/$(PROJECT_NAME).hex:i + +AVRDUDE_FLAGS = -V -F -D -C $(AVRDUDECONFIG_PATH)/avrdude.conf \ +-p $(MCU) -c $(AVRDUDE_PROTOCOL) -b $(UPLOAD_RATE) + +# Program settings +CC = $(AVR_TOOLS_PATH)/avr-gcc +CXX = $(AVR_TOOLS_PATH)/avr-g++ +LD = $(AVR_TOOLS_PATH)/avr-gcc +OBJCOPY = $(AVR_TOOLS_PATH)/avr-objcopy +OBJDUMP = $(AVR_TOOLS_PATH)/avr-objdump +AR = $(AVR_TOOLS_PATH)/avr-ar +SIZE = $(AVR_TOOLS_PATH)/avr-size +NM = $(AVR_TOOLS_PATH)/avr-nm +AVRDUDE = $(AVR_TOOLS_PATH)/avrdude +REMOVE = rm -f +MV = mv -f + +# Define all object files. +OBJ = $(SRC:.c=.o) $(CXXSRC:.cpp=.o) $(ASRC:.S=.o) +OBJ_MODULES = $(C_MODULES:.c=.o) $(CXX_MODULES:.cpp=.o) + +# Define all listing files. +LST = $(ASRC:.S=.lst) $(CXXSRC:.cpp=.lst) $(SRC:.c=.lst) + +# Combine all necessary flags and optional flags. +# Add target processor to flags. +ALL_CFLAGS = $(CFLAGS) -mmcu=$(MCU) +ALL_CXXFLAGS = $(CXXFLAGS) -mmcu=$(MCU) +ALL_ASFLAGS = -x assembler-with-cpp $(ASFLAGS) -mmcu=$(MCU) +ALL_LDFLAGS = $(LDFLAGS) -mmcu=$(MCU) + +# Default target. +# This is th etarget that gets executed with a make command +# that has no parameters, ie "make". +all: applet_files build sym lss size upload + +build: elf hex + +output/$(PROJECT_NAME).cpp: $(PROJECT_NAME).pde + test -d output || mkdir output + echo "#include " > $@ + echo "#line 1 \"$<\"" >> $@ + cat $< >> $@ + +elf: output/$(PROJECT_NAME).elf +hex: output/$(PROJECT_NAME).hex +eep: output/$(PROJECT_NAME).eep +lss: output/$(PROJECT_NAME).lss +#sym: output/$(PROJECT_NAME).sym + +# Upload HEX file to Arduino +upload: output/$(PROJECT_NAME).hex + $(AVRDUDE) $(AVRDUDE_FLAGS) -P $(PORT) $(AVRDUDE_WRITE_FLASH) + $(AVRDUDE) $(AVRDUDE_FLAGS) -P $(PORT2) $(AVRDUDE_WRITE_FLASH) + +sym: + $(NM) -n -C --format=posix output/$(PROJECT_NAME).elf > output/$(PROJECT_NAME).sym + +# Display size of file. +size: + $(SIZE) output/$(PROJECT_NAME).elf + +# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB. +COFFCONVERT=$(OBJCOPY) --debugging \ +--change-section-address .data-0x800000 \ +--change-section-address .bss-0x800000 \ +--change-section-address .noinit-0x800000 \ +--change-section-address .eeprom-0x810000 + +coff: output/$(PROJECT_NAME).elf + $(COFFCONVERT) -O coff-avr output/$(PROJECT_NAME).elf $(PROJECT_NAME).cof + + extcoff: $(PROJECT_NAME).elf + $(COFFCONVERT) -O coff-ext-avr output/$(PROJECT_NAME).elf $(PROJECT_NAME).cof + +.SUFFIXES: .elf .hex .eep .lss .sym + +.elf.hex: + $(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@ + +.elf.eep: + $(OBJCOPY) -O $(FORMAT) -j .eeprom --set-section-flags=.eeprom="alloc,load" \ + --no-change-warnings \ + --change-section-lma .eeprom=0 $< $@ + +# Create extended listing file from ELF output file. +.elf.lss: + $(OBJDUMP) -h -S $< > $@ + +# Link: create ELF output file from library. +#output/$(PROJECT_NAME).elf: $(PROJECT_NAME).c output/core.a +output/$(PROJECT_NAME).elf: output/$(PROJECT_NAME).o output/core.a + $(LD) $(ALL_LDFLAGS) -o $@ output/$(PROJECT_NAME).o output/core.a + +output/core.a: $(OBJ_MODULES) + @for i in $(OBJ_MODULES); do echo $(AR) rcs output/core.a $$i; $(AR) rcs output/core.a $$i; done + +# Compile: create object files from C++ source files. +.cpp.o: + $(CXX) -c $(ALL_CXXFLAGS) $< -o $@ + +# Compile: create object files from C source files. +.c.o: + $(CC) -c $(ALL_CFLAGS) $< -o $@ + +# Compile: create assembler files from C source files. +.c.s: + $(CC) -S $(ALL_CFLAGS) $< -o $@ + +# Assemble: create object files from assembler source files. +.S.o: + $(CC) -c $(ALL_ASFLAGS) $< -o $@ + +# Automatic dependencies +%.d: %.c + $(CC) -M $(ALL_CFLAGS) $< | sed "s;$(notdir $*).o:;$*.o $*.d:;" > $@ + +%.d: %.cpp + $(CXX) -M $(ALL_CXXFLAGS) $< | sed "s;$(notdir $*).o:;$*.o $*.d:;" > $@ + +# Target: clean project. +clean: + $(REMOVE) output/$(PROJECT_NAME).hex output/$(PROJECT_NAME).eep output/$(PROJECT_NAME).cof output/$(PROJECT_NAME).elf \ + output/$(PROJECT_NAME).map output/$(PROJECT_NAME).sym output/$(PROJECT_NAME).lss output/core.a \ + $(OBJ) $(LST) $(SRC:.c=.s) $(SRC:.c=.d) $(CXXSRC:.cpp=.s) $(CXXSRC:.cpp=.d) + +#.PHONY: all build elf hex eep lss sym program coff extcoff clean applet_files sizebefore sizeafter +.PHONY: all build elf hex eep lss sym program coff extcoff applet_files sizebefore sizeafter + +#include $(SRC:.c=.d) +#include $(CXXSRC:.cpp=.d) diff --git a/examples/pingpair_sleepy/pingpair_sleepy.pde b/examples/pingpair_sleepy/pingpair_sleepy.pde new file mode 100644 index 0000000..9098644 --- /dev/null +++ b/examples/pingpair_sleepy/pingpair_sleepy.pde @@ -0,0 +1,205 @@ +/* + Copyright (C) 2011 James Coliz, Jr. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. + */ + +/** + * Example 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. + * 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 "nRF24L01.h" +#include "RF24.h" +#include "printf.h" + +// +// Hardware configuration +// + +// Set up nRF24L01 radio on SPI bus plus pins 8 & 9 + +RF24 radio(8,9); + +// 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; + +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(9600); + printf_begin(); + printf("\n\rRF24/examples/pingpair_sleepy/\n\r"); + printf("ROLE: %s\n\r",role_friendly_name[role]); + + // + // Setup and configure rf radio + // + + radio.begin(); + + // + // Open pipes to other nodes for communication + // + + // This simple sketch opens 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); + } + + // Try again 1s later + delay(1000); + } + + // + // Pong back role. Receive each packet, dump it out, and send it back + // + + if ( role == role_pong_back ) + { + // if there is data ready + if ( radio.available() ) + { + // Dump the payloads until we've gotten everything + unsigned long got_time; + boolean done = false; + while (!done) + { + // Fetch the payload, and see if this was the last one. + done = radio.read( &got_time, sizeof(unsigned long) ); + + // Spew it + printf("Got payload %lu...",got_time); + } + + // 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(); + } + } +} +// vim:ci sts=2 sw=2 ft=cpp diff --git a/examples/pingpair_sleepy/printf.h b/examples/pingpair_sleepy/printf.h new file mode 100644 index 0000000..63501e4 --- /dev/null +++ b/examples/pingpair_sleepy/printf.h @@ -0,0 +1,33 @@ +/* + Copyright (C) 2011 James Coliz, Jr. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. + */ + +/** + * @file printf.h + * + * Setup necessary to direct stdout to the Arduino Serial library, which + * enables 'printf' + */ + +#ifndef __PRINTF_H__ +#define __PRINTF_H__ + +#include "WProgram.h" + +int serial_putc( char c, FILE *t ) +{ + Serial.write( c ); + + return c; +} + +void printf_begin(void) +{ + fdevopen( &serial_putc, 0 ); +} + +#endif // __PRINTF_H__ From b697fd4e79453c2450b88a441e2e1a36e78442fc Mon Sep 17 00:00:00 2001 From: maniacbug Date: Tue, 10 May 2011 15:16:06 -0700 Subject: [PATCH 09/10] Added powerDown(). --- RF24.cpp | 7 +++++++ RF24.h | 8 ++++++++ 2 files changed, 15 insertions(+) diff --git a/RF24.cpp b/RF24.cpp index 215ade7..24c074a 100644 --- a/RF24.cpp +++ b/RF24.cpp @@ -333,6 +333,13 @@ void RF24::stopListening(void) /******************************************************************/ +void RF24::powerDown(void) +{ + write_register(CONFIG,0); +} + +/******************************************************************/ + boolean RF24::write( const void* buf, uint8_t len ) { boolean result = false; diff --git a/RF24.h b/RF24.h index e920b3f..593e80c 100644 --- a/RF24.h +++ b/RF24.h @@ -223,6 +223,14 @@ public: */ void stopListening(void); + /** + * Enter low-power mode + * + * To return to normal power mode, either write() some data or + * startListening(). + */ + void powerDown(void); + /** * Write to the open writing pipe * From 31793823eaefee67246638621e6cdc126e3bea5b Mon Sep 17 00:00:00 2001 From: maniacbug Date: Tue, 10 May 2011 15:16:41 -0700 Subject: [PATCH 10/10] First complete compile/link with sleep functionality. Haven't run it yet. --- examples/pingpair_sleepy/pingpair_sleepy.pde | 76 ++++++++++++++++++-- 1 file changed, 72 insertions(+), 4 deletions(-) diff --git a/examples/pingpair_sleepy/pingpair_sleepy.pde b/examples/pingpair_sleepy/pingpair_sleepy.pde index 9098644..79fb29a 100644 --- a/examples/pingpair_sleepy/pingpair_sleepy.pde +++ b/examples/pingpair_sleepy/pingpair_sleepy.pde @@ -17,6 +17,7 @@ */ #include +#include #include "nRF24L01.h" #include "RF24.h" #include "printf.h" @@ -59,6 +60,19 @@ 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); + +// +// Normal operation +// + void setup(void) { // @@ -85,6 +99,14 @@ void setup(void) 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 2s to send a ping + if ( role == role_ping_out ) + setup_watchdog(wdt_2s); + // // Setup and configure rf radio // @@ -164,14 +186,25 @@ void loop(void) // Spew it printf("Got response %lu, round-trip delay: %lu\n\r",got_time,millis()-got_time); } - - // Try again 1s later - delay(1000); + + // + // Shut down the system + // + + // 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. + do_sleep(); } // // 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 ) { @@ -202,4 +235,39 @@ void loop(void) } } } -// vim:ci sts=2 sw=2 ft=cpp + +// +// Sleep helpers +// + +// 0=16ms, 1=32ms,2=64ms,3=128ms,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); +} + +// Even though it does nothing, it's necessary to have a WDT ISR +ISR(WDT_vect) { +} + +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