From 89180f284404e0d598675b8c0ccc5edd301f89b7 Mon Sep 17 00:00:00 2001 From: maniacbug Date: Tue, 2 Aug 2011 16:32:21 -0700 Subject: [PATCH] Added another test of a simpler calling pattern. No IRQ, no dynamic payload or ack packet. --- tests/pingpair_blocking/Jamfile | 206 +++++++++++++ tests/pingpair_blocking/pingpair_blocking.pde | 270 ++++++++++++++++++ tests/pingpair_blocking/printf.h | 33 +++ tests/pingpair_blocking/runtest.py | 25 ++ tests/pingpair_blocking/runtests.sh | 9 + 5 files changed, 543 insertions(+) create mode 100644 tests/pingpair_blocking/Jamfile create mode 100644 tests/pingpair_blocking/pingpair_blocking.pde create mode 100644 tests/pingpair_blocking/printf.h create mode 100755 tests/pingpair_blocking/runtest.py create mode 100755 tests/pingpair_blocking/runtests.sh diff --git a/tests/pingpair_blocking/Jamfile b/tests/pingpair_blocking/Jamfile new file mode 100644 index 0000000..98ec12f --- /dev/null +++ b/tests/pingpair_blocking/Jamfile @@ -0,0 +1,206 @@ +PROJECT_NAME = $(PWD:B) ; +PROJECT_DIR = . ; +PROJECT_LIBS = SPI RF24 ; + +OUT_DIR = ojam ; +F_CPU = 16000000 ; +MCU = atmega328p ; +PORTS = /dev/tty.usbserial-A600eHIs /dev/tty.usbserial-A40081RP /dev/tty.usbserial-A9007LmI ; + +UPLOAD_RATE = 57600 ; +AVRDUDE_PROTOCOL = stk500v1 ; +COM = 33 ; + +# Host-specific overrides for locations +if $(OS) = MACOSX +{ +ARDUINO_VERSION = 22 ; +OLD_DIR = /opt/arduino-0021 ; +AVR_TOOLS_PATH = $(OLD_DIR)/hardware/tools/avr/bin ; +AVRDUDECONFIG_PATH = $(OLD_DIR)/hardware/tools/avr/etc ; +ARDUINO_DIR = /opt/Arduino ; +ARDUINO_AVR = /usr/lib/avr/include ; +} + +# Where is everything? +ARDUINO_VERSION ?= 22 ; +AVR_TOOLS_PATH ?= /usr/bin ; +ARDUINO_DIR ?= /opt/arduino-00$(ARDUINO_VERSION) ; +ARDUINO_AVR ?= $(ARDUINO_DIR)/hardware/tools/avr/avr/include/avr ; +AVRDUDECONFIG_PATH ?= $(ARDUINO_DIR)/hardware/tools ; +ARDUINO_CORE = $(ARDUINO_DIR)/hardware/arduino/cores/arduino ; +ARDUINO_LIB = $(ARDUINO_DIR)/libraries ; +SKETCH_LIB = $(HOME)/Source/Arduino/libraries ; +AVR_CC = $(AVR_TOOLS_PATH)/avr-gcc ; +AVR_CXX = $(AVR_TOOLS_PATH)/avr-g++ ; +AVR_LD = $(AVR_TOOLS_PATH)/avr-gcc ; +AVR_OBJCOPY = $(AVR_TOOLS_PATH)/avr-objcopy ; +AVRDUDE = $(AVR_TOOLS_PATH)/avrdude ; + +DEFINES = F_CPU=$(F_CPU)L ARDUINO=$(ARDUINO_VERSION) VERSION_H ; +CTUNING = -ffunction-sections -fdata-sections ; +CXXTUNING = -fno-exceptions -fno-strict-aliasing ; +CFLAGS = -Os -Werror -Wall -Wextra -mmcu=$(MCU) $(CTUNING) ; +CXXFLAGS = $(CFLAGS) $(CXXTUNING) ; +LDFLAGS = -Os -lm -Wl,--gc-sections -mmcu=atmega328p ; + +# Search everywhere for headers +HDRS = $(PROJECT_DIR) $(ARDUINO_AVR) $(ARDUINO_CORE) [ GLOB $(ARDUINO_LIB) $(SKETCH_LIB) : [^.]* ] ; + +# Grab everything from the core directory +CORE_MODULES = [ GLOB $(ARDUINO_CORE) : *.c *.cpp ] ; + +# Grab everything from libraries. To avoid this "grab everything" behaviour, you +# can specify specific modules to pick up in PROJECT_MODULES +LIB_MODULES = [ GLOB $(ARDUINO_LIB)/$(PROJECT_LIBS) $(SKETCH_LIB)/$(PROJECT_LIBS) : *.cpp ] ; + +# In addition to explicitly-specified program modules, pick up anything from the current +# dir. +PROJECT_MODULES += [ GLOB $(PROJECT_DIR) : *.c *.cpp *.pde ] ; + +# Shortcut for the out files +OUT = $(OUT_DIR)/$(PROJECT_NAME) ; + +# AvrDude setup +AVRDUDE_FLAGS = -V -F -D -C $(AVRDUDECONFIG_PATH)/avrdude.conf -p $(MCU) -c $(AVRDUDE_PROTOCOL) -b $(UPLOAD_RATE) ; + +rule GitVersion +{ + Always $(<) ; + Depends all : $(<) ; +} + +actions GitVersion +{ + echo "const char program_version[] = \"\\" > $(<) + git log -1 --pretty=format:%h >> $(<) + echo "\";" >> $(<) +} + +GitVersion version.h ; + +rule AvrCc +{ + Depends $(<) : $(>) ; + Depends $(<) : $(<:D) ; + Clean clean : $(<) ; + + CCHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] ; + CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ; +} + +actions AvrCc +{ + $(AVR_CC) -c -o $(<) $(CCHDRS) $(CCDEFS) $(CFLAGS) $(>) +} + +rule AvrC++ +{ + Depends $(<) : $(>) ; + Depends $(<) : $(<:D) ; + Clean clean : $(<) ; + + CCHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] ; + CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ; +} + +actions AvrC++ +{ + $(AVR_CXX) -c -o $(<) $(CCHDRS) $(CCDEFS) $(CXXFLAGS) $(>) +} + +rule Pde +{ + Depends $(<) : $(>) ; + Depends $(<) : $(<:D) ; + Clean clean : $(<) ; + +} + +actions Pde +{ + echo "#include " > $(<) + echo "#line 1 \"$(>)\"" >> $(<) + cat $(>) >> $(<) +} + +rule AvrPde +{ + local _CPP = $(OUT_DIR)/$(_I:B).cpp ; + Pde $(_CPP) : $(>) ; + AvrC++ $(<) : $(_CPP) ; +} + +rule AvrObject +{ + switch $(>:S) + { + case .c : AvrCc $(<) : $(>) ; + case .cpp : AvrC++ $(<) : $(>) ; + case .pde : AvrPde $(<) : $(>) ; + } +} + +rule AvrObjects +{ + for _I in $(<) + { + AvrObject $(OUT_DIR)/$(_I:B).o : $(_I) ; + } +} + +rule AvrMainFromObjects +{ + Depends $(<) : $(>) ; + Depends $(<) : $(<:D) ; + MkDir $(<:D) ; + Depends all : $(<) ; + Clean clean : $(<) ; +} + +actions AvrMainFromObjects +{ + $(AVR_LD) $(LDFLAGS) -o $(<) $(>) +} + +rule AvrMain +{ + AvrMainFromObjects $(<) : $(OUT_DIR)/$(>:B).o ; + AvrObjects $(>) ; +} + +rule AvrHex +{ + Depends $(<) : $(>) ; + Depends $(<) : $(<:D) ; + Depends hex : $(<) ; + Clean clean : $(<) ; +} + +actions AvrHex +{ + $(AVR_OBJCOPY) -O ihex -R .eeprom $(>) $(<) +} + +rule AvrUpload +{ + Depends $(1) : $(2) ; + Depends $(2) : $(3) ; + NotFile $(1) ; + Always $(1) ; + Always $(2) ; + AvrUploadAction $(2) : $(3) ; +} + +actions AvrUploadAction +{ + $(AVRDUDE) $(AVRDUDE_FLAGS) -P $(<) $(AVRDUDE_WRITE_FLASH) -U flash:w:$(>):i +} + +AvrMain $(OUT).elf : $(CORE_MODULES) $(LIB_MODULES) $(PROJECT_MODULES) ; +AvrHex $(OUT).hex : $(OUT).elf ; + +AvrUpload p6 : /dev/tty.usbserial-A600eHIs : $(OUT).hex ; +AvrUpload p4 : /dev/tty.usbserial-A40081RP : $(OUT).hex ; +AvrUpload p9 : /dev/tty.usbserial-A9007LmI : $(OUT).hex ; + diff --git a/tests/pingpair_blocking/pingpair_blocking.pde b/tests/pingpair_blocking/pingpair_blocking.pde new file mode 100644 index 0000000..817310d --- /dev/null +++ b/tests/pingpair_blocking/pingpair_blocking.pde @@ -0,0 +1,270 @@ +/* + 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. + */ + +#include +#include "nRF24L01.h" +#include "RF24.h" +#include "printf.h" + +// +// Test version of RF24, exposes some protected interface +// + +class RF24Test: public RF24 +{ +public: RF24Test(int a, int b): RF24(a,b) {} +}; + + +// +// Hardware configuration +// + +// Set up nRF24L01 radio on SPI bus plus pins 8 & 9 + +RF24Test 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; + +// +// Test state +// + +bool done; //*< Are we done with the test? */ +bool passed; //*< Have we passed the test? */ +bool notified; //*< Have we notified the user we're done? */ +const int num_needed = 10; //*< How many success/failures until we're done? */ +int receives_remaining = num_needed; //*< How many ack packets until we declare victory? */ +int failures_remaining = num_needed; //*< How many more failed sends until we declare failure? */ +const int interval = 100; //*< ms to wait between sends */ + +char configuration = '1'; //*< Configuration key, one char sent in by the test framework to tell us how to configure, this is the default */ + +void one_ok(void) +{ + // Have we received enough yet? + if ( ! --receives_remaining ) + { + done = true; + passed = true; + } +} + +void one_failed(void) +{ + // Have we failed enough yet? + if ( ! --failures_remaining ) + { + done = true; + passed = false; + } +} + +void setup(void) +{ + // + // Role + // + + // set up the role pin + pinMode(role_pin, INPUT); + digitalWrite(role_pin,HIGH); + delay(20); // Just to get a solid reading on the role pin + + // read the address pin, establish our role + if ( digitalRead(role_pin) ) + role = role_ping_out; + else + role = role_pong_back; + + // + // Print preamble + // + + Serial.begin(57600); + printf_begin(); + printf("\n\rRF24/tests/pingpair_blocking/\n\r"); + printf("ROLE: %s\n\r",role_friendly_name[role]); + + // + // get test config + // + + printf("+READY press any key to start\n\r\n\r"); + + while (! Serial.available() ) {} + configuration = Serial.read(); + printf("Configuration\t = %c\n\r",configuration); + + // + // 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 > 200 ) + timeout = true; + + // Describe the results + if ( timeout ) + { + printf("Failed, response timed out.\n\r"); + one_failed(); + } + 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); + one_ok(); + } + + // Try again later + delay(250); + } + + // + // Pong back role. Receive each packet, dump it out, and send it back + // + + if ( role == role_pong_back ) + { + // if there is data ready + if ( radio.available() ) + { + // Dump the payloads until we've gotten everything + unsigned long got_time; + bool done = false; + while (!done) + { + // Fetch the payload, and see if this was the last one. + done = radio.read( &got_time, sizeof(unsigned long) ); + + // Spew it + printf("Got payload %lu...",got_time); + + // Delay just a little bit to let the other unit + // make the transition to receiver + delay(20); + } + + // First, stop listening so we can talk + radio.stopListening(); + + // Send the final one back. + radio.write( &got_time, sizeof(unsigned long) ); + printf("Sent response.\n\r"); + + // Now, resume listening so we catch the next packets. + radio.startListening(); + + } + } + + // + // Stop the test if we're done and report results + // + if ( done && ! notified ) + { + notified = true; + + printf("\n\r+OK "); + if ( passed ) + printf("PASS\n\r\n\r"); + else + printf("FAIL\n\r\n\r"); + } +} +// vim:cin:ai:sts=2 sw=2 ft=cpp diff --git a/tests/pingpair_blocking/printf.h b/tests/pingpair_blocking/printf.h new file mode 100644 index 0000000..df6c46a --- /dev/null +++ b/tests/pingpair_blocking/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__ diff --git a/tests/pingpair_blocking/runtest.py b/tests/pingpair_blocking/runtest.py new file mode 100755 index 0000000..45fb65c --- /dev/null +++ b/tests/pingpair_blocking/runtest.py @@ -0,0 +1,25 @@ +#!/opt/local/bin/python + +import sys,serial + +def read_until(token): + while 1: + line = ser.readline(None,"\r") + sys.stdout.write(line) + + if (line.startswith(token)): + break + return line + + +ser = serial.Serial(sys.argv[1], 57600, timeout=5, dsrdtr=False, rtscts=False) + +read_until("+READY") +ser.write(sys.argv[2]) + +line = read_until("+OK") +ser.close() +if (line.find("PASS") != -1): + sys.exit(0) +else: + sys.exit(1) diff --git a/tests/pingpair_blocking/runtests.sh b/tests/pingpair_blocking/runtests.sh new file mode 100755 index 0000000..53b16f9 --- /dev/null +++ b/tests/pingpair_blocking/runtests.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +# Connect p6 to receiver, p4 to sender + +jam p4 p6 || exit 1 +./runtest.py /dev/tty.usbserial-A600eHIs 1 & +./runtest.py /dev/tty.usbserial-A40081RP 1 || ( kill `jobs -p` && exit 1 ) +kill `jobs -p` +exit 0