subree of RF24 merged

This commit is contained in:
Henrik Ekblad
2014-05-01 00:16:07 +02:00
parent 1897409bde
commit ab3bad4b1c
80 changed files with 18009 additions and 0 deletions
+14
View File
@@ -0,0 +1,14 @@
*.bak
*.o
.*.swp
*.orig
.swp
docs/
output/
ojam/
out/
16000000/
8000000/
out_native/
version.h
Session.vim
File diff suppressed because it is too large Load Diff
+53
View File
@@ -0,0 +1,53 @@
/**
* @page FAQ Frequently Asked Questions
*
* @ref starting
*
* @ref hardware
*
* @ref range
*
* @ref issues
*
* @ref ram
*
* @ref tests
*
* @section starting Where do I start?
*
* See my blog post:
* <a href="http://maniacbug.wordpress.com/2011/11/02/getting-started-rf24/">Getting Started with nRF24L01+ on Arduino</a>
*
* @section hardware Where can I buy some hardware?
*
* @li iTeadStudio sells the basic <a href="http://iteadstudio.com/store/index.php?main_page=product_info&cPath=7&products_id=53">2.4G Wireless nRF24L01+ Module</a> for $4. Such a deal!
* @li MDfly.com sells the same unit, <a href="http://www.mdfly.com/index.php?main_page=product_info&cPath=8_52&products_id=81">2.4Ghz Wireless nRF24L01+ Transceiver Module</a> for $6.95, but it ships from the US so it gets there a lot faster. Great place to get a few units and get started quickly.
* @li MDfly.com also has the <a href="http://www.mdfly.com/index.php?main_page=product_info&cPath=8_52&products_id=433">nRF24L01 2.4GHz Transceiver Module w/ Power Amplifier</a> for $13.95, which increases range dramatically and uses a chip antenna
* @li MDfly.com also has the <a href="http://www.mdfly.com/index.php?main_page=product_info&cPath=8_52&products_id=583">2.4GHz Transceiver Module w/ Power Amplifier</a> with an external antenna for $19.95
*
* @section range What is the range of these units?
*
* Here are some results from measurements I have taken, using the basic $4 iTeadStudio units.
* I recommend that everyone take their own measurements in their particular circumstances.
*
* @li non-plus unit, 2MBps (worst case), 41+ ft line of sight indoors, immediate dropoff with any deviation from LOS. (41 ft is as far as I can go in my house without turning a corner)
* @li Plus unit, 250kbps (best case), 46 ft around two corners indoors, 49 ft around one corner. More importantly, at 250k, packet loss is almost negligible through almost all of that range.
* @li Both units at 1MBps, plus unit gets about 10% range improvement over non-plus in almost all situations.
*
* @section issues What should I do if I find a problem?
*
* Please <a href="https://github.com/maniacbug/RF24/issues/new">open an issue</a> on github if you find any problems using it with any version of Arduino or Maple.
*
* @section ram What is the RAM footprint of this library?
*
* 16 bytes. A single radio object consumes 16 bytes of RAM, and the library
* does not use any other RAM statically.
*
* @section tests Why are the examples in the 'tests' directory failing?
*
* The sketches in the 'tests' directory are not for general use.
* Please use the examples in the 'examples' directory instead.
*
* The 'tests' directory is only for people making changes to the library
* to ensure that their changes do not break anything.
*/
+41
View File
@@ -0,0 +1,41 @@
# Optimized High Speed Arduino driver for nRF24L01 2.4GHz Wireless Transceiver
Design Goals: This library is designed to be...
* More compliant with the manufacturer specified operation of the chip, while allowing advanced users
* to work outside the reccommended operation.
* Utilize the capabilities of the radio to their full potential via Arduino
* More reliable and feature rich
* Easy for beginners to use, with well documented examples and features
* Consumed with a public interface that's similiar to other Arduino standard libraries
* Built against the standard SPI library.
April 2014: Official Release: Still some work to do, but most benefits have been realized
* The library has been tweaked to allow full use of the FIFO buffers for maximum transfer speeds
* Changes to read() and available () functionality have increased reliability and response
* Extended timeout periods have been added to aid in noisy or otherwise unreliable environments
* Delays have been removed where possible to ensure maximum efficiency
* Full Due support with extended SPI functions
* ATTiny 24/44/84 25/45/85 now supported.
* More! See the links below and class documentation for more info.
Please refer to:
* [Documentation Main Page](http://tmrh20.github.io/)
* [Class Reference]( http://tmrh20.github.io/RF24/classRF24.html)
* [Source Code](https://github.com/tmrh20/RF24)
* [Downloads](https://github.com/TMRh20/RF24/archive/master.zip)
* [Chip Datasheet](http://www.nordicsemi.com/files/Product/data_sheet/nRF24L01_Product_Specification_v2_0.pdf)
This chip uses the SPI bus, plus two chip control pins. Remember that pin 10 must still remain an output, or
the SPI hardware will go into 'slave' mode.
Supported Boards:
* Uno, Nano, etc (328 based boards)
* Mega Types (2560, 1280, etc)
* ARM (Arduino Due) via extended SPI methods
* ATTiny 24/44/84 25/45/85
* Raspberry Pi
* See the [documentation](http://tmrh20.github.io/) for more info
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+129
View File
@@ -0,0 +1,129 @@
/*
Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
Added Arduino Due support from https://github.com/mcrosson/
*/
#ifndef __RF24_CONFIG_H__
#define __RF24_CONFIG_H__
#if ARDUINO < 100
#include <WProgram.h>
#else
#include <Arduino.h>
#endif
#include <stddef.h>
//TMRh20:
//#define MINIMAL
// Define _BV for non-Arduino platforms and for Arduino DUE
#if defined (ARDUINO)
#include <SPI.h>
#else
#include <stdint.h>
#include <stdio.h>
#include <string.h>
extern HardwareSPI SPI;
#define _BV(x) (1<<(x))
#endif
#undef SERIAL_DEBUG
#ifdef SERIAL_DEBUG
#define IF_SERIAL_DEBUG(x) ({x;})
#else
#define IF_SERIAL_DEBUG(x)
#if defined(__AVR_ATtiny84__) || defined(__AVR_ATtiny85__)
#define printf_P(...)
#endif
#endif
// Avoid spurious warnings
// Arduino DUE is arm and uses traditional PROGMEM constructs
#if 1
#if ! defined( NATIVE ) && defined( ARDUINO ) && ! defined(__arm__)
#undef PROGMEM
#define PROGMEM __attribute__(( section(".progmem.data") ))
#undef PSTR
#define PSTR(s) (__extension__({static const char __c[] PROGMEM = (s); &__c[0];}))
#endif
#endif
// Progmem is Arduino-specific
// Arduino DUE is arm and does not include avr/pgmspace
#if defined(ARDUINO) && ! defined(__arm__)
#include <avr/pgmspace.h>
#define PRIPSTR "%S"
#else
#if ! defined(ARDUINO) // This doesn't work on Arduino DUE
typedef char const char;
#else // Fill in pgm_read_byte that is used, but missing from DUE
#define pgm_read_byte(addr) (*(const unsigned char *)(addr))
#endif
typedef uint16_t prog_uint16_t;
#define PSTR(x) (x)
#define printf_P printf
#define strlen_P strlen
#define PROGMEM
#define pgm_read_word(p) (*(p))
#define PRIPSTR "%s"
#endif
// ATTiny support code is from https://github.com/jscrane/RF24
#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
#include <stdio.h>
#include <Arduino.h>
#include <avr/pgmspace.h>
#define SPI_CLOCK_DIV4 0x00
#define SPI_CLOCK_DIV16 0x01
#define SPI_CLOCK_DIV64 0x02
#define SPI_CLOCK_DIV128 0x03
#define SPI_CLOCK_DIV2 0x04
#define SPI_CLOCK_DIV8 0x05
#define SPI_CLOCK_DIV32 0x06
//#define SPI_CLOCK_DIV64 0x07
#define SPI_MODE0 0x00
#define SPI_MODE1 0x04
#define SPI_MODE2 0x08
#define SPI_MODE3 0x0C
#define SPI_MODE_MASK 0x0C // CPOL = bit 3, CPHA = bit 2 on SPCR
#define SPI_CLOCK_MASK 0x03 // SPR1 = bit 1, SPR0 = bit 0 on SPCR
#define SPI_2XCLOCK_MASK 0x01 // SPI2X = bit 0 on SPSR
class SPIClass {
public:
static byte transfer(byte _data);
// SPI Configuration methods
inline static void attachInterrupt();
inline static void detachInterrupt(); // Default
static void begin(); // Default
static void end();
static void setBitOrder(uint8_t);
static void setDataMode(uint8_t);
static void setClockDivider(uint8_t);
};
extern SPIClass SPI;
#endif //ATTiny
#endif // __RF24_CONFIG_H__
+55
View File
@@ -0,0 +1,55 @@
#############################################################################
#
# Makefile for librf24-bcm on Raspberry Pi
#
# License: GPL (General Public License)
# Author: Charles-Henri Hallard
# Date: 2013/03/13
#
# Description:
# ------------
# use make all and mak install to install the library
# You can change the install directory by editing the LIBDIR line
#
PREFIX=/usr/local
# Library parameters
# where to put the lib
LIBDIR=$(PREFIX)/lib
# lib name
LIB=librf24-bcm
# shared library name
LIBNAME=$(LIB).so.1.0
# The recommended compiler flags for the Raspberry Pi
CCFLAGS=-Ofast -mfpu=vfp -mfloat-abi=hard -march=armv6zk -mtune=arm1176jzf-s
# make all
# reinstall the library after each recompilation
all: librf24-bcm install
# Make the library
librf24-bcm: RF24.o bcm2835.o
g++ -shared -Wl,-soname,$@.so.1 ${CCFLAGS} -o ${LIBNAME} $^
# Library parts
RF24.o: RF24.cpp
g++ -Wall -fPIC ${CCFLAGS} -c $^
bcm2835.o: bcm2835.c
gcc -Wall -fPIC ${CCFLAGS} -c $^
# clear build files
clean:
rm -rf *.o ${LIB}.*
# Install the library to LIBPATH
install:
@echo "[Install]"
@if ( test ! -d $(PREFIX)/lib ) ; then mkdir -p $(PREFIX)/lib ; fi
#@install -m 0755 ${LIB}.a ${LIBDIR}
@install -m 0755 ${LIBNAME} ${LIBDIR}
@ln -sf ${LIBDIR}/${LIBNAME} ${LIBDIR}/${LIB}.so.1
@ln -sf ${LIBDIR}/${LIBNAME} ${LIBDIR}/${LIB}.so
@ldconfig
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+34
View File
@@ -0,0 +1,34 @@
/*
Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
03/17/2013 : Charles-Henri Hallard (http://hallard.me)
Modified to use with Arduipi board http://hallard.me/arduipi
Modified to use the great bcm2835 library for I/O and SPI
*/
#ifndef __RF24_CONFIG_H__
#define __RF24_CONFIG_H__
#include <stdint.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <sys/time.h>
#include <stddef.h>
#include "bcm2835.h"
// GCC a Arduino Missing
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
#define _BV(x) (1<<(x))
#define pgm_read_word(p) (*(p))
#define pgm_read_byte(p) (*(p))
#endif // __RF24_CONFIG_H__
// vim:ai:cin:sts=2 sw=2 ft=cpp
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+40
View File
@@ -0,0 +1,40 @@
#############################################################################
#
# Makefile for librf24 examples on Raspberry Pi
#
# License: GPL (General Public License)
# Author: gnulnulf <arco@appeltaart.mine.nu>
# Date: 2013/02/07 (version 1.0)
#
# Description:
# ------------
# use make all and make install to install the examples
# You can change the install directory by editing the prefix line
#
prefix := /usr/local
# The recommended compiler flags for the Raspberry Pi
CCFLAGS=-Ofast -mfpu=vfp -mfloat-abi=hard -march=armv6zk -mtune=arm1176jzf-s
#CCFLAGS=
# define all programs
#PROGRAMS = scanner pingtest gettingstarted
PROGRAMS = gettingstarted gettingstarted_call_response transfer pingpair_dyn
SOURCES = ${PROGRAMS:=.cpp}
all: ${PROGRAMS}
${PROGRAMS}: ${SOURCES}
g++ ${CCFLAGS} -Wall -I../ -lrf24-bcm $@.cpp -o $@
clean:
rm -rf $(PROGRAMS)
install: all
test -d $(prefix) || mkdir $(prefix)
test -d $(prefix)/bin || mkdir $(prefix)/bin
for prog in $(PROGRAMS); do \
install -m 0755 $$prog $(prefix)/bin; \
done
.PHONY: install
@@ -0,0 +1,40 @@
#############################################################################
#
# Makefile for librf24 examples on Raspberry Pi
#
# License: GPL (General Public License)
# Author: gnulnulf <arco@appeltaart.mine.nu>
# Date: 2013/02/07 (version 1.0)
#
# Description:
# ------------
# use make all and make install to install the examples
# You can change the install directory by editing the prefix line
#
prefix := /usr/local
# The recommended compiler flags for the Raspberry Pi
CCFLAGS=-Ofast -mfpu=vfp -mfloat-abi=hard -march=armv6zk -mtune=arm1176jzf-s
#CCFLAGS=
# define all programs
PROGRAMS = rpi-hub scanner
SOURCES = ${PROGRAMS:=.cpp}
all: ${PROGRAMS}
${PROGRAMS}: ${SOURCES}
g++ ${CCFLAGS} -Wall -I../ -lrf24-bcm $@.cpp -o $@
clean:
rm -rf $(PROGRAMS)
install: all
test -d $(prefix) || mkdir $(prefix)
test -d $(prefix)/bin || mkdir $(prefix)/bin
for prog in $(PROGRAMS); do \
install -m 0755 $$prog $(prefix)/bin; \
done
.PHONY: install
@@ -0,0 +1,134 @@
/*
*
* Filename : rpi-hub.cpp
*
* This program makes the RPi as a hub listening to all six pipes from the remote sensor nodes ( usually Arduino )
* and will return the packet back to the sensor on pipe0 so that the sender can calculate the round trip delays
* when the payload matches.
*
* I encounter that at times, it also receive from pipe7 ( or pipe0 ) with content of FFFFFFFFF that I will not sent
* back to the sender
*
* Refer to RF24/examples/rpi_hub_arduino/ for the corresponding Arduino sketches to work with this code.
*
*
* CE is not used and CSN is GPIO25 (not pinout)
*
* Refer to RPi docs for GPIO numbers
*
* Author : Stanley Seow
* e-mail : stanleyseow@gmail.com
* date : 6th Mar 2013
*
* 03/17/2013 : Charles-Henri Hallard (http://hallard.me)
* Modified to use with Arduipi board http://hallard.me/arduipi
* Changed to use modified bcm2835 and RF24 library
*
*
*/
#include <cstdlib>
#include <iostream>
#include "../RF24.h"
using namespace std;
// Radio pipe addresses for the 2 nodes to communicate.
// First pipe is for writing, 2nd, 3rd, 4th, 5th & 6th is for reading...
const uint64_t pipes[6] =
{ 0xF0F0F0F0D2LL, 0xF0F0F0F0E1LL,
0xF0F0F0F0E2LL, 0xF0F0F0F0E3LL,
0xF0F0F0F0F1, 0xF0F0F0F0F2
};
// CE Pin, CSN Pin, SPI Speed
// Setup for GPIO 22 CE and GPIO 25 CSN with SPI Speed @ 1Mhz
//RF24 radio(RPI_V2_GPIO_P1_22, RPI_V2_GPIO_P1_18, BCM2835_SPI_SPEED_1MHZ);
// Setup for GPIO 22 CE and CE0 CSN with SPI Speed @ 4Mhz
//RF24 radio(RPI_V2_GPIO_P1_15, BCM2835_SPI_CS0, BCM2835_SPI_SPEED_4MHZ);
// Setup for GPIO 22 CE and CE1 CSN with SPI Speed @ 8Mhz
RF24 radio(RPI_V2_GPIO_P1_15, RPI_V2_GPIO_P1_26, BCM2835_SPI_SPEED_8MHZ);
int main(int argc, char** argv)
{
uint8_t len;
// Refer to RF24.h or nRF24L01 DS for settings
radio.begin();
radio.enableDynamicPayloads();
radio.setAutoAck(1);
radio.setRetries(15,15);
radio.setDataRate(RF24_1MBPS);
radio.setPALevel(RF24_PA_MAX);
radio.setChannel(76);
radio.setCRCLength(RF24_CRC_16);
// Open 6 pipes for readings ( 5 plus pipe0, also can be used for reading )
radio.openWritingPipe(pipes[0]);
radio.openReadingPipe(1,pipes[1]);
radio.openReadingPipe(2,pipes[2]);
radio.openReadingPipe(3,pipes[3]);
radio.openReadingPipe(4,pipes[4]);
radio.openReadingPipe(5,pipes[5]);
//
// Start listening
//
radio.startListening();
//
// Dump the configuration of the rf unit for debugging
//
radio.printDetails();
printf("Output below : \n");
delay(1);
while(1)
{
char receivePayload[32];
uint8_t pipe = 1;
// Start listening
radio.startListening();
while ( radio.available(&pipe) )
{
len = radio.getDynamicPayloadSize();
radio.read( receivePayload, len );
// Display it on screen
printf("Recv: size=%i payload=%s pipe=%i",len,receivePayload,pipe);
// Send back payload to sender
radio.stopListening();
// if pipe is 7, do not send it back
if ( pipe != 7 )
{
radio.write(receivePayload,len);
receivePayload[len]=0;
printf("\t Send: size=%i payload=%s pipe:%i\n",len,receivePayload,pipe);
}
else
{
printf("\n");
}
pipe++;
// reset pipe to 0
if ( pipe > 6 )
pipe = 0;
}
delayMicroseconds(20);
}
return 0;
}
@@ -0,0 +1,147 @@
/*
Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
03/17/2013 : Charles-Henri Hallard (http://hallard.me)
Modified to use with Arduipi board http://hallard.me/arduipi
Changed to use modified bcm2835 and RF24 library
*/
/**
* Channel scanner
*
* Example to detect interference on the various channels available.
* This is a good diagnostic tool to check whether you're picking a
* good channel for your application.
*
* Inspired by cpixip.
* See http://arduino.cc/forum/index.php/topic,54795.0.html
*/
#include <cstdlib>
#include <iostream>
#include "../RF24.h"
using namespace std;
//
// Hardware configuration
//
// CE Pin, CSN Pin, SPI Speed
// Setup for GPIO 22 CE and GPIO 25 CSN with SPI Speed @ 1Mhz
//RF24 radio(RPI_V2_GPIO_P1_22, RPI_V2_GPIO_P1_18, BCM2835_SPI_SPEED_1MHZ);
// Setup for GPIO 22 CE and CE0 CSN with SPI Speed @ 4Mhz
//RF24 radio(RPI_V2_GPIO_P1_15, BCM2835_SPI_CS0, BCM2835_SPI_SPEED_4MHZ);
// Setup for GPIO 22 CE and CE1 CSN with SPI Speed @ 8Mhz
RF24 radio(RPI_V2_GPIO_P1_15, RPI_V2_GPIO_P1_26, BCM2835_SPI_SPEED_8MHZ);
//
// Channel info
//
//const uint8_t num_channels = 128;
const uint8_t num_channels = 120;
uint8_t values[num_channels];
const int num_reps = 100;
int reset_array=0;
int main(int argc, char** argv)
{
//
// Print preamble
//
//Serial.begin(57600);
//printf_begin();
printf("RF24/examples/scanner/\n");
//
// Setup and configure rf radio
//
radio.begin();
radio.setAutoAck(false);
// Get into standby mode
radio.startListening();
radio.stopListening();
radio.printDetails();
// Print out header, high then low digit
int i = 0;
while ( i < num_channels )
{
printf("%x",i>>4);
++i;
}
printf("\n");
i = 0;
while ( i < num_channels )
{
printf("%x",i&0xf);
++i;
}
printf("\n");
// forever loop
while(1)
{
if ( reset_array == 1 )
{
// Clear measurement values
memset(values,0,sizeof(values));
printf("\n");
}
// Scan all channels num_reps times
int i = num_channels;
while (i--)
{
// Select this channel
radio.setChannel(i);
// Listen for a little
radio.startListening();
delayMicroseconds(128);
//radio.stopListening();
// Did we get a carrier?
if ( radio.testCarrier() )
++values[i];
if ( values[i] == 0xf )
{
reset_array = 2;
}
radio.stopListening();
}
// Print out channel measurements, clamped to a single hex digit
i = 0;
while ( i < num_channels )
{
printf("%x",min(0xf,(values[i]&0xf)));
++i;
}
printf("\n");
}
return 0;
}
// vim:ai:cin:sts=2 sw=2 ft=cpp
@@ -0,0 +1,187 @@
/*
Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
03/17/2013 : Charles-Henri Hallard (http://hallard.me)
Modified to use with Arduipi board http://hallard.me/arduipi
Changed to use modified bcm2835 and RF24 library
TMRh20 2014 - Updated to work with optimized RF24 Arduino library
*/
/**
* Example RF Radio Ping Pair
*
* This is an example of how to use the RF24 class on RPi, communicating to an Arduino running
* the GettingStarted sketch.
*/
#include <cstdlib>
#include <iostream>
#include <sstream>
#include <string>
#include "./RF24.h"
using namespace std;
//
// Hardware configuration
//
// CE Pin, CSN Pin, SPI Speed
// Setup for GPIO 22 CE and CE1 CSN with SPI Speed @ 1Mhz
//RF24 radio(RPI_V2_GPIO_P1_22, RPI_V2_GPIO_P1_26, BCM2835_SPI_SPEED_1MHZ);
// Setup for GPIO 22 CE and CE0 CSN with SPI Speed @ 4Mhz
//RF24 radio(RPI_V2_GPIO_P1_15, BCM2835_SPI_CS0, BCM2835_SPI_SPEED_4MHZ);
// Setup for GPIO 22 CE and CE0 CSN with SPI Speed @ 8Mhz
RF24 radio(RPI_V2_GPIO_P1_15, RPI_V2_GPIO_P1_24, BCM2835_SPI_SPEED_8MHZ);
// Radio pipe addresses for the 2 nodes to communicate.
const uint64_t pipes[2] = { 0xABCDABCD71LL, 0x544d52687CLL };
bool role_ping_out = 1, role_pong_back = 0;
bool role = 0;
int main(int argc, char** argv){
// Print preamble:
printf("RF24/examples/pingtest/\n");
// Setup and configure rf radio
radio.begin();
// optionally, increase the delay between retries & # of retries
radio.setRetries(15,15);
// Dump the configuration of the rf unit for debugging
radio.printDetails();
/********* Role chooser ***********/
printf("\n ************ Role Setup ***********\n");
string input = "";
char myChar = {0};
cout << "Choose a role: Enter 0 for pong_back, 1 for ping_out (CTRL+C to exit) \n>";
getline(cin,input);
if(input.length() == 1) {
myChar = input[0];
if(myChar == '0'){
cout << "Role: Pong Back, awaiting transmission " << endl << endl;
}else{ cout << "Role: Ping Out, starting transmission " << endl << endl;
role = role_ping_out;
}
}
/***********************************/
// This simple sketch opens two pipes for these two nodes to communicate
// back and forth.
if ( role == role_ping_out ) {
radio.openWritingPipe(pipes[0]);
radio.openReadingPipe(1,pipes[1]);
} else {
radio.openWritingPipe(pipes[1]);
radio.openReadingPipe(1,pipes[0]);
radio.startListening();
}
// forever loop
while (1)
{
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
printf("Now sending...\n");
unsigned long time = millis();
bool ok = radio.write( &time, sizeof(unsigned long) );
if (!ok){
printf("failed.\n");
}
// 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 ) {
// by bcatalin » Thu Feb 14, 2013 11:26 am
//delay(5); //add a small delay to let radio.available to check payload
if (millis() - started_waiting_at > 200 )
timeout = true;
}
// Describe the results
if ( timeout )
{
printf("Failed, response timed out.\n");
}
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",got_time,millis()-got_time);
}
// Try again 1s later
// delay(1000);
sleep(1);
}
//
// Pong back role. Receive each packet, dump it out, and send it back
//
if ( role == role_pong_back )
{
// if there is data ready
//printf("Check available...\n");
//delay(3);
if ( radio.available() )
{
// Dump the payloads until we've gotten everything
unsigned long got_time;
// Fetch the payload, and see if this was the last one.
radio.read( &got_time, sizeof(unsigned long) );
radio.stopListening();
//delay(1);
// Seem to need a delay, or the RPi is too quick
radio.write( &got_time, sizeof(unsigned long) );
//delay(1);
// Now, resume listening so we catch the next packets.
radio.startListening();
//delay(1);
// Spew it
printf("Got payload(%d) %lu...\n",sizeof(unsigned long), got_time);
}
//delay(5);
}
} // forever loop
return 0;
}
@@ -0,0 +1,137 @@
/*
TMRh20 2014 - Updated to work with optimized RF24 Arduino library
*/
/**
* Example for efficient call-response using ack-payloads
*
* This example continues to make use of all the normal functionality of the radios including
* the auto-ack and auto-retry features, but allows ack-payloads to be written optionlly as well.
* This allows very fast call-response communication, with the responding radio never having to
* switch out of Primary Receiver mode to send back a payload, but having the option to switch to
* primary transmitter if wanting to initiate communication instead of respond to a commmunication.
*/
#include <cstdlib>
#include <iostream>
#include <sstream>
#include <string>
#include "./RF24.h"
using namespace std;
//
// Hardware configuration
//
// CE Pin, CSN Pin, SPI Speed
// Setup for GPIO 22 CE and CE1 CSN with SPI Speed @ 1Mhz
//RF24 radio(RPI_V2_GPIO_P1_22, RPI_V2_GPIO_P1_26, BCM2835_SPI_SPEED_1MHZ);
// Setup for GPIO 22 CE and CE0 CSN with SPI Speed @ 4Mhz
//RF24 radio(RPI_V2_GPIO_P1_15, BCM2835_SPI_CS0, BCM2835_SPI_SPEED_4MHZ);
// Setup for GPIO 22 CE and CE0 CSN with SPI Speed @ 8Mhz
RF24 radio(RPI_V2_GPIO_P1_15, RPI_V2_GPIO_P1_24, BCM2835_SPI_SPEED_8MHZ);
// Radio pipe addresses for the 2 nodes to communicate.
const uint64_t addresses[2] = { 0xABCDABCD71LL, 0x544d52687CLL };
bool role_ping_out = 1, role_pong_back = 0, role = 0;
uint8_t counter = 1; // A single byte to keep track of the data being sent back and forth
int main(int argc, char** argv){
printf("RF24/examples/gettingstarted_call_response\n");
radio.begin();
radio.setAutoAck(1); // Ensure autoACK is enabled
radio.enableAckPayload(); // Allow optional ack payloads
radio.setRetries(1,15); // Smallest time between retries, max no. of retries
radio.setPayloadSize(1); // Here we are sending 1-byte payloads to test the call-response speed
//radio.powerUp();
radio.printDetails(); // Dump the configuration of the rf unit for debugging
/********* Role chooser ***********/
printf("\n ************ Role Setup ***********\n");
string input = "";
char myChar = {0};
cout << "Choose a role: Enter 0 for pong_back, 1 for ping_out (CTRL+C to exit)\n>";
getline(cin,input);
if(input.length() == 1) {
myChar = input[0];
if(myChar == '0'){
cout << "Role: Pong Back, awaiting transmission " << endl << endl;
}else{ cout << "Role: Ping Out, starting transmission " << endl << endl;
role = role_ping_out;
}
}
/***********************************/
// This simple sketch opens two pipes for these two nodes to communicate
// back and forth.
if ( role == role_ping_out ) {
radio.openWritingPipe(addresses[0]);
radio.openReadingPipe(1,addresses[1]);
}else{
radio.openWritingPipe(addresses[1]);
radio.openReadingPipe(1,addresses[0]);
radio.startListening();
}
// forever loop
while (1){
/****************** Ping Out Role ***************************/
if (role == role_ping_out){ // Radio is in ping mode
uint8_t gotByte; // Initialize a variable for the incoming response
radio.stopListening(); // First, stop listening so we can talk.
printf("Now sending %d as payload. ",counter); // Use a simple byte counter as payload
unsigned long time = millis(); // Record the current microsecond count
if ( radio.write(&counter,1) ){ // Send the counter variable to the other radio
if(!radio.available()){ // If nothing in the buffer, we got an ack but it is blank
printf("Got blank response. round-trip delay: %lu ms\n\r",millis()-time);
}else{
while(radio.available() ){ // If an ack with payload was received
radio.read( &gotByte, 1 ); // Read it, and display the response time
printf("Got response %d, round-trip delay: %lu ms\n\r",gotByte,millis()-time);
counter++; // Increment the counter variable
}
}
}else{ printf("Sending failed.\n\r"); } // If no ack response, sending failed
sleep(1); // Try again later
}
/****************** Pong Back Role ***************************/
if ( role == role_pong_back ) {
uint8_t pipeNo, gotByte; // Declare variables for the pipe and the byte received
while( radio.available(&pipeNo)){ // Read all available payloads
radio.read( &gotByte, 1 );
// Since this is a call-response. Respond directly with an ack payload.
// Ack payloads are much more efficient than switching to transmit mode to respond to a call
radio.writeAckPayload(pipeNo,&gotByte, 1 ); // This can be commented out to send empty payloads.
printf("Sent response %d \n\r", gotByte);
}
}
} //while 1
} //main
@@ -0,0 +1,181 @@
/*
TMRh20 2014 - Optimized RF24 Library Fork
*/
/**
* Example using Dynamic Payloads
*
* This is an example of how to use payloads of a varying (dynamic) size.
*/
#include <cstdlib>
#include <iostream>
#include <sstream>
#include <string>
#include "./RF24.h"
using namespace std;
//
// Hardware configuration
//
// CE Pin, CSN Pin, SPI Speed
// Setup for GPIO 22 CE and CE1 CSN with SPI Speed @ 1Mhz
//RF24 radio(RPI_V2_GPIO_P1_22, RPI_V2_GPIO_P1_26, BCM2835_SPI_SPEED_1MHZ);
// Setup for GPIO 22 CE and CE0 CSN with SPI Speed @ 4Mhz
//RF24 radio(RPI_V2_GPIO_P1_15, BCM2835_SPI_CS0, BCM2835_SPI_SPEED_4MHZ);
// Setup for GPIO 22 CE and CE0 CSN with SPI Speed @ 8Mhz
RF24 radio(RPI_V2_GPIO_P1_15, RPI_V2_GPIO_P1_24, BCM2835_SPI_SPEED_8MHZ);
// Radio pipe addresses for the 2 nodes to communicate.
const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };
bool role_ping_out = 1, role_pong_back = 0;
bool role = 0;
const int min_payload_size = 4;
const int max_payload_size = 32;
const int payload_size_increments_by = 1;
int next_payload_size = min_payload_size;
char receive_payload[max_payload_size+1]; // +1 to allow room for a terminating NULL char
int main(int argc, char** argv){
// Print preamble:
printf("RF24/examples/pingpair_dyn/\n");
// Setup and configure rf radio
radio.begin();
radio.enableDynamicPayloads();
radio.setRetries(5,15);
radio.printDetails();
/********* Role chooser ***********/
printf("\n ************ Role Setup ***********\n");
string input = "";
char myChar = {0};
cout << "Choose a role: Enter 0 for receiver, 1 for transmitter (CTRL+C to exit) \n>";
getline(cin,input);
if(input.length() == 1) {
myChar = input[0];
if(myChar == '0'){
cout << "Role: Pong Back, awaiting transmission " << endl << endl;
}else{ cout << "Role: Ping Out, starting transmission " << endl << endl;
role = role_ping_out;
}
}
/***********************************/
if ( role == role_ping_out ) {
radio.openWritingPipe(pipes[0]);
radio.openReadingPipe(1,pipes[1]);
} else {
radio.openWritingPipe(pipes[1]);
radio.openReadingPipe(1,pipes[0]);
radio.startListening();
}
// forever loop
while (1)
{
if (role == role_ping_out)
{
// The payload will always be the same, what will change is how much of it we send.
static char send_payload[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ789012";
// First, stop listening so we can talk.
radio.stopListening();
// Take the time, and send it. This will block until complete
printf("Now sending length %i...",next_payload_size);
radio.write( send_payload, next_payload_size );
// Now, continue listening
radio.startListening();
// Wait here until we get a response, or timeout
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
{
// Grab the response, compare, and send to debugging spew
uint8_t len = radio.getDynamicPayloadSize();
radio.read( receive_payload, len );
// Put a zero at the end for easy printing
receive_payload[len] = 0;
// Spew it
printf("Got response size=%i value=%s\n\r",len,receive_payload);
}
// Update size for next time.
next_payload_size += payload_size_increments_by;
if ( next_payload_size > max_payload_size )
next_payload_size = min_payload_size;
// Try again 1s later
delay(100);
}
//
// 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
uint8_t len;
while (radio.available())
{
// Fetch the payload, and see if this was the last one.
len = radio.getDynamicPayloadSize();
radio.read( receive_payload, len );
// Put a zero at the end for easy printing
receive_payload[len] = 0;
// Spew it
printf("Got payload size=%i value=%s\n\r",len,receive_payload);
}
// First, stop listening so we can talk
radio.stopListening();
// Send the final one back.
radio.write( receive_payload, len );
printf("Sent response.\n\r");
// Now, resume listening so we catch the next packets.
radio.startListening();
}
}
}
}
@@ -0,0 +1,148 @@
/*
TMRh20 2014
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.
*/
/** General Data Transfer Rate Test
* This example demonstrates basic data transfer functionality with the
updated library. This example will display the transfer rates acheived using
the slower form of high-speed transfer using blocking-writes.
*/
#include <cstdlib>
#include <iostream>
#include <sstream>
#include <string>
#include "./RF24.h"
using namespace std;
//
// Hardware configuration
//
// CE Pin, CSN Pin, SPI Speed
// Setup for GPIO 22 CE and CE1 CSN with SPI Speed @ 1Mhz
//RF24 radio(RPI_V2_GPIO_P1_22, RPI_V2_GPIO_P1_26, BCM2835_SPI_SPEED_1MHZ);
// Setup for GPIO 22 CE and CE0 CSN with SPI Speed @ 4Mhz
//RF24 radio(RPI_V2_GPIO_P1_15, BCM2835_SPI_CS0, BCM2835_SPI_SPEED_4MHZ);
// Setup for GPIO 22 CE and CE0 CSN with SPI Speed @ 8Mhz
RF24 radio(RPI_V2_GPIO_P1_15, RPI_V2_GPIO_P1_24, BCM2835_SPI_SPEED_8MHZ);
// Radio pipe addresses for the 2 nodes to communicate.
const uint64_t addresses[2] = { 0xABCDABCD71LL, 0x544d52687CLL };
bool role_ping_out = 1, role_pong_back = 0;
bool role = 0;
uint8_t data[32];
unsigned long startTime, stopTime, counter, rxTimer=0;
int main(int argc, char** argv){
// Print preamble:
printf("RF24/examples/Transfer/\n");
radio.begin(); // Setup and configure rf radio
radio.setChannel(1);
radio.setPALevel(RF24_PA_MAX);
radio.setDataRate(RF24_2MBPS);
radio.setAutoAck(1); // Ensure autoACK is enabled
radio.setRetries(2,15); // Optionally, increase the delay between retries & # of retries
radio.setCRCLength(RF24_CRC_8);
radio.printDetails();
/********* Role chooser ***********/
printf("\n ************ Role Setup ***********\n");
string input = "";
char myChar = {0};
cout << "Choose a role: Enter 0 for receiver, 1 for transmitter (CTRL+C to exit)\n>";
getline(cin,input);
if(input.length() == 1) {
myChar = input[0];
if(myChar == '0'){
cout << "Role: Pong Back, awaiting transmission " << endl << endl;
}else{ cout << "Role: Ping Out, starting transmission " << endl << endl;
role = role_ping_out;
}
}
/***********************************/
if ( role == role_ping_out ) {
radio.openWritingPipe(addresses[0]);
radio.openReadingPipe(1,addresses[1]);
} else {
radio.openWritingPipe(addresses[1]);
radio.openReadingPipe(1,addresses[0]);
radio.startListening();
}
for(int i=0; i<32; i++){
data[i] = rand() % 255; //Load the buffer with random data
}
// forever loop
while (1){
if (role == role_ping_out){
sleep(2);
printf("Initiating Basic Data Transfer\n\r");
long int cycles = 10000; //Change this to a higher or lower number.
startTime = millis();
for(int i=0; i<cycles; i++){ //Loop through a number of cycles
data[0] = i; //Change the first byte of the payload for identification
if(!radio.writeFast(&data,32)){ //Write to the FIFO buffers
counter++; //Keep count of failed payloads
}
}
stopTime = millis();
if(!radio.txStandBy()){ counter+=3; }
float numBytes = cycles*32;
float rate = numBytes / (stopTime - startTime);
printf("Transfer complete at %.2f KB/s \n\r",rate);
printf("%lu of %lu Packets Failed to Send\n\r",counter,cycles);
counter = 0;
}
if(role == role_pong_back){
while(radio.available()){
radio.read(&data,32);
counter++;
}
if(millis() - rxTimer > 1000){
rxTimer = millis();
printf("Rate: ");
float numBytes = counter*32;
printf("%.2f KB/s \n\r",numBytes/1000);
printf("Payload Count: %lu \n\r", counter);
counter = 0;
}
}
} // loop
} // main
+127
View File
@@ -0,0 +1,127 @@
/*
Copyright (c) 2007 Stefan Engelke <mbox@stefanengelke.de>
Portions Copyright (C) 2011 Greg Copeland
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
/* Memory Map */
#define CONFIG 0x00
#define EN_AA 0x01
#define EN_RXADDR 0x02
#define SETUP_AW 0x03
#define SETUP_RETR 0x04
#define RF_CH 0x05
#define RF_SETUP 0x06
#define STATUS 0x07
#define OBSERVE_TX 0x08
#define CD 0x09
#define RX_ADDR_P0 0x0A
#define RX_ADDR_P1 0x0B
#define RX_ADDR_P2 0x0C
#define RX_ADDR_P3 0x0D
#define RX_ADDR_P4 0x0E
#define RX_ADDR_P5 0x0F
#define TX_ADDR 0x10
#define RX_PW_P0 0x11
#define RX_PW_P1 0x12
#define RX_PW_P2 0x13
#define RX_PW_P3 0x14
#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
#define MASK_TX_DS 5
#define MASK_MAX_RT 4
#define EN_CRC 3
#define CRCO 2
#define PWR_UP 1
#define PRIM_RX 0
#define ENAA_P5 5
#define ENAA_P4 4
#define ENAA_P3 3
#define ENAA_P2 2
#define ENAA_P1 1
#define ENAA_P0 0
#define ERX_P5 5
#define ERX_P4 4
#define ERX_P3 3
#define ERX_P2 2
#define ERX_P1 1
#define ERX_P0 0
#define AW 0
#define ARD 4
#define ARC 0
#define PLL_LOCK 4
#define RF_DR 3
#define RF_PWR 6
#define RX_DR 6
#define TX_DS 5
#define MAX_RT 4
#define RX_P_NO 1
#define TX_FULL 0
#define PLOS_CNT 4
#define ARC_CNT 0
#define TX_REUSE 6
#define FIFO_FULL 5
#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
#define NOP 0xFF
/* Non-P omissions */
#define LNA_HCURR 0
/* P model memory Map */
#define RPD 0x09
#define W_TX_PAYLOAD_NO_ACK 0xB0
/* P model bit Mnemonics */
#define RF_DR_LOW 5
#define RF_DR_HIGH 3
#define RF_PWR_LOW 1
#define RF_PWR_HIGH 2
+117
View File
@@ -0,0 +1,117 @@
Optimized Raspberry Pi RF24 and RF24 Network Libraries
=============================================
General Documentation: http://tmrh20.github.io
Library functions are mostly the same.
See the included examples for RPi specific usage
##Raspberry Pi - PreConfig
####Possible pre-configuration:
If SPI is not already enabled, load it on boot:
```
sudo raspi-config
```
A. Update the tool via the menu as required
B. Select Advanced and enable the SPI kernel module
C. Update other software and libraries:
```
sudo apt-get update
sudo apt-get upgrade
```
RPi - RF24 Quick-Start
======================
A. Make a directory to contain the RF24 and possibly RF24Network lib and enter it:
```
mkdir ~/rf24libs
cd ~/rf24libs
```
B. Clone the RF24 Repo
```
git clone https://github.com/tmrh20/RF24.git rtemp
```
C. Copy the RPi library folder to the current directory, and delete the rest
```
mv rtemp/RPi/RF24 ./
rm -r rtemp
cd RF24
```
D. Build the library, and run an example file:
```
sudo make
cd examples
sudo make
sudo ./gettingstarted
```
RPi - RF24Network Quick-Start
=============================
A. Enter the same directory that contains the RF24 library folder
```
cd ~/rf24libs
```
B. Clone the RF24Network Repo
```
git clone https://github.com/tmrh20/RF24Network.git ntemp
```
C. Copy the RF24Network folder to the current directory, and delete the rest
```
mv ntemp/RPi/RF24Network ./
rm -r ntemp
cd RF24Network
```
D. Build the library
```
sudo make
cd examples
sudo make
sudo ./helloworld_rx OR sudo ./helloworld_tx
```
Connection Info
===============
Using pin 15/GPIO 22 for CE, pin 24/GPIO8 (CE0) for CSN
Can use either RPi CE0 or CE1 pins for radio CSN.
Choose any RPi output pin for radio CE pin.
**Constructor:**
```
RF24 radio(RPI_V2_GPIO_P1_15,BCM2835_SPI_CS0, BCM2835_SPI_SPEED_8MHZ);
or
RF24 radio(RPI_V2_GPIO_P1_15,BCM2835_SPI_CS1, BCM2835_SPI_SPEED_8MHZ);
```
**Pins:**
|NRF24L01 | RPI | P1 Connector |
|-----|-----------|-------------|
| VCC | rpi-3v3 | (17) |
| GND | rpi-gnd | (25) |
| CE | rpi-gpio22 | (15) |
| CSN | rpi-gpio8 | (24) |
| SCK | rpi-sckl | (23) |
| MOSI | rpi-mosi | (19) |
| MISO | rpi-miso | (21) |
See http://www.airspayce.com/mikem/bcm2835/index.html for BCM2835 class documentation.
Note: The BCM library has been customized slightly to allow use of hardware CE pins not
in use for SPI, and to include a millis() function.
****************
Based on the arduino lib from J. Coliz <maniacbug@ymail.com>.
the library was berryfied by Purinda Gunasekara <purinda@gmail.com>.
then forked from github stanleyseow/RF24 to https://github.com/jscrane/RF24-rpi
Network lib also based on https://github.com/farconada/RF24Network
Currently optimized and aligned with Arduino fork of libraries by TMRh20:
https://github.com/tmrh20/RF24/RPi and https://github.com/tmrh20/RF24Network/RPi
Documentation: http://tmrh20.github.io
+117
View File
@@ -0,0 +1,117 @@
Optimized Raspberry Pi RF24 and RF24 Network Libraries
=============================================
General Documentation: http://tmrh20.github.io
Library functions are mostly the same.
See the included examples for RPi specific usage
##Raspberry Pi - PreConfig
####Possible pre-configuration:
If SPI is not already enabled, load it on boot:
```
sudo raspi-config
```
A. Update the tool via the menu as required
B. Select Advanced and enable the SPI kernel module
C. Update other software and libraries:
```
sudo apt-get update
sudo apt-get upgrade
```
RPi - RF24 Quick-Start
======================
A. Make a directory to contain the RF24 and possibly RF24Network lib and enter it:
```
mkdir ~/rf24libs
cd ~/rf24libs
```
B. Clone the RF24 Repo
```
git clone https://github.com/tmrh20/RF24.git rtemp
```
C. Copy the RPi library folder to the current directory, and delete the rest
```
mv rtemp/RPi/RF24 ./
rm -r rtemp
cd RF24
```
D. Build the library, and run an example file:
```
sudo make
cd examples
sudo make
sudo ./gettingstarted
```
RPi - RF24Network Quick-Start
=============================
A. Enter the same directory that contains the RF24 library folder
```
cd ~/rf24libs
```
B. Clone the RF24Network Repo
```
git clone https://github.com/tmrh20/RF24Network.git ntemp
```
C. Copy the RF24Network folder to the current directory, and delete the rest
```
mv ntemp/RPi/RF24Network ./
rm -r ntemp
cd RF24Network
```
D. Build the library
```
sudo make
cd examples
sudo make
sudo ./helloworld_rx OR sudo ./helloworld_tx
```
Connection Info
===============
Using pin 15/GPIO 22 for CE, pin 24/GPIO8 (CE0) for CSN
Can use either RPi CE0 or CE1 pins for radio CSN.
Choose any RPi output pin for radio CE pin.
**Constructor:**
```
RF24 radio(RPI_V2_GPIO_P1_15,BCM2835_SPI_CS0, BCM2835_SPI_SPEED_8MHZ);
or
RF24 radio(RPI_V2_GPIO_P1_15,BCM2835_SPI_CS1, BCM2835_SPI_SPEED_8MHZ);
```
**Pins:**
|NRF24L01 | RPI | P1 Connector |
|-----|-----------|-------------|
| VCC | rpi-3v3 | (17) |
| GND | rpi-gnd | (25) |
| CE | rpi-gpio22 | (15) |
| CSN | rpi-gpio8 | (24) |
| SCK | rpi-sckl | (23) |
| MOSI | rpi-mosi | (19) |
| MISO | rpi-miso | (21) |
See http://www.airspayce.com/mikem/bcm2835/index.html for BCM2835 class documentation.
Note: The BCM library has been customized slightly to allow use of hardware CE pins not
in use for SPI, and to include a millis() function.
****************
Based on the arduino lib from J. Coliz <maniacbug@ymail.com>.
the library was berryfied by Purinda Gunasekara <purinda@gmail.com>.
then forked from github stanleyseow/RF24 to https://github.com/jscrane/RF24-rpi
Network lib also based on https://github.com/farconada/RF24Network
Currently optimized and aligned with Arduino fork of libraries by TMRh20:
https://github.com/tmrh20/RF24/RPi and https://github.com/tmrh20/RF24Network/RPi
Documentation: http://tmrh20.github.io
+835
View File
@@ -0,0 +1,835 @@
/* The standard CSS for doxygen */
body, table, div, p, dl {
font-family: Lucida Grande, Verdana, Geneva, Arial, sans-serif;
font-size: 12px;
}
/* @group Heading Levels */
h1 {
font-size: 150%;
}
.title {
font-size: 150%;
font-weight: bold;
margin: 10px 2px;
}
h2 {
font-size: 120%;
}
h3 {
font-size: 100%;
}
dt {
font-weight: bold;
}
div.multicol {
-moz-column-gap: 1em;
-webkit-column-gap: 1em;
-moz-column-count: 3;
-webkit-column-count: 3;
}
p.startli, p.startdd, p.starttd {
margin-top: 2px;
}
p.endli {
margin-bottom: 0px;
}
p.enddd {
margin-bottom: 4px;
}
p.endtd {
margin-bottom: 2px;
}
/* @end */
caption {
font-weight: bold;
}
span.legend {
font-size: 70%;
text-align: center;
}
h3.version {
font-size: 90%;
text-align: center;
}
div.qindex, div.navtab{
background-color: #EBEFF6;
border: 1px solid #A3B4D7;
text-align: center;
margin: 2px;
padding: 2px;
}
div.qindex, div.navpath {
width: 100%;
line-height: 140%;
}
div.navtab {
margin-right: 15px;
}
/* @group Link Styling */
a {
color: #3D578C;
font-weight: normal;
text-decoration: none;
}
.contents a:visited {
color: #4665A2;
}
a:hover {
text-decoration: underline;
}
a.qindex {
font-weight: bold;
}
a.qindexHL {
font-weight: bold;
background-color: #9CAFD4;
color: #ffffff;
border: 1px double #869DCA;
}
.contents a.qindexHL:visited {
color: #ffffff;
}
a.el {
font-weight: bold;
}
a.elRef {
}
a.code {
color: #4665A2;
}
a.codeRef {
color: #4665A2;
}
/* @end */
dl.el {
margin-left: -1cm;
}
.fragment {
font-family: monospace, fixed;
font-size: 105%;
}
pre.fragment {
border: 1px solid #C4CFE5;
background-color: #FBFCFD;
padding: 4px 6px;
margin: 4px 8px 4px 2px;
overflow: auto;
word-wrap: break-word;
font-size: 9pt;
line-height: 125%;
}
div.ah {
background-color: black;
font-weight: bold;
color: #ffffff;
margin-bottom: 3px;
margin-top: 3px;
padding: 0.2em;
border: solid thin #333;
border-radius: 0.5em;
-webkit-border-radius: .5em;
-moz-border-radius: .5em;
box-shadow: 2px 2px 3px #999;
-webkit-box-shadow: 2px 2px 3px #999;
-moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px;
background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444));
background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000);
}
div.groupHeader {
margin-left: 16px;
margin-top: 12px;
font-weight: bold;
}
div.groupText {
margin-left: 16px;
font-style: italic;
}
body {
background: white;
color: black;
margin: 0;
}
div.contents {
margin-top: 10px;
margin-left: 10px;
margin-right: 5px;
}
td.indexkey {
background-color: #EBEFF6;
font-weight: bold;
border: 1px solid #C4CFE5;
margin: 2px 0px 2px 0;
padding: 2px 10px;
}
td.indexvalue {
background-color: #EBEFF6;
border: 1px solid #C4CFE5;
padding: 2px 10px;
margin: 2px 0px;
}
tr.memlist {
background-color: #EEF1F7;
}
p.formulaDsp {
text-align: center;
}
img.formulaDsp {
}
img.formulaInl {
vertical-align: middle;
}
div.center {
text-align: center;
margin-top: 0px;
margin-bottom: 0px;
padding: 0px;
}
div.center img {
border: 0px;
}
address.footer {
text-align: right;
padding-right: 12px;
}
img.footer {
border: 0px;
vertical-align: middle;
}
/* @group Code Colorization */
span.keyword {
color: #008000
}
span.keywordtype {
color: #604020
}
span.keywordflow {
color: #e08000
}
span.comment {
color: #800000
}
span.preprocessor {
color: #806020
}
span.stringliteral {
color: #002080
}
span.charliteral {
color: #008080
}
span.vhdldigit {
color: #ff00ff
}
span.vhdlchar {
color: #000000
}
span.vhdlkeyword {
color: #700070
}
span.vhdllogic {
color: #ff0000
}
/* @end */
/*
.search {
color: #003399;
font-weight: bold;
}
form.search {
margin-bottom: 0px;
margin-top: 0px;
}
input.search {
font-size: 75%;
color: #000080;
font-weight: normal;
background-color: #e8eef2;
}
*/
td.tiny {
font-size: 75%;
}
.dirtab {
padding: 4px;
border-collapse: collapse;
border: 1px solid #A3B4D7;
}
th.dirtab {
background: #EBEFF6;
font-weight: bold;
}
hr {
height: 0px;
border: none;
border-top: 1px solid #4A6AAA;
}
hr.footer {
height: 1px;
}
/* @group Member Descriptions */
table.memberdecls {
border-spacing: 0px;
padding: 0px;
}
.mdescLeft, .mdescRight,
.memItemLeft, .memItemRight,
.memTemplItemLeft, .memTemplItemRight, .memTemplParams {
background-color: #F9FAFC;
border: none;
margin: 4px;
padding: 1px 0 0 8px;
}
.mdescLeft, .mdescRight {
padding: 0px 8px 4px 8px;
color: #555;
}
.memItemLeft, .memItemRight, .memTemplParams {
border-top: 1px solid #C4CFE5;
}
.memItemLeft, .memTemplItemLeft {
white-space: nowrap;
}
.memItemRight {
width: 100%;
}
.memTemplParams {
color: #4665A2;
white-space: nowrap;
}
/* @end */
/* @group Member Details */
/* Styles for detailed member documentation */
.memtemplate {
font-size: 80%;
color: #4665A2;
font-weight: normal;
margin-left: 9px;
}
.memnav {
background-color: #EBEFF6;
border: 1px solid #A3B4D7;
text-align: center;
margin: 2px;
margin-right: 15px;
padding: 2px;
}
.mempage {
width: 100%;
}
.memitem {
padding: 0;
margin-bottom: 10px;
margin-right: 5px;
}
.memname {
white-space: nowrap;
font-weight: bold;
margin-left: 6px;
}
.memproto {
border-top: 1px solid #A8B8D9;
border-left: 1px solid #A8B8D9;
border-right: 1px solid #A8B8D9;
padding: 6px 0px 6px 0px;
color: #253555;
font-weight: bold;
text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9);
/* opera specific markup */
box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
border-top-right-radius: 8px;
border-top-left-radius: 8px;
/* firefox specific markup */
-moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px;
-moz-border-radius-topright: 8px;
-moz-border-radius-topleft: 8px;
/* webkit specific markup */
-webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
-webkit-border-top-right-radius: 8px;
-webkit-border-top-left-radius: 8px;
background-image:url('nav_f.png');
background-repeat:repeat-x;
background-color: #E2E8F2;
}
.memdoc {
border-bottom: 1px solid #A8B8D9;
border-left: 1px solid #A8B8D9;
border-right: 1px solid #A8B8D9;
padding: 2px 5px;
background-color: #FBFCFD;
border-top-width: 0;
/* opera specific markup */
border-bottom-left-radius: 8px;
border-bottom-right-radius: 8px;
box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
/* firefox specific markup */
-moz-border-radius-bottomleft: 8px;
-moz-border-radius-bottomright: 8px;
-moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px;
background-image: -moz-linear-gradient(center top, #FFFFFF 0%, #FFFFFF 60%, #F7F8FB 95%, #EEF1F7);
/* webkit specific markup */
-webkit-border-bottom-left-radius: 8px;
-webkit-border-bottom-right-radius: 8px;
-webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
background-image: -webkit-gradient(linear,center top,center bottom,from(#FFFFFF), color-stop(0.6,#FFFFFF), color-stop(0.60,#FFFFFF), color-stop(0.95,#F7F8FB), to(#EEF1F7));
}
.paramkey {
text-align: right;
}
.paramtype {
white-space: nowrap;
}
.paramname {
color: #602020;
white-space: nowrap;
}
.paramname em {
font-style: normal;
}
.params, .retval, .exception, .tparams {
border-spacing: 6px 2px;
}
.params .paramname, .retval .paramname {
font-weight: bold;
vertical-align: top;
}
.params .paramtype {
font-style: italic;
vertical-align: top;
}
.params .paramdir {
font-family: "courier new",courier,monospace;
vertical-align: top;
}
/* @end */
/* @group Directory (tree) */
/* for the tree view */
.ftvtree {
font-family: sans-serif;
margin: 0px;
}
/* these are for tree view when used as main index */
.directory {
font-size: 9pt;
font-weight: bold;
margin: 5px;
}
.directory h3 {
margin: 0px;
margin-top: 1em;
font-size: 11pt;
}
/*
The following two styles can be used to replace the root node title
with an image of your choice. Simply uncomment the next two styles,
specify the name of your image and be sure to set 'height' to the
proper pixel height of your image.
*/
/*
.directory h3.swap {
height: 61px;
background-repeat: no-repeat;
background-image: url("yourimage.gif");
}
.directory h3.swap span {
display: none;
}
*/
.directory > h3 {
margin-top: 0;
}
.directory p {
margin: 0px;
white-space: nowrap;
}
.directory div {
display: none;
margin: 0px;
}
.directory img {
vertical-align: -30%;
}
/* these are for tree view when not used as main index */
.directory-alt {
font-size: 100%;
font-weight: bold;
}
.directory-alt h3 {
margin: 0px;
margin-top: 1em;
font-size: 11pt;
}
.directory-alt > h3 {
margin-top: 0;
}
.directory-alt p {
margin: 0px;
white-space: nowrap;
}
.directory-alt div {
display: none;
margin: 0px;
}
.directory-alt img {
vertical-align: -30%;
}
/* @end */
div.dynheader {
margin-top: 8px;
}
address {
font-style: normal;
color: #2A3D61;
}
table.doxtable {
border-collapse:collapse;
}
table.doxtable td, table.doxtable th {
border: 1px solid #2D4068;
padding: 3px 7px 2px;
}
table.doxtable th {
background-color: #374F7F;
color: #FFFFFF;
font-size: 110%;
padding-bottom: 4px;
padding-top: 5px;
text-align:left;
}
.tabsearch {
top: 0px;
left: 10px;
height: 36px;
background-image: url('tab_b.png');
z-index: 101;
overflow: hidden;
font-size: 13px;
}
.navpath ul
{
font-size: 11px;
background-image:url('tab_b.png');
background-repeat:repeat-x;
height:30px;
line-height:30px;
color:#8AA0CC;
border:solid 1px #C2CDE4;
overflow:hidden;
margin:0px;
padding:0px;
}
.navpath li
{
list-style-type:none;
float:left;
padding-left:10px;
padding-right:15px;
background-image:url('bc_s.png');
background-repeat:no-repeat;
background-position:right;
color:#364D7C;
}
.navpath li.navelem a
{
height:32px;
display:block;
text-decoration: none;
outline: none;
}
.navpath li.navelem a:hover
{
color:#6884BD;
}
.navpath li.footer
{
list-style-type:none;
float:right;
padding-left:10px;
padding-right:15px;
background-image:none;
background-repeat:no-repeat;
background-position:right;
color:#364D7C;
font-size: 8pt;
}
div.summary
{
float: right;
font-size: 8pt;
padding-right: 5px;
width: 50%;
text-align: right;
}
div.summary a
{
white-space: nowrap;
}
div.ingroups
{
font-size: 8pt;
padding-left: 5px;
width: 50%;
text-align: left;
}
div.ingroups a
{
white-space: nowrap;
}
div.header
{
background-image:url('nav_h.png');
background-repeat:repeat-x;
background-color: #F9FAFC;
margin: 0px;
border-bottom: 1px solid #C4CFE5;
}
div.headertitle
{
padding: 5px 5px 5px 10px;
}
dl
{
padding: 0 0 0 10px;
}
dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug
{
border-left:4px solid;
padding: 0 0 0 6px;
}
dl.note
{
border-color: #D0C000;
}
dl.warning, dl.attention
{
border-color: #FF0000;
}
dl.pre, dl.post, dl.invariant
{
border-color: #00D000;
}
dl.deprecated
{
border-color: #505050;
}
dl.todo
{
border-color: #00C0E0;
}
dl.test
{
border-color: #3030E0;
}
dl.bug
{
border-color: #C08050;
}
#projectlogo
{
text-align: center;
vertical-align: bottom;
border-collapse: separate;
}
#projectlogo img
{
border: 0px none;
}
#projectname
{
font: 300% Tahoma, Arial,sans-serif;
margin: 0px;
padding: 2px 0px;
}
#projectbrief
{
font: 120% Tahoma, Arial,sans-serif;
margin: 0px;
padding: 0px;
}
#projectnumber
{
font: 50% Tahoma, Arial,sans-serif;
margin: 0px;
padding: 0px;
}
#titlearea
{
padding: 0px;
margin: 0px;
width: 100%;
border-bottom: 1px solid #5373B4;
}
.image
{
text-align: left;
}
.dotgraph
{
text-align: center;
}
.mscgraph
{
text-align: center;
}
.caption
{
font-weight: bold;
}
@@ -0,0 +1,136 @@
/*
Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
//2014 - TMRh20 - Updated along with Optimized RF24 Library fork
*/
/**
* Example for Getting Started with nRF24L01+ radios.
*
* This is an example of how to use the RF24 class to communicate on a basic level. Write this sketch to two
* different nodes. Put one of the nodes into 'transmit' mode by connecting with the serial monitor and
* sending a 'T'. The ping node sends the current time to the pong node, which responds by sending the value
* back. The ping node can then see how long the whole cycle took.
* Note: For a more efficient call-response scenario see the GettingStarted_CallResponse.ino example.
* Note: When switching between sketches, the radio may need to be powered down to clear settings that are not "un-set" otherwise
*/
#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"
#include "printf.h"
// Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins 9 & 10
RF24 radio(7,8);
const uint64_t addresses[2] = { 0xABCDABCD71LL, 0x544d52687CLL }; // Radio pipe addresses for the 2 nodes to communicate.
// Set up roles to simplify testing
boolean role; // The main role variable, holds the current role identifier
boolean role_ping_out = 1, role_pong_back = 0; // The two different roles.
void setup() {
Serial.begin(57600);
printf_begin();
printf("\n\rRF24/examples/GettingStarted/\n\r");
printf("*** PRESS 'T' to begin transmitting to the other node\n\r");
// Setup and configure rf radio
radio.begin(); // Start up the radio
radio.setAutoAck(1); // Ensure autoACK is enabled
radio.setRetries(15,15); // Max delay between retries & number of retries
radio.openWritingPipe(addresses[1]); // Open a writing pipe on pipe 0, with address 1
radio.openReadingPipe(1,addresses[0]); // Open a reading pipe on pipe 1, with address 0
radio.startListening(); // Start listening
radio.printDetails(); // Dump the configuration of the rf unit for debugging
}
void loop(void){
/****************** Ping Out Role ***************************/
if (role == role_ping_out) {
radio.stopListening(); // First, stop listening so we can talk.
printf("Now sending \n\r");
unsigned long time = micros(); // Take the time, and send it. This will block until complete
if (!radio.write( &time, sizeof(unsigned long) )){ printf("failed.\n\r"); }
radio.startListening(); // Now, continue listening
unsigned long started_waiting_at = micros(); // Set up a timeout period, get the current microseconds
boolean timeout = false; // Set up a variable to indicate if a response was received or not
while ( ! radio.available() ){ // While nothing is received
if (micros() - started_waiting_at > 200000 ){ // If waited longer than 200ms, indicate timeout and exit while loop
timeout = true;
break;
}
}
if ( timeout ){ // Describe the results
printf("Failed, response timed out.\n\r");
}else{
unsigned long got_time; // Grab the response, compare, and send to debugging spew
radio.read( &got_time, sizeof(unsigned long) );
// Spew it
printf("Sent %lu, Got response %lu, round-trip delay: %lu microseconds\n\r",time,got_time,micros()-got_time);
}
// Try again 1s later
delay(1000);
}
/****************** Pong Back Role ***************************/
if ( role == role_pong_back )
{
if( radio.available()){
unsigned long got_time; // Variable for the received timestamp
while (radio.available()) { // While there is data ready
radio.read( &got_time, sizeof(unsigned long) ); // Get the payload
}
radio.stopListening(); // First, stop listening so we can talk
radio.write( &got_time, sizeof(unsigned long) ); // Send the final one back.
radio.startListening(); // Now, resume listening so we catch the next packets.
printf("Sent response %lu \n\r", got_time);
}
}
/****************** Change Roles via Serial Commands ***************************/
if ( Serial.available() )
{
char c = toupper(Serial.read());
if ( c == 'T' && role == role_pong_back )
{
printf("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK\n\r");
role = role_ping_out; // Become the primary transmitter (ping out)
radio.openWritingPipe(addresses[0]);
radio.openReadingPipe(1,addresses[1]);
}
else if ( c == 'R' && role == role_ping_out )
{
printf("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK\n\r");
role = role_pong_back; // Become the primary receiver (pong back)
radio.openWritingPipe(addresses[1]);
radio.openReadingPipe(1,addresses[0]);
}
}
}
@@ -0,0 +1,37 @@
/*
Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
*/
/**
* @file printf.h
*
* Setup necessary to direct stdout to the Arduino Serial library, which
* enables 'printf'
*/
#ifndef __PRINTF_H__
#define __PRINTF_H__
#ifdef ARDUINO
int serial_putc( char c, FILE * )
{
Serial.write( c );
return c;
}
void printf_begin(void)
{
fdevopen( &serial_putc, 0 );
}
#else
#error This example is only for use on Arduino.
#endif // ARDUINO
#endif // __PRINTF_H__
@@ -0,0 +1,124 @@
/*
March 2014 - TMRh20 - Updated along with High Speed RF24 Library fork
Parts derived from examples by J. Coliz <maniacbug@ymail.com>
*/
/**
* Example for efficient call-response using ack-payloads
*
* This example continues to make use of all the normal functionality of the radios including
* the auto-ack and auto-retry features, but allows ack-payloads to be written optionlly as well.
* This allows very fast call-response communication, with the responding radio never having to
* switch out of Primary Receiver mode to send back a payload, but having the option to switch to
* primary transmitter if wanting to initiate communication instead of respond to a commmunication.
*/
#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"
#include "printf.h"
// Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins 9 & 10
RF24 radio(7,8);
// Topology
const uint64_t addresses[2] = { 0xABCDABCD71LL, 0x544d52687CLL }; // Radio pipe addresses for the 2 nodes to communicate.
// Role management: Set up role. This sketch uses the same software for all the nodes
// in this system. Doing so greatly simplifies testing.
typedef enum { role_ping_out = 1, role_pong_back } role_e; // The various roles supported by this sketch
const char* role_friendly_name[] = { "invalid", "Ping out", "Pong back"}; // The debug-friendly names of those roles
role_e role = role_pong_back; // The role of the current running sketch
byte counter = 1; // A single byte to keep track of the data being sent back and forth
void setup(){
Serial.begin(57600);
printf_begin();
printf("\n\rRF24/examples/GettingStarted/\n\r");
printf("ROLE: %s\n\r",role_friendly_name[role]);
printf("*** PRESS 'T' to begin transmitting to the other node\n\r");
// Setup and configure radio
radio.begin();
radio.setAutoAck(1); // Ensure autoACK is enabled
radio.enableAckPayload(); // Allow optional ack payloads
radio.setRetries(0,15); // Smallest time between retries, max no. of retries
radio.setPayloadSize(1); // Here we are sending 1-byte payloads to test the call-response speed
radio.openWritingPipe(addresses[1]); // Both radios listen on the same pipes by default, and switch when writing
radio.openReadingPipe(1,addresses[0]); // Open a reading pipe on address 0, pipe 1
radio.startListening(); // Start listening
radio.powerUp();
radio.printDetails(); // Dump the configuration of the rf unit for debugging
}
void loop(void) {
/****************** Ping Out Role ***************************/
if (role == role_ping_out){ // Radio is in ping mode
byte gotByte; // Initialize a variable for the incoming response
radio.stopListening(); // First, stop listening so we can talk.
printf("Now sending %d as payload. ",counter); // Use a simple byte counter as payload
unsigned long time = micros(); // Record the current microsecond count
if ( radio.write(&counter,1) ){ // Send the counter variable to the other radio
if(!radio.available()){ // If nothing in the buffer, we got an ack but it is blank
printf("Got blank response. round-trip delay: %lu microseconds\n\r",micros()-time);
}else{
while(radio.available() ){ // If an ack with payload was received
radio.read( &gotByte, 1 ); // Read it, and display the response time
printf("Got response %d, round-trip delay: %lu microseconds\n\r",gotByte,micros()-time);
counter++; // Increment the counter variable
}
}
}else{ printf("Sending failed.\n\r"); } // If no ack response, sending failed
delay(1000); // Try again later
}
/****************** Pong Back Role ***************************/
if ( role == role_pong_back ) {
byte pipeNo, gotByte; // Declare variables for the pipe and the byte received
while( radio.available(&pipeNo)){ // Read all available payloads
radio.read( &gotByte, 1 );
// Since this is a call-response. Respond directly with an ack payload.
// Ack payloads are much more efficient than switching to transmit mode to respond to a call
radio.writeAckPayload(pipeNo,&gotByte, 1 ); // This can be commented out to send empty payloads.
printf("Sent response %d \n\r", gotByte);
}
}
/****************** Change Roles via Serial Commands ***************************/
if ( Serial.available() )
{
char c = toupper(Serial.read());
if ( c == 'T' && role == role_pong_back )
{
printf("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK\n\r");
role = role_ping_out; // Change roles (ping out)
radio.openWritingPipe(addresses[0]); // Open different pipes when writing. Write on pipe 0, address 0
radio.openReadingPipe(1,addresses[1]); // Read on pipe 1, as address 1
}
else if ( c == 'R' && role == role_ping_out )
{
printf("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK\n\r");
role = role_pong_back; // Become the primary receiver (pong back)
radio.openWritingPipe(addresses[1]); // Since only two radios involved, both listen on the same addresses and pipe numbers in RX mode
radio.openReadingPipe(1,addresses[0]); // then switch pipes & addresses to transmit.
radio.startListening(); // Need to start listening after opening new reading pipes
}
}
}
@@ -0,0 +1,37 @@
/*
Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
*/
/**
* @file printf.h
*
* Setup necessary to direct stdout to the Arduino Serial library, which
* enables 'printf'
*/
#ifndef __PRINTF_H__
#define __PRINTF_H__
#ifdef ARDUINO
int serial_putc( char c, FILE * )
{
Serial.write( c );
return c;
}
void printf_begin(void)
{
fdevopen( &serial_putc, 0 );
}
#else
#error This example is only for use on Arduino.
#endif // ARDUINO
#endif // __PRINTF_H__
@@ -0,0 +1,144 @@
/*
TMRh20 2014
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.
*/
/** General Data Transfer Rate Test
* This example demonstrates basic data transfer functionality with the
updated library. This example will display the transfer rates acheived using
the slower form of high-speed transfer using blocking-writes.
*/
#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"
#include "printf.h"
/************* USER Configuration *****************************/
// Hardware configuration
RF24 radio(48,49); // Set up nRF24L01 radio on SPI bus plus pins 7 & 8
boolean RADIO_NO = 0; //SET THIS TO 0 or 1 for 1st or 2nd radio
/***************************************************************/
const uint64_t pipes[2] = { 0xABCDABCD71LL, 0x544d52687CLL }; // Radio pipe addresses for the 2 nodes to communicate.
byte data[32]; //Data buffer for testing data transfer speeds
unsigned long counter, rxTimer; //Counter and timer for keeping track transfer info
unsigned long startTime, stopTime;
bool TX=1,RX=0,role=0;
void setup(void) {
Serial.begin(57600);
printf_begin();
radio.begin(); // Setup and configure rf radio
radio.setChannel(1);
radio.setPALevel(RF24_PA_MAX);
radio.setDataRate(RF24_1MBPS);
radio.setAutoAck(1); // Ensure autoACK is enabled
radio.setRetries(2,15); // Optionally, increase the delay between retries & # of retries
radio.setCRCLength(RF24_CRC_8);
//radio.disableCRC();
radio.openWritingPipe(pipes[0]);
radio.openReadingPipe(1,pipes[1]);
radio.startListening(); // Start listening
radio.printDetails(); // Dump the configuration of the rf unit for debugging
printf("\n\rRF24/examples/Transfer Rates/\n\r");
printf("*** PRESS 'T' to begin transmitting to the other node\n\r");
randomSeed(analogRead(0)); //Seed for random number generation
for(int i=0; i<32; i++){
data[i] = random(255); //Load the buffer with random data
}
radio.powerUp(); //Power up the radio
}
void loop(void){
if(role == TX){
delay(2000);
printf("Initiating Basic Data Transfer\n\r");
unsigned long cycles = 10000; //Change this to a higher or lower number.
startTime = millis();
for(int i=0; i<cycles; i++){ //Loop through a number of cycles
data[0] = i; //Change the first byte of the payload for identification
if(!radio.writeFast(&data,32)){ //Write to the FIFO buffers
counter++; //Keep count of failed payloads
}
}
stopTime = millis();
//This should be called to wait for completion and put the radio in standby mode after transmission, returns 0 if data still in FIFO (timed out), 1 if success
if(!radio.txStandBy()){ counter+=3; } //Standby, block only until FIFO empty or auto-retry timeout. Flush TX FIFO if failed
//radio.txStandBy(1000); //Standby, using extended timeout period of 1 second
float numBytes = cycles*32;
float rate = numBytes / (stopTime - startTime);
printf("Transfer complete at "); Serial.print(rate); printf(" KB/s \n\r");
printf("%d of ",counter); Serial.print(cycles); printf(" Packets Failed to Send\n\r");
counter = 0;
}
if(role == RX){
while(radio.available()){
radio.read(&data,32);
counter++;
}
if(millis() - rxTimer > 1000){
rxTimer = millis();
printf("Rate: ");
float numBytes = counter*32;
Serial.print(numBytes/1000);
printf(" KB/s\n\r");
printf("Payload Count: %d \n\r", counter);
counter = 0;
}
}
//
// Change roles
//
if ( Serial.available() )
{
char c = toupper(Serial.read());
if ( c == 'T' && role == RX )
{
printf("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK\n\r");
radio.openWritingPipe(pipes[1]);
radio.openReadingPipe(1,pipes[0]);
radio.stopListening();
role = TX; // Become the primary transmitter (ping out)
}
else if ( c == 'R' && role == TX )
{
radio.openWritingPipe(pipes[0]);
radio.openReadingPipe(1,pipes[1]);
radio.startListening();
printf("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK\n\r");
role = RX; // Become the primary receiver (pong back)
}
}
}
// vim:cin:ai:sts=2 sw=2 ft=cpp
+37
View File
@@ -0,0 +1,37 @@
/*
Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
*/
/**
* @file printf.h
*
* Setup necessary to direct stdout to the Arduino Serial library, which
* enables 'printf'
*/
#ifndef __PRINTF_H__
#define __PRINTF_H__
#ifdef ARDUINO
int serial_putc( char c, FILE * )
{
Serial.write( c );
return c;
}
void printf_begin(void)
{
fdevopen( &serial_putc, 0 );
}
#else
#error This example is only for use on Arduino.
#endif // ARDUINO
#endif // __PRINTF_H__
@@ -0,0 +1,189 @@
/*
TMRh20 2014
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.
*/
/** Reliably transmitting large volumes of data with a low signal or in noisy environments
* This example demonstrates data transfer functionality with the use of auto-retry
and auto-reUse functionality enabled. This sketch demonstrates how a user can extend
the auto-retry functionality to any chosen time period, preventing data loss and ensuring
the consistency of data.
This sketh demonstrates use of the writeBlocking() functionality, and extends the standard
retry functionality of the radio. Payloads will be auto-retried until successful or the
extended timeout period is reached.
*/
#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"
#include "printf.h"
/************* USER Configuration *****************************/
RF24 radio(48,49); // Set up nRF24L01 radio on SPI bus plus pins 7 & 8
unsigned long timeoutPeriod = 3000; // Set a user-defined timeout period. With auto-retransmit set to (15,15) retransmission will take up to 60ms and as little as 7.5ms with it set to (1,15).
// With a timeout period of 1000, the radio will retry each payload for up to 1 second before giving up on the transmission and starting over
/***************************************************************/
const uint64_t pipes[2] = { 0xABCDABCD71LL, 0x544d52687CLL }; // Radio pipe addresses for the 2 nodes to communicate.
byte data[32]; //Data buffer
volatile unsigned long counter;
unsigned long rxTimer,startTime, stopTime, payloads = 0;
bool TX=1,RX=0,role=0, transferInProgress = 0;
void setup(void) {
Serial.begin(57600);
printf_begin();
radio.begin(); // Setup and configure rf radio
radio.setChannel(1); // Set the channel
radio.setPALevel(RF24_PA_LOW); // Set PA LOW for this demonstration. We want the radio to be as lossy as possible for this example.
radio.setDataRate(RF24_1MBPS); // Raise the data rate to reduce transmission distance and increase lossiness
radio.setAutoAck(1); // Ensure autoACK is enabled
radio.setRetries(2,15); // Optionally, increase the delay between retries. Want the number of auto-retries as high as possible (15)
radio.setCRCLength(RF24_CRC_16); // Set CRC length to 16-bit to ensure quality of data
radio.openWritingPipe(pipes[0]); // Open the default reading and writing pipe
radio.openReadingPipe(1,pipes[1]);
radio.startListening(); // Start listening
radio.printDetails(); // Dump the configuration of the rf unit for debugging
printf("\n\rRF24/examples/Transfer Rates/\n\r");
printf("*** PRESS 'T' to begin transmitting to the other node\n\r");
randomSeed(analogRead(0)); //Seed for random number generation
for(int i=0; i<32; i++){
data[i] = random(255); //Load the buffer with random data
}
radio.powerUp(); //Power up the radio
}
void loop(void){
if(role == TX){
delay(2000); // Pause for a couple seconds between transfers
printf("Initiating Extended Timeout Data Transfer\n\r");
unsigned long cycles = 1000; // Change this to a higher or lower number. This is the number of payloads that will be sent.
unsigned long transferCMD[] = {'H','S',cycles }; // Indicate to the other radio that we are starting, and provide the number of payloads that will be sent
radio.writeFast(&transferCMD,12); // Send the transfer command
if(radio.txStandBy(timeoutPeriod)){ // If transfer initiation was successful, do the following
startTime = millis(); // For calculating transfer rate
boolean timedOut = 0; // Boolean for keeping track of failures
for(int i=0; i<cycles; i++){ // Loop through a number of cycles
data[0] = i; // Change the first byte of the payload for identification
if(!radio.writeBlocking(&data,32,timeoutPeriod)){ // If retries are failing and the user defined timeout is exceeded
timedOut = 1; // Indicate failure
counter = cycles; // Set the fail count to maximum
break; // Break out of the for loop
}
}
stopTime = millis(); // Capture the time of completion or failure
//This should be called to wait for completion and put the radio in standby mode after transmission, returns 0 if data still in FIFO (timed out), 1 if success
if(timedOut){ radio.txStandBy(); } //Partially blocking standby, blocks until success or max retries. FIFO flushed if auto timeout reached
else{ radio.txStandBy(timeoutPeriod); } //Standby, block until FIFO empty (sent) or user specified timeout reached. FIFO flushed if user timeout reached.
}else{
Serial.println("Communication not established"); //If unsuccessful initiating transfer, exit and retry later
}
float rate = cycles * 32 / (stopTime - startTime); //Display results:
Serial.print("Transfer complete at "); Serial.print(rate); printf(" KB/s \n\r");
Serial.print(counter);
Serial.print(" of ");
Serial.print(cycles); Serial.println(" Packets Failed to Send");
counter = 0;
}
if(role == RX){
if(!transferInProgress){ // If a bulk data transfer has not been started
if(radio.available()){
radio.read(&data,32); //Read any available payloads for analysis
if(data[0] == 'H' && data[4] == 'S'){ // If a bulk data transfer command has been received
payloads = data[8]; // Read the first two bytes of the unsigned long. Need to read the 3rd and 4th if sending more than 65535 payloads
payloads |= data[9] << 8; // This is the number of payloads that will be sent
counter = 0; // Reset the payload counter to 0
transferInProgress = 1; // Indicate it has started
startTime = rxTimer = millis(); // Capture the start time to measure transfer rate and calculate timeouts
}
}
}else{
if(radio.available()){ // If in bulk transfer mode, and a payload is available
radio.read(&data,32); // Read the payload
rxTimer = millis(); // Reset the timeout timer
counter++; // Keep a count of received payloads
}else
if(millis() - rxTimer > timeoutPeriod){ // If no data available, check the timeout period
Serial.println("Transfer Failed"); // If per-payload timeout exceeeded, end the transfer
transferInProgress = 0;
}else
if(counter >= payloads){ // If the specified number of payloads is reached, transfer is completed
startTime = millis() - startTime; // Calculate the total time spent during transfer
float numBytes = counter*32; // Calculate the number of bytes transferred
Serial.print("Rate: "); // Print the transfer rate and number of payloads
Serial.print(numBytes/startTime);
Serial.println(" KB/s");
printf("Payload Count: %d \n\r", counter);
transferInProgress = 0; // End the transfer as complete
}
}
}
//
// Change roles
//
if ( Serial.available() )
{
char c = toupper(Serial.read());
if ( c == 'T' && role == RX )
{
printf("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK\n\r");
radio.openWritingPipe(pipes[1]);
radio.openReadingPipe(1,pipes[0]);
radio.stopListening();
role = TX; // Become the primary transmitter (ping out)
}
else if ( c == 'R' && role == TX )
{
radio.openWritingPipe(pipes[0]);
radio.openReadingPipe(1,pipes[1]);
radio.startListening();
printf("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK\n\r");
role = RX; // Become the primary receiver (pong back)
}
}
}
@@ -0,0 +1,37 @@
/*
Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
*/
/**
* @file printf.h
*
* Setup necessary to direct stdout to the Arduino Serial library, which
* enables 'printf'
*/
#ifndef __PRINTF_H__
#define __PRINTF_H__
#ifdef ARDUINO
int serial_putc( char c, FILE * )
{
Serial.write( c );
return c;
}
void printf_begin(void)
{
fdevopen( &serial_putc, 0 );
}
#else
#error This example is only for use on Arduino.
#endif // ARDUINO
#endif // __PRINTF_H__
@@ -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 -Wall -Wextra -mmcu=$(MCU) $(CTUNING) ;
CXXFLAGS = $(CFLAGS) $(CXXTUNING) ;
LDFLAGS = -Os -lm -Wl,--gc-sections -mmcu=atmega328p ;
# Search everywhere for headers
HDRS = $(PROJECT_DIR) $(ARDUINO_AVR) $(ARDUINO_CORE) [ GLOB $(ARDUINO_LIB) $(SKETCH_LIB) : [^.]* ] ;
# Grab everything from the core directory
CORE_MODULES = [ GLOB $(ARDUINO_CORE) : *.c *.cpp ] ;
# Grab everything from libraries. To avoid this "grab everything" behaviour, you
# can specify specific modules to pick up in PROJECT_MODULES
LIB_MODULES = [ GLOB $(ARDUINO_LIB)/$(PROJECT_LIBS) $(SKETCH_LIB)/$(PROJECT_LIBS) : *.cpp ] ;
# In addition to explicitly-specified program modules, pick up anything from the current
# dir.
PROJECT_MODULES += [ GLOB $(PROJECT_DIR) : *.c *.cpp *.pde ] ;
# Shortcut for the out files
OUT = $(OUT_DIR)/$(PROJECT_NAME) ;
# AvrDude setup
AVRDUDE_FLAGS = -V -F -D -C $(AVRDUDECONFIG_PATH)/avrdude.conf -p $(MCU) -c $(AVRDUDE_PROTOCOL) -b $(UPLOAD_RATE) ;
rule GitVersion
{
Always $(<) ;
Depends all : $(<) ;
}
actions GitVersion
{
echo "const char program_version[] = \"\\" > $(<)
git log -1 --pretty=format:%h >> $(<)
echo "\";" >> $(<)
}
GitVersion version.h ;
rule AvrCc
{
Depends $(<) : $(>) ;
Depends $(<) : $(<:D) ;
Clean clean : $(<) ;
CCHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] ;
CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ;
}
actions AvrCc
{
$(AVR_CC) -c -o $(<) $(CCHDRS) $(CCDEFS) $(CFLAGS) $(>)
}
rule AvrC++
{
Depends $(<) : $(>) ;
Depends $(<) : $(<:D) ;
Clean clean : $(<) ;
CCHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] ;
CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ;
}
actions AvrC++
{
$(AVR_CXX) -c -o $(<) $(CCHDRS) $(CCDEFS) $(CXXFLAGS) $(>)
}
rule Pde
{
Depends $(<) : $(>) ;
Depends $(<) : $(<:D) ;
Clean clean : $(<) ;
}
actions Pde
{
echo "#include <WProgram.h>" > $(<)
echo "#line 1 \"$(>)\"" >> $(<)
cat $(>) >> $(<)
}
rule AvrPde
{
local _CPP = $(OUT_DIR)/$(_I:B).cpp ;
Pde $(_CPP) : $(>) ;
AvrC++ $(<) : $(_CPP) ;
}
rule AvrObject
{
switch $(>:S)
{
case .c : AvrCc $(<) : $(>) ;
case .cpp : AvrC++ $(<) : $(>) ;
case .pde : AvrPde $(<) : $(>) ;
}
}
rule AvrObjects
{
for _I in $(<)
{
AvrObject $(OUT_DIR)/$(_I:B).o : $(_I) ;
}
}
rule AvrMainFromObjects
{
Depends $(<) : $(>) ;
Depends $(<) : $(<:D) ;
MkDir $(<:D) ;
Depends all : $(<) ;
Clean clean : $(<) ;
}
actions AvrMainFromObjects
{
$(AVR_LD) $(LDFLAGS) -o $(<) $(>)
}
rule AvrMain
{
AvrMainFromObjects $(<) : $(OUT_DIR)/$(>:B).o ;
AvrObjects $(>) ;
}
rule AvrHex
{
Depends $(<) : $(>) ;
Depends $(<) : $(<:D) ;
Depends hex : $(<) ;
Clean clean : $(<) ;
}
actions AvrHex
{
$(AVR_OBJCOPY) -O ihex -R .eeprom $(>) $(<)
}
rule AvrUpload
{
Depends $(1) : $(2) ;
Depends $(2) : $(3) ;
NotFile $(1) ;
Always $(1) ;
Always $(2) ;
AvrUploadAction $(2) : $(3) ;
}
actions AvrUploadAction
{
$(AVRDUDE) $(AVRDUDE_FLAGS) -P $(<) $(AVRDUDE_WRITE_FLASH) -U flash:w:$(>):i
}
AvrMain $(OUT).elf : $(CORE_MODULES) $(LIB_MODULES) $(PROJECT_MODULES) ;
AvrHex $(OUT).hex : $(OUT).elf ;
AvrUpload p6 : /dev/tty.usbserial-A600eHIs : $(OUT).hex ;
AvrUpload p4 : /dev/tty.usbserial-A40081RP : $(OUT).hex ;
AvrUpload p9 : /dev/tty.usbserial-A9007LmI : $(OUT).hex ;
@@ -0,0 +1,255 @@
/*
Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
*/
/**
* Example LED Remote
*
* This is an example of how to use the RF24 class to control a remote
* bank of LED's using buttons on a remote control.
*
* On the 'remote', connect any number of buttons or switches from
* an arduino pin to ground. Update 'button_pins' to reflect the
* pins used.
*
* On the 'led' board, connect the same number of LED's from an
* arduino pin to a resistor to ground. Update 'led_pins' to reflect
* the pins used. Also connect a separate pin to ground and change
* the 'role_pin'. This tells the sketch it's running on the LED board.
*
* Every time the buttons change on the remote, the entire state of
* buttons is send to the led board, which displays the state.
*/
#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"
#include "printf.h"
//
// Hardware configuration
//
// Set up nRF24L01 radio on SPI bus plus pins 9 & 10
RF24 radio(9,10);
// sets the role of this unit in hardware. Connect to GND to be the 'led' board receiver
// Leave open to be the 'remote' transmitter
const int role_pin = A4;
// Pins on the remote for buttons
const uint8_t button_pins[] = { 2,3,4,5,6,7 };
const uint8_t num_button_pins = sizeof(button_pins);
// Pins on the LED board for LED's
const uint8_t led_pins[] = { 2,3,4,5,6,7 };
const uint8_t num_led_pins = sizeof(led_pins);
//
// 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_remote = 1, role_led } role_e;
// The debug-friendly names of those roles
const char* role_friendly_name[] = { "invalid", "Remote", "LED Board"};
// The role of the current running sketch
role_e role;
//
// Payload
//
uint8_t button_states[num_button_pins];
uint8_t led_states[num_led_pins];
//
// Setup
//
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_remote;
else
role = role_led;
//
// Print preamble
//
Serial.begin(57600);
printf_begin();
printf("\n\rRF24/examples/led_remote/\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 a single pipes for these two nodes to communicate
// back and forth. One listens on it, the other talks to it.
if ( role == role_remote )
{
radio.openWritingPipe(pipe);
}
else
{
radio.openReadingPipe(1,pipe);
}
//
// Start listening
//
if ( role == role_led )
radio.startListening();
//
// Dump the configuration of the rf unit for debugging
//
radio.printDetails();
//
// Set up buttons / LED's
//
// Set pull-up resistors for all buttons
if ( role == role_remote )
{
int i = num_button_pins;
while(i--)
{
pinMode(button_pins[i],INPUT);
digitalWrite(button_pins[i],HIGH);
}
}
// Turn LED's ON until we start getting keys
if ( role == role_led )
{
int i = num_led_pins;
while(i--)
{
pinMode(led_pins[i],OUTPUT);
led_states[i] = HIGH;
digitalWrite(led_pins[i],led_states[i]);
}
}
}
//
// Loop
//
void loop(void)
{
//
// Remote role. If the state of any button has changed, send the whole state of
// all buttons.
//
if ( role == role_remote )
{
// Get the current state of buttons, and
// Test if the current state is different from the last state we sent
int i = num_button_pins;
bool different = false;
while(i--)
{
uint8_t state = ! digitalRead(button_pins[i]);
if ( state != button_states[i] )
{
different = true;
button_states[i] = state;
}
}
// Send the state of the buttons to the LED board
if ( different )
{
printf("Now sending...");
bool ok = radio.write( button_states, num_button_pins );
if (ok)
printf("ok\n\r");
else
printf("failed\n\r");
}
// Try again in a short while
delay(20);
}
//
// LED role. Receive the state of all buttons, and reflect that in the LEDs
//
if ( role == role_led )
{
// if there is data ready
if ( radio.available() )
{
// Dump the payloads until we've gotten everything
bool done = false;
while (!done)
{
// Fetch the payload, and see if this was the last one.
done = radio.read( button_states, num_button_pins );
// Spew it
printf("Got buttons\n\r");
// For each button, if the button now on, then toggle the LED
int i = num_led_pins;
while(i--)
{
if ( button_states[i] )
{
led_states[i] ^= HIGH;
digitalWrite(led_pins[i],led_states[i]);
}
}
}
}
}
}
// vim:ai:cin:sts=2 sw=2 ft=cpp
@@ -0,0 +1,37 @@
/*
Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
*/
/**
* @file printf.h
*
* Setup necessary to direct stdout to the Arduino Serial library, which
* enables 'printf'
*/
#ifndef __PRINTF_H__
#define __PRINTF_H__
#ifdef ARDUINO
int serial_putc( char c, FILE * )
{
Serial.write( c );
return c;
}
void printf_begin(void)
{
fdevopen( &serial_putc, 0 );
}
#else
#error This example is only for use on Arduino.
#endif // ARDUINO
#endif // __PRINTF_H__
@@ -0,0 +1,219 @@
# (1) Project Information
PROJECT_LIBS = RF24 SPI ;
PROJECT_DIRS = $(PWD) ;
# (2) Board Information
UPLOAD_PROTOCOL ?= stk500v1 ;
UPLOAD_SPEED ?= 115200 ;
MCU ?= atmega328p ;
F_CPU ?= 16000000 ;
CORE ?= arduino ;
VARIANT ?= standard ;
ARDUINO_VERSION ?= 100 ;
# (3) USB Ports
PORTS = p4 p6 p9 u0 u1 u2 ;
PORT_p6 = /dev/tty.usbserial-A600eHIs ;
PORT_p4 = /dev/tty.usbserial-A40081RP ;
PORT_p9 = /dev/tty.usbserial-A9007LmI ;
PORT_u0 = /dev/ttyUSB0 ;
PORT_u1 = /dev/ttyUSB1 ;
PORT_u2 = /dev/ttyUSB2 ;
# (4) Location of AVR tools
#
# This configuration assumes using avr-tools that were obtained separate from the Arduino
# distribution.
if $(OS) = MACOSX
{
AVR_BIN = /usr/local/avrtools/bin ;
AVR_ETC = /usr/local/avrtools/etc ;
AVR_INCLUDE = /usr/local/avrtools/include ;
}
else
{
AVR_BIN = /usr/bin ;
AVR_INCLUDE = /usr/lib/avr/include ;
AVR_ETC = /etc ;
}
# (5) Directories where Arduino core and libraries are located
ARDUINO_DIR ?= /opt/Arduino ;
ARDUINO_CORE = $(ARDUINO_DIR)/hardware/arduino/cores/$(CORE) $(ARDUINO_DIR)/hardware/arduino/variants/$(VARIANT) ;
ARDUINO_LIB = $(ARDUINO_DIR)/libraries ;
SKETCH_LIB = $(HOME)/Source/Arduino/libraries ;
#
# --------------------------------------------------
# Below this line usually never needs to be modified
#
# Tool locations
CC = $(AVR_BIN)/avr-gcc ;
C++ = $(AVR_BIN)/avr-g++ ;
LINK = $(AVR_BIN)/avr-gcc ;
AR = $(AVR_BIN)/avr-ar rcs ;
RANLIB = ;
OBJCOPY = $(AVR_BIN)/avr-objcopy ;
AVRDUDE = $(AVR_BIN)/avrdude ;
# Flags
DEFINES += F_CPU=$(F_CPU)L ARDUINO=$(ARDUINO_VERSION) VERSION_H ;
OPTIM = -Os ;
CCFLAGS = -Wall -Wextra -Wno-strict-aliasing -mmcu=$(MCU) -ffunction-sections -fdata-sections ;
C++FLAGS = $(CCFLAGS) -fno-exceptions -fno-strict-aliasing ;
LINKFLAGS = $(OPTIM) -lm -Wl,--gc-sections -mmcu=$(MCU) ;
AVRDUDEFLAGS = -V -F -D -C $(AVR_ETC)/avrdude.conf -p $(MCU) -c $(UPLOAD_PROTOCOL) -b $(UPLOAD_SPEED) ;
# Search everywhere for headers
HDRS = $(PROJECT_DIRS) $(AVR_INCLUDE) $(ARDUINO_CORE) $(ARDUINO_LIB)/$(PROJECT_LIBS) $(ARDUINO_LIB)/$(PROJECT_LIBS)/utility $(SKETCH_LIB)/$(PROJECT_LIBS) ;
# Output locations
LOCATE_TARGET = $(F_CPU) ;
LOCATE_SOURCE = $(F_CPU) ;
#
# Custom rules
#
rule GitVersion
{
Always $(<) ;
Depends all : $(<) ;
}
actions GitVersion
{
echo "const char program_version[] = \"\\" > $(<)
git log -1 --pretty=format:%h >> $(<)
echo "\";" >> $(<)
}
GitVersion version.h ;
rule Pde
{
Depends $(<) : $(>) ;
MakeLocate $(<) : $(LOCATE_SOURCE) ;
Clean clean : $(<) ;
}
if ( $(ARDUINO_VERSION) < 100 )
{
ARDUINO_H = WProgram.h ;
}
else
{
ARDUINO_H = Arduino.h ;
}
actions Pde
{
echo "#include <$(ARDUINO_H)>" > $(<)
echo "#line 1 \"$(>)\"" >> $(<)
cat $(>) >> $(<)
}
rule C++Pde
{
local _CPP = $(>:B).cpp ;
Pde $(_CPP) : $(>) ;
C++ $(<) : $(_CPP) ;
}
rule UserObject
{
switch $(>:S)
{
case .ino : C++Pde $(<) : $(>) ;
case .pde : C++Pde $(<) : $(>) ;
}
}
rule Objects
{
local _i ;
for _i in [ FGristFiles $(<) ]
{
local _b = $(_i:B)$(SUFOBJ) ;
local _o = $(_b:G=$(SOURCE_GRIST:E)) ;
Object $(_o) : $(_i) ;
Depends obj : $(_o) ;
}
}
rule Library
{
LibraryFromObjects $(<) : $(>:B)$(SUFOBJ) ;
Objects $(>) ;
}
rule Main
{
MainFromObjects $(<) : $(>:B)$(SUFOBJ) ;
Objects $(>) ;
}
rule Hex
{
Depends $(<) : $(>) ;
MakeLocate $(<) : $(LOCATE_TARGET) ;
Depends hex : $(<) ;
Clean clean : $(<) ;
}
actions Hex
{
$(OBJCOPY) -O ihex -R .eeprom $(>) $(<)
}
rule Upload
{
Depends $(1) : $(2) ;
Depends $(2) : $(3) ;
NotFile $(1) ;
Always $(1) ;
Always $(2) ;
UploadAction $(2) : $(3) ;
}
actions UploadAction
{
$(AVRDUDE) $(AVRDUDEFLAGS) -P $(<) $(AVRDUDE_WRITE_FLASH) -U flash:w:$(>):i
}
rule Arduino
{
LINKFLAGS on $(<) = $(LINKFLAGS) -Wl,-Map=$(LOCATE_TARGET)/$(<:B).map ;
Main $(<) : $(>) ;
LinkLibraries $(<) : libs core ;
Hex $(<:B).hex : $(<) ;
for _p in $(PORTS)
{
Upload $(_p) : $(PORT_$(_p)) : $(<:B).hex ;
}
}
#
# Targets
#
# Grab everything from the core directory
Library core : [ GLOB $(ARDUINO_CORE) : *.c *.cpp ] ;
# Grab everything from libraries. To avoid this "grab everything" behaviour, you
# can specify specific modules to pick up in PROJECT_MODULES
Library libs : [ GLOB $(ARDUINO_LIB)/$(PROJECT_LIBS) $(ARDUINO_LIB)/$(PROJECT_LIBS)/utility $(SKETCH_LIB)/$(PROJECT_LIBS) : *.cpp *.c ] ;
# Main output executable
Arduino $(PWD:B).elf : $(PROJECT_MODULES) [ GLOB $(PROJECT_DIRS) : *.c *.cpp *.pde *.ino ] ;
@@ -0,0 +1,142 @@
/*
Copyright (C) 2012 J. Coliz <maniacbug@ymail.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
*/
/**
* Example Nordic FOB Receiver
*
* This is an example of how to use the RF24 class to receive signals from the
* Sparkfun Nordic FOB. Thanks to Kirk Mower for providing test hardware.
*
* See blog post at http://maniacbug.wordpress.com/2012/01/08/nordic-fob/
*/
#include <SPI.h>
#include <RF24.h>
#include "nRF24L01.h"
#include "printf.h"
//
// Hardware configuration
//
// Set up nRF24L01 radio on SPI bus plus pins 9 & 10
RF24 radio(9,10);
//
// Payload
//
struct payload_t
{
uint8_t buttons;
uint16_t id;
uint8_t empty;
};
const char* button_names[] = { "Up", "Down", "Left", "Right", "Center" };
const int num_buttons = 5;
//
// Forward declarations
//
uint16_t flip_endian(uint16_t in);
//
// Setup
//
void setup(void)
{
//
// Print preamble
//
Serial.begin(57600);
printf_begin();
printf("\r\nRF24/examples/nordic_fob/\r\n");
//
// Setup and configure rf radio according to the built-in parameters
// of the FOB.
//
radio.begin();
radio.setChannel(2);
radio.setPayloadSize(4);
radio.setAutoAck(false);
radio.setCRCLength(RF24_CRC_8);
radio.openReadingPipe(1,0xE7E7E7E7E7LL);
//
// Start listening
//
radio.startListening();
//
// Dump the configuration of the rf unit for debugging
//
radio.printDetails();
}
//
// Loop
//
void loop(void)
{
//
// Receive each packet, dump it out
//
// if there is data ready
if ( radio.available() )
{
// Get the packet from the radio
payload_t payload;
radio.read( &payload, sizeof(payload) );
// Print the ID of this message. Note that the message
// is sent 'big-endian', so we have to flip it.
printf("#%05u Buttons ",flip_endian(payload.id));
// Print the name of each button
int i = num_buttons;
while (i--)
{
if ( ! ( payload.buttons & _BV(i) ) )
{
printf("%s ",button_names[i]);
}
}
// If no buttons, print None
if ( payload.buttons == _BV(num_buttons) - 1 )
printf("None");
printf("\r\n");
}
}
//
// Helper functions
//
// Change a big-endian word into a little-endian
uint16_t flip_endian(uint16_t in)
{
uint16_t low = in >> 8;
uint16_t high = in << 8;
return high | low;
}
// vim:cin:ai:sts=2 sw=2 ft=cpp
@@ -0,0 +1,37 @@
/*
Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
*/
/**
* @file printf.h
*
* Setup necessary to direct stdout to the Arduino Serial library, which
* enables 'printf'
*/
#ifndef __PRINTF_H__
#define __PRINTF_H__
#ifdef ARDUINO
int serial_putc( char c, FILE * )
{
Serial.write( c );
return c;
}
void printf_begin(void)
{
fdevopen( &serial_putc, 0 );
}
#else
#error This example is only for use on Arduino.
#endif // ARDUINO
#endif // __PRINTF_H__
@@ -0,0 +1,182 @@
MCU = cortex-m3 ;
CHIP = STM32F103ZE ;
BOARD = maple_native ;
#CHIP = at91sam3u4 ;
#BOARD = sam3u-ek ;
if ! $(TOOLSET)
{
TOOLSET = devkit ;
Echo "Assuming TOOLSET=devkit" ;
}
if $(TOOLSET) = yagarto
{
TOOLS_PATH = ~/Source/yagarto-4.6.2/bin ;
TOOLS_ARCH = arm-none-eabi- ;
}
if $(TOOLSET) = yagarto-install
{
TOOLS_PATH = ~/Source/yagarto/install/bin ;
TOOLS_ARCH = arm-none-eabi- ;
}
else if $(TOOLSET) = devkit
{
TOOLS_PATH = /opt/devkitARM/bin ;
TOOLS_ARCH = arm-eabi- ;
}
else if $(TOOLSET) = maple
{
TOOLS_PATH = /opt/Maple/Resources/Java/hardware/tools/arm/bin ;
TOOLS_ARCH = arm-none-eabi- ;
}
else if $(TOOLSET) = ports
{
TOOLS_PATH = /opt/local/bin ;
TOOLS_ARCH = arm-none-eabi- ;
}
CC = $(TOOLS_PATH)/$(TOOLS_ARCH)gcc ;
C++ = $(TOOLS_PATH)/$(TOOLS_ARCH)g++ ;
AS = $(TOOLS_PATH)/$(TOOLS_ARCH)gcc -c ;
LINK = $(TOOLS_PATH)/$(TOOLS_ARCH)g++ ;
OBJCOPY = $(TOOLS_PATH)/$(TOOLS_ARCH)objcopy ;
DFU = dfu-util ;
DEFINES += VECT_TAB_FLASH BOARD_$(BOARD) MCU_$(CHIP) ERROR_LED_PORT=GPIOC ERROR_LED_PIN=15 STM32_HIGH_DENSITY MAPLE_IDE ;
OPTIM = -Os ;
MFLAGS = cpu=$(MCU) thumb arch=armv7-m ;
CCFLAGS = -Wall -m$(MFLAGS) -g -nostdlib -ffunction-sections -fdata-sections -Wl,--gc-sections ;
C++FLAGS = $(CCFLAGS) -fno-rtti -fno-exceptions ;
LINKFLAGS += -m$(MFLAGS) -Xlinker --gc-sections ;
DFUFLAGS = -a1 -d 0x1eaf:0x0003 -R ;
MAPLE_DIR = $(HOME)/Source/SAM3U/libmaple ;
MAPLE_LIBS = Servo LiquidCrystal Wire FreeRTOS ;
MAPLE_SUBDIRS = wirish wirish/comm wirish/boards libmaple libmaple/usb libmaple/usb/usb_lib ;
SKETCH_DIR = $(HOME)/Source/Arduino ;
SKETCH_LIBS = RF24 ;
MODULE_DIRS = . $(MAPLE_DIR)/$(MAPLE_SUBDIRS) $(MAPLE_DIR)/libraries/$(MAPLE_LIBS) $(SKETCH_DIR)/libraries/$(SKETCH_LIBS) ;
HDRS = $(MODULE_DIRS) ;
LOCATE_TARGET = out/$(TOOLSET) ;
LOCATE_SOURCE = $(LOCATE_TARGET) ;
rule Pde
{
Depends $(<) : $(>) ;
MakeLocate $(<) : $(LOCATE_SOURCE) ;
Clean clean : $(<) ;
}
if ( $(ARDUINO_VERSION) < 100 )
{
ARDUINO_H = WProgram.h ;
}
else
{
ARDUINO_H = Arduino.h ;
}
actions Pde
{
echo "#include <$(ARDUINO_H)>" > $(<)
echo "#line 1 \"$(>)\"" >> $(<)
cat $(>) >> $(<)
}
rule C++Pde
{
local _CPP = $(>:B).cpp ;
Pde $(_CPP) : $(>) ;
C++ $(<) : $(_CPP) ;
}
rule Hex
{
Depends $(<) : $(>) ;
MakeLocate $(<) : $(LOCATE_TARGET) ;
Depends hex : $(<) ;
Clean clean : $(<) ;
}
actions Hex
{
$(OBJCOPY) -O ihex $(>) $(<)
}
rule Binary
{
Depends $(<) : $(>) ;
MakeLocate $(<) : $(LOCATE_TARGET) ;
Depends binary : $(<) ;
Clean clean : $(<) ;
}
actions Binary
{
$(OBJCOPY) -O binary $(>) $(<)
}
rule UserObject
{
switch $(>:S)
{
case .S : As $(<) : $(>) ;
case .ino : C++Pde $(<) : $(>) ;
case .pde : C++Pde $(<) : $(>) ;
}
}
rule Upload
{
Depends up : $(<) ;
NotFile up ;
Always $(<) ;
Always up ;
}
actions Upload
{
$(DFU) $(DFUFLAGS) -D $(<)
}
# Override base objects rule, so all output can go in the output dir
rule Objects
{
local _i ;
for _i in [ FGristFiles $(<) ]
{
local _b = $(_i:B)$(SUFOBJ) ;
local _o = $(_b:G=$(SOURCE_GRIST:E)) ;
Object $(_o) : $(_i) ;
Depends obj : $(_o) ;
}
}
# Override base main rule, so all output can go in the output dir
rule Main
{
MainFromObjects $(<) : $(>:B)$(SUFOBJ) ;
Objects $(>) ;
}
# Modules
MODULES = [ GLOB $(MODULE_DIRS) : *.pde *.c *.cpp *.S ] ;
# Main output executable
MAIN = $(PWD:B).elf ;
# Linker script
LINK_DIR = $(MAPLE_DIR)/support/ld ;
LINKSCRIPT = $(LINK_DIR)/$(BOARD)/flash.ld ;
# Bring in the map and link script
LINKFLAGS += -Wl,-Map=$(LOCATE_TARGET)/$(MAIN:B).map -T$(LINKSCRIPT) -L$(LINK_DIR) ;
Main $(MAIN) : $(MODULES) ;
Binary $(MAIN:B).bin : $(MAIN) ;
Upload $(MAIN:B).bin ;
@@ -0,0 +1,87 @@
#ifdef MAPLE_IDE
#include <stdio.h>
#include "wirish.h"
extern void setup(void);
extern void loop(void);
void board_start(const char* program_name)
{
// Set up the LED to steady on
pinMode(BOARD_LED_PIN, OUTPUT);
digitalWrite(BOARD_LED_PIN, HIGH);
// Setup the button as input
pinMode(BOARD_BUTTON_PIN, INPUT);
digitalWrite(BOARD_BUTTON_PIN, HIGH);
SerialUSB.begin();
SerialUSB.println("Press BUT");
// Wait for button press
while ( !isButtonPressed() )
{
}
SerialUSB.println("Welcome!");
SerialUSB.println(program_name);
int i = 11;
while (i--)
{
toggleLED();
delay(50);
}
}
/**
* Custom version of _write, which will print to the USB.
* In order to use it you MUST ADD __attribute__((weak))
* to _write in libmaple/syscalls.c
*/
extern "C" int _write (int file, char * ptr, int len)
{
if ( (file != 1) && (file != 2) )
return 0;
else
SerialUSB.write(ptr,len);
return len;
}
/**
* Re-entrant version of _write. Yagarto and Devkit now use
* the re-entrant newlib, so these get called instead of the
* non_r versions.
*/
extern "C" int _write_r (void*, int file, char * ptr, int len)
{
return _write( file, ptr, len);
}
__attribute__((constructor)) __attribute__ ((weak)) void premain()
{
init();
}
__attribute__((weak)) void setup(void)
{
board_start("No program defined");
}
__attribute__((weak)) void loop(void)
{
}
__attribute__((weak)) int main(void)
{
setup();
while (true)
{
loop();
}
return 0;
}
#endif // ifdef MAPLE_IDE
// vim:cin:ai:sts=2 sw=2 ft=cpp
@@ -0,0 +1,242 @@
/*
Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
*/
/**
* Example RF Radio Ping Pair ... for Maple
*
* 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 "WProgram.h"
#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"
//
// Maple specific setup. Other than this section, the sketch is the same on Maple as on
// Arduino
//
#ifdef MAPLE_IDE
// External startup function
extern void board_start(const char* program_name);
// Use SPI #2.
HardwareSPI SPI(2);
#else
#define board_startup printf
#define toggleLED(x) (x)
#endif
//
// Hardware configuration
//
// Set up nRF24L01 radio on SPI bus plus pins 7 & 6
// (This works for the Getting Started board plugged into the
// Maple Native backwards.)
RF24 radio(7,6);
// 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 = 10;
//
// 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
//
board_start("\n\rRF24/examples/pingpair/\n\r");
printf("ROLE: %s\n\r",role_friendly_name[role]);
//
// Setup and configure rf radio
//
radio.begin();
// optionally, increase the delay between retries & # of retries
radio.setRetries(15,15);
// optionally, reduce the payload size. seems to
// improve reliability
radio.setPayloadSize(8);
//
// 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)
{
toggleLED();
// 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);
bool ok = radio.write( &time, sizeof(unsigned long) );
if (ok)
printf("ok...\r\n");
else
printf("failed.\r\n");
// 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.\r\n");
}
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\r\n",got_time,millis()-got_time);
}
toggleLED();
// 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;
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.\r\n");
// Now, resume listening so we catch the next packets.
radio.startListening();
}
}
}
// vim:cin:ai:sts=2 sw=2 ft=cpp
@@ -0,0 +1,123 @@
/*
// March 2014 - TMRh20 - Updated along with High Speed RF24 Library fork
// Parts derived from examples by J. Coliz <maniacbug@ymail.com>
*/
/**
* Example for efficient call-response using ack-payloads
*
* This example continues to make use of all the normal functionality of the radios including
* the auto-ack and auto-retry features, but allows ack-payloads to be written optionlly as well.
* This allows very fast call-response communication, with the responding radio never having to
* switch out of Primary Receiver mode to send back a payload, but having the option to if wanting
* to initiate communication instead of respond to a commmunication.
*/
#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"
#include "printf.h"
// Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins 9 & 10
RF24 radio(7,8);
// Topology
const uint64_t pipes[2] = { 0xABCDABCD71LL, 0x544d52687CLL }; // Radio pipe addresses for the 2 nodes to communicate.
// Role management: Set up role. This sketch uses the same software for all the nodes
// in this system. Doing so greatly simplifies testing.
typedef enum { role_ping_out = 1, role_pong_back } role_e; // The various roles supported by this sketch
const char* role_friendly_name[] = { "invalid", "Ping out", "Pong back"}; // The debug-friendly names of those roles
role_e role = role_pong_back; // The role of the current running sketch
// A single byte to keep track of the data being sent back and forth
byte counter = 1;
void setup(){
Serial.begin(57600);
printf_begin();
printf("\n\rRF24/examples/GettingStarted/\n\r");
printf("ROLE: %s\n\r",role_friendly_name[role]);
printf("*** PRESS 'T' to begin transmitting to the other node\n\r");
// Setup and configure rf radio
radio.begin();
radio.setAutoAck(1); // Ensure autoACK is enabled
radio.enableAckPayload(); // Allow optional ack payloads
radio.setRetries(0,15); // Smallest time between retries, max no. of retries
radio.setPayloadSize(1); // Here we are sending 1-byte payloads to test the call-response speed
radio.openWritingPipe(pipes[1]); // Both radios listen on the same pipes by default, and switch when writing
radio.openReadingPipe(1,pipes[0]);
radio.startListening(); // Start listening
radio.printDetails(); // Dump the configuration of the rf unit for debugging
}
void loop(void) {
if (role == role_ping_out){
radio.stopListening(); // First, stop listening so we can talk.
printf("Now sending %d as payload. ",counter);
byte gotByte;
unsigned long time = micros(); // Take the time, and send it. This will block until complete
//Called when STANDBY-I mode is engaged (User is finished sending)
if (!radio.write( &counter, 1 )){
printf("failed.\n\r");
}else{
if(!radio.available()){
printf("Blank Payload Received\n\r");
}else{
while(radio.available() ){
unsigned long tim = micros();
radio.read( &gotByte, 1 );
printf("Got response %d, round-trip delay: %lu microseconds\n\r",gotByte,tim-time);
counter++;
}
}
}
// Try again later
delay(1000);
}
// Pong back role. Receive each packet, dump it out, and send it back
if ( role == role_pong_back ) {
byte pipeNo;
byte gotByte; // Dump the payloads until we've gotten everything
while( radio.available(&pipeNo)){
radio.read( &gotByte, 1 );
radio.writeAckPayload(pipeNo,&gotByte, 1 );
}
}
// Change roles
if ( Serial.available() )
{
char c = toupper(Serial.read());
if ( c == 'T' && role == role_pong_back )
{
printf("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK\n\r");
role = role_ping_out; // Become the primary transmitter (ping out)
radio.openWritingPipe(pipes[0]);
radio.openReadingPipe(1,pipes[1]);
}
else if ( c == 'R' && role == role_ping_out )
{
printf("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK\n\r");
role = role_pong_back; // Become the primary receiver (pong back)
radio.openWritingPipe(pipes[1]);
radio.openReadingPipe(1,pipes[0]);
radio.startListening();
}
}
}
@@ -0,0 +1,37 @@
/*
Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
*/
/**
* @file printf.h
*
* Setup necessary to direct stdout to the Arduino Serial library, which
* enables 'printf'
*/
#ifndef __PRINTF_H__
#define __PRINTF_H__
#ifdef ARDUINO
int serial_putc( char c, FILE * )
{
Serial.write( c );
return c;
}
void printf_begin(void)
{
fdevopen( &serial_putc, 0 );
}
#else
#error This example is only for use on Arduino.
#endif // ARDUINO
#endif // __PRINTF_H__
@@ -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 -Wall -Wextra -mmcu=$(MCU) $(CTUNING) ;
CXXFLAGS = $(CFLAGS) $(CXXTUNING) ;
LDFLAGS = -Os -lm -Wl,--gc-sections -mmcu=atmega328p ;
# Search everywhere for headers
HDRS = $(PROJECT_DIR) $(ARDUINO_AVR) $(ARDUINO_CORE) [ GLOB $(ARDUINO_LIB) $(SKETCH_LIB) : [^.]* ] ;
# Grab everything from the core directory
CORE_MODULES = [ GLOB $(ARDUINO_CORE) : *.c *.cpp ] ;
# Grab everything from libraries. To avoid this "grab everything" behaviour, you
# can specify specific modules to pick up in PROJECT_MODULES
LIB_MODULES = [ GLOB $(ARDUINO_LIB)/$(PROJECT_LIBS) $(SKETCH_LIB)/$(PROJECT_LIBS) : *.cpp ] ;
# In addition to explicitly-specified program modules, pick up anything from the current
# dir.
PROJECT_MODULES += [ GLOB $(PROJECT_DIR) : *.c *.cpp *.pde ] ;
# Shortcut for the out files
OUT = $(OUT_DIR)/$(PROJECT_NAME) ;
# AvrDude setup
AVRDUDE_FLAGS = -V -F -D -C $(AVRDUDECONFIG_PATH)/avrdude.conf -p $(MCU) -c $(AVRDUDE_PROTOCOL) -b $(UPLOAD_RATE) ;
rule GitVersion
{
Always $(<) ;
Depends all : $(<) ;
}
actions GitVersion
{
echo "const char program_version[] = \"\\" > $(<)
git log -1 --pretty=format:%h >> $(<)
echo "\";" >> $(<)
}
GitVersion version.h ;
rule AvrCc
{
Depends $(<) : $(>) ;
Depends $(<) : $(<:D) ;
Clean clean : $(<) ;
CCHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] ;
CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ;
}
actions AvrCc
{
$(AVR_CC) -c -o $(<) $(CCHDRS) $(CCDEFS) $(CFLAGS) $(>)
}
rule AvrC++
{
Depends $(<) : $(>) ;
Depends $(<) : $(<:D) ;
Clean clean : $(<) ;
CCHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] ;
CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ;
}
actions AvrC++
{
$(AVR_CXX) -c -o $(<) $(CCHDRS) $(CCDEFS) $(CXXFLAGS) $(>)
}
rule Pde
{
Depends $(<) : $(>) ;
Depends $(<) : $(<:D) ;
Clean clean : $(<) ;
}
actions Pde
{
echo "#include <WProgram.h>" > $(<)
echo "#line 1 \"$(>)\"" >> $(<)
cat $(>) >> $(<)
}
rule AvrPde
{
local _CPP = $(OUT_DIR)/$(_I:B).cpp ;
Pde $(_CPP) : $(>) ;
AvrC++ $(<) : $(_CPP) ;
}
rule AvrObject
{
switch $(>:S)
{
case .c : AvrCc $(<) : $(>) ;
case .cpp : AvrC++ $(<) : $(>) ;
case .pde : AvrPde $(<) : $(>) ;
}
}
rule AvrObjects
{
for _I in $(<)
{
AvrObject $(OUT_DIR)/$(_I:B).o : $(_I) ;
}
}
rule AvrMainFromObjects
{
Depends $(<) : $(>) ;
Depends $(<) : $(<:D) ;
MkDir $(<:D) ;
Depends all : $(<) ;
Clean clean : $(<) ;
}
actions AvrMainFromObjects
{
$(AVR_LD) $(LDFLAGS) -o $(<) $(>)
}
rule AvrMain
{
AvrMainFromObjects $(<) : $(OUT_DIR)/$(>:B).o ;
AvrObjects $(>) ;
}
rule AvrHex
{
Depends $(<) : $(>) ;
Depends $(<) : $(<:D) ;
Depends hex : $(<) ;
Clean clean : $(<) ;
}
actions AvrHex
{
$(AVR_OBJCOPY) -O ihex -R .eeprom $(>) $(<)
}
rule AvrUpload
{
Depends $(1) : $(2) ;
Depends $(2) : $(3) ;
NotFile $(1) ;
Always $(1) ;
Always $(2) ;
AvrUploadAction $(2) : $(3) ;
}
actions AvrUploadAction
{
$(AVRDUDE) $(AVRDUDE_FLAGS) -P $(<) $(AVRDUDE_WRITE_FLASH) -U flash:w:$(>):i
}
AvrMain $(OUT).elf : $(CORE_MODULES) $(LIB_MODULES) $(PROJECT_MODULES) ;
AvrHex $(OUT).hex : $(OUT).elf ;
AvrUpload p6 : /dev/tty.usbserial-A600eHIs : $(OUT).hex ;
AvrUpload p4 : /dev/tty.usbserial-A40081RP : $(OUT).hex ;
AvrUpload p9 : /dev/tty.usbserial-A9007LmI : $(OUT).hex ;
@@ -0,0 +1,232 @@
/*
Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
*/
/**
* Example using Dynamic Payloads
*
* This is an example of how to use payloads of a varying (dynamic) size.
*/
#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"
#include "printf.h"
//
// Hardware configuration
//
// Set up nRF24L01 radio on SPI bus plus pins 9 & 10
RF24 radio(7,8);
// sets the role of this unit in hardware. Connect to GND to be the 'pong' receiver
// Leave open to be the 'ping' transmitter
const int role_pin = 5;
//
// Topology
//
// Radio pipe addresses for the 2 nodes to communicate.
const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };
//
// Role management
//
// Set up role. This sketch uses the same software for all the nodes
// in this system. Doing so greatly simplifies testing. The hardware itself specifies
// which node it is.
//
// This is done through the role_pin
//
// The various roles supported by this sketch
typedef enum { role_ping_out = 1, role_pong_back } role_e;
// The debug-friendly names of those roles
const char* role_friendly_name[] = { "invalid", "Ping out", "Pong back"};
// The role of the current running sketch
role_e role;
//
// Payload
//
const int min_payload_size = 4;
const int max_payload_size = 32;
const int payload_size_increments_by = 1;
int next_payload_size = min_payload_size;
char receive_payload[max_payload_size+1]; // +1 to allow room for a terminating NULL char
void setup(void)
{
//
// Role
//
// set up the role pin
pinMode(role_pin, INPUT);
digitalWrite(role_pin,HIGH);
delay(20); // Just to get a solid reading on the role pin
// read the address pin, establish our role
if ( digitalRead(role_pin) )
role = role_ping_out;
else
role = role_pong_back;
//
// Print preamble
//
Serial.begin(57600);
printf_begin();
printf("\n\rRF24/examples/pingpair_dyn/\n\r");
printf("ROLE: %s\n\r",role_friendly_name[role]);
//
// Setup and configure rf radio
//
radio.begin();
// enable dynamic payloads
radio.enableDynamicPayloads();
// optionally, increase the delay between retries & # of retries
radio.setRetries(5,15);
//
// 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)
{
// The payload will always be the same, what will change is how much of it we send.
static char send_payload[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ789012";
// First, stop listening so we can talk.
radio.stopListening();
// Take the time, and send it. This will block until complete
printf("Now sending length %i...",next_payload_size);
radio.write( send_payload, next_payload_size );
// Now, continue listening
radio.startListening();
// Wait here until we get a response, or timeout
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
{
// Grab the response, compare, and send to debugging spew
uint8_t len = radio.getDynamicPayloadSize();
radio.read( receive_payload, len );
// Put a zero at the end for easy printing
receive_payload[len] = 0;
// Spew it
printf("Got response size=%i value=%s\n\r",len,receive_payload);
}
// Update size for next time.
next_payload_size += payload_size_increments_by;
if ( next_payload_size > max_payload_size )
next_payload_size = min_payload_size;
// Try again 1s later
delay(100);
}
//
// 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
uint8_t len;
bool done = false;
while (radio.available())
{
// Fetch the payload, and see if this was the last one.
len = radio.getDynamicPayloadSize();
radio.read( receive_payload, len );
// Put a zero at the end for easy printing
receive_payload[len] = 0;
// Spew it
printf("Got payload size=%i value=%s\n\r",len,receive_payload);
}
// First, stop listening so we can talk
radio.stopListening();
// Send the final one back.
radio.write( receive_payload, len );
printf("Sent response.\n\r");
// Now, resume listening so we catch the next packets.
radio.startListening();
}
}
}
// vim:cin:ai:sts=2 sw=2 ft=cpp
@@ -0,0 +1,37 @@
/*
Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
*/
/**
* @file printf.h
*
* Setup necessary to direct stdout to the Arduino Serial library, which
* enables 'printf'
*/
#ifndef __PRINTF_H__
#define __PRINTF_H__
#ifdef ARDUINO
int serial_putc( char c, FILE * )
{
Serial.write( c );
return c;
}
void printf_begin(void)
{
fdevopen( &serial_putc, 0 );
}
#else
#error This example is only for use on Arduino.
#endif // ARDUINO
#endif // __PRINTF_H__
@@ -0,0 +1,137 @@
/*
Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
Update 2014 - TMRh20
*/
/**
* Example of using interrupts
*
* This is an example of how to user interrupts to interact with the radio, and a demonstration
* of how to use them to sleep when receiving, and not miss any payloads.
* The pingpair_sleepy example expands on sleep functionality with a timed sleep option for the transmitter.
* Sleep functionality is built directly into my fork of the RF24Network library
*/
#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"
#include "printf.h"
#include <avr/sleep.h>
#include <avr/power.h>
// Hardware configuration
RF24 radio(7,8); // Set up nRF24L01 radio on SPI bus plus pins 9 & 10
const short role_pin = 5; // sets the role of this unit in hardware. Connect to GND to be the 'pong' receiver
// Leave open to be the 'ping' transmitter
const uint64_t address[2] = {0xABCDABCD71LL, 0x544d52687CLL}; // Radio pipe addresses for the 2 nodes to communicate.
// Role management
// Set up role. This sketch uses the same software for all the nodes in this
// system. Doing so greatly simplifies testing. The hardware itself specifies
// which node it is.
// This is done through the role_pin
typedef enum { role_sender = 1, role_receiver } role_e; // The various roles supported by this sketch
const char* role_friendly_name[] = { "invalid", "Sender", "Receiver"}; // The debug-friendly names of those roles
role_e role; // The role of the current running sketch
boolean gotMsg = 0; // So we know when to go to sleep
/********************** Setup *********************/
void setup(){
pinMode(role_pin, INPUT); // set up the role pin
digitalWrite(role_pin,HIGH); // Change this to LOW/HIGH instead of using an external pin
delay(20); // Just to get a solid reading on the role pin
if ( digitalRead(role_pin) ) // read the address pin, establish our role
role = role_sender;
else
role = role_receiver;
Serial.begin(115200);
printf_begin();
printf("\n\rRF24/examples/pingpair_irq/\n\r");
printf("ROLE: %s\n\r",role_friendly_name[role]);
// Setup and configure rf radio
radio.begin();
radio.enableAckPayload(); // We will be using the Ack Payload feature, so please enable it
// Open pipes to other node for communication
if ( role == role_sender ) { // This simple sketch opens a pipe on a single address for these two nodes to
radio.openWritingPipe(address[0]); // communicate back and forth. One listens on it, the other talks to it.
radio.openReadingPipe(1,address[1]);
}else{
radio.openWritingPipe(address[1]);
radio.openReadingPipe(1,address[0]);
radio.startListening();
}
radio.printDetails(); // Dump the configuration of the rf unit for debugging
delay(50);
attachInterrupt(0, check_radio, FALLING); // Attach interrupt handler to interrupt #0 (using pin 2) on BOTH the sender and receiver
}
static uint32_t message_count = 0;
/********************** Main Loop *********************/
void loop() {
if (role == role_sender) { // Sender role. Repeatedly send the current time
unsigned long time = millis(); // Take the time, and send it.
printf("Now sending %lu\n\r",time);
radio.startWrite( &time, sizeof(unsigned long) ,0);
delay(2000); // Try again soon
}
if(role == role_receiver){ // Receiver does nothing except in IRQ
}
}
/********************** Interrupt *********************/
void check_radio(void) // Receiver role: Does nothing! All the work is in IRQ
{
bool tx,fail,rx;
radio.whatHappened(tx,fail,rx); // What happened?
if ( tx ) { // Have we successfully transmitted?
if ( role == role_sender ){ printf("Send:OK\n\r"); }
if ( role == role_receiver ){ printf("Ack Payload:Sent\n\r"); }
}
if ( fail ) { // Have we failed to transmit?
if ( role == role_sender ){ printf("Send:Failed\n\r"); }
if ( role == role_receiver ){ printf("Ack Payload:Failed\n\r"); }
}
if ( rx || radio.available()){ // Did we receive a message?
if ( role == role_sender ) { // If we're the sender, we've received an ack payload
radio.read(&message_count,sizeof(message_count));
printf("Ack:%lu\n\r",message_count);
}
if ( role == role_receiver ) { // If we're the receiver, we've received a time message
static unsigned long got_time; // Get this payload and dump it
radio.read( &got_time, sizeof(got_time) );
printf("Got payload %lu\n\r",got_time);
radio.writeAckPayload( 1, &message_count, sizeof(message_count) ); // Add an ack packet for the next time around. This is a simple
++message_count; // packet counter
}
}
}
@@ -0,0 +1,37 @@
/*
Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
*/
/**
* @file printf.h
*
* Setup necessary to direct stdout to the Arduino Serial library, which
* enables 'printf'
*/
#ifndef __PRINTF_H__
#define __PRINTF_H__
#ifdef ARDUINO
int serial_putc( char c, FILE * )
{
Serial.write( c );
return c;
}
void printf_begin(void)
{
fdevopen( &serial_putc, 0 );
}
#else
#error This example is only for use on Arduino.
#endif // ARDUINO
#endif // __PRINTF_H__
@@ -0,0 +1,225 @@
/*
Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
TMRh20 2014 - Updates to the library allow sleeping both in TX and RX modes:
TX Mode: The radio can be powered down (.9uA current) and the Arduino slept using the watchdog timer
RX Mode: The radio can be left in standby mode (22uA current) and the Arduino slept using an interrupt pin
*/
/**
* Example RF Radio Ping Pair which Sleeps between Sends
*
* This is an example of how to use the RF24 class to create a battery-
* efficient system. It is just like the GettingStarted_CallResponse example, but the
* ping node powers down the radio and sleeps the MCU after every
* ping/pong cycle, and the receiver sleeps between payloads.
*
* Write this sketch to two different nodes,
* connect the role_pin to ground on one. The ping node sends the current
* time to the pong node, which responds by sending the value back. The ping
* node can then see how long the whole cycle took.
*/
#include <SPI.h>
#include <avr/sleep.h>
#include <avr/power.h>
#include "nRF24L01.h"
#include "RF24.h"
#include "printf.h"
// Set up nRF24L01 radio on SPI bus plus pins 9 & 10
RF24 radio(7,8);
// sets the role of this unit in hardware. Connect to GND to be the 'pong' receiver
// Leave open to be the 'ping' transmitter
const int role_pin = 5;
const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL }; // Radio pipe addresses for the 2 nodes to communicate.
// Role management
// Set up role. This sketch uses the same software for all the nodes
// in this system. Doing so greatly simplifies testing. The hardware itself specifies
// which node it is.
// The various roles supported by this sketch
typedef enum { role_ping_out = 1, role_pong_back } role_e;
// The debug-friendly names of those roles
const char* role_friendly_name[] = { "invalid", "Ping out", "Pong back"};
// The role of the current running sketch
role_e role;
// Sleep declarations
typedef enum { wdt_16ms = 0, wdt_32ms, wdt_64ms, wdt_128ms, wdt_250ms, wdt_500ms, wdt_1s, wdt_2s, wdt_4s, wdt_8s } wdt_prescalar_e;
void setup_watchdog(uint8_t prescalar);
void do_sleep(void);
const short sleep_cycles_per_transmission = 4;
volatile short sleep_cycles_remaining = sleep_cycles_per_transmission;
void setup(){
// set up the role pin
pinMode(role_pin, INPUT);
digitalWrite(role_pin,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;
Serial.begin(57600);
printf_begin();
printf("\n\rRF24/examples/pingpair_sleepy/\n\r");
printf("ROLE: %s\n\r",role_friendly_name[role]);
// Prepare sleep parameters
// Only the ping out role uses WDT. Wake up every 4s to send a ping
//if ( role == role_ping_out )
setup_watchdog(wdt_4s);
// Setup and configure rf radio
radio.begin();
// Open pipes to other nodes for communication
// This simple sketch opens two pipes for these two nodes to communicate
// back and forth.
// Open 'our' pipe for writing
// Open the 'other' pipe for reading, in position #1 (we can have up to 5 pipes open for reading)
if ( role == role_ping_out ) {
radio.openWritingPipe(pipes[0]);
radio.openReadingPipe(1,pipes[1]);
} else {
radio.openWritingPipe(pipes[1]);
radio.openReadingPipe(1,pipes[0]);
}
// Start listening
radio.startListening();
// Dump the configuration of the rf unit for debugging
//radio.printDetails();
}
void loop(){
if (role == role_ping_out) { // Ping out role. Repeatedly send the current time
radio.powerUp(); // Power up the radio after sleeping
radio.stopListening(); // First, stop listening so we can talk.
unsigned long time = millis(); // Take the time, and send it.
printf("Now sending... %lu \n\r",time);
radio.write( &time, sizeof(unsigned long) );
radio.startListening(); // Now, continue listening
unsigned long started_waiting_at = millis(); // Wait here until we get a response, or timeout (250ms)
bool timeout = false;
while ( ! radio.available() ){
if (millis() - started_waiting_at > 250 ){ // Break out of the while loop if nothing available
timeout = true;
break;
}
}
if ( timeout ) { // Describe the results
printf("Failed, response timed out.\n\r");
}else{
unsigned long got_time; // Grab the response, compare, and send to debugging spew
radio.read( &got_time, sizeof(unsigned long) );
printf("Got response %lu, round-trip delay: %lu\n\r",got_time,millis()-got_time);
}
// Shut down the system
delay(500); // Experiment with some delay here to see if it has an effect
// Power down the radio.
radio.powerDown(); // NOTE: The radio MUST be powered back up again manually
// Sleep the MCU.
do_sleep();
}
// Pong back role. Receive each packet, dump it out, and send it back
if ( role == role_pong_back ) {
if ( radio.available() ) { // if there is data ready
unsigned long got_time;
while (radio.available()) { // Dump the payloads until we've gotten everything
radio.read( &got_time, sizeof(unsigned long) ); // Get the payload, and see if this was the last one.
// Spew it. Include our time, because the ping_out millis counter is unreliable
printf("Got payload %lu @ %lu...",got_time,millis()); // due to it sleeping
}
radio.stopListening(); // First, stop listening so we can talk
radio.write( &got_time, sizeof(unsigned long) ); // Send the final one back.
printf("Sent response.\n\r");
radio.startListening(); // Now, resume listening so we catch the next packets.
}else{
Serial.println("Sleeping");
delay(50); // Delay so the serial data can print out
do_sleep();
}
}
}
void wakeUp(){
sleep_disable();
}
// Sleep helpers
//Prescaler values
// 0=16ms, 1=32ms,2=64ms,3=125ms,4=250ms,5=500ms
// 6=1 sec,7=2 sec, 8=4 sec, 9= 8sec
void setup_watchdog(uint8_t prescalar){
uint8_t wdtcsr = prescalar & 7;
if ( prescalar & 8 )
wdtcsr |= _BV(WDP3);
MCUSR &= ~_BV(WDRF); // Clear the WD System Reset Flag
WDTCSR = _BV(WDCE) | _BV(WDE); // Write the WD Change enable bit to enable changing the prescaler and enable system reset
WDTCSR = _BV(WDCE) | wdtcsr | _BV(WDIE); // Write the prescalar bits (how long to sleep, enable the interrupt to wake the MCU
}
ISR(WDT_vect)
{
//--sleep_cycles_remaining;
Serial.println("WDT");
}
void do_sleep(void)
{
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
sleep_enable();
attachInterrupt(0,wakeUp,LOW);
WDTCSR |= _BV(WDIE);
sleep_mode(); // System sleeps here
// The WDT_vect interrupt wakes the MCU from here
sleep_disable(); // System continues execution here when watchdog timed out
detachInterrupt(0);
WDTCSR &= ~_BV(WDIE);
}
@@ -0,0 +1,37 @@
/*
Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
*/
/**
* @file printf.h
*
* Setup necessary to direct stdout to the Arduino Serial library, which
* enables 'printf'
*/
#ifndef __PRINTF_H__
#define __PRINTF_H__
#ifdef ARDUINO
int serial_putc( char c, FILE * )
{
Serial.write( c );
return c;
}
void printf_begin(void)
{
fdevopen( &serial_putc, 0 );
}
#else
#error This example is only for use on Arduino.
#endif // ARDUINO
#endif // __PRINTF_H__
+210
View File
@@ -0,0 +1,210 @@
# (1) Project Information
PROJECT_LIBS = SPI RF24 ;
# (2) Board Information
UPLOAD_PROTOCOL ?= stk500v1 ;
UPLOAD_SPEED ?= 57600 ;
MCU ?= atmega328p ;
F_CPU ?= 16000000 ;
CORE ?= arduino ;
VARIANT ?= standard ;
ARDUINO_VERSION ?= 100 ;
# (3) USB Ports
PORTS = p4 p6 p9 u0 u1 u2 ;
PORT_p6 = /dev/tty.usbserial-A600eHIs ;
PORT_p4 = /dev/tty.usbserial-A40081RP ;
PORT_p9 = /dev/tty.usbserial-A9007LmI ;
PORT_u0 = /dev/ttyUSB0 ;
PORT_u1 = /dev/ttyUSB1 ;
PORT_u2 = /dev/ttyUSB2 ;
# (4) Location of AVR tools
#
# This configuration assumes using avr-tools that were obtained separate from the Arduino
# distribution.
if $(OS) = MACOSX
{
AVR_BIN = /usr/local/avrtools/bin ;
AVR_ETC = /usr/local/avrtools/etc ;
AVR_INCLUDE = /usr/local/avrtools/include ;
}
else
{
AVR_BIN = /usr/bin ;
AVR_INCLUDE = /usr/lib/avr/include ;
AVR_ETC = /etc ;
}
# (5) Directories where Arduino core and libraries are located
ARDUINO_DIR ?= /opt/Arduino ;
ARDUINO_CORE = $(ARDUINO_DIR)/hardware/arduino/cores/$(CORE) $(ARDUINO_DIR)/hardware/arduino/variants/$(VARIANT) ;
ARDUINO_LIB = $(ARDUINO_DIR)/libraries ;
SKETCH_LIB = $(HOME)/Source/Arduino/libraries ;
#
# --------------------------------------------------
# Below this line usually never needs to be modified
#
# Tool locations
CC = $(AVR_BIN)/avr-gcc ;
C++ = $(AVR_BIN)/avr-g++ ;
LINK = $(AVR_BIN)/avr-gcc ;
OBJCOPY = $(AVR_BIN)/avr-objcopy ;
AVRDUDE = $(AVR_BIN)/avrdude ;
# Flags
DEFINES += F_CPU=$(F_CPU)L ARDUINO=$(ARDUINO_VERSION) VERSION_H ;
OPTIM = -Os ;
CCFLAGS = -Wall -Wextra -mmcu=$(MCU) -ffunction-sections -fdata-sections ;
C++FLAGS = $(CCFLAGS) -fno-exceptions -fno-strict-aliasing ;
LINKFLAGS = $(OPTIM) -lm -Wl,--gc-sections -mmcu=$(MCU) ;
AVRDUDEFLAGS = -V -F -D -C $(AVR_ETC)/avrdude.conf -p $(MCU) -c $(UPLOAD_PROTOCOL) -b $(UPLOAD_SPEED) ;
# Search everywhere for headers
HDRS = $(PWD) $(AVR_INCLUDE) $(ARDUINO_CORE) $(ARDUINO_LIB)/$(PROJECT_LIBS) $(ARDUINO_LIB)/$(PROJECT_LIBS)/utility $(SKETCH_LIB)/$(PROJECT_LIBS) ;
# Output locations
LOCATE_TARGET = $(F_CPU) ;
LOCATE_SOURCE = $(F_CPU) ;
#
# Custom rules
#
rule GitVersion
{
Always $(<) ;
Depends all : $(<) ;
}
actions GitVersion
{
echo "const char program_version[] = \"\\" > $(<)
git log -1 --pretty=format:%h >> $(<)
echo "\";" >> $(<)
}
GitVersion version.h ;
rule Pde
{
Depends $(<) : $(>) ;
MakeLocate $(<) : $(LOCATE_SOURCE) ;
Clean clean : $(<) ;
}
if ( $(ARDUINO_VERSION) < 100 )
{
ARDUINO_H = WProgram.h ;
}
else
{
ARDUINO_H = Arduino.h ;
}
actions Pde
{
echo "#include <$(ARDUINO_H)>" > $(<)
echo "#line 1 \"$(>)\"" >> $(<)
cat $(>) >> $(<)
}
rule C++Pde
{
local _CPP = $(>:B).cpp ;
Pde $(_CPP) : $(>) ;
C++ $(<) : $(_CPP) ;
}
rule UserObject
{
switch $(>:S)
{
case .ino : C++Pde $(<) : $(>) ;
case .pde : C++Pde $(<) : $(>) ;
}
}
rule Objects
{
local _i ;
for _i in [ FGristFiles $(<) ]
{
local _b = $(_i:B)$(SUFOBJ) ;
local _o = $(_b:G=$(SOURCE_GRIST:E)) ;
Object $(_o) : $(_i) ;
Depends obj : $(_o) ;
}
}
rule Main
{
MainFromObjects $(<) : $(>:B)$(SUFOBJ) ;
Objects $(>) ;
}
rule Hex
{
Depends $(<) : $(>) ;
MakeLocate $(<) : $(LOCATE_TARGET) ;
Depends hex : $(<) ;
Clean clean : $(<) ;
}
actions Hex
{
$(OBJCOPY) -O ihex -R .eeprom $(>) $(<)
}
rule Upload
{
Depends $(1) : $(2) ;
Depends $(2) : $(3) ;
NotFile $(1) ;
Always $(1) ;
Always $(2) ;
UploadAction $(2) : $(3) ;
}
actions UploadAction
{
$(AVRDUDE) $(AVRDUDEFLAGS) -P $(<) $(AVRDUDE_WRITE_FLASH) -U flash:w:$(>):i
}
#
# Targets
#
# Grab everything from the core directory
CORE_MODULES = [ GLOB $(ARDUINO_CORE) : *.c *.cpp ] ;
# Grab everything from libraries. To avoid this "grab everything" behaviour, you
# can specify specific modules to pick up in PROJECT_MODULES
LIB_MODULES = [ GLOB $(ARDUINO_LIB)/$(PROJECT_LIBS) $(ARDUINO_LIB)/$(PROJECT_LIBS)/utility $(SKETCH_LIB)/$(PROJECT_LIBS) : *.cpp *.c ] ;
# Grab everything from the current dir
PROJECT_MODULES += [ GLOB $(PWD) : *.c *.cpp *.pde *.ino ] ;
# Main output executable
MAIN = $(PWD:B).elf ;
Main $(MAIN) : $(CORE_MODULES) $(LIB_MODULES) $(PROJECT_MODULES) ;
Hex $(MAIN:B).hex : $(MAIN) ;
# Upload targets
for _p in $(PORTS)
{
Upload $(_p) : $(PORT_$(_p)) : $(MAIN:B).hex ;
}
Binary file not shown.
@@ -0,0 +1,128 @@
#include <WProgram.h>
#line 1 "scanner.pde"
/*
Copyright (C) 2011 James Coliz, Jr. <maniacbug@ymail.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
*/
/**
* Channel scanner
*
* Example to detect interference on the various channels available.
* This is a good diagnostic tool to check whether you're picking a
* good channel for your application.
*
* Inspired by cpixip.
* See http://arduino.cc/forum/index.php/topic,54795.0.html
*/
#include <SPI.h>
#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);
//
// Channel info
//
const short num_channels = 128;
short values[num_channels];
//
// Setup
//
void setup(void)
{
//
// Print preamble
//
Serial.begin(57600);
printf_begin();
printf("\n\rRF24/examples/scanner/\n\r");
//
// Setup and configure rf radio
//
radio.begin();
radio.setAutoAck(false);
// Get into standby mode
radio.startListening();
radio.stopListening();
// Print out header, high then low digit
int i = 0;
while ( i < num_channels )
{
printf("%x",i>>4);
++i;
}
printf("\n\r");
i = 0;
while ( i < num_channels )
{
printf("%x",i&0xf);
++i;
}
printf("\n\r");
}
//
// Loop
//
const short num_reps = 100;
void loop(void)
{
// Clear measurement values
memset(values,0,num_channels);
// Scan all channels num_reps times
int rep_counter = num_reps;
while (rep_counter--)
{
int i = num_channels;
while (i--)
{
// Select this channel
radio.setChannel(i);
// Listen for a little
radio.startListening();
delayMicroseconds(128);
radio.stopListening();
// Did we get a carrier?
if ( radio.testCarrier() )
++values[i];
}
}
// Print out channel measurements, clamped to a single hex digit
int i = 0;
while ( i < num_channels )
{
printf("%x",min(0xf,values[i]&0xf));
++i;
}
printf("\n\r");
}
// vim:ai:cin:sts=2 sw=2 ft=cpp
Binary file not shown.
@@ -0,0 +1,325 @@
:100000000C9463000C948B000C948B000C948B006C
:100010000C948B000C948B000C948B000C948B0034
:100020000C948B000C948B000C948B000C948B0024
:100030000C948B000C948B000C948B000C948B0014
:100040000C948F050C948B000C9423060C948B005D
:100050000C948B000C948B000C948B000C948B00F4
:100060000C948B000C948B000000000024002700EF
:100070002A0000000000250028002B0000000000DE
:1000800023002600290004040404040404040202DA
:100090000202020203030303030301020408102007
:1000A0004080010204081020010204081020000012
:1000B0000007000201000003040600000000000029
:1000C000000090043B0711241FBECFEFD8E0DEBF35
:1000D000CDBF11E0A0E0B1E0E6EFF3E102C0059092
:1000E0000D92AA33B107D9F712E0AAE3B1E001C03B
:1000F0001D92A13FB107E1F710E0C6ECD0E004C0CB
:100100002297FE010E94F509C23CD107C9F70E945F
:100110001C060C94F9090C9400000F931F93CF93C5
:10012000DF938C01EB01009731F46115710519F42F
:1001300020E030E038C081E090E06EE070E00E94A6
:10014000CB02FC019C01009771F180E8838320972A
:1001500071F0D387C28781E883838091E702909111
:10016000E802892B21F4F093E802E093E7020115FD
:100170001105C9F011870087838182608383809194
:10018000E9029091EA02892B71F4F093EA02E0937C
:10019000E9028091EB029091EC02892B21F4F0931B
:1001A000EC02E093EB02C901DF91CF911F910F9117
:1001B0000895A0E0B0E0EFEDF0E00C94CC09FE0172
:1001C0003596619171918091E9029091EA02AF01B7
:1001D0000E94EE002096E2E00C94E809ABE0B0E06B
:1001E000E4EFF0E00C94BC093C012B015A01FC0146
:1001F00017821682838181FD03C06FEF7FEFC6C136
:100200009AE0892E1E010894211C311CF3012381E0
:10021000F20123FD859123FF81912F01882309F4A9
:10022000B2C1853239F423FD859123FF81912F01DD
:10023000853229F490E0B3010E940604E7CF982F9D
:10024000FF24EE249924FFE1FF15D0F09B3269F0E2
:100250009C3228F4903259F0933291F40EC09D32C2
:1002600049F0903369F441E024C052E0F52A84E07B
:10027000F82A28C098E0F92A25C0E0E1FE2A22C029
:10028000F7FC29C0892F80538A3070F4F6FE05C030
:10029000989C902C1124980E15C0E89CE02C1124F9
:1002A000E80EF0E2FF2A0EC09E3229F4F6FC6BC184
:1002B00040E4F42A07C09C3619F450E8F52A02C03D
:1002C000983649F4F20123FD959123FF91912F0176
:1002D000992309F0B8CF892F8554833018F08052C4
:1002E000833038F444E050E0A40EB51E5FE3598338
:1002F0000FC0933631F0933779F0933509F056C03B
:1003000020C0F5018081898342E050E0A40EB51E33
:10031000610101E010E012C0F501C080D180F6FC5F
:1003200003C06FEF7FEF02C0692D70E042E050E044
:10033000A40EB51EC6010E94FB038C015FE7F522E7
:1003400014C0F501C080D180F6FC03C06FEF7FEFD1
:1003500002C0692D70E042E050E0A40EB51EC60157
:100360000E94E9038C0150E8F52AF3FE07C01AC089
:1003700080E290E0B3010E940604EA948E2D90E0A2
:1003800008171907A8F30EC0F601F7FC8591F7FED0
:1003900081916F0190E0B3010E940604E110EA949C
:1003A000015010400115110579F7EAC0943611F09B
:1003B000993669F5F7FE08C0F50120813181428147
:1003C000538184E090E00AC0F501808191819C0115
:1003D000442737FD4095542F82E090E0A80EB91EC7
:1003E0009FE6F92257FF09C0509540953095219519
:1003F0003F4F4F4F5F4FE0E8FE2ACA01B901A1010C
:100400002AE030E00E943204D82ED21840C095373E
:1004100029F41F2D1F7E2AE030E01DC01F2D197FFB
:100420009F3661F0903720F4983509F0ACC00FC0CA
:10043000903739F0983709F0A6C004C028E030E0C2
:100440000AC0106114FD146020E130E004C014FD06
:10045000166020E132E017FF08C0F501608171816C
:100460008281938144E050E008C0F5018081918150
:10047000BC0180E090E042E050E0A40EB51EA10176
:100480000E943204D82ED2188FE7F82EF122F6FE01
:100490000BC05EEFF522D91438F4F4FE07C0F2FC6D
:1004A00005C08FEEF82202C01D2D01C0192DF4FEEB
:1004B0000DC0FE01ED0DF11D8081803319F499EE20
:1004C000F92208C01F5FF2FE05C003C08F2D867899
:1004D00009F01F5F0F2DF3FC14C0F0FE0FC01E15B6
:1004E00010F09D2C0BC09D2C9E0C911A1E2D06C049
:1004F00080E290E0B3010E9406041F5F1E15C0F366
:1005000004C01E1510F4E11A01C0EE2404FF0FC050
:1005100080E390E0B3010E94060402FF1DC001FDCC
:1005200003C088E790E00EC088E590E00BC0802F04
:10053000867891F001FF02C08BE201C080E2F7FCF7
:100540008DE290E0B3010E94060406C080E390E0D3
:10055000B3010E9406049A94D914C0F3DA94F1010D
:10056000ED0DF11D808190E0B3010E940604DD20B5
:10057000A9F706C080E290E0B3010E940604EA9465
:10058000EE20C1F743CEF30166817781CB012B9634
:10059000E2E10C94D8090F931F93CF93DF93689FE8
:1005A0008001699F100D789F100D1124C8010E94D1
:1005B000E702EC01009729F060E070E0A8010E94DA
:1005C000F403CE01DF91CF911F910F910895CF9346
:1005D000DF93BC018230910510F462E070E0A091DD
:1005E000EF02B091F002ED01E0E0F0E040E050E019
:1005F00021C0888199818617970769F48A819B8138
:10060000309719F09383828304C09093F002809313
:10061000EF02FE0134C06817790738F4411551051F
:1006200019F08417950708F4AC01FE018A819B81BB
:100630009C01E9012097E9F641155105A9F1CA018C
:10064000861B970B049708F4BA01E0E0F0E02AC09B
:100650008D919C91119784179507F9F4641775078C
:1006600081F412968D919C911397309719F0938392
:10067000828304C09093F0028093EF02FD013296D2
:100680004CC0CA01861B970BFD01E80FF91F61934F
:10069000719302978D939C9340C0FD018281938159
:1006A0009C01D9011097A1F68091ED029091EE0284
:1006B000892B41F480912301909124019093EE02C3
:1006C0008093ED024091250150912601411551057D
:1006D00041F44DB75EB78091210190912201481BF2
:1006E000590B2091ED023091EE02CA01821B930B4F
:1006F0008617970780F0AB014E5F5F4F8417950711
:1007000050F0420F531F5093EE024093ED02F90157
:100710006193719302C0E0E0F0E0CF01DF91CF91EF
:100720000895CF93DF93009709F450C0EC0122970E
:100730001B821A82A091EF02B091F002109709F18A
:1007400040E050E0AC17BD0708F1BB83AA83FE016F
:1007500021913191E20FF31FAE17BF0779F48D910C
:100760009C911197280F391F2E5F3F4F39832883A3
:1007700012968D919C9113979B838A834115510505
:1007800071F4D093F002C093EF0220C012968D91C5
:100790009C911397AD01009711F0DC01D3CFFA01C2
:1007A000D383C28321913191E20FF31FCE17DF076C
:1007B00069F488819981280F391F2E5F3F4FFA0114
:1007C000318320838A819B8193838283DF91CF91C0
:1007D0000895FC010590615070400110D8F7809594
:1007E00090958E0F9F1F0895DC0101C06D934150BD
:1007F0005040E0F70895FC016150704001900110F5
:10080000D8F7809590958E0F9F1F08950F931F9393
:10081000CF93DF938C01EB018B8181FF1BC082FFA3
:100820000DC02E813F818C819D812817390764F48A
:10083000E881F9810193F983E88306C0E885F985A9
:10084000802F0995892B31F48E819F8101969F839A
:100850008E8302C00FEF1FEFC801DF91CF911F9170
:100860000F910895FA01AA27283051F1203181F122
:10087000E8946F936E7F6E5F7F4F8F4F9F4FAF4FA8
:10088000B1E03ED0B4E03CD0670F781F891F9A1FBB
:10089000A11D680F791F8A1F911DA11D6A0F711D6F
:1008A000811D911DA11D20D009F468943F912AE07B
:1008B000269F11243019305D3193DEF6CF01089563
:1008C000462F4770405D4193B3E00FD0C9F7F6CF94
:1008D000462F4F70405D4A3318F0495D31FD40525C
:1008E000419302D0A9F7EACFB4E0A69597958795F2
:1008F00077956795BA95C9F70097610571050895D1
:100900009B01AC010A2E069457954795379527957C
:10091000BA95C9F7620F731F841F951FA01D089514
:100920008AE391E068E049E00E9475070895FF922C
:100930000F931F93CF93DF9380E8E7E4F1E0DF01AB
:100940001D928A95E9F704E610E021C08AE391E060
:100950006F2D0E94F2078AE391E00E94840880E8EC
:1009600090E00E94D7058AE391E00E947C078AE329
:1009700091E00E944608882329F088819981019698
:10098000998388832297FA94BFEFFB16F9F60150FA
:100990001040EFEF0F3F1E0729F0C5E4D2E08FE7CC
:1009A000F82ED4CFC7E4D1E000E011E000D000D0B1
:1009B000ADB7BEB712961C930E931197899199917A
:1009C0008F70907014969C938E9313970E94D90009
:1009D0000F900F900F900F90B2E0C734DB0731F704
:1009E00000D083E091E0EDB7FEB7928381830E944F
:1009F000D9000F900F90DF91CF911F910F91FF9031
:100A0000089580E895E060E070E00E948D00089510
:100A10000F931F93CF93DF9384ED92E040E051EE6C
:100A200060E070E00E9454060E94010500D086E05C
:100A300091E0EDB7FEB7928381830E94D9000F90B9
:100A40000F908AE391E00E944B088AE391E060E016
:100A50000E94E8078AE391E00E9484088AE391E01B
:100A60000E947C07C0E0D0E000E011E000D000D0A0
:100A7000EDB7FEB712830183CE0124E095958795EB
:100A80002A95E1F7948383830E94D90021960F90E1
:100A90000F900F900F90C038D10541F700D083E040
:100AA00091E0EDB7FEB7928381830E94D900C0E048
:100AB000D0E00F900F9000D000D0EDB7FEB70183CB
:100AC0001283CE018F709070948383830E94D9002B
:100AD00021960F900F900F900F90C038D10559F7C5
:100AE00000D083E091E0EDB7FEB7928381830E944E
:100AF000D9000F900F90DF91CF911F910F91089522
:100B00000F931F93082F84ED92E0602F0E94280717
:100B1000112707FD1095C8011F910F9108951F928D
:100B20000F920FB60F9211242F933F938F939F93A1
:100B3000AF93BF9380914B0290914C02A0914D02D4
:100B4000B0914E0230914F020196A11DB11D232F8D
:100B50002D5F2D3720F02D570196A11DB11D20933B
:100B60004F0280934B0290934C02A0934D02B0939E
:100B70004E028091470290914802A0914902B091A3
:100B80004A020196A11DB11D80934702909348022D
:100B9000A0934902B0934A02BF91AF919F918F9168
:100BA0003F912F910F900FBE0F901F9018950197B6
:100BB00039F0880F991F880F991F02970197F1F755
:100BC0000895789484B5826084BD84B5816084BDC5
:100BD00085B5826085BD85B5816085BDEEE6F0E0B6
:100BE000808181608083E1E8F0E010828081826012
:100BF0008083808181608083E0E8F0E08081816093
:100C00008083E1EBF0E0808184608083E0EBF0E0C2
:100C1000808181608083EAE7F0E080818460808366
:100C20008081826080838081816080838081806810
:100C300080831092C10008950E94E1050E9408057A
:100C40000E949704FDCF1F920F920FB60F921124AE
:100C50002F933F934F938F939F93EF93FF934091E5
:100C6000C600E091D002F091D10231969F012F771A
:100C7000307031978091D2029091D30228173907B2
:100C800039F0E05BFD4F40833093D1022093D002D6
:100C9000FF91EF919F918F914F913F912F910F90E5
:100CA0000FBE0F901F901895AF92BF92DF92EF92F8
:100CB000FF920F931F93CF93DF93EC017A018B0187
:100CC000DD24403081EE580780E0680780E0780737
:100CD00011F0DD24D39491E0A92EB12CE885F9859B
:100CE000DD2069F0C5010A8802C0880F991F0A94A7
:100CF000E2F7808360E079E08DE390E005C0108248
:100D000060E874E88EE190E0A80197010E949A09DA
:100D10002150304040405040569547953795279593
:100D200080E12030380720F0DD2011F0DD24D6CF1F
:100D3000EC81FD813083EE81FF812083EA85FB8594
:100D4000208141E050E0CA010E8402C0880F991F43
:100D50000A94E2F7282B2083EA85FB852081CA01CB
:100D60000F8402C0880F991F0A94E2F7282B208372
:100D7000EA85FB858081088802C0440F551F0A94CC
:100D8000E2F7842B8083DF91CF911F910F91FF9029
:100D9000EF90DF90BF90AF900895DC011296ED9137
:100DA000FC911397E058FF4F2191319180819181FF
:100DB000281B390B2F773070C9010895DC0112967A
:100DC000ED91FC911397EE57FF4F20813181929165
:100DD0008291E058F0408217930719F42FEF3FEF0C
:100DE00005C0E20FF31F8081282F30E0C90108956C
:100DF000DC011296ED91FC911397DF01AE57BF4FC6
:100E00002D913C911197E058FF4F80819181E058DE
:100E1000F0408217930719F42FEF3FEF0BC0E20F5A
:100E2000F31F80812F5F3F4F2F7730702D933C93BE
:100E3000282F30E0C9010895DC011296ED91FC9154
:100E40001397EE57FF4F808191819293829308957B
:100E5000FC01A085B18521898C9190E0022E02C011
:100E6000959587950A94E2F780FFF6CF0484F5857F
:100E7000E02D608308958BE291E09093D5028093FA
:100E8000D40280E592E09093D7028093D60285EC5D
:100E900090E09093D9028093D80284EC90E09093F4
:100EA000DB028093DA0280EC90E09093DD02809385
:100EB000DC0281EC90E09093DF028093DE0286EC0E
:100EC00090E09093E1028093E00284E08093E2025C
:100ED00083E08093E30287E08093E40285E08093DF
:100EE000E50281E08093E6020895FC01608341837E
:100EF00080E2828313820895FC01808160E00E9479
:100F0000CD080895FF920F931F938C01F62E80E079
:100F10000E94650985E00E946A09F80181816F2DB0
:100F20000E94CD081F910F91FF9008951F93CF93BA
:100F3000DF93EC0160E070E00E94820781EE8EBDDD
:100F40000DB407FEFDCF1EB5CE0161E070E00E943A
:100F50008207812FDF91CF911F9108951F93CF9327
:100F6000DF93EC0160E070E00E94820782EE8EBDAC
:100F70000DB407FEFDCF1EB5CE0161E070E00E940A
:100F80008207812FDF91CF911F9108950F931F93B7
:100F9000CF93DF93EC01162F042F60E070E00E94E6
:100FA00082071F7110621EBD0DB407FEFDCF1EB576
:100FB0000EBD0DB407FEFDCF8EB5CE0161E070E031
:100FC0000E948207812FDF91CF911F910F91089589
:100FD000662319F061E04FE302C061E040E00E9447
:100FE000C6070895462F603808F04FE765E00E9475
:100FF000C6070895EF92FF920F931F93CF93DF934D
:101000007C01162FEA01022F60E070E00E94820747
:101010001F7110621EBD0DB407FEFDCF1EB508C0C6
:1010200088818EBD0DB407FEFDCF21968EB501508F
:101030000023B1F7C70161E070E00E948207812FB1
:10104000DF91CF911F910F91FF90EF9008951F9323
:10105000CF93DF93EC01162F60E070E00E948207CF
:101060001F711EBD0DB407FEFDCF8EB58FEF8EBD77
:101070000DB407FEFDCF1EB5CE0161E070E00E9409
:101080008207812FDF91CF911F91089569E00E941F
:101090002708817008950F931F938C01FC018081B4
:1010A00061E00E94A708F801818161E00E94A70821
:1010B000F801808160E00E94CD08C80161E070E025
:1010C0000E9482070E947B0981E00E945C0980E007
:1010D0000E94650985E00E946A09C80164E04FEF3B
:1010E0000E94C607C80167E040E70E94C607C80122
:1010F0000E94AE07C8010E949607C80161E00E94E5
:10110000F2071F910F9108950F931F938C0160E0D8
:101110004BE00E94C607C80167E040E70E94C6078F
:10112000A8014B5F5F4FC8016AE025E00E94FA0703
:10113000C8010E94AE07F801808161E00E94CD08DD
:1011400082E890E00E94D7051F910F910895482FE3
:1011500050E0CA0186569F4FFC0124914A575F4FC9
:10116000FA0184918823C1F0E82FF0E0EE0FFF1F11
:10117000E859FF4FA591B491662341F49FB7F894C5
:101180008C91209582238C939FBF08959FB7F894EC
:101190008C91822B8C939FBF0895482F50E0CA01F9
:1011A00082559F4FFC012491CA0186569F4FFC0136
:1011B00034914A575F4FFA019491992309F444C03E
:1011C000222351F1233071F0243028F42130A1F092
:1011D000223011F514C02630B1F02730C1F0243090
:1011E000D9F404C0809180008F7703C08091800083
:1011F0008F7D8093800010C084B58F7702C084B546
:101200008F7D84BD09C08091B0008F7703C080912D
:10121000B0008F7D8093B000E92FF0E0EE0FFF1F4C
:10122000EE58FF4FA591B491662341F49FB7F8940F
:101230008C91309583238C939FBF08959FB7F8942A
:101240008C91832B8C939FBF08950F931F93CF9303
:10125000DF938C01EB0109C02196D801ED91FC913F
:101260000190F081E02DC801099568816623A1F7FE
:10127000DF91CF911F910F910895EF92FF920F93FD
:101280001F93CF93DF938C017B01EA010CC0D70140
:101290006D917D01D801ED91FC910190F081E02DDF
:1012A000C80109952197209791F7DF91CF911F9160
:1012B0000F91FF90EF900895882319F48CB5806208
:1012C00002C08CB58F7D8CBD08959CB5937F982B03
:1012D0009CBD08952CB5382F33702C7F322B3CBD2C
:1012E0002DB590E0959587959595879581702E7F82
:1012F000822B8DBD08958DE061E00E94A7088BE0F0
:1013000061E00E94A7088AE061E00E94A7088DE0E2
:1013100060E00E94CD088BE060E00E94CD088AE08A
:1013200061E00E94CD088CB580618CBD8CB5806475
:101330008CBD0895A1E21A2EAA1BBB1BFD010DC096
:10134000AA1FBB1FEE1FFF1FA217B307E407F50775
:1013500020F0A21BB30BE40BF50B661F771F881F51
:10136000991F1A9469F760957095809590959B01E7
:10137000AC01BD01CF0108952F923F924F925F9231
:101380006F927F928F929F92AF92BF92CF92DF9295
:10139000EF92FF920F931F93CF93DF93CDB7DEB7FA
:1013A000CA1BDB0B0FB6F894DEBF0FBECDBF09948E
:1013B0002A88398848885F846E847D848C849B84E5
:1013C000AA84B984C884DF80EE80FD800C811B81F3
:1013D000AA81B981CE0FD11D0FB6F894DEBF0FBE22
:1013E000CDBFED010895EE0FFF1F0590F491E02DA4
:0613F0000994F894FFCF00
:1013F6002578000A0D000A0D524632342F657861B1
:101406006D706C65732F7363616E6E65722F0A0D56
:10141600002000F102000000000000280725093D19
:0A14260009CD06F806DE061C0700DB
:00000001FF
+31
View File
@@ -0,0 +1,31 @@
/*
Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
*/
/**
* @file printf.h
*
* Setup necessary to direct stdout to the Arduino Serial library, which
* enables 'printf'
*/
#ifndef __PRINTF_H__
#define __PRINTF_H__
int serial_putc( char c, FILE * )
{
Serial.write( c );
return c;
}
void printf_begin(void)
{
fdevopen( &serial_putc, 0 );
}
#endif // __PRINTF_H__
+126
View File
@@ -0,0 +1,126 @@
/*
Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
*/
/**
* Channel scanner
*
* Example to detect interference on the various channels available.
* This is a good diagnostic tool to check whether you're picking a
* good channel for your application.
*
* Inspired by cpixip.
* See http://arduino.cc/forum/index.php/topic,54795.0.html
*/
#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"
#include "printf.h"
//
// Hardware configuration
//
// Set up nRF24L01 radio on SPI bus plus pins 9 & 10
RF24 radio(9,10);
//
// Channel info
//
const uint8_t num_channels = 128;
uint8_t values[num_channels];
//
// Setup
//
void setup(void)
{
//
// Print preamble
//
Serial.begin(57600);
printf_begin();
printf("\n\rRF24/examples/scanner/\n\r");
//
// Setup and configure rf radio
//
radio.begin();
radio.setAutoAck(false);
// Get into standby mode
radio.startListening();
radio.stopListening();
// Print out header, high then low digit
int i = 0;
while ( i < num_channels )
{
printf("%x",i>>4);
++i;
}
printf("\n\r");
i = 0;
while ( i < num_channels )
{
printf("%x",i&0xf);
++i;
}
printf("\n\r");
}
//
// Loop
//
const int num_reps = 100;
void loop(void)
{
// Clear measurement values
memset(values,0,sizeof(values));
// Scan all channels num_reps times
int rep_counter = num_reps;
while (rep_counter--)
{
int i = num_channels;
while (i--)
{
// Select this channel
radio.setChannel(i);
// Listen for a little
radio.startListening();
delayMicroseconds(225);
// Did we get a carrier?
if ( radio.testCarrier() ){
++values[i];
}
radio.stopListening();
}
}
// Print out channel measurements, clamped to a single hex digit
int i = 0;
while ( i < num_channels )
{
printf("%x",min(0xf,values[i]&0xf));
++i;
}
printf("\n\r");
}
// vim:ai:cin:sts=2 sw=2 ft=cpp
+206
View File
@@ -0,0 +1,206 @@
PROJECT_NAME = $(PWD:B) ;
PROJECT_DIR = . ;
PROJECT_LIBS = EEPROM SPI RF24 ;
OUT_DIR = ojam ;
F_CPU = 16000000 ;
MCU = atmega328p ;
PORTS = /dev/tty.usbserial-A600eHIs /dev/tty.usbserial-A40081RP /dev/tty.usbserial-A9007LmI ;
UPLOAD_RATE = 57600 ;
AVRDUDE_PROTOCOL = stk500v1 ;
COM = 33 ;
# Host-specific overrides for locations
if $(OS) = MACOSX
{
ARDUINO_VERSION = 22 ;
OLD_DIR = /opt/arduino-0021 ;
AVR_TOOLS_PATH = $(OLD_DIR)/hardware/tools/avr/bin ;
AVRDUDECONFIG_PATH = $(OLD_DIR)/hardware/tools/avr/etc ;
ARDUINO_DIR = /opt/Arduino ;
ARDUINO_AVR = /usr/lib/avr/include ;
}
# Where is everything?
ARDUINO_VERSION ?= 22 ;
AVR_TOOLS_PATH ?= /usr/bin ;
ARDUINO_DIR ?= /opt/arduino-00$(ARDUINO_VERSION) ;
ARDUINO_AVR ?= $(ARDUINO_DIR)/hardware/tools/avr/avr/include/avr ;
AVRDUDECONFIG_PATH ?= $(ARDUINO_DIR)/hardware/tools ;
ARDUINO_CORE = $(ARDUINO_DIR)/hardware/arduino/cores/arduino ;
ARDUINO_LIB = $(ARDUINO_DIR)/libraries ;
SKETCH_LIB = $(HOME)/Source/Arduino/libraries ;
AVR_CC = $(AVR_TOOLS_PATH)/avr-gcc ;
AVR_CXX = $(AVR_TOOLS_PATH)/avr-g++ ;
AVR_LD = $(AVR_TOOLS_PATH)/avr-gcc ;
AVR_OBJCOPY = $(AVR_TOOLS_PATH)/avr-objcopy ;
AVRDUDE = $(AVR_TOOLS_PATH)/avrdude ;
DEFINES = F_CPU=$(F_CPU)L ARDUINO=$(ARDUINO_VERSION) VERSION_H ;
CTUNING = -ffunction-sections -fdata-sections ;
CXXTUNING = -fno-exceptions -fno-strict-aliasing ;
CFLAGS = -Os -Wall -Wextra -mmcu=$(MCU) $(CTUNING) ;
CXXFLAGS = $(CFLAGS) $(CXXTUNING) ;
LDFLAGS = -Os -lm -Wl,--gc-sections -mmcu=atmega328p ;
# Search everywhere for headers
HDRS = $(PROJECT_DIR) $(ARDUINO_AVR) $(ARDUINO_CORE) [ GLOB $(ARDUINO_LIB) $(SKETCH_LIB) : [^.]* ] ;
# Grab everything from the core directory
CORE_MODULES = [ GLOB $(ARDUINO_CORE) : *.c *.cpp ] ;
# Grab everything from libraries. To avoid this "grab everything" behaviour, you
# can specify specific modules to pick up in PROJECT_MODULES
LIB_MODULES = [ GLOB $(ARDUINO_LIB)/$(PROJECT_LIBS) $(SKETCH_LIB)/$(PROJECT_LIBS) : *.cpp ] ;
# In addition to explicitly-specified program modules, pick up anything from the current
# dir.
PROJECT_MODULES += [ GLOB $(PROJECT_DIR) : *.c *.cpp *.pde ] ;
# Shortcut for the out files
OUT = $(OUT_DIR)/$(PROJECT_NAME) ;
# AvrDude setup
AVRDUDE_FLAGS = -V -F -D -C $(AVRDUDECONFIG_PATH)/avrdude.conf -p $(MCU) -c $(AVRDUDE_PROTOCOL) -b $(UPLOAD_RATE) ;
rule GitVersion
{
Always $(<) ;
Depends all : $(<) ;
}
actions GitVersion
{
echo "const char program_version[] = \"\\" > $(<)
git log -1 --pretty=format:%h >> $(<)
echo "\";" >> $(<)
}
GitVersion version.h ;
rule AvrCc
{
Depends $(<) : $(>) ;
Depends $(<) : $(<:D) ;
Clean clean : $(<) ;
CCHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] ;
CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ;
}
actions AvrCc
{
$(AVR_CC) -c -o $(<) $(CCHDRS) $(CCDEFS) $(CFLAGS) $(>)
}
rule AvrC++
{
Depends $(<) : $(>) ;
Depends $(<) : $(<:D) ;
Clean clean : $(<) ;
CCHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] ;
CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ;
}
actions AvrC++
{
$(AVR_CXX) -c -o $(<) $(CCHDRS) $(CCDEFS) $(CXXFLAGS) $(>)
}
rule Pde
{
Depends $(<) : $(>) ;
Depends $(<) : $(<:D) ;
Clean clean : $(<) ;
}
actions Pde
{
echo "#include <WProgram.h>" > $(<)
echo "#line 1 \"$(>)\"" >> $(<)
cat $(>) >> $(<)
}
rule AvrPde
{
local _CPP = $(OUT_DIR)/$(_I:B).cpp ;
Pde $(_CPP) : $(>) ;
AvrC++ $(<) : $(_CPP) ;
}
rule AvrObject
{
switch $(>:S)
{
case .c : AvrCc $(<) : $(>) ;
case .cpp : AvrC++ $(<) : $(>) ;
case .pde : AvrPde $(<) : $(>) ;
}
}
rule AvrObjects
{
for _I in $(<)
{
AvrObject $(OUT_DIR)/$(_I:B).o : $(_I) ;
}
}
rule AvrMainFromObjects
{
Depends $(<) : $(>) ;
Depends $(<) : $(<:D) ;
MkDir $(<:D) ;
Depends all : $(<) ;
Clean clean : $(<) ;
}
actions AvrMainFromObjects
{
$(AVR_LD) $(LDFLAGS) -o $(<) $(>)
}
rule AvrMain
{
AvrMainFromObjects $(<) : $(OUT_DIR)/$(>:B).o ;
AvrObjects $(>) ;
}
rule AvrHex
{
Depends $(<) : $(>) ;
Depends $(<) : $(<:D) ;
Depends hex : $(<) ;
Clean clean : $(<) ;
}
actions AvrHex
{
$(AVR_OBJCOPY) -O ihex -R .eeprom $(>) $(<)
}
rule AvrUpload
{
Depends $(1) : $(2) ;
Depends $(2) : $(3) ;
NotFile $(1) ;
Always $(1) ;
Always $(2) ;
AvrUploadAction $(2) : $(3) ;
}
actions AvrUploadAction
{
$(AVRDUDE) $(AVRDUDE_FLAGS) -P $(<) $(AVRDUDE_WRITE_FLASH) -U flash:w:$(>):i
}
AvrMain $(OUT).elf : $(CORE_MODULES) $(LIB_MODULES) $(PROJECT_MODULES) ;
AvrHex $(OUT).hex : $(OUT).elf ;
AvrUpload p6 : /dev/tty.usbserial-A600eHIs : $(OUT).hex ;
AvrUpload p4 : /dev/tty.usbserial-A40081RP : $(OUT).hex ;
AvrUpload p9 : /dev/tty.usbserial-A9007LmI : $(OUT).hex ;
+37
View File
@@ -0,0 +1,37 @@
/*
Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
*/
/**
* @file printf.h
*
* Setup necessary to direct stdout to the Arduino Serial library, which
* enables 'printf'
*/
#ifndef __PRINTF_H__
#define __PRINTF_H__
#ifdef ARDUINO
int serial_putc( char c, FILE * )
{
Serial.write( c );
return c;
}
void printf_begin(void)
{
fdevopen( &serial_putc, 0 );
}
#else
#error This example is only for use on Arduino.
#endif // ARDUINO
#endif // __PRINTF_H__
@@ -0,0 +1,293 @@
/*
Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
*/
/**
* Example RF Radio Ping Star Group
*
* This sketch is a more complex example of using the RF24 library for Arduino.
* Deploy this on up to six nodes. Set one as the 'pong receiver' by tying the
* role_pin low, and the others will be 'ping transmit' units. The ping units
* unit will send out the value of millis() once a second. The pong unit will
* respond back with a copy of the value. Each ping unit can get that response
* back, and determine how long the whole cycle took.
*
* This example requires a bit more complexity to determine which unit is which.
* The pong receiver is identified by having its role_pin tied to ground.
* The ping senders are further differentiated by a byte in eeprom.
*/
#include <SPI.h>
#include <EEPROM.h>
#include "nRF24L01.h"
#include "RF24.h"
#include "printf.h"
//
// Hardware configuration
//
// Set up nRF24L01 radio on SPI bus plus pins 9 & 10
RF24 radio(9,10);
// sets the role of this unit in hardware. Connect to GND to be the 'pong' receiver
// Leave open to be the 'pong' receiver.
const int role_pin = 7;
//
// Topology
//
// Radio pipe addresses for the nodes to communicate. Only ping nodes need
// dedicated pipes in this topology. Each ping node has a talking pipe
// that it will ping into, and a listening pipe that it will listen for
// the pong. The pong node listens on all the ping node talking pipes
// and sends the pong back on the sending node's specific listening pipe.
const uint64_t talking_pipes[5] = { 0xF0F0F0F0D2LL, 0xF0F0F0F0C3LL, 0xF0F0F0F0B4LL, 0xF0F0F0F0A5LL, 0xF0F0F0F096LL };
const uint64_t listening_pipes[5] = { 0x3A3A3A3AD2LL, 0x3A3A3A3AC3LL, 0x3A3A3A3AB4LL, 0x3A3A3A3AA5LL, 0x3A3A3A3A96LL };
//
// 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_invalid = 0, role_ping_out, 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;
//
// Address management
//
// Where in EEPROM is the address stored?
const uint8_t address_at_eeprom_location = 0;
// What is our address (SRAM cache of the address from EEPROM)
// Note that zero is an INVALID address. The pong back unit takes address
// 1, and the rest are 2-6
uint8_t node_address;
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;
//
// Address
//
if ( role == role_pong_back )
node_address = 1;
else
{
// Read the address from EEPROM
uint8_t reading = EEPROM.read(address_at_eeprom_location);
// If it is in a valid range for node addresses, it is our
// address.
if ( reading >= 2 && reading <= 6 )
node_address = reading;
// Otherwise, it is invalid, so set our address AND ROLE to 'invalid'
else
{
node_address = 0;
role = role_invalid;
}
}
//
// Print preamble
//
Serial.begin(57600);
printf_begin();
printf("\n\rRF24/examples/starping/\n\r");
printf("ROLE: %s\n\r",role_friendly_name[role]);
printf("ADDRESS: %i\n\r",node_address);
//
// Setup and configure rf radio
//
radio.begin();
//
// Open pipes to other nodes for communication
//
// The pong node listens on all the ping node talking pipes
// and sends the pong back on the sending node's specific listening pipe.
if ( role == role_pong_back )
{
radio.openReadingPipe(1,talking_pipes[0]);
radio.openReadingPipe(2,talking_pipes[1]);
radio.openReadingPipe(3,talking_pipes[2]);
radio.openReadingPipe(4,talking_pipes[3]);
radio.openReadingPipe(5,talking_pipes[4]);
}
// Each ping node has a talking pipe that it will ping into, and a listening
// pipe that it will listen for the pong.
if ( role == role_ping_out )
{
// Write on our talking pipe
radio.openWritingPipe(talking_pipes[node_address-2]);
// Listen on our listening pipe
radio.openReadingPipe(1,listening_pipes[node_address-2]);
}
//
// Start listening
//
radio.startListening();
//
// Dump the configuration of the rf unit for debugging
//
radio.printDetails();
//
// Prompt the user to assign a node address if we don't have one
//
if ( role == role_invalid )
{
printf("\n\r*** NO NODE ADDRESS ASSIGNED *** Send 1 through 6 to assign an address\n\r");
}
}
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
uint8_t pipe_num;
if ( radio.available(&pipe_num) )
{
// 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 from node %i...",got_time,pipe_num+1);
}
// First, stop listening so we can talk
radio.stopListening();
// Open the correct pipe for writing
radio.openWritingPipe(listening_pipes[pipe_num-1]);
// Retain the low 2 bytes to identify the pipe for the spew
uint16_t pipe_id = listening_pipes[pipe_num-1] & 0xffff;
// Send the final one back.
radio.write( &got_time, sizeof(unsigned long) );
printf("Sent response to %04x.\n\r",pipe_id);
// Now, resume listening so we catch the next packets.
radio.startListening();
}
}
//
// Listen for serial input, which is how we set the address
//
if (Serial.available())
{
// If the character on serial input is in a valid range...
char c = Serial.read();
if ( c >= '1' && c <= '6' )
{
// It is our address
EEPROM.write(address_at_eeprom_location,c-'0');
// And we are done right now (no easy way to soft reset)
printf("\n\rManually reset address to: %c\n\rPress RESET to continue!",c);
while(1) ;
}
}
}
// vim:ai:ci sts=2 sw=2 ft=cpp
+16
View File
@@ -0,0 +1,16 @@
RF24 KEYWORD1
begin KEYWORD2
setChannel KEYWORD2
setPayloadSize KEYWORD2
getPayloadSize KEYWORD2
print_details KEYWORD2
startListening KEYWORD2
stopListening KEYWORD2
write KEYWORD2
writeFast KEYWORD2
writeBlocking KEYWORD2
txStandBy KEYWORD2
available KEYWORD2
read KEYWORD2
openWritingPipe KEYWORD2
openReadingPipe KEYWORD2
+127
View File
@@ -0,0 +1,127 @@
/*
Copyright (c) 2007 Stefan Engelke <mbox@stefanengelke.de>
Portions Copyright (C) 2011 Greg Copeland
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
/* Memory Map */
#define CONFIG 0x00
#define EN_AA 0x01
#define EN_RXADDR 0x02
#define SETUP_AW 0x03
#define SETUP_RETR 0x04
#define RF_CH 0x05
#define RF_SETUP 0x06
#define STATUS 0x07
#define OBSERVE_TX 0x08
#define CD 0x09
#define RX_ADDR_P0 0x0A
#define RX_ADDR_P1 0x0B
#define RX_ADDR_P2 0x0C
#define RX_ADDR_P3 0x0D
#define RX_ADDR_P4 0x0E
#define RX_ADDR_P5 0x0F
#define TX_ADDR 0x10
#define RX_PW_P0 0x11
#define RX_PW_P1 0x12
#define RX_PW_P2 0x13
#define RX_PW_P3 0x14
#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
#define MASK_TX_DS 5
#define MASK_MAX_RT 4
#define EN_CRC 3
#define CRCO 2
#define PWR_UP 1
#define PRIM_RX 0
#define ENAA_P5 5
#define ENAA_P4 4
#define ENAA_P3 3
#define ENAA_P2 2
#define ENAA_P1 1
#define ENAA_P0 0
#define ERX_P5 5
#define ERX_P4 4
#define ERX_P3 3
#define ERX_P2 2
#define ERX_P1 1
#define ERX_P0 0
#define AW 0
#define ARD 4
#define ARC 0
#define PLL_LOCK 4
#define RF_DR 3
#define RF_PWR 6
#define RX_DR 6
#define TX_DS 5
#define MAX_RT 4
#define RX_P_NO 1
#define TX_FULL 0
#define PLOS_CNT 4
#define ARC_CNT 0
#define TX_REUSE 6
#define FIFO_FULL 5
#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
#define NOP 0xFF
/* Non-P omissions */
#define LNA_HCURR 0
/* P model memory Map */
#define RPD 0x09
#define W_TX_PAYLOAD_NO_ACK 0xB0
/* P model bit Mnemonics */
#define RF_DR_LOW 5
#define RF_DR_HIGH 3
#define RF_PWR_LOW 1
#define RF_PWR_HIGH 2
+7
View File
@@ -0,0 +1,7 @@
The sketches in this directory are intended to be checkin tests.
No code should be pushed to github without these tests passing.
See "runtests.sh" script inside each sketch dir. This script is fully compatible with
git bisest.
Note that this requires python and py-serial
+300
View File
@@ -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 <WProgram.h>" > $(<)
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) ;
@@ -0,0 +1,223 @@
/*
Copyright (C) 2011 James Coliz, Jr. <maniacbug@ymail.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
*/
/**
* 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 <SPI.h>
#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
+33
View File
@@ -0,0 +1,33 @@
/*
Copyright (C) 2011 James Coliz, Jr. <maniacbug@ymail.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
*/
/**
* @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__
@@ -0,0 +1,219 @@
# (1) Project Information
PROJECT_LIBS = SPI RF24 ;
PROJECT_DIRS = $(PWD) ;
# (2) Board Information
UPLOAD_PROTOCOL ?= arduino ;
UPLOAD_SPEED ?= 115200 ;
MCU ?= atmega328p ;
F_CPU ?= 16000000 ;
CORE ?= arduino ;
VARIANT ?= standard ;
ARDUINO_VERSION ?= 100 ;
# (3) USB Ports
PORTS = p4 p6 p9 u0 u1 u2 ;
PORT_p6 = /dev/tty.usbserial-A600eHIs ;
PORT_p4 = /dev/tty.usbserial-A40081RP ;
PORT_p9 = /dev/tty.usbserial-A9007LmI ;
PORT_u0 = /dev/ttyUSB0 ;
PORT_u1 = /dev/ttyUSB1 ;
PORT_u2 = /dev/ttyUSB2 ;
# (4) Location of AVR tools
#
# This configuration assumes using avr-tools that were obtained separate from the Arduino
# distribution.
if $(OS) = MACOSX
{
AVR_BIN ?= /usr/local/avrtools/bin ;
AVR_ETC = /usr/local/avrtools/etc ;
AVR_INCLUDE = /usr/local/avrtools/include ;
}
else
{
AVR_BIN ?= /usr/bin ;
AVR_INCLUDE = /usr/lib/avr/include ;
AVR_ETC = /etc ;
}
# (5) Directories where Arduino core and libraries are located
ARDUINO_DIR ?= /opt/Arduino ;
ARDUINO_CORE = $(ARDUINO_DIR)/hardware/arduino/cores/$(CORE) $(ARDUINO_DIR)/hardware/arduino/variants/$(VARIANT) ;
ARDUINO_LIB = $(ARDUINO_DIR)/libraries ;
SKETCH_LIB = $(HOME)/Source/Arduino/libraries ;
#
# --------------------------------------------------
# Below this line usually never needs to be modified
#
# Tool locations
CC = $(AVR_BIN)/avr-gcc ;
C++ = $(AVR_BIN)/avr-g++ ;
LINK = $(AVR_BIN)/avr-gcc ;
AR = $(AVR_BIN)/avr-ar rcs ;
RANLIB = ;
OBJCOPY = $(AVR_BIN)/avr-objcopy ;
AVRDUDE ?= $(AVR_BIN)/avrdude ;
# Flags
DEFINES += F_CPU=$(F_CPU)L ARDUINO=$(ARDUINO_VERSION) VERSION_H ;
OPTIM = -Os ;
CCFLAGS = -Wall -Wextra -Wno-strict-aliasing -mmcu=$(MCU) -ffunction-sections -fdata-sections ;
C++FLAGS = $(CCFLAGS) -fno-exceptions -fno-strict-aliasing ;
LINKFLAGS = $(OPTIM) -lm -Wl,--gc-sections -mmcu=$(MCU) ;
AVRDUDEFLAGS = -V -F -D -C $(AVR_ETC)/avrdude.conf -p $(MCU) -c $(UPLOAD_PROTOCOL) -b $(UPLOAD_SPEED) ;
# Search everywhere for headers
HDRS = $(PROJECT_DIRS) $(AVR_INCLUDE) $(ARDUINO_CORE) $(ARDUINO_LIB)/$(PROJECT_LIBS) $(ARDUINO_LIB)/$(PROJECT_LIBS)/utility $(SKETCH_LIB)/$(PROJECT_LIBS) ;
# Output locations
LOCATE_TARGET = $(F_CPU) ;
LOCATE_SOURCE = $(F_CPU) ;
#
# Custom rules
#
rule GitVersion
{
Always $(<) ;
Depends all : $(<) ;
}
actions GitVersion
{
echo "const char program_version[] = \"\\" > $(<)
git log -1 --pretty=format:%h >> $(<)
echo "\";" >> $(<)
}
GitVersion version.h ;
rule Pde
{
Depends $(<) : $(>) ;
MakeLocate $(<) : $(LOCATE_SOURCE) ;
Clean clean : $(<) ;
}
if ( $(ARDUINO_VERSION) < 100 )
{
ARDUINO_H = WProgram.h ;
}
else
{
ARDUINO_H = Arduino.h ;
}
actions Pde
{
echo "#include <$(ARDUINO_H)>" > $(<)
echo "#line 1 \"$(>)\"" >> $(<)
cat $(>) >> $(<)
}
rule C++Pde
{
local _CPP = $(>:B).cpp ;
Pde $(_CPP) : $(>) ;
C++ $(<) : $(_CPP) ;
}
rule UserObject
{
switch $(>:S)
{
case .ino : C++Pde $(<) : $(>) ;
case .pde : C++Pde $(<) : $(>) ;
}
}
rule Objects
{
local _i ;
for _i in [ FGristFiles $(<) ]
{
local _b = $(_i:B)$(SUFOBJ) ;
local _o = $(_b:G=$(SOURCE_GRIST:E)) ;
Object $(_o) : $(_i) ;
Depends obj : $(_o) ;
}
}
rule Library
{
LibraryFromObjects $(<) : $(>:B)$(SUFOBJ) ;
Objects $(>) ;
}
rule Main
{
MainFromObjects $(<) : $(>:B)$(SUFOBJ) ;
Objects $(>) ;
}
rule Hex
{
Depends $(<) : $(>) ;
MakeLocate $(<) : $(LOCATE_TARGET) ;
Depends hex : $(<) ;
Clean clean : $(<) ;
}
actions Hex
{
$(OBJCOPY) -O ihex -R .eeprom $(>) $(<)
}
rule Upload
{
Depends $(1) : $(2) ;
Depends $(2) : $(3) ;
NotFile $(1) ;
Always $(1) ;
Always $(2) ;
UploadAction $(2) : $(3) ;
}
actions UploadAction
{
$(AVRDUDE) $(AVRDUDEFLAGS) -P $(<) $(AVRDUDE_WRITE_FLASH) -U flash:w:$(>):i
}
rule Arduino
{
LINKFLAGS on $(<) = $(LINKFLAGS) -Wl,-Map=$(LOCATE_TARGET)/$(<:B).map ;
Main $(<) : $(>) ;
LinkLibraries $(<) : core libs ;
Hex $(<:B).hex : $(<) ;
for _p in $(PORTS)
{
Upload $(_p) : $(PORT_$(_p)) : $(<:B).hex ;
}
}
#
# Targets
#
# Grab everything from the core directory
Library core : [ GLOB $(ARDUINO_CORE) : *.c *.cpp ] ;
# Grab everything from libraries. To avoid this "grab everything" behaviour, you
# can specify specific modules to pick up in PROJECT_MODULES
Library libs : [ GLOB $(ARDUINO_LIB)/$(PROJECT_LIBS) $(ARDUINO_LIB)/$(PROJECT_LIBS)/utility $(SKETCH_LIB)/$(PROJECT_LIBS) : *.cpp *.c ] ;
# Main output executable
Arduino $(PWD:B).elf : $(PROJECT_MODULES) [ GLOB $(PROJECT_DIRS) : *.c *.cpp *.pde *.ino ] ;
@@ -0,0 +1,273 @@
/*
Copyright (C) 2011 James Coliz, Jr. <maniacbug@ymail.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
*/
#include <SPI.h>
#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(48,49);
// sets the role of this unit in hardware. Connect to GND to be the 'pong' receiver
// Leave open to be the 'ping' transmitter
const int role_pin = 5;
//
// Topology
//
// Radio pipe addresses for the 2 nodes to communicate.
const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };
//
// Role management
//
// Set up role. This sketch uses the same software for all the nodes
// in this system. Doing so greatly simplifies testing. The hardware itself specifies
// which node it is.
//
// This is done through the role_pin
//
// The various roles supported by this sketch
typedef enum { role_ping_out = 1, role_pong_back } role_e;
// The debug-friendly names of those roles
const char* role_friendly_name[] = { "invalid", "Ping out", "Pong back"};
// The role of the current running sketch
role_e role;
//
// 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();
if ( role == role_pong_back )
printf("\n\r+OK ");
}
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 (radio.available())
{
// Fetch the payload, and see if this was the last one.
radio.read( &got_time, sizeof(unsigned long) );
}
// 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();
// Spew it
printf("Got payload %lu...",got_time);
// Send the final one back.
radio.write( &got_time, sizeof(unsigned long) );
// Now, resume listening so we catch the next packets.
radio.startListening();
printf("Sent response.\n\r");
}
}
//
// 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
@@ -0,0 +1,37 @@
/*
Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
*/
/**
* @file printf.h
*
* Setup necessary to direct stdout to the Arduino Serial library, which
* enables 'printf'
*/
#ifndef __PRINTF_H__
#define __PRINTF_H__
#ifdef ARDUINO
int serial_putc( char c, FILE * )
{
Serial.write( c );
return c;
}
void printf_begin(void)
{
fdevopen( &serial_putc, 0 );
}
#else
#error This example is only for use on Arduino.
#endif // ARDUINO
#endif // __PRINTF_H__
+25
View File
@@ -0,0 +1,25 @@
#!/usr/bin/python
import sys,serial
def read_until(token):
while 1:
line = ser.readline(None)
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)
+5
View File
@@ -0,0 +1,5 @@
#!/bin/sh
# Connect u0 to receiver, u1 to sender
jam u0 u1 && expect test.ex
+11
View File
@@ -0,0 +1,11 @@
#/usr/bin/expect
set timeout 100
spawn picocom -b 57600 /dev/ttyUSB0
expect "+READY"
send "1"
expect "+OK"
spawn picocom -b 57600 /dev/ttyUSB1
expect "+READY"
send "1"
expect "+OK"
+219
View File
@@ -0,0 +1,219 @@
# (1) Project Information
PROJECT_LIBS = SPI RF24 ;
PROJECT_DIRS = $(PWD) ;
# (2) Board Information
UPLOAD_PROTOCOL ?= arduino ;
UPLOAD_SPEED ?= 115200 ;
MCU ?= atmega328p ;
F_CPU ?= 16000000 ;
CORE ?= arduino ;
VARIANT ?= standard ;
ARDUINO_VERSION ?= 100 ;
# (3) USB Ports
PORTS = p4 p6 p9 u0 u1 u2 ;
PORT_p6 = /dev/tty.usbserial-A600eHIs ;
PORT_p4 = /dev/tty.usbserial-A40081RP ;
PORT_p9 = /dev/tty.usbserial-A9007LmI ;
PORT_u0 = /dev/ttyUSB0 ;
PORT_u1 = /dev/ttyUSB1 ;
PORT_u2 = /dev/ttyUSB2 ;
# (4) Location of AVR tools
#
# This configuration assumes using avr-tools that were obtained separate from the Arduino
# distribution.
if $(OS) = MACOSX
{
AVR_BIN ?= /usr/local/avrtools/bin ;
AVR_ETC = /usr/local/avrtools/etc ;
AVR_INCLUDE = /usr/local/avrtools/include ;
}
else
{
AVR_BIN ?= /usr/bin ;
AVR_INCLUDE = /usr/lib/avr/include ;
AVR_ETC = /etc ;
}
# (5) Directories where Arduino core and libraries are located
ARDUINO_DIR ?= /opt/Arduino ;
ARDUINO_CORE = $(ARDUINO_DIR)/hardware/arduino/cores/$(CORE) $(ARDUINO_DIR)/hardware/arduino/variants/$(VARIANT) ;
ARDUINO_LIB = $(ARDUINO_DIR)/libraries ;
SKETCH_LIB = $(HOME)/Source/Arduino/libraries ;
#
# --------------------------------------------------
# Below this line usually never needs to be modified
#
# Tool locations
CC = $(AVR_BIN)/avr-gcc ;
C++ = $(AVR_BIN)/avr-g++ ;
LINK = $(AVR_BIN)/avr-gcc ;
AR = $(AVR_BIN)/avr-ar rcs ;
RANLIB = ;
OBJCOPY = $(AVR_BIN)/avr-objcopy ;
AVRDUDE ?= $(AVR_BIN)/avrdude ;
# Flags
DEFINES += F_CPU=$(F_CPU)L ARDUINO=$(ARDUINO_VERSION) VERSION_H ;
OPTIM = -Os ;
CCFLAGS = -Wall -Wextra -Wno-strict-aliasing -mmcu=$(MCU) -ffunction-sections -fdata-sections ;
C++FLAGS = $(CCFLAGS) -fno-exceptions -fno-strict-aliasing ;
LINKFLAGS = $(OPTIM) -lm -Wl,--gc-sections -mmcu=$(MCU) ;
AVRDUDEFLAGS = -V -F -D -C $(AVR_ETC)/avrdude.conf -p $(MCU) -c $(UPLOAD_PROTOCOL) -b $(UPLOAD_SPEED) ;
# Search everywhere for headers
HDRS = $(PROJECT_DIRS) $(AVR_INCLUDE) $(ARDUINO_CORE) $(ARDUINO_LIB)/$(PROJECT_LIBS) $(ARDUINO_LIB)/$(PROJECT_LIBS)/utility $(SKETCH_LIB)/$(PROJECT_LIBS) ;
# Output locations
LOCATE_TARGET = $(F_CPU) ;
LOCATE_SOURCE = $(F_CPU) ;
#
# Custom rules
#
rule GitVersion
{
Always $(<) ;
Depends all : $(<) ;
}
actions GitVersion
{
echo "const char program_version[] = \"\\" > $(<)
git log -1 --pretty=format:%h >> $(<)
echo "\";" >> $(<)
}
GitVersion version.h ;
rule Pde
{
Depends $(<) : $(>) ;
MakeLocate $(<) : $(LOCATE_SOURCE) ;
Clean clean : $(<) ;
}
if ( $(ARDUINO_VERSION) < 100 )
{
ARDUINO_H = WProgram.h ;
}
else
{
ARDUINO_H = Arduino.h ;
}
actions Pde
{
echo "#include <$(ARDUINO_H)>" > $(<)
echo "#line 1 \"$(>)\"" >> $(<)
cat $(>) >> $(<)
}
rule C++Pde
{
local _CPP = $(>:B).cpp ;
Pde $(_CPP) : $(>) ;
C++ $(<) : $(_CPP) ;
}
rule UserObject
{
switch $(>:S)
{
case .ino : C++Pde $(<) : $(>) ;
case .pde : C++Pde $(<) : $(>) ;
}
}
rule Objects
{
local _i ;
for _i in [ FGristFiles $(<) ]
{
local _b = $(_i:B)$(SUFOBJ) ;
local _o = $(_b:G=$(SOURCE_GRIST:E)) ;
Object $(_o) : $(_i) ;
Depends obj : $(_o) ;
}
}
rule Library
{
LibraryFromObjects $(<) : $(>:B)$(SUFOBJ) ;
Objects $(>) ;
}
rule Main
{
MainFromObjects $(<) : $(>:B)$(SUFOBJ) ;
Objects $(>) ;
}
rule Hex
{
Depends $(<) : $(>) ;
MakeLocate $(<) : $(LOCATE_TARGET) ;
Depends hex : $(<) ;
Clean clean : $(<) ;
}
actions Hex
{
$(OBJCOPY) -O ihex -R .eeprom $(>) $(<)
}
rule Upload
{
Depends $(1) : $(2) ;
Depends $(2) : $(3) ;
NotFile $(1) ;
Always $(1) ;
Always $(2) ;
UploadAction $(2) : $(3) ;
}
actions UploadAction
{
$(AVRDUDE) $(AVRDUDEFLAGS) -P $(<) $(AVRDUDE_WRITE_FLASH) -U flash:w:$(>):i
}
rule Arduino
{
LINKFLAGS on $(<) = $(LINKFLAGS) -Wl,-Map=$(LOCATE_TARGET)/$(<:B).map ;
Main $(<) : $(>) ;
LinkLibraries $(<) : core libs ;
Hex $(<:B).hex : $(<) ;
for _p in $(PORTS)
{
Upload $(_p) : $(PORT_$(_p)) : $(<:B).hex ;
}
}
#
# Targets
#
# Grab everything from the core directory
Library core : [ GLOB $(ARDUINO_CORE) : *.c *.cpp ] ;
# Grab everything from libraries. To avoid this "grab everything" behaviour, you
# can specify specific modules to pick up in PROJECT_MODULES
Library libs : [ GLOB $(ARDUINO_LIB)/$(PROJECT_LIBS) $(ARDUINO_LIB)/$(PROJECT_LIBS)/utility $(SKETCH_LIB)/$(PROJECT_LIBS) : *.cpp *.c ] ;
# Main output executable
Arduino $(PWD:B).elf : $(PROJECT_MODULES) [ GLOB $(PROJECT_DIRS) : *.c *.cpp *.pde *.ino ] ;
@@ -0,0 +1,435 @@
/*
Copyright (C) 2011 James Coliz, Jr. <maniacbug@ymail.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
*/
/**
* Full test on single RF pair
*
* This sketches uses as many RF24 methods as possible in a single test.
*
* To operate:
* Upload this sketch on two nodes, each with IRQ -> pin 2
* One node needs pin 7 -> GND, the other NC. That's the receiving node
* Monitor the sending node's serial output
* Look for "+OK PASS" or "+OK FAIL"
*/
#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"
#include "printf.h"
//
// Hardware configuration
//
// Set up nRF24L01 radio on SPI bus plus pins 8 & 9
RF24 radio(7,8);
// sets the role of this unit in hardware. Connect to GND to be the 'pong' receiver
// Leave open to be the 'ping' transmitter
const short role_pin = 5;
//
// 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);
//
// Payload
//
const int min_payload_size = 4;
const int max_payload_size = 32;
int payload_size_increments_by = 2;
int next_payload_size = min_payload_size;
char receive_payload[max_payload_size+1]; // +1 to allow room for a terminating NULL char
//
// 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 */
uint8_t pipe_number = 1; // Which pipe to send on.
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;
}
}
//
// Setup
//
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/tests/pingpair_test/\n\r");
printf("ROLE: %s\n\r",role_friendly_name[role]);
//
// Read configuration from serial
//
// It would be a much better test if this program could accept configuration
// from the serial port. Then it would be possible to run the same test under
// lots of different circumstances.
//
// The idea is that we will print "+READY" at this point. The python script
// will wait for it, and then send down a configuration script that we
// execute here and then run with.
//
// The test controller will need to configure the receiver first, then go run
// the test on the sender.
//
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();
// We will be using the Ack Payload feature, so please enable it
radio.enableAckPayload();
// Config 2 is special radio config
if (configuration=='2')
{
radio.setCRCLength(RF24_CRC_8);
radio.setDataRate(RF24_250KBPS);
radio.setChannel(10);
}
else
{
//Otherwise, default radio config
// Optional: Increase CRC length for improved reliability
radio.setCRCLength(RF24_CRC_16);
// Optional: Decrease data rate for improved reliability
radio.setDataRate(RF24_1MBPS);
// Optional: Pick a high channel
radio.setChannel(90);
}
// Config 3 is static payloads only
if (configuration == '3')
{
next_payload_size = 16;
payload_size_increments_by = 0;
radio.setPayloadSize(next_payload_size);
}
else
{
// enable dynamic payloads
radio.enableDynamicPayloads();
}
// Config 4 tests out a higher pipe ##
if (configuration == '4' && role == role_sender)
{
// Set top 4 bytes of the address in pipe 1
radio.openReadingPipe(1,pipe & 0xFFFFFFFF00ULL);
// indicate the pipe to use
pipe_number = 5;
}
else if ( role == role_sender )
{
radio.openReadingPipe(5,0);
}
//
// 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(pipe_number,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);
delay(50);
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
//
static uint32_t message_count = 0;
static uint32_t last_message_count = 0;
void loop(void)
{
//
// Sender role. Repeatedly send the current time
//
if (role == role_sender && !done)
{
// The payload will always be the same, what will change is how much of it we send.
static char send_payload[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ789012";
// First, stop listening so we can talk.
radio.stopListening();
// Send it. This will block until complete
printf("\n\rNow sending length %i...",next_payload_size);
radio.startWrite( send_payload, next_payload_size,0 );
// Update size for next time.
next_payload_size += payload_size_increments_by;
if ( next_payload_size > max_payload_size )
next_payload_size = min_payload_size;
// Try again soon
delay(interval);
// Timeout if we have not received anything back ever
if ( ! last_message_count && millis() > interval * 100 )
{
printf("No responses received. Are interrupts connected??\n\r");
done = true;
}
}
//
// 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<uint8_t*>(prbuf_out),write_length);
prbuf_out += write_length;
}
//
// 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");
}
}
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 )
prbuf_in += sprintf(prbuf_in,"Send:OK ");
if ( role == role_receiver )
prbuf_in += sprintf(prbuf_in,"Ack Payload:Sent\n\r");
}
// Have we failed to transmit?
if ( fail )
{
if ( role == role_sender )
{
prbuf_in += sprintf(prbuf_in,"Send:Failed ");
// log status of this line
one_failed();
}
if ( role == role_receiver )
prbuf_in += sprintf(prbuf_in,"Ack Payload:Failed\n\r");
}
// Not powering down since radio is in standby mode
//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));
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 ) )
{
prbuf_in += sprintf(prbuf_in,"OK ");
one_ok();
}
else
{
prbuf_in += sprintf(prbuf_in,"FAILED ");
one_failed();
}
last_message_count = message_count;
}
// If we're the receiver, we've received a time message
if ( role == role_receiver )
{
// Get this payload and dump it
size_t len = max_payload_size;
memset(receive_payload,0,max_payload_size);
if ( configuration == '3' ){
len = next_payload_size;
}else{
len = radio.getDynamicPayloadSize();
}
radio.read( receive_payload, len );
// Put a zero at the end for easy printing
receive_payload[len] = 0;
// Spew it
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.
radio.writeAckPayload( pipe_number, &len, sizeof(len) );
++message_count;
}
}
}
@@ -0,0 +1,37 @@
/*
Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
*/
/**
* @file printf.h
*
* Setup necessary to direct stdout to the Arduino Serial library, which
* enables 'printf'
*/
#ifndef __PRINTF_H__
#define __PRINTF_H__
#ifdef ARDUINO
int serial_putc( char c, FILE * )
{
Serial.write( c );
return c;
}
void printf_begin(void)
{
fdevopen( &serial_putc, 0 );
}
#else
#error This example is only for use on Arduino.
#endif // ARDUINO
#endif // __PRINTF_H__
+25
View File
@@ -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)
+21
View File
@@ -0,0 +1,21 @@
#!/bin/sh
# Connect u0 to receiver, u0 to sender
# WARNING: Test config 2 only works with PLUS units.
jam u0 u1 && expect test.ex 1
sleep 1
stty 57600 raw ignbrk hup < /dev/ttyUSB0
sleep 1
stty 57600 raw ignbrk hup < /dev/ttyUSB1
expect test.ex 2
sleep 1
stty 57600 raw ignbrk hup < /dev/ttyUSB0
sleep 1
stty 57600 raw ignbrk hup < /dev/ttyUSB1
expect test.ex 3
sleep 1
stty 57600 raw ignbrk hup < /dev/ttyUSB0
sleep 1
stty 57600 raw ignbrk hup < /dev/ttyUSB1
expect test.ex 4
+11
View File
@@ -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"
+41
View File
@@ -0,0 +1,41 @@
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text" standalone="yes" />
<xsl:template match="/">
<xsl:apply-templates select="//sectiondef[@kind='public-func']/memberdef[@kind='function']" />
</xsl:template>
<xsl:template match="memberdef">
<!-- xsl:text>&#xA;=== </xsl:text><xsl:value-of select="definition"/> <xsl:value-of select="argsstring"/><xsl:text> ===&#xA;</xsl:text -->
<xsl:text>&#xA;=== </xsl:text><xsl:value-of select="name"/><xsl:text> ===&#xA;&#xA;</xsl:text>
<xsl:apply-templates select="briefdescription"/>
<xsl:if test="count(detaileddescription/para[not(./*)]) &lt; 1"><xsl:text>&#xA;</xsl:text></xsl:if>
<xsl:apply-templates select="detaileddescription"/>
</xsl:template>
<xsl:template match="briefdescription/para">''<xsl:value-of select="."/>'' </xsl:template>
<xsl:template match="detaileddescription/para/parameterlist">
Parameters:
<xsl:apply-templates select="parameteritem"/>
</xsl:template>
<xsl:template match="parameteritem">* ''<xsl:value-of select="parameternamelist/parametername"/>'': <xsl:value-of select="parameterdescription/para"/><xsl:text>&#xA;</xsl:text>
</xsl:template>
<xsl:template match="detaileddescription/para[not(./*)]">
<xsl:value-of select="."/><xsl:text>&#xA;</xsl:text>
</xsl:template>
<xsl:template match="detaileddescription/para/simplesect[@kind='return']/para">
Returns:
* <xsl:value-of select="."/><xsl:text>&#xA;</xsl:text>
</xsl:template>
<xsl:template match="detaileddescription/para/simplesect[@kind='warning']/para">
Warning: <xsl:value-of select="."/><xsl:text>&#xa;</xsl:text>
</xsl:template>
<xsl:template match="detaileddescription/para/programlisting">
<xsl:text>&#xa;&lt;pre&gt;&#xa;</xsl:text><xsl:apply-templates select="codeline"/><xsl:text>&lt;/pre&gt;&#xa;</xsl:text>
</xsl:template>
<xsl:template match="codeline">
<xsl:value-of select="."/><xsl:text>&#xa;</xsl:text>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>