From dc48235343acae2e23a16278b24aa96665fea04b Mon Sep 17 00:00:00 2001 From: maniacbug Date: Sun, 15 Jan 2012 22:15:45 -0800 Subject: [PATCH] Refactor pingpair_test to remove all serial io from within the irq handler, as necessitated by Arduino 1.0 --- tests/pingpair_test/Jamfile | 290 ++++++++++++++------------ tests/pingpair_test/pingpair_test.pde | 48 +++-- tests/pingpair_test/printf.h | 8 +- tests/pingpair_test/runtests.sh | 16 +- tests/pingpair_test/test.ex | 11 + 5 files changed, 208 insertions(+), 165 deletions(-) create mode 100755 tests/pingpair_test/test.ex diff --git a/tests/pingpair_test/Jamfile b/tests/pingpair_test/Jamfile index ebc0bae..6268f4b 100644 --- a/tests/pingpair_test/Jamfile +++ b/tests/pingpair_test/Jamfile @@ -1,207 +1,219 @@ -PROJECT_NAME = $(PWD:B) ; -PROJECT_DIR = . ; -PROJECT_LIBS = SPI RF24 ; +# (1) Project Information -OUT_DIR = ojam ; -F_CPU = 16000000 ; -MCU = atmega328p ; -PORTS = /dev/tty.usbserial-A600eHIs /dev/tty.usbserial-A40081RP /dev/tty.usbserial-A9007LmI ; +PROJECT_LIBS = SPI RF24 ; +PROJECT_DIRS = $(PWD) ; -UPLOAD_RATE = 57600 ; -AVRDUDE_PROTOCOL = stk500v1 ; -COM = 33 ; +# (2) Board Information + +UPLOAD_PROTOCOL ?= arduino ; +UPLOAD_SPEED ?= 57600 ; +MCU ?= atmega328p ; +F_CPU ?= 16000000 ; +CORE ?= arduino ; +VARIANT ?= standard ; +ARDUINO_VERSION ?= 100 ; + +# (3) USB Ports + +PORTS = p4 p6 p9 u0 u1 u2 ; +PORT_p6 = /dev/tty.usbserial-A600eHIs ; +PORT_p4 = /dev/tty.usbserial-A40081RP ; +PORT_p9 = /dev/tty.usbserial-A9007LmI ; +PORT_u0 = /dev/ttyUSB0 ; +PORT_u1 = /dev/ttyUSB1 ; +PORT_u2 = /dev/ttyUSB2 ; + +# (4) Location of AVR tools +# +# This configuration assumes using avr-tools that were obtained separate from the Arduino +# distribution. -# 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_DIR = $(OLD_DIR) ; -ARDUINO_AVR = /usr/lib/avr/include ; + AVR_BIN ?= /usr/local/avrtools/bin ; + AVR_ETC = /usr/local/avrtools/etc ; + AVR_INCLUDE = /usr/local/avrtools/include ; +} +else +{ + AVR_BIN ?= /usr/bin ; + AVR_INCLUDE = /usr/lib/avr/include ; + AVR_ETC = /etc ; } -# 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 ; +# (5) Directories where Arduino core and libraries are located + +ARDUINO_DIR ?= /opt/Arduino ; +ARDUINO_CORE = $(ARDUINO_DIR)/hardware/arduino/cores/$(CORE) $(ARDUINO_DIR)/hardware/arduino/variants/$(VARIANT) ; ARDUINO_LIB = $(ARDUINO_DIR)/libraries ; SKETCH_LIB = $(HOME)/Source/Arduino/libraries ; -AVR_CC = $(AVR_TOOLS_PATH)/avr-gcc ; -AVR_CXX = $(AVR_TOOLS_PATH)/avr-g++ ; -AVR_LD = $(AVR_TOOLS_PATH)/avr-gcc ; -AVR_OBJCOPY = $(AVR_TOOLS_PATH)/avr-objcopy ; -AVRDUDE = $(AVR_TOOLS_PATH)/avrdude ; -DEFINES = F_CPU=$(F_CPU)L ARDUINO=$(ARDUINO_VERSION) VERSION_H ; -CTUNING = -ffunction-sections -fdata-sections ; -CXXTUNING = -fno-exceptions -fno-strict-aliasing ; -CFLAGS = -Os -Wall -Wextra -mmcu=$(MCU) $(CTUNING) ; -CXXFLAGS = $(CFLAGS) $(CXXTUNING) ; -LDFLAGS = -Os -lm -Wl,--gc-sections -mmcu=atmega328p ; +# +# -------------------------------------------------- +# Below this line usually never needs to be modified +# + +# Tool locations + +CC = $(AVR_BIN)/avr-gcc ; +C++ = $(AVR_BIN)/avr-g++ ; +LINK = $(AVR_BIN)/avr-gcc ; +AR = $(AVR_BIN)/avr-ar rcs ; +RANLIB = ; +OBJCOPY = $(AVR_BIN)/avr-objcopy ; +AVRDUDE ?= $(AVR_BIN)/avrdude ; + +# Flags + +DEFINES += F_CPU=$(F_CPU)L ARDUINO=$(ARDUINO_VERSION) VERSION_H ; +OPTIM = -Os ; +CCFLAGS = -Wall -Wextra -Wno-strict-aliasing -mmcu=$(MCU) -ffunction-sections -fdata-sections ; +C++FLAGS = $(CCFLAGS) -fno-exceptions -fno-strict-aliasing ; +LINKFLAGS = $(OPTIM) -lm -Wl,--gc-sections -mmcu=$(MCU) ; +AVRDUDEFLAGS = -V -F -D -C $(AVR_ETC)/avrdude.conf -p $(MCU) -c $(UPLOAD_PROTOCOL) -b $(UPLOAD_SPEED) ; # Search everywhere for headers -HDRS = $(PROJECT_DIR) $(ARDUINO_AVR) $(ARDUINO_CORE) [ GLOB $(ARDUINO_LIB) $(SKETCH_LIB) : [^.]* ] ; -# Grab everything from the core directory -CORE_MODULES = [ GLOB $(ARDUINO_CORE) : *.c *.cpp ] ; +HDRS = $(PROJECT_DIRS) $(AVR_INCLUDE) $(ARDUINO_CORE) $(ARDUINO_LIB)/$(PROJECT_LIBS) $(ARDUINO_LIB)/$(PROJECT_LIBS)/utility $(SKETCH_LIB)/$(PROJECT_LIBS) ; -# 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 ] ; +# Output locations -# In addition to explicitly-specified program modules, pick up anything from the current -# dir. -PROJECT_MODULES += [ GLOB $(PROJECT_DIR) : *.c *.cpp *.pde ] ; +LOCATE_TARGET = $(F_CPU) ; +LOCATE_SOURCE = $(F_CPU) ; -# 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) ; +# +# Custom rules +# rule GitVersion { - Always $(<) ; - Depends all : $(<) ; + Always $(<) ; + Depends all : $(<) ; } actions GitVersion { - echo "const char program_version[] = \"\\" > $(<) - git log -1 --pretty=format:%h >> $(<) - echo "\";" >> $(<) + 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 : $(<) ; + Depends $(<) : $(>) ; + MakeLocate $(<) : $(LOCATE_SOURCE) ; + Clean clean : $(<) ; +} +if ( $(ARDUINO_VERSION) < 100 ) +{ + ARDUINO_H = WProgram.h ; +} +else +{ + ARDUINO_H = Arduino.h ; } actions Pde { - echo "#include " > $(<) - echo "#line 1 \"$(>)\"" >> $(<) - cat $(>) >> $(<) + echo "#include <$(ARDUINO_H)>" > $(<) + echo "#line 1 \"$(>)\"" >> $(<) + cat $(>) >> $(<) } -rule AvrPde +rule C++Pde { - local _CPP = $(OUT_DIR)/$(_I:B).cpp ; - Pde $(_CPP) : $(>) ; - AvrC++ $(<) : $(_CPP) ; + local _CPP = $(>:B).cpp ; + Pde $(_CPP) : $(>) ; + C++ $(<) : $(_CPP) ; } -rule AvrObject +rule UserObject { - switch $(>:S) - { - case .c : AvrCc $(<) : $(>) ; - case .cpp : AvrC++ $(<) : $(>) ; - case .pde : AvrPde $(<) : $(>) ; - } + switch $(>:S) + { + case .ino : C++Pde $(<) : $(>) ; + case .pde : C++Pde $(<) : $(>) ; + } } -rule AvrObjects +rule Objects { - for _I in $(<) - { - AvrObject $(OUT_DIR)/$(_I:B).o : $(_I) ; - } + local _i ; + + for _i in [ FGristFiles $(<) ] + { + local _b = $(_i:B)$(SUFOBJ) ; + local _o = $(_b:G=$(SOURCE_GRIST:E)) ; + Object $(_o) : $(_i) ; + Depends obj : $(_o) ; + } } -rule AvrMainFromObjects +rule Library { - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - MkDir $(<:D) ; - Depends all : $(<) ; - Clean clean : $(<) ; + LibraryFromObjects $(<) : $(>:B)$(SUFOBJ) ; + Objects $(>) ; } -actions AvrMainFromObjects +rule Main { - $(AVR_LD) $(LDFLAGS) -o $(<) $(>) + MainFromObjects $(<) : $(>:B)$(SUFOBJ) ; + Objects $(>) ; } -rule AvrMain +rule Hex { - AvrMainFromObjects $(<) : $(OUT_DIR)/$(>:B).o ; - AvrObjects $(>) ; + Depends $(<) : $(>) ; + MakeLocate $(<) : $(LOCATE_TARGET) ; + Depends hex : $(<) ; + Clean clean : $(<) ; } -rule AvrHex +actions Hex { - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - Depends hex : $(<) ; - Clean clean : $(<) ; + $(OBJCOPY) -O ihex -R .eeprom $(>) $(<) } -actions AvrHex +rule Upload { - $(AVR_OBJCOPY) -O ihex -R .eeprom $(>) $(<) + Depends $(1) : $(2) ; + Depends $(2) : $(3) ; + NotFile $(1) ; + Always $(1) ; + Always $(2) ; + UploadAction $(2) : $(3) ; } -rule AvrUpload +actions UploadAction { - Depends $(1) : $(2) ; - Depends $(2) : $(3) ; - NotFile $(1) ; - Always $(1) ; - Always $(2) ; - AvrUploadAction $(2) : $(3) ; + $(AVRDUDE) $(AVRDUDEFLAGS) -P $(<) $(AVRDUDE_WRITE_FLASH) -U flash:w:$(>):i } -actions AvrUploadAction +rule Arduino { - $(AVRDUDE) $(AVRDUDE_FLAGS) -P $(<) $(AVRDUDE_WRITE_FLASH) -U flash:w:$(>):i + LINKFLAGS on $(<) = $(LINKFLAGS) -Wl,-Map=$(LOCATE_TARGET)/$(<:B).map ; + Main $(<) : $(>) ; + LinkLibraries $(<) : core libs ; + Hex $(<:B).hex : $(<) ; + for _p in $(PORTS) + { + Upload $(_p) : $(PORT_$(_p)) : $(<:B).hex ; + } } -AvrMain $(OUT).elf : $(CORE_MODULES) $(LIB_MODULES) $(PROJECT_MODULES) ; -AvrHex $(OUT).hex : $(OUT).elf ; +# +# Targets +# -AvrUpload p6 : /dev/tty.usbserial-A600eHIs : $(OUT).hex ; -AvrUpload p4 : /dev/tty.usbserial-A40081RP : $(OUT).hex ; -AvrUpload p9 : /dev/tty.usbserial-A9007LmI : $(OUT).hex ; +# Grab everything from the core directory +Library core : [ GLOB $(ARDUINO_CORE) : *.c *.cpp ] ; +# Grab everything from libraries. To avoid this "grab everything" behaviour, you +# can specify specific modules to pick up in PROJECT_MODULES +Library libs : [ GLOB $(ARDUINO_LIB)/$(PROJECT_LIBS) $(ARDUINO_LIB)/$(PROJECT_LIBS)/utility $(SKETCH_LIB)/$(PROJECT_LIBS) : *.cpp *.c ] ; + +# Main output executable +Arduino $(PWD:B).elf : $(PROJECT_MODULES) [ GLOB $(PROJECT_DIRS) : *.c *.cpp *.pde *.ino ] ; diff --git a/tests/pingpair_test/pingpair_test.pde b/tests/pingpair_test/pingpair_test.pde index c16db2b..61ad29b 100644 --- a/tests/pingpair_test/pingpair_test.pde +++ b/tests/pingpair_test/pingpair_test.pde @@ -230,7 +230,7 @@ void setup(void) // Dump the configuration of the rf unit for debugging // - radio.printDetails(); + //radio.printDetails(); // // Attach interrupt handler to interrupt #0 (using pin 2) @@ -238,8 +238,23 @@ void setup(void) // attachInterrupt(0, check_radio, FALLING); + + if ( role == role_receiver ) + printf("\n\r+OK "); } +// +// Print buffer +// +// Printing from the interrupt handler is a bad idea, so we print from there +// to this intermediate buffer +// + +char prbuf[1000]; +char *prbuf_end = prbuf + sizeof(prbuf); +char *prbuf_in = prbuf; +char *prbuf_out = prbuf; + // // Loop // @@ -274,7 +289,7 @@ void loop(void) delay(interval); // Timeout if we have not received anything back ever - if ( ! last_message_count && millis() > interval * 10 ) + if ( ! last_message_count && millis() > interval * 100 ) { printf("No responses received. Are interrupts connected??\n\r"); done = true; @@ -285,6 +300,17 @@ void loop(void) // Receiver role: Does nothing! All the work is in IRQ // + // + // Spew print buffer + // + + size_t write_length = prbuf_in - prbuf_out; + if ( write_length ) + { + Serial.write(reinterpret_cast(prbuf_out),write_length); + prbuf_out += write_length; + } + // // Stop the test if we're done and report results // @@ -299,8 +325,6 @@ void loop(void) printf("FAIL\n\r\n\r"); } - // - // } void check_radio(void) @@ -313,10 +337,10 @@ void check_radio(void) if ( tx ) { if ( role == role_sender ) - printf("Send:OK "); + prbuf_in += sprintf(prbuf_in,"Send:OK "); if ( role == role_receiver ) - printf("Ack Payload:Sent\n\r"); + prbuf_in += sprintf(prbuf_in,"Ack Payload:Sent\n\r"); } // Have we failed to transmit? @@ -324,14 +348,14 @@ void check_radio(void) { if ( role == role_sender ) { - printf("Send:Failed "); + prbuf_in += sprintf(prbuf_in,"Send:Failed "); // log status of this line one_failed(); } if ( role == role_receiver ) - printf("Ack Payload:Failed\n\r"); + prbuf_in += sprintf(prbuf_in,"Ack Payload:Failed\n\r"); } // Transmitter can power down for now, because @@ -346,19 +370,19 @@ void check_radio(void) if ( role == role_sender ) { radio.read(&message_count,sizeof(message_count)); - printf("Ack:%lu ",message_count); + prbuf_in += sprintf(prbuf_in,"Ack:%lu ",message_count); // is this ack what we were expecting? to account // for failures, we simply want to make sure we get a // DIFFERENT ack every time. if ( ( message_count != last_message_count ) || ( configuration=='3' && message_count == 16 ) ) { - printf("OK "); + prbuf_in += sprintf(prbuf_in,"OK "); one_ok(); } else { - printf("FAILED "); + prbuf_in += sprintf(prbuf_in,"FAILED "); one_failed(); } last_message_count = message_count; @@ -382,7 +406,7 @@ void check_radio(void) receive_payload[len] = 0; // Spew it - printf("Got payload size=%i value=%s strlen=%u\n\r",len,receive_payload,strlen(receive_payload)); + prbuf_in += sprintf(prbuf_in,"Recv size=%i val=%s len=%u\n\r",len,receive_payload,strlen(receive_payload)); // Add an ack packet for the next time around. // Here we will report back how many bytes we got this time. diff --git a/tests/pingpair_test/printf.h b/tests/pingpair_test/printf.h index df6c46a..b2efd56 100644 --- a/tests/pingpair_test/printf.h +++ b/tests/pingpair_test/printf.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2011 James Coliz, Jr. + Copyright (C) 2011 J. Coliz This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -16,7 +16,7 @@ #ifndef __PRINTF_H__ #define __PRINTF_H__ -#include "WProgram.h" +#ifdef ARDUINO int serial_putc( char c, FILE * ) { @@ -30,4 +30,8 @@ void printf_begin(void) fdevopen( &serial_putc, 0 ); } +#else +#error This example is only for use on Arduino. +#endif // ARDUINO + #endif // __PRINTF_H__ diff --git a/tests/pingpair_test/runtests.sh b/tests/pingpair_test/runtests.sh index 76f8f77..53360c3 100755 --- a/tests/pingpair_test/runtests.sh +++ b/tests/pingpair_test/runtests.sh @@ -1,16 +1,8 @@ #!/bin/sh -# Connect p6 to receiver, p4 to sender +# Connect u0 to receiver, u0 to sender # WARNING: Test config 2 only works with PLUS units. -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` -./runtest.py /dev/tty.usbserial-A600eHIs 2 & -./runtest.py /dev/tty.usbserial-A40081RP 2 || ( kill `jobs -p` && exit 1 ) -kill `jobs -p` -./runtest.py /dev/tty.usbserial-A600eHIs 3 & -./runtest.py /dev/tty.usbserial-A40081RP 3 || ( kill `jobs -p` && exit 1 ) -kill `jobs -p` -exit 0 +jam u0 u1 && expect test.ex 1 +jam u0 u1 && expect test.ex 2 +jam u0 u1 && expect test.ex 3 diff --git a/tests/pingpair_test/test.ex b/tests/pingpair_test/test.ex new file mode 100755 index 0000000..a14ffef --- /dev/null +++ b/tests/pingpair_test/test.ex @@ -0,0 +1,11 @@ +#/usr/bin/expect + +set timeout 100 +spawn picocom -b 57600 /dev/ttyUSB0 +expect "+READY" +send [lindex $argv 0] +expect "+OK" +spawn picocom -b 57600 /dev/ttyUSB1 +expect "+READY" +send [lindex $argv 0] +expect "+OK"