diff --git a/.gitignore b/.gitignore index 1ac5497..12bc711 100644 --- a/.gitignore +++ b/.gitignore @@ -6,5 +6,6 @@ docs/ output/ ojam/ +out_native/ version.h Session.vim diff --git a/RF24.cpp b/RF24.cpp index 6ad87e4..5e4fc6a 100644 --- a/RF24.cpp +++ b/RF24.cpp @@ -19,10 +19,12 @@ #endif // Avoid spurious warnings +#ifndef NATIVE #undef PROGMEM #define PROGMEM __attribute__(( section(".progmem.data") )) #undef PSTR #define PSTR(s) (__extension__({static prog_char __c[] PROGMEM = (s); &__c[0];})) +#endif /****************************************************************************/ diff --git a/tests/native/Jamfile b/tests/native/Jamfile new file mode 100644 index 0000000..10d0336 --- /dev/null +++ b/tests/native/Jamfile @@ -0,0 +1,300 @@ +PROJECT_NAME = $(PWD:B) ; +PROJECT_DIR = . ; +PROJECT_LIBS = 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 ; +SKETCH_DIR = $(HOME)/Source/Arduino ; +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 = $(SKETCH_DIR)/libraries ; +AVR_AS = $(AVR_TOOLS_PATH)/avr-as ; +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 HAL=1 ; +CTUNING = -ffunction-sections -fdata-sections ; +CXXTUNING = -fno-exceptions -fno-strict-aliasing ; +ASFLAGS = -mmcu=$(MCU) ; +CFLAGS = -Os -Wall -Wextra $(ASFLAGS) $(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) : [^.]* ] ; +HDRS += [ GLOB $(HDRS) : utility ] ; + +# 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 ] ; + +# 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 AvrAsm +{ + Depends $(<) : $(>) ; + Depends $(<) : $(<:D) ; + Clean clean : $(<) ; + + CCHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] ; + CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ; +} + +actions AvrAsm +{ + $(AVR_AS) $(ASFLAGS) -o $(<) $(>) +} + +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 AvrAsmFromC++ +{ + Depends $(<) : $(>) ; + Depends $(<) : $(<:D) ; + Clean clean : $(<) ; + + CCHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] ; + CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ; +} + +actions AvrAsmFromC++ +{ + $(AVR_CXX) -S -fverbose-asm -o $(<) $(CCHDRS) $(CCDEFS) $(CXXFLAGS) $(>) +} + +rule Pde +{ + Depends $(<) : $(>) ; + Depends $(<) : $(<:D) ; + Clean clean : $(<) ; +} + +actions Pde +{ + echo "#include " > $(<) + echo "#line 1 \"$(>)\"" >> $(<) + cat $(>) >> $(<) +} + +rule AvrPde +{ + local _CPP = $(OUT_DIR)/$(_I:B).cpp ; + Pde $(_CPP) : $(>) ; + AvrC++ $(<) : $(_CPP) ; +} + +rule AvrObject +{ + switch $(>:S) + { + case .S : AvrAsm $(<) : $(>) ; + 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 ; + +# +# Native +# + +OUT_DIR_NATIVE = out_native ; +OUT_NATIVE = $(OUT_DIR_NATIVE)/$(PROJECT_NAME) ; +NATIVE_CORE = $(SKETCH_DIR)/hardware/native ; +HDRS = $(NATIVE_CORE) $(HDRS) ; +NATIVE_CORE_MODULES = [ GLOB $(NATIVE_CORE) : *.c *.cpp ] ; +NATIVE_MODULES = ; +DEFINES += NATIVE ; + +rule NativePde +{ + local _CPP = $(OUT_DIR_NATIVE)/$(_I:B).cpp ; + Pde $(_CPP) : $(>) ; + C++ $(<) : $(_CPP) ; +} + +rule UserObject +{ + switch $(>) + { + case *.pde : NativePde $(<) : $(>) ; + } +} + +rule Objects +{ + for _I in $(<) + { + local _O = $(OUT_DIR_NATIVE)/$(_I:B).o ; + Object $(_O) : $(_I) ; + } +} + +rule Main +{ + MainFromObjects $(<) : $(OUT_DIR_NATIVE)/$(>:B).o ; + Objects $(>) ; +} + +actions C++ +{ + c++ -c -o $(<) $(CCHDRS) $(CCDEFS) $(>) +} + +actions Link +{ + c++ -o $(<) $(>) +} + + + +MkDir $(OUT_DIR_NATIVE) ; +Depends $(OUT_NATIVE) : $(OUT_DIR_NATIVE) ; +Main $(OUT_NATIVE) : $(NATIVE_CORE_MODULES) $(NATIVE_MODULES) $(LIB_MODULES) $(PROJECT_MODULES) ; + +Depends native : $(OUT_NATIVE) ; + diff --git a/tests/native/pingpair_irq.pde b/tests/native/pingpair_irq.pde new file mode 100644 index 0000000..99c2cdf --- /dev/null +++ b/tests/native/pingpair_irq.pde @@ -0,0 +1,223 @@ +/* + 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. + */ + +/** + * Interrupt-driven test for native target + * + * This example is the friendliest for the native target because it doesn't do + * any polling. Made a slight change to call done() at the end of setup. + */ + +#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; + +// +// 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); + + // + // On the native target, this is as far as we get + // +#if NATIVE + done(); +#endif +} + +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",(unsigned long)message_count); + } + + // If we're the receiver, we've received a time message + if ( role == role_receiver ) + { + // Get this payload and dump it + static unsigned long got_time; + radio.read( &got_time, sizeof(got_time) ); + printf("Got payload %lu\n\r",got_time); + + // Add an ack packet for the next time around. This is a simple + // packet counter + radio.writeAckPayload( 1, &message_count, sizeof(message_count) ); + ++message_count; + } + } +} + +// vim:ai:cin:sts=2 sw=2 ft=cpp diff --git a/tests/native/printf.h b/tests/native/printf.h new file mode 100644 index 0000000..df6c46a --- /dev/null +++ b/tests/native/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 * ) +{ + Serial.write( c ); + + return c; +} + +void printf_begin(void) +{ + fdevopen( &serial_putc, 0 ); +} + +#endif // __PRINTF_H__